bc2a2ea1dcf030b6a8452678a56089b160488875
[cascardo/rnetclient.git] / decfile.c
1 /*
2  *  Copyright (C) 2012-2014  Thadeu Lima de Souza Cascardo <cascardo@minaslivre.org>
3  *  Copyright (C) 2014  Alexandre Oliva <lxoliva@fsfla.org>
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19
20 #define _GNU_SOURCE
21 #include "decfile.h"
22 #include <string.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <errno.h>
26 #include <unistd.h>
27 #include <gcrypt.h>
28 #include "pmhash.h"
29 #include "rnet_message.h"
30
31 #ifndef MAX
32 #define MAX(a,b) (a >= b) ? a : b
33 #endif
34
35 struct rnet_decfile {
36         char *filename;
37         FILE *file;
38         char **lines;
39         int lines_len;
40         struct pmhash *header;
41         struct rnet_message *message;
42 };
43
44 /*
45  * line should be an allocated buffer given to append_line
46  * this means, free(line) will be called when decfile is released
47  */
48 static int append_line(struct rnet_decfile *decfile, char *line)
49 {
50         size_t len;
51         char **old_lines;
52         decfile->lines_len += 1;
53         len = sizeof(*decfile->lines) * decfile->lines_len;
54         old_lines = decfile->lines;
55         decfile->lines = realloc(decfile->lines, len);
56         if (!decfile->lines) {
57                 decfile->lines = old_lines;
58                 goto out;
59         }
60         decfile->lines[decfile->lines_len - 1] = line;
61         return 0;
62 out:
63         decfile->lines_len -= 1;
64         return -ENOMEM;
65 }
66
67 static void decfile_release_lines(struct rnet_decfile *decfile)
68 {
69         int i;
70         for (i = 0; i < decfile->lines_len; i++)
71                 free(decfile->lines[i]);
72         free(decfile->lines);
73         decfile->lines = NULL;
74 }
75
76 static char * get_header(struct rnet_decfile *decfile);
77 static int parse_header_common(struct pmhash *hash, char **buffer);
78 static int parse_header_2013(struct pmhash *hash, char *buffer);
79 static int parse_header_2014(struct pmhash *hash, char *buffer);
80 static int parse_header_2015(struct pmhash *hash, char *buffer);
81 static int decfile_parse_file(struct rnet_decfile *decfile);
82
83 static int decfile_parse_header(struct rnet_decfile *decfile)
84 {
85         char *buffer;
86         int r;
87         char *p;
88
89         p = buffer = get_header(decfile);
90         if (!buffer)
91                 return -EINVAL;
92
93         r = parse_header_common(decfile->header, &p);
94         if (r)
95                 return r;
96
97         switch (strlen(buffer)) {
98         case RNET_HEADER_SIZE_2013:
99                 return parse_header_2013(decfile->header, p);
100         case RNET_HEADER_SIZE_2014:
101                 return parse_header_2014(decfile->header, p);
102         case RNET_HEADER_SIZE_2015:
103                 return parse_header_2015(decfile->header, p);
104         default:
105                 fprintf(stderr, "Unknown file version, but proceeding anyway.\n");
106         }
107         return 0;
108 }
109
110 static int decfile_parse(struct rnet_decfile *decfile)
111 {
112         char *buffer = NULL;
113         size_t len = 0;
114         int r;
115         while ((r = getline(&buffer, &len, decfile->file)) > 0) {
116                 r = append_line(decfile, buffer);
117                 if (r) {
118                         free(buffer);
119                         goto out;
120                 }
121                 buffer = NULL;
122                 len = 0;
123         }
124         if (!(r = decfile_parse_header(decfile)) && !(r = decfile_parse_file(decfile)))
125                 return 0;
126 out:
127         decfile_release_lines(decfile);
128         return r;
129 }
130
131 struct rnet_decfile * rnet_decfile_open(char *filename)
132 {
133         struct rnet_decfile *decfile;
134         int r = -ENOMEM;
135         decfile = malloc(sizeof(*decfile));
136         if (!decfile)
137                 return NULL;
138         decfile->header = pmhash_new();
139         if (!decfile->header)
140                 goto out_header;
141         decfile->message = rnet_message_new();
142         if (!decfile->message)
143                 goto out_message;
144         decfile->filename = strdup(filename);
145         if (!decfile->filename)
146                 goto out_filename;
147         decfile->file = fopen(filename, "r");
148         if (!decfile->file)
149                 goto out_file;
150         decfile->lines_len = 0;
151         decfile->lines = NULL;
152         if ((r = decfile_parse(decfile)))
153                 goto out_parse;
154         return decfile;
155 out_parse:
156         fclose(decfile->file);
157 out_file:
158         free(decfile->filename);
159 out_filename:
160         rnet_message_del(decfile->message);
161 out_message:
162         pmhash_del(decfile->header);
163 out_header:
164         free(decfile);
165         errno = -r;
166         return NULL;
167 }
168
169 void rnet_decfile_close(struct rnet_decfile *decfile)
170 {
171         decfile_release_lines(decfile);
172         fclose(decfile->file);
173         free(decfile->filename);
174         free(decfile);
175 }
176
177 static char * get_header(struct rnet_decfile *decfile)
178 {
179         int i;
180         for (i = 0; i < decfile->lines_len; i++) {
181                 if (!strncmp(decfile->lines[i], "IRPF", 4)) {
182                         return decfile->lines[i];
183                 }
184         }
185         return NULL;
186 }
187
188 #define parse(field, sz) \
189         r = -ENOMEM; \
190         val = malloc(sz + 1); \
191         if (!val) \
192                 goto out_val; \
193         val[sz] = 0; \
194         memcpy(val, p, sz); \
195         p += sz; \
196         key = strdup(field); \
197         if (!key) \
198                 goto out_key; \
199         if (pmhash_add(&hash, key, val)) \
200                 goto out_add;
201
202 static int parse_header_common(struct pmhash *hash, char **buffer)
203 {
204         int r;
205         char *p = *buffer;
206         char *key;
207         char *val;
208
209         parse("sistema", 8);
210         parse("exerc", 4);
211         parse("ano", 4);
212         parse("codigo_recnet", 4);
213         parse("in_ret", 1);
214         parse("cpf", 11);
215         parse("filler", 3);
216         parse("tipo_ni", 1);
217         parse("nr_versao", 3);
218         parse("nome", 60);
219         parse("uf", 2);
220         parse("hash", 10);
221
222         if (p - *buffer != RNET_HEADER_HEAD_COMMON) {
223                 fprintf(stderr, "RNET_HEADER_HEAD_COMMON in decfile.h needs to be adjusted to %ti\n", p - *buffer);
224                 goto out_val;
225         }
226
227         *buffer = p;
228
229         return 0;
230 out_add:
231         free(key);
232 out_key:
233         free(val);
234 out_val:
235         return r;
236 }
237
238 static int parse_header_2015(struct pmhash *hash, char *buffer)
239 {
240         int r;
241         char *p = buffer;
242         char *key;
243         char *val;
244         char *tail;
245         char *exerc;
246
247         exerc = pmhash_get(hash, "exerc");
248         if (strcmp(exerc, "2015")) {
249                 r = -EINVAL;
250                 goto out_val;
251         }
252
253         parse("in_cert", 1);
254         parse("dt_nasc", 8);
255         parse("in_comp", 1);
256         parse("in_res", 1);
257         parse("in_gerada", 1);
258         parse("nr_recibo_anterior", 10);
259         parse("in_pgd", 1);
260         parse("so", 14);
261         parse("versao_so", 7);
262         parse("jvm", 9);
263         parse("nr_recibo", 10);
264         parse("municipio", 4);
265         parse("conjuge", 11);
266         parse("obrig", 1);
267         parse("impdevido", 13);
268         parse("nr_recibo", 10);
269         parse("in_seg", 1);
270         parse("imppago", 2);
271         parse("impant", 1);
272         parse("mudend", 1);
273         parse("cep", 8);
274         parse("debito", 1);
275         parse("banco", 3);
276         parse("agencia", 4);
277         parse("filler", 1);
278         parse("data_julgado", 8);
279         parse("imppagar", 13);
280         parse("tribfonte", 1);
281         parse("cpfrra", 11);
282         parse("trib_rra", 1);
283         parse("cpf_rra2", 11);
284         parse("trib_3rra", 1);
285         parse("cpf_rra3", 11);
286         parse("trib_4rra", 1);
287         parse("cpf_rra4", 11);
288         parse("vr_doacao", 13);
289         parse("cnpj1", 14);
290         parse("cnpj2", 14);
291         parse("cnpj3", 14);
292         parse("cnpj4", 14);
293         parse("cpf_dep1", 11);
294         parse("dnas_dep1", 8);
295         parse("cpf_dep2", 11);
296         parse("dnas_dep2", 8);
297         parse("cpf_dep3", 11);
298         parse("dnas_dep3", 8);
299         parse("cpf_dep4", 11);
300         parse("dnas_dep4", 8);
301         parse("cpf_dep5", 11);
302         parse("dnas_dep5", 8);
303         parse("cpf_dep6", 11);
304         parse("dnas_dep6", 8);
305         parse("cnpj_med1", 14);
306         parse("cnpj_med2", 14);
307         parse("cpf_alim", 11);
308         parse("cpf_invent", 11);
309         parse("municipio", 40);
310         parse("contribuinte", 60);
311         parse("filler", 11);
312         parse("mac", 12);
313         parse("data_nao_residente", 8);
314         parse("cpf_procurador", 11);
315         parse("obrigatoriedade", 3);
316         parse("rendtrib", 13);
317         parse("cnpj_prev", 14);
318         parse("cnpj_prev2", 14);
319         parse("vr_totisentos", 13);
320         parse("vr_totexclusivo", 13);
321         parse("vr_totpagamentos", 13);
322         parse("nr_conta", 13);
323         parse("nr_dv_conta", 2);
324         parse("in_dv_conta", 1);
325
326         parse("codnaturezaocup", 2);
327         parse("cpfdomestic@", 11);
328         parse("nitdomestic@", 11);
329         parse("cpfdomestic@2", 11);
330         parse("nitdomestic@2", 11);
331         parse("cpfdomestic@3", 11);
332         parse("nitdomestic@3", 11);
333         parse("deciniciada", 1);
334         parse("utilpgd", 1);
335         parse("utilapp", 1);
336         parse("utilonline", 1);
337         parse("utilrascunho", 1);
338         parse("utilprepreenchida", 1);
339         parse("utilfontes", 1);
340         parse("utilplanosaude", 1);
341         parse("utilrecuperar", 1);
342         parse("dectransmitida", 1);
343         tail = p;
344
345         parse("versaotestpgd", 3);
346         parse("controle", 10);
347
348         if (*p++ != '\r') {
349                 fprintf(stderr,
350                         "missing CR at the %tith header character\n",
351                         p - buffer);
352                 goto out_val;
353         } else if (*p++ != '\n') {
354                 fprintf(stderr,
355                         "missing LF at the %tith header character\n",
356                         p - buffer);
357                 goto out_val;
358         } else if (*p != 0) {
359                 fprintf(stderr,
360                         "missing NUL at the %tith header character\n",
361                         p - buffer);
362                 goto out_val;
363         } else if (p - buffer != RNET_HEADER_SIZE_2015) {
364                 fprintf(stderr, "RNET_HEADER_SIZE_2015 in decfile.h needs to be adjusted to %ti,\nor parse_header in decfile.c needs updating\n", p - buffer);
365                 goto out_val;
366         } else if (p - tail != RNET_HEADER_TAIL_COMMON) {
367                 fprintf(stderr, "RNET_HEADER_TAIL_COMMON in decfile.h needs to be adjusted to %ti\n", p - tail);
368                 goto out_val;
369         }
370
371         return 0;
372 out_add:
373         free(key);
374 out_key:
375         free(val);
376 out_val:
377         return r;
378 }
379
380 static int parse_header_2014(struct pmhash *hash, char *buffer)
381 {
382         int r;
383         char *p = buffer;
384         char *key;
385         char *val;
386         char *tail;
387         char *exerc;
388
389         exerc = pmhash_get(hash, "exerc");
390         if (strcmp(exerc, "2014")) {
391                 r = -EINVAL;
392                 goto out_val;
393         }
394
395         parse("in_cert", 1);
396         parse("dt_nasc", 8);
397         parse("in_comp", 1);
398         parse("in_res", 1);
399         parse("in_gerada", 1);
400         parse("nr_recibo_anterior", 10);
401         parse("in_pgd", 1);
402         parse("so", 14);
403         parse("versao_so", 7);
404         parse("jvm", 9);
405         parse("nr_recibo", 10);
406         parse("municipio", 4);
407         parse("conjuge", 11);
408         parse("obrig", 1);
409         parse("impdevido", 13);
410         parse("nr_recibo", 10);
411         parse("in_seg", 1);
412         parse("imppago", 2);
413         parse("impant", 1);
414         parse("mudend", 1);
415         parse("cep", 8);
416         parse("debito", 1);
417         parse("banco", 3);
418         parse("agencia", 4);
419         parse("filler", 1);
420         parse("data_julgado", 8);
421         parse("imppagar", 13);
422         parse("tribfonte", 1);
423         parse("cpfrra", 11);
424         parse("trib_rra", 1);
425         parse("cpf_rra2", 11);
426         parse("trib_3rra", 1);
427         parse("cpf_rra3", 11);
428         parse("trib_4rra", 1);
429         parse("cpf_rra4", 11);
430         parse("vr_doacao", 13);
431         parse("cnpj1", 14);
432         parse("cnpj2", 14);
433         parse("cnpj3", 14);
434         parse("cnpj4", 14);
435         parse("cpf_dep1", 11);
436         parse("dnas_dep1", 8);
437         parse("cpf_dep2", 11);
438         parse("dnas_dep2", 8);
439         parse("cpf_dep3", 11);
440         parse("dnas_dep3", 8);
441         parse("cpf_dep4", 11);
442         parse("dnas_dep4", 8);
443         parse("cpf_dep5", 11);
444         parse("dnas_dep5", 8);
445         parse("cpf_dep6", 11);
446         parse("dnas_dep6", 8);
447         parse("cnpj_med1", 14);
448         parse("cnpj_med2", 14);
449         parse("cpf_alim", 11);
450         parse("cpf_invent", 11);
451         parse("municipio", 40);
452         parse("contribuinte", 60);
453         parse("cpf_empregada", 11);
454         parse("hashcode", 12);
455         parse("data_nao_residente", 8);
456         parse("cpf_procurador", 11);
457         parse("obrigatoriedade", 3);
458         parse("rendtrib", 13);
459         parse("cnpj_prev", 14);
460         parse("cnpj_prev2", 14);
461         parse("vr_totisentos", 13);
462         parse("vr_totexclusivo", 13);
463         parse("vr_totpagamentos", 13);
464         parse("nr_conta", 13);
465         parse("nr_dv_conta", 2);
466         parse("in_dv_conta", 1);
467
468         tail = p;
469
470         parse("versaotestpgd", 3);
471         parse("controle", 10);
472
473         if (*p++ != '\r') {
474                 fprintf(stderr,
475                         "missing CR at the %tith header character\n",
476                         p - buffer);
477                 goto out_val;
478         } else if (*p++ != '\n') {
479                 fprintf(stderr,
480                         "missing LF at the %tith header character\n",
481                         p - buffer);
482                 goto out_val;
483         } else if (*p != 0) {
484                 fprintf(stderr,
485                         "missing NUL at the %tith header character\n",
486                         p - buffer);
487                 goto out_val;
488         } else if (p - buffer != RNET_HEADER_SIZE_2014) {
489                 fprintf(stderr, "RNET_HEADER_SIZE_2014 in decfile.h needs to be adjusted to %ti,\nor parse_header in decfile.c needs updating\n", p - buffer);
490                 goto out_val;
491         } else if (p - tail != RNET_HEADER_TAIL_COMMON) {
492                 fprintf(stderr, "RNET_HEADER_TAIL_COMMON in decfile.h needs to be adjusted to %ti\n", p - tail);
493                 goto out_val;
494         }
495
496         return 0;
497 out_add:
498         free(key);
499 out_key:
500         free(val);
501 out_val:
502         return r;
503 }
504
505 static int parse_header_2013(struct pmhash *hash, char *buffer)
506 {
507         int r;
508         char *p = buffer;
509         char *key;
510         char *val;
511         char *tail;
512         char *exerc;
513
514         exerc = pmhash_get(hash, "exerc");
515         if (strcmp(exerc, "2013")) {
516                 r = -EINVAL;
517                 goto out_val;
518         }
519
520         parse("in_cert", 1);
521         parse("dt_nasc", 8);
522         parse("in_comp", 1);
523         parse("in_res", 1);
524         parse("in_gerada", 1);
525         parse("nr_recibo_anterior", 10);
526         parse("in_pgd", 1);
527         parse("so", 14);
528         parse("versao_so", 7);
529         parse("jvm", 9);
530         parse("nr_recibo", 10);
531         parse("municipio", 4);
532         parse("conjuge", 11);
533         parse("obrig", 1);
534         parse("impdevido", 13);
535         parse("nr_recibo", 10);
536         parse("in_seg", 1);
537         parse("imppago", 2);
538         parse("impant", 1);
539         parse("mudend", 1);
540         parse("cep", 8);
541         parse("debito", 1);
542         parse("banco", 3);
543         parse("agencia", 4);
544         parse("filler", 1);
545         parse("data_julgado", 8);
546         parse("imppagar", 13);
547         parse("tribfonte", 1);
548         parse("cpfrra", 11);
549         parse("trib_rra", 1);
550         parse("cpf_rra2", 11);
551         parse("trib_3rra", 1);
552         parse("cpf_rra3", 11);
553         parse("vr_doacao", 13);
554         parse("cnpj1", 14);
555         parse("cnpj2", 14);
556         parse("cnpj3", 14);
557         parse("cnpj4", 14);
558         parse("cpf_dep1", 11);
559         parse("dnas_dep1", 8);
560         parse("cpf_dep2", 11);
561         parse("dnas_dep2", 8);
562         parse("cpf_dep3", 11);
563         parse("dnas_dep3", 8);
564         parse("cpf_dep4", 11);
565         parse("dnas_dep4", 8);
566         parse("cpf_dep5", 11);
567         parse("dnas_dep5", 8);
568         parse("cpf_dep6", 11);
569         parse("dnas_dep6", 8);
570         parse("cnpj_med1", 14);
571         parse("cnpj_med2", 14);
572         parse("cpf_alim", 11);
573         parse("cpf_invent", 11);
574         parse("municipio", 40);
575         parse("contribuinte", 60);
576         parse("cpf_empregada", 11);
577         parse("hashcode", 12);
578         parse("data_nao_residente", 8);
579         parse("cpf_procurador", 11);
580         parse("obrigatoriedade", 3);
581         parse("rendtrib", 13);
582         parse("cnpj_prev", 14);
583         parse("cnpj_prev2", 14);
584         parse("vr_totisentos", 13);
585         parse("vr_totexclusivo", 13);
586         parse("vr_totpagamentos", 13);
587
588         tail = p;
589
590         parse("versaotestpgd", 3);
591         parse("controle", 10);
592
593         if (*p++ != '\r') {
594                 fprintf(stderr,
595                         "missing CR at the %tith header character\n",
596                         p - buffer);
597                 goto out_val;
598         } else if (*p++ != '\n') {
599                 fprintf(stderr,
600                         "missing LF at the %tith header character\n",
601                         p - buffer);
602                 goto out_val;
603         } else if (*p != 0) {
604                 fprintf(stderr,
605                         "missing NUL at the %tith header character\n",
606                         p - buffer);
607                 goto out_val;
608         } else if (p - buffer != RNET_HEADER_SIZE_2013) {
609                 fprintf(stderr, "RNET_HEADER_SIZE_2013 in decfile.h needs to be adjusted to %ti,\nor parse_header in decfile.c needs updating\n", p - buffer);
610                 goto out_val;
611         } else if (p - tail != RNET_HEADER_TAIL_COMMON) {
612                 fprintf(stderr, "RNET_HEADER_TAIL_COMMON in decfile.h needs to be adjusted to %ti\n", p - tail);
613                 goto out_val;
614         }
615
616         return 0;
617 out_add:
618         free(key);
619 out_key:
620         free(val);
621 out_val:
622         return r;
623 }
624
625 #undef parse
626
627 char *rnet_decfile_get_header_field(struct rnet_decfile *decfile, char *field)
628 {
629         return pmhash_get(decfile->header, field);
630 }
631
632 /* returns true if register is declaration and not a receipt */
633 static int decfile_reg_is_dec(char *line)
634 {
635         if (line[0] >= '0' && line[0] <= '9' &&
636             line[1] >= '0' && line[1] <= '9')
637                 return 1;
638         if (!strncmp(line, "IRPF    ", 8))
639                 return 1;
640         if (!strncmp(line, "T9", 2))
641                 return 1;
642         return 0;
643 }
644
645 /* strip a register from its control number and append it to message */
646 static int append_stripped_reg_ctrl(struct rnet_message **message, char *line)
647 {
648         size_t len;
649         struct rnet_message *msg = *message;
650         int growth;
651         if (!decfile_reg_is_dec(line))
652                 return 0;
653         len = strlen(line);
654         if (len < 12)
655                 return -EINVAL;
656         growth = msg->len + len - 10 - msg->alen;
657         if (growth > 0) {
658                 if (rnet_message_expand(message, growth))
659                         return -ENOMEM;
660                 msg = *message;
661         }
662         memcpy(&msg->buffer[msg->len], line, len - 12);
663         msg->buffer[msg->len + len - 12] = '\r';
664         msg->buffer[msg->len + len - 11] = '\n';
665         msg->len += len - 10;
666         return 0;
667 }
668
669 static int decfile_parse_file(struct rnet_decfile *decfile)
670 {
671         int i;
672         int r;
673         for (i = 0; i < decfile->lines_len; i++) {
674                 r = append_stripped_reg_ctrl(&decfile->message,
675                                                 decfile->lines[i]);
676                 if (r)
677                         return r;
678         }
679         return 0;
680 }
681
682 struct rnet_message * rnet_decfile_get_file(struct rnet_decfile *decfile)
683 {
684         return decfile->message;
685 }
686
687 char * rnet_decfile_get_file_hash(struct rnet_decfile *decfile)
688 {
689         char *hash;
690         size_t len;
691         if (gcry_md_test_algo(GCRY_MD_MD5))
692                 return NULL;
693         len = gcry_md_get_algo_dlen(GCRY_MD_MD5);
694         hash = malloc(len);
695         if (!hash)
696                 return NULL;
697         gcry_md_hash_buffer(GCRY_MD_MD5, hash, decfile->message->buffer,
698                                         decfile->message->len);
699         return hash;
700 }
701
702 char * rnet_decfile_get_header(struct rnet_decfile *decfile)
703 {
704         return get_header(decfile);
705 }