]> git.deb.at Git - pkg/abook.git/blob - filter.c
fixed string truncation in mutt inport filter
[pkg/abook.git] / filter.c
1
2 /*
3  * $Id$
4  *
5  * by JH <jheinonen@users.sourceforge.net>
6  *
7  * Copyright (C) Jaakko Heinonen
8  */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ctype.h>
14 #include <pwd.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include "abook_curses.h"
18 #include "filter.h"
19 #include "abook.h"
20 #include "database.h"
21 #include "edit.h"
22 #include "list.h"
23 #include "misc.h"
24 #include "options.h"
25 #include <assert.h>
26
27 extern int items;
28 extern list_item *database;
29 extern struct abook_field abook_fields[];
30
31 /*
32  * function declarations
33  */
34
35 /*
36  * import filter prototypes
37  */
38
39 static int      ldif_parse_file(FILE *handle);
40 static int      mutt_parse_file(FILE *in);
41 static int      pine_parse_file(FILE *in);
42 static int      csv_parse_file(FILE *in);
43
44 /*
45  * export filter prototypes
46  */
47
48 static int      ldif_export_database(FILE *out, struct db_enumerator e);
49 static int      html_export_database(FILE *out, struct db_enumerator e);
50 static int      pine_export_database(FILE *out, struct db_enumerator e);
51 static int      csv_export_database(FILE *out, struct db_enumerator e);
52 static int      palm_export_database(FILE *out, struct db_enumerator e);
53 static int      gcrd_export_database(FILE *out, struct db_enumerator e);
54 static int      mutt_alias_export(FILE *out, struct db_enumerator e);
55 static int      elm_alias_export(FILE *out, struct db_enumerator e);
56 static int      text_export_database(FILE *out, struct db_enumerator e);
57 static int      spruce_export_database(FILE *out, struct db_enumerator e);
58
59 /*
60  * end of function declarations
61  */
62
63 struct abook_input_filter i_filters[] = {
64         { "abook", "abook native format", parse_database },
65         { "ldif", "ldif / Netscape addressbook", ldif_parse_file },
66         { "mutt", "mutt alias", mutt_parse_file },
67         { "pine", "pine addressbook", pine_parse_file },
68         { "csv", "comma separated values", csv_parse_file },
69         { "\0", NULL, NULL }
70 };
71
72 struct abook_output_filter e_filters[] = {
73         { "abook", "abook native format", write_database },
74         { "ldif", "ldif / Netscape addressbook (.4ld)", ldif_export_database },
75         { "mutt", "mutt alias", mutt_alias_export },
76         { "html", "html document", html_export_database },
77         { "pine", "pine addressbook", pine_export_database },
78         { "gcrd", "GnomeCard (VCard) addressbook", gcrd_export_database },
79         { "csv", "comma separated values", csv_export_database },
80         { "palmcsv", "Palm comma separated values", palm_export_database},
81         { "elm", "elm alias", elm_alias_export },
82         { "text", "plain text", text_export_database },
83         { "spruce", "Spruce address book", spruce_export_database },
84         { "\0", NULL, NULL }
85 };
86
87 /*
88  * common functions
89  */
90
91 void
92 print_filters()
93 {
94         int i;
95         
96         puts("input:");
97         for(i=0; *i_filters[i].filtname ; i++)
98                 printf("\t%s\t%s\n", i_filters[i].filtname,
99                         i_filters[i].desc);
100
101         putchar('\n');
102         
103         puts("output:");
104         for(i=0; *e_filters[i].filtname ; i++)
105                 printf("\t%s\t%s\n", e_filters[i].filtname,
106                         e_filters[i].desc);
107
108         putchar('\n');
109 }
110
111 static int
112 number_of_output_filters()
113 {
114         int i;
115
116         for(i=0; *e_filters[i].filtname ; i++)
117                 ;
118
119         return i;
120 }
121
122 static int
123 number_of_input_filters()
124 {
125         int i;
126
127         for(i=0; *i_filters[i].filtname ; i++)
128                 ;
129
130         return i;
131 }
132
133 static char *
134 get_real_name()
135 {
136         char *username = getenv("USER");
137         struct passwd *pwent;
138         int rtn;
139         char *tmp;
140
141         pwent = getpwnam(username);
142
143         if((tmp = strdup(pwent->pw_gecos)) == NULL)
144                 return strdup(username);
145
146         rtn = sscanf(pwent->pw_gecos, "%[^,]", tmp);
147         if (rtn == EOF || rtn == 0) {
148                 free(tmp);
149                 return strdup(username);
150         } else
151                 return tmp;
152 }
153
154 /*
155  * import
156  */
157         
158 static int              i_read_file(char *filename, int (*func) (FILE *in));
159
160 static void
161 import_screen()
162 {
163         int i;
164         
165         clear();
166
167         refresh_statusline();
168         headerline("import database");
169
170         mvaddstr(3, 1, "please select a filter");
171         
172
173         for(i=0; *i_filters[i].filtname ; i++)
174                 mvprintw(5 + i, 6, "%c -\t%s\t%s\n", 'a' + i,
175                         i_filters[i].filtname,
176                         i_filters[i].desc);
177
178         mvprintw(6 + i, 6, "x -\tcancel");
179 }
180
181 int
182 import_database()
183 {
184         int filter;
185         char *filename;
186         int tmp = items;
187
188         import_screen();
189         
190         filter = getch() - 'a';
191         if(filter == 'x' - 'a' ||
192                 filter >= number_of_input_filters() || filter < 0) {
193                 refresh_screen();
194                 return 1;
195         }
196         
197         mvaddstr(5+filter, 2, "->");
198         
199         filename = ask_filename("Filename: ");
200         if( !filename ) {
201                 refresh_screen();
202                 return 2;
203         }
204                 
205         if(  i_read_file(filename, i_filters[filter].func ) )
206                 statusline_msg("Error occured while opening the file");
207         else if( tmp == items )
208                 statusline_msg("Hmm.., file seems not to be a valid file");
209         
210         refresh_screen();
211         free(filename);
212
213         return 0;
214 }
215
216
217
218 static int
219 i_read_file(char *filename, int (*func) (FILE *in))
220 {
221         FILE *in;
222         int ret = 0;
223
224         if( ( in = abook_fopen( filename, "r" ) ) == NULL )
225                 return 1;
226
227         ret = (*func) (in);
228
229         fclose(in);
230
231         return ret;     
232 }
233
234 int
235 import_file(char filtname[FILTNAME_LEN], char *filename)
236 {
237         int i;
238         int tmp = items;
239         int ret = 0;
240
241         for(i=0;; i++) {
242                 if( ! strncasecmp(i_filters[i].filtname, filtname,
243                                         FILTNAME_LEN) )
244                         break;
245                 if( ! *i_filters[i].filtname ) {
246                         i = -1;
247                         break;
248                 }
249         }
250
251         if( i<0 )
252                 return -1;
253
254         if( !strcmp(filename, "-") ) {
255                 struct stat s;
256                 if( (fstat(fileno(stdin), &s)) == -1 || S_ISDIR(s.st_mode))
257                         ret = 1;
258                 else
259                         ret = (*i_filters[i].func) (stdin);
260         } else
261                 ret =  i_read_file(filename, i_filters[i].func);
262         
263         if( tmp == items )
264                 ret = 1;
265         
266         return ret;
267 }
268
269 /*
270  * export
271  */
272
273 static int              e_write_file(char *filename,
274                 int (*func) (FILE *in, struct db_enumerator e), int mode);
275
276 static void
277 export_screen()
278 {
279         int i;
280         
281         clear();
282
283
284         refresh_statusline();
285         headerline("export database");
286
287         mvaddstr(3, 1, "please select a filter");
288         
289
290         for(i=0; *e_filters[i].filtname ; i++)
291                 mvprintw(5 + i, 6, "%c -\t%s\t%s\n", 'a' + i,
292                         e_filters[i].filtname,
293                         e_filters[i].desc);
294
295         mvprintw(6 + i, 6, "x -\tcancel");
296 }
297
298 int
299 export_database()
300 {
301         int filter;
302         int enum_mode = ENUM_ALL;
303         char *filename;
304
305         export_screen();
306         
307         filter = getch() - 'a';
308         if(filter == 'x' - 'a' ||
309                 filter >= number_of_output_filters() || filter < 0) {
310                 refresh_screen();
311                 return 1;
312         }
313         
314         mvaddstr(5+filter, 2, "->");
315
316         if( selected_items() ) {
317                 statusline_addstr("Export All/Selected/Cancel (A/s/c)");
318                 switch( tolower(getch()) ) {
319                         case 's':
320                                 enum_mode = ENUM_SELECTED;
321                                 break;
322                         case 'c':
323                                 clear_statusline();
324                                 return 1;
325                 }
326                 clear_statusline();
327         }
328         
329         filename = ask_filename("Filename: ");
330         if( !filename ) {
331                 refresh_screen();
332                 return 2;
333         }
334         
335         if(  e_write_file(filename, e_filters[filter].func, enum_mode ) )
336                 statusline_msg("Error occured while exporting");
337         
338         refresh_screen();
339         free(filename);
340
341         return 0;
342 }
343
344 static int
345 e_write_file(char *filename, int (*func) (FILE *in, struct db_enumerator e),
346                 int mode)
347 {
348         FILE *out;
349         int ret = 0;
350         struct db_enumerator enumerator = init_db_enumerator(mode);
351
352         if( (out = fopen(filename, "a")) == NULL )
353                 return 1;
354
355         if( ftell(out) )
356                 return 1;
357
358         ret = (*func) (out, enumerator);
359         
360         fclose(out);
361         
362         return ret;
363 }
364
365 int
366 fexport(char filtname[FILTNAME_LEN], FILE *handle, int enum_mode)
367 {
368         int i;
369         struct db_enumerator e = init_db_enumerator(enum_mode);
370
371         for(i=0;; i++) {
372                 if( ! strncasecmp(e_filters[i].filtname, filtname,
373                                         FILTNAME_LEN) )
374                         break;
375                 if( ! *e_filters[i].filtname ) {
376                         i = -1;
377                         break;
378                 }
379         }
380
381         return (e_filters[i].func) (handle, e);
382 }
383
384
385
386 int
387 export_file(char filtname[FILTNAME_LEN], char *filename)
388 {
389         const int mode = ENUM_ALL;
390         int i;
391         int ret = 0;
392         struct db_enumerator e = init_db_enumerator(mode);
393         
394         for(i=0;; i++) {
395                 if( ! strncasecmp(e_filters[i].filtname, filtname,
396                                         FILTNAME_LEN) )
397                         break;
398                 if( ! *e_filters[i].filtname ) {
399                         i = -1;
400                         break;
401                 }
402         }
403
404         if( i<0 )
405                 return -1;
406
407         if( !strcmp(filename, "-") )
408                 ret = (e_filters[i].func) (stdout, e);
409         else
410                 ret =  e_write_file(filename, e_filters[i].func, mode);
411
412         return ret;
413 }
414
415 /*
416  * end of common functions
417  */
418
419 /*
420  * ldif import
421  */
422
423 #include "ldif.h"
424
425 static void     ldif_fix_string(char *str);
426
427 #define LDIF_ITEM_FIELDS        16
428
429 typedef char*  ldif_item[LDIF_ITEM_FIELDS];
430
431 static ldif_item ldif_field_names = {
432         "cn",   
433         "mail",
434         "streetaddress",
435         "streetaddress2",
436         "locality",
437         "st",
438         "postalcode",
439         "countryname",
440         "homephone",
441         "description",
442         "homeurl",
443         "facsimiletelephonenumber",
444         "cellphone",
445         "xmozillaanyphone",
446         "xmozillanickname",
447         "objectclass", /* this must be the last entry */
448 };
449
450 static int ldif_conv_table[LDIF_ITEM_FIELDS] = {
451         NAME,           /* "cn" */
452         EMAIL,          /* "mail" */
453         ADDRESS,        /* "streetaddress" */
454         ADDRESS2,       /* "streetaddress2" */     
455         CITY,           /* "locality" */
456         STATE,          /* "st" */
457         ZIP,            /* "postalcode" */
458         COUNTRY,        /* "countryname" */
459         PHONE,          /* "homephone" */
460         NOTES,          /* "description" */
461         URL,            /* "homeurl" */
462         FAX,            /* "facsimiletelephonenumber" */
463         MOBILEPHONE,    /* "cellphone" */
464         WORKPHONE,      /* "xmozillaanyphone" */
465         NICK,           /* "xmozillanickname" */
466         -1,             /* "objectclass" */ /* this must be the last entry */
467 };
468
469
470 static char * 
471 ldif_read_line(FILE *in)
472 {
473         char *buf = NULL;
474         char *ptr, *tmp;
475         long pos;
476         int i;
477
478         for(i = 1;;i++) {
479                 char *line;
480
481                 pos = ftell(in);
482                 line = getaline(in);
483                 
484                 if( feof(in) || !line )
485                         break;
486                 
487                 if(i == 1) {
488                         buf = line;
489                         continue;
490                 }
491
492                 if(*line != ' ') {
493                         fseek(in, pos, SEEK_SET); /* fixme ! */
494                         free(line);
495                         break;
496                 }
497
498                 ptr = line;
499                 while( *ptr == ' ')
500                         ptr++;
501
502                 tmp = buf;
503                 buf = strconcat(buf, ptr, NULL);
504                 free(tmp);
505                 free(line);
506         }
507
508         if(buf && *buf == '#' ) {
509                 free(buf);
510                 return NULL;
511         }
512
513         return buf;
514 }
515
516 static void
517 ldif_add_item(ldif_item ldif_item)
518 {
519         list_item abook_item;
520         int i;
521
522         memset(abook_item, 0, sizeof(abook_item));
523
524         if( !ldif_item[LDIF_ITEM_FIELDS -1] )
525                 goto bail_out;
526
527
528         for(i=0; i < LDIF_ITEM_FIELDS; i++) {
529                 if(ldif_conv_table[i] >= 0 && ldif_item[i] && *ldif_item[i] )
530                         abook_item[ldif_conv_table[i]] = strdup(ldif_item[i]);
531         }
532
533         add_item2database(abook_item);
534
535 bail_out:
536         for(i=0; i < LDIF_ITEM_FIELDS; i++)
537                 my_free(ldif_item[i]);
538
539 }
540
541 static void
542 ldif_convert(ldif_item item, char *type, char *value)
543 {
544         int i;
545
546         if( !strcmp(type, "dn") ) {
547                 ldif_add_item(item);
548                 return;
549         }
550
551         for(i=0; i < LDIF_ITEM_FIELDS; i++) {
552                 if( !safe_strcmp(ldif_field_names[i], type) && *value ) {
553                         if( i == LDIF_ITEM_FIELDS -1) /* this is a dirty hack */
554                                 if( safe_strcmp("person", value))
555                                         break;
556                         if(item[i])
557                                 my_free(item[i]);
558                         item[i] = strdup(value);
559                 }
560         }
561 }
562
563 static int
564 ldif_parse_file(FILE *handle)
565 {
566         char *line = NULL;
567         char *type, *value;
568         int vlen;
569         ldif_item item;
570
571         memset(item, 0, sizeof(item));
572
573         do {
574                 if( ! (line = ldif_read_line(handle)) )
575                         continue;
576
577                 if( -1 == ( str_parse_line(line, &type, &value, &vlen)) ) {
578                         my_free(line);
579                         continue; /* just skip the errors */
580                 }
581
582                 ldif_fix_string(value);
583
584                 ldif_convert(item, type, value);
585
586                 my_free(line);
587         } while ( !feof(handle) );
588
589         ldif_convert(item, "dn", "");
590
591         return 0;
592 }
593
594 static void
595 ldif_fix_string(char *str)
596 {
597         int i, j;
598
599         for( i = 0, j = 0; j < (int)strlen(str); i++, j++)
600                 str[i] = ( str[j] == (char)0xc3 ?
601                                 (char) str[++j] + (char) 0x40 :
602                                 str[j] );
603
604         str[i] = 0;
605 }
606
607 /*
608  * end of ldif import
609  */
610
611 /*
612  * mutt alias import filter
613  */
614
615 #include "getname.h"
616
617 static int
618 mutt_read_line(FILE *in, char **alias, char **rest)
619 {
620         char *line, *ptr, *tmp;
621         size_t alias_len;
622
623         if( !(line = ptr = getaline(in)) )
624                 return 1; /* error / EOF */
625
626         while( ISSPACE(*ptr) )
627                 ptr++;
628
629         if( strncmp("alias", ptr, 5) ) {
630                 free(line);
631                 return 1;
632         }
633
634         ptr += 5;
635
636         while( ISSPACE(*ptr) )
637                 ptr++;
638
639         tmp = ptr;
640
641         while( ! ISSPACE(*ptr) )
642                 ptr++;
643
644         /* includes also the trailing zero */
645         alias_len = (size_t)(ptr - tmp + 1);
646
647         if( (*alias = (char *)malloc(alias_len)) == NULL) {
648                 free(line);
649                 return 1;
650         }
651
652         strncpy(*alias, tmp, alias_len - 1);
653         *(*alias + alias_len - 1) = 0;
654
655         while(ISSPACE(*ptr))
656                 ptr++;
657
658         *rest = strdup(ptr);    
659
660         free(line);
661         return 0;
662 }
663
664 static void
665 mutt_fix_quoting(char *p)
666 {
667         char *escape = 0;
668
669         for(; *p; p++) {
670                 switch(*p) {
671                         case '\"':
672                                 if(escape)
673                                         *escape = ' ';
674                                 break;
675                         case '\\':
676                                 escape = p;
677                                 break;
678                         default:
679                                 escape = 0;
680                 }
681         }
682 }
683
684 static void
685 mutt_parse_email(list_item item)
686 {
687         char *line = item[NAME];
688         char *tmp;
689         char *name, *email;
690 #if 0
691         char *start = line;
692         int i = 0;
693 #endif
694
695         mutt_fix_quoting(line);
696         tmp = strconcat("From: ", line, NULL);
697         getname(tmp, &name, &email);
698         free(tmp);
699
700         if(name)
701                 item[NAME] = name;
702         else
703                 return;
704         if(email)
705                 item[EMAIL] = email;
706         else
707                 return;
708
709         /*
710          * this is completely broken
711          */
712 #if 0
713         while( (start = strchr(start, ',')) && i++ < MAX_EMAILS - 1) {
714                 tmp = strconcat("From: ", ++start, NULL);
715                 getname(tmp, &name, &email);
716                 free(tmp);
717                 free(name);
718                 if(email) {
719                         if(*email) {
720                                 tmp = strconcat(item[EMAIL], ",", email, NULL);
721                                 free(item[EMAIL]);
722                                 item[EMAIL] = tmp;
723                         } else {
724                                 my_free(email);
725                         }
726                 }
727         }
728 #endif
729 }
730
731 static int
732 mutt_parse_file(FILE *in)
733 {
734         list_item item;
735
736         for(;;) {
737                 memset(item, 0, sizeof(item));
738
739                 if( !mutt_read_line(in, &item[NICK],
740                                 &item[NAME]) )
741                         mutt_parse_email(item);
742
743                 if( feof(in) ) {
744                         free_list_item(item);
745                         break;
746                 }
747
748                 add_item2database(item);
749         }
750
751         return 0;
752 }
753
754 /*
755  * end of mutt alias import filter
756  */
757
758
759 /*
760  * ldif export filter
761  */
762
763 static void
764 ldif_fput_type_and_value(FILE *out,char *type, char *value )
765 {
766         char *tmp;
767
768         tmp = ldif_type_and_value(type, value, strlen(value));
769
770         fputs(tmp, out);
771
772         free(tmp);
773 }
774
775 static int
776 ldif_export_database(FILE *out, struct db_enumerator e)
777 {
778         char email[MAX_EMAILSTR_LEN];
779
780         fprintf(out, "version: 1\n");
781
782         db_enumerate_items(e) {
783                 char *tmp;
784                 int j;
785                 get_first_email(email, e.item);
786
787                 tmp = mkstr("cn=%s,mail=%s", database[e.item][NAME], email);
788                 ldif_fput_type_and_value(out, "dn", tmp);
789                 free(tmp);
790
791                 for(j=0; j < LDIF_ITEM_FIELDS; j++) {
792                         if(ldif_conv_table[j] >= 0) {
793                                 if(ldif_conv_table[j] == EMAIL)
794                                         ldif_fput_type_and_value(out,
795                                                 ldif_field_names[j], email);
796                                 else if(database[e.item][ldif_conv_table[j]])
797                                         ldif_fput_type_and_value(out,
798                                                 ldif_field_names[j],
799                                                 database[e.item][ldif_conv_table[j]]);
800                         }
801                 }
802
803                 fprintf(out, "objectclass: top\n"
804                                 "objectclass: person\n\n");
805         }
806
807         return 0;
808 }
809
810 /*
811  * end of ldif export filter
812  */
813
814 /*
815  * html export filter
816  */
817
818 static void            html_export_write_head(FILE *out, int extra_column);
819 static void            html_export_write_tail(FILE *out);
820
821 extern int extra_column;
822
823 static int
824 html_export_database(FILE *out, struct db_enumerator e)
825 {
826         char tmp[MAX_EMAILSTR_LEN];
827
828         if( items < 1 )
829                 return 2;
830
831         extra_column = (extra_column > 2 && extra_column < ITEM_FIELDS) ?
832                 extra_column : PHONE;
833
834         html_export_write_head(out, extra_column);
835
836         db_enumerate_items(e) {
837                 get_first_email(tmp, e.item);
838                 if (*tmp)
839                     fprintf(out, "<tr>\n<td><a href=\"mailto:%s\">%s</a>\n",
840                             tmp,
841                             database[e.item][NAME] );
842                 else
843                     fprintf(out, "<tr>\n<td>%s\n",
844                             database[e.item][NAME] );
845
846                 fprintf(out, "<td>%s\n<td>%s\n",
847                                 database[e.item][EMAIL],
848                                 safe_str(database[e.item][extra_column]) );
849                 fprintf(out, "</tr>\n\n");
850         }
851
852         html_export_write_tail(out);
853
854         return 0;
855 }
856
857
858 static void
859 html_export_write_head(FILE *out, int extra_column)
860 {
861         char *realname = get_real_name();
862
863         fprintf(out, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n");
864         fprintf(out, "<html>\n<head>\n <title>%s's addressbook</title>", realname );
865         fprintf(out, "\n</head>\n<body>\n");
866         fprintf(out, "\n<h2>%s's addressbook</h2>\n", realname );
867         fprintf(out, "<br><br>\n\n");
868
869         fprintf(out, "<table border=\"1\" align=\"center\">\n");
870         fprintf(out, "\n<tr><th>Name<th>E-mail address(es)<th>%s</tr>\n\n",
871                         abook_fields[extra_column].name);
872
873         free(realname);
874 }
875
876 static void
877 html_export_write_tail(FILE *out)
878 {
879         fprintf(out, "\n</table>\n");
880         fprintf(out, "\n</body>\n</html>\n");
881 }
882         
883 /*
884  * end of html export filter
885  */
886
887
888 /*
889  * pine addressbook import filter
890  */
891
892 #define PINE_BUF_SIZE 2048
893
894 static void
895 pine_fixbuf(char *buf)
896 {
897         int i,j;
898
899         for(i=0,j=0; j < (int)strlen(buf); i++, j++)
900                 buf[i] = buf[j] == '\n' ? buf[++j] : buf[j];
901 }
902
903 static void
904 pine_convert_emails(char *s)
905 {
906         int i;
907         char *tmp;
908
909         if( s == NULL || *s != '(' )
910                 return;
911
912         for(i=0; s[i]; i++ )
913                 s[i] = s[i+1];
914
915         if( ( tmp = strchr(s,')')) )
916                 *tmp=0;
917
918         for(i=1; ( tmp = strchr(s, ',') ) != NULL ; i++, s=tmp+1 )
919                 if( i > MAX_EMAILS - 1 ) {
920                         *tmp = 0;
921                         break;  
922                 }
923
924 }
925
926 static void
927 pine_parse_buf(char *buf)
928 {
929         list_item item;
930         char *start = buf;
931         char *end;
932         char tmp[PINE_BUF_SIZE];
933         int i, len, last;
934         int pine_conv_table[]= {NICK, NAME, EMAIL, -1, NOTES};
935
936         memset(&item, 0, sizeof(item) );
937         
938         for(i=0, last=0; !last ; i++) {
939                 if( ! (end = strchr(start, '\t')) )
940                         last=1;
941
942                 len = last ? strlen(start) : (int) (end-start);
943                 len = min(len, PINE_BUF_SIZE - 1);
944
945                 if(i < (int)(sizeof(pine_conv_table) / sizeof(*pine_conv_table))
946                                 && pine_conv_table[i] >= 0) {
947                         strncpy(tmp, start, len);
948                         tmp[len] = 0;
949                         if(*tmp)
950                                 item[pine_conv_table[i]] = strdup(tmp);
951                 }
952                 start = end + 1;
953         }
954
955         pine_convert_emails(item[EMAIL]);
956         add_item2database(item);
957 }
958
959
960 #define LINESIZE        1024
961
962 static int
963 pine_parse_file(FILE *in)
964 {
965         char line[LINESIZE];
966         char *buf = NULL;
967         char *ptr;
968         int i;
969
970         fgets(line, LINESIZE, in);      
971
972         while(!feof(in)) {
973                 for(i = 2;;i++) {
974                         buf = (char *) realloc(buf, i*LINESIZE);
975                         if(i == 2)
976                                 strcpy(buf, line);
977                         fgets(line, LINESIZE, in);
978                         ptr=(char *)&line;
979                         if(*ptr != ' ' || feof(in) )
980                                 break;
981                         else
982                                 while( *ptr == ' ')
983                                         ptr++;
984
985                         strcat(buf, ptr);
986                 }
987                 if( *buf == '#' ) {
988                         my_free(buf);
989                         continue;
990                 }
991                 pine_fixbuf(buf);
992
993                 pine_parse_buf(buf);
994
995                 my_free(buf);
996         }
997
998         return 0;
999 }
1000
1001 /*
1002  * end of pine addressbook import filter
1003  */
1004
1005
1006 /*
1007  * pine addressbook export filter
1008  *
1009  *  filter doesn't wrap the lines as it should but Pine seems to handle
1010  *  created files without problems - JH
1011  */
1012
1013 static int
1014 pine_export_database(FILE *out, struct db_enumerator e)
1015 {
1016         db_enumerate_items(e) {
1017                 fprintf(out, have_multiple_emails(e.item) ?
1018                                 "%s\t%s\t(%s)\t\t%s\n" : "%s\t%s\t%s\t\t%s\n",
1019                                 safe_str(database[e.item][NICK]),
1020                                 safe_str(database[e.item][NAME]),
1021                                 safe_str(database[e.item][EMAIL]),
1022                                 safe_str(database[e.item][NOTES])
1023                                 );
1024         }
1025
1026         return 0;
1027 }
1028
1029 /*
1030  * end of pine addressbook export filter
1031  */
1032
1033
1034 /*
1035  * csv import filter
1036  */
1037
1038 /* FIXME
1039  * these files should be parsed according to a certain
1040  * lay out, or the default if layout is not given, at 
1041  * the moment only default is done...
1042  */ 
1043
1044 #define CSV_COMMENT_CHAR        '#'
1045
1046 static int csv_conv_table[] = {
1047         NAME,
1048         EMAIL,
1049         PHONE,
1050         NOTES,
1051         NICK
1052 };
1053
1054 static void
1055 csv_convert_emails(char *s)
1056 {
1057         int i;
1058         char *tmp;
1059
1060         if( s == NULL )
1061                 return;
1062
1063         for(i=1; ( tmp = strchr(s, ',') ) != NULL ; i++, s = tmp + 1 )
1064                 if( i > MAX_EMAILS - 1 ) {
1065                         *tmp = 0;
1066                         break;  
1067                 }
1068
1069 }
1070
1071 static char *
1072 csv_remove_quotes(char *s)
1073 {
1074         char *copy, *trimmed;
1075         int len;
1076
1077         copy = trimmed = strdup(s);
1078         strtrim(trimmed);
1079
1080         len = strlen(trimmed);
1081         if(trimmed[len - 1] == '\"' && *trimmed == '\"') {
1082                 if(len < 3) {
1083                         my_free(copy);
1084                         return NULL;
1085                 }
1086                 trimmed[len - 1] = 0;
1087                 trimmed++;
1088                 trimmed = strdup(trimmed);
1089                 free(copy);
1090                 return trimmed;
1091         }
1092
1093         my_free(copy);
1094         return strdup(s);
1095 }
1096
1097 static void
1098 csv_store_field(list_item item, char *s, int field)
1099 {
1100         char *newstr = NULL;
1101
1102         if(!s || !*s)
1103                 return;
1104
1105         if( !(newstr = csv_remove_quotes(s)) )
1106                 return;
1107
1108         if(field < (int)(sizeof(csv_conv_table) / sizeof(*csv_conv_table))
1109                         && csv_conv_table[field] >= 0) {
1110                 item[csv_conv_table[field]] = newstr;
1111         } else {
1112                 my_free(newstr);
1113         }
1114 }
1115
1116 static int
1117 csv_is_valid_quote_end(char *p)
1118 {
1119         if(*p != '\"')
1120                 return FALSE;
1121
1122         for(p++; *p; p++) {
1123                 if(*p == ',')
1124                         return TRUE;
1125                 else if(!ISSPACE(*p))
1126                         return FALSE;
1127         }
1128
1129         return TRUE;
1130 }
1131
1132 static int
1133 csv_is_valid_quote_start(char *p)
1134 {
1135         for(; *p; p++) {
1136                 if(*p == '\"')
1137                         return TRUE;
1138                 else if(!ISSPACE(*p))
1139                         return FALSE;
1140         }
1141
1142         return FALSE;
1143 }
1144
1145 static void
1146 csv_parse_line(char *line)
1147 {
1148         char *p, *start;
1149         int field;
1150         bool in_quote = FALSE;
1151         list_item item;
1152
1153         memset(item, 0, sizeof(item));
1154
1155         for(p = start = line, field = 0; *p; p++) {
1156                 if(in_quote) {
1157                         if(csv_is_valid_quote_end(p))
1158                                 in_quote = FALSE;
1159                 } else {
1160                         if ( (((p - start) / sizeof (char)) < 2 ) &&
1161                                 csv_is_valid_quote_start(p) )
1162                                 in_quote = TRUE;
1163                 }
1164
1165                 if( *p == ',' && !in_quote) {
1166                         *p = 0;
1167                         csv_store_field(item, start, field);
1168                         field++;
1169                         start = p + 1;
1170                 }
1171         }
1172         /*
1173          * store last field
1174          */
1175         csv_store_field(item, start, field);
1176
1177         csv_convert_emails(item[EMAIL]);
1178         add_item2database(item);
1179 }
1180
1181
1182 static int
1183 csv_parse_file(FILE *in)
1184 {
1185         char *line = NULL;
1186
1187         while(!feof(in)) {
1188                 line = getaline(in);
1189
1190                 if(line && *line && *line != CSV_COMMENT_CHAR)
1191                         csv_parse_line(line);
1192
1193                 my_free(line);
1194         }
1195
1196         return 0;
1197 }
1198
1199 /*
1200  * end of csv import filter
1201  */
1202
1203 /*
1204  * csv addressbook export filters
1205  */
1206
1207 #define CSV_LAST                (-1)
1208 #define CSV_UNDEFINED           (-2)
1209 #define CSV_SPECIAL(X)          (-3 - (X))
1210 #define CSV_IS_SPECIAL(X)       ((X) <= -3)
1211
1212 static int
1213 csv_export_common(FILE *out, struct db_enumerator e,
1214                 int fields[], void (*special_func)(FILE *, int, int))
1215 {
1216         int i;
1217
1218         db_enumerate_items(e) {
1219                 for(i = 0; fields[i] != CSV_LAST; i++) {
1220                         if(fields[i] == CSV_UNDEFINED)
1221                                 fprintf(out, "\"\"");
1222                         else if(CSV_IS_SPECIAL(fields[i])) {
1223                                 if(special_func)
1224                                         (*special_func)(out, e.item, fields[i]);
1225                         } else
1226                                 /*fprintf(out,(
1227                         strchr(safe_str(database[e.item][fields[i]]), ',') ||
1228                         strchr(safe_str(database[e.item][fields[i]]), '\"')) ?
1229                                 "\"%s\"" : "%s",
1230                                 safe_str(database[e.item][fields[i]])
1231                                 );*/
1232                                 fprintf(out, "\"%s\"",
1233                                         safe_str(database[e.item][fields[i]]));
1234
1235                         if(fields[i + 1] != CSV_LAST)
1236                                 fputc(',', out);
1237                 }
1238                 fputc('\n', out);
1239         }
1240
1241         return 0;
1242 }
1243
1244 static int
1245 csv_export_database(FILE *out, struct db_enumerator e)
1246 {
1247         int csv_export_fields[] = {
1248                 NAME,
1249                 EMAIL,
1250                 PHONE,
1251                 NOTES,
1252                 NICK,
1253                 CSV_LAST
1254         };
1255
1256         csv_export_common(out, e, csv_export_fields, NULL);
1257         
1258         return 0;
1259 }
1260
1261 /*
1262  * palm csv
1263  */
1264
1265 #define PALM_CSV_NAME   CSV_SPECIAL(0)
1266 #define PALM_CSV_END    CSV_SPECIAL(1)
1267 #define PALM_CSV_CAT    CSV_SPECIAL(2)
1268
1269 static void 
1270 palm_split_and_write_name(FILE *out, char *name)
1271 {
1272         char *p;
1273
1274         assert(name);
1275
1276         if ( (p = strchr(name, ' ')) ) {
1277                 /*
1278                  * last name first
1279                  */
1280                 fprintf(out, "\"%s\",\"" , p + 1);
1281                 fwrite((void *)name, p - name, sizeof(char), out);
1282                 fputc('\"', out);
1283         } else {
1284                 fprintf(out, "\"%s\"", safe_str(name));
1285         }
1286 }
1287
1288 static void 
1289 palm_csv_handle_specials(FILE *out, int item, int field)
1290 {
1291         switch(field) {
1292                 case PALM_CSV_NAME:
1293                         palm_split_and_write_name(out, database[item][NAME]);
1294                         break;
1295                 case PALM_CSV_CAT:
1296                         fprintf(out, "\"abook\"");
1297                         break;
1298                 case PALM_CSV_END:
1299                         fprintf(out, "\"0\"");
1300                         break;
1301                 default:
1302                         assert(0);
1303         }
1304 }
1305
1306 static int
1307 palm_export_database(FILE *out, struct db_enumerator e)
1308 {
1309         int palm_export_fields[] = {
1310                 PALM_CSV_NAME,          /* LASTNAME, FIRSTNAME  */
1311                 CSV_UNDEFINED,          /* TITLE                */
1312                 CSV_UNDEFINED,          /* COMPANY              */
1313                 WORKPHONE,              /* WORK PHONE           */
1314                 PHONE,                  /* HOME PHONE           */
1315                 FAX,                    /* FAX                  */
1316                 MOBILEPHONE,            /* OTHER                */
1317                 EMAIL,                  /* EMAIL                */
1318                 ADDRESS,                /* ADDRESS              */ 
1319                 CITY,                   /* CITY                 */
1320                 STATE,                  /* STATE                */
1321                 ZIP,                    /* ZIP                  */
1322                 COUNTRY,                /* COUNTRY              */
1323                 NICK,                   /* DEFINED 1            */
1324                 URL,                    /* DEFINED 2            */
1325                 CSV_UNDEFINED,          /* DEFINED 3            */
1326                 CSV_UNDEFINED,          /* DEFINED 4            */
1327                 NOTES,                  /* NOTE                 */
1328                 PALM_CSV_END,           /* "0"                  */
1329                 PALM_CSV_CAT,           /* CATEGORY             */
1330                 CSV_LAST
1331         };
1332
1333         csv_export_common(out, e, palm_export_fields, palm_csv_handle_specials);
1334
1335         return 0;
1336 }
1337
1338 /*
1339  * end of csv export filters
1340  */
1341
1342 /*
1343  * GnomeCard (VCard) addressbook export filter
1344  */
1345
1346 static int
1347 gcrd_export_database(FILE *out, struct db_enumerator e)
1348 {
1349         char emails[MAX_EMAILS][MAX_EMAIL_LEN];
1350         int j;
1351         char *name;
1352
1353         db_enumerate_items(e) {
1354                 fprintf(out, "BEGIN:VCARD\nFN:%s\n",
1355                                 safe_str(database[e.item][NAME]));
1356
1357                 name = get_surname(database[e.item][NAME]);
1358                 for( j = strlen(database[e.item][NAME]) - 1; j >= 0; j-- ) {
1359                         if(database[e.item][NAME][j] == ' ')
1360                                 break;
1361                 } 
1362                 fprintf(out, "N:%s;%.*s\n",
1363                         safe_str(name),
1364                         j,
1365                         safe_str(database[e.item][NAME])
1366                         ); 
1367
1368                 free(name);
1369
1370                 if ( database[e.item][ADDRESS] )
1371                         fprintf(out, "ADR:;;%s;%s;%s;%s;%s;%s\n",
1372                                 safe_str(database[e.item][ADDRESS]),
1373                                 safe_str(database[e.item][ADDRESS2]),                           
1374                                 safe_str(database[e.item][CITY]),
1375                                 safe_str(database[e.item][STATE]),
1376                                 safe_str(database[e.item][ZIP]),
1377                                 safe_str(database[e.item][COUNTRY])
1378                                 );
1379                 
1380                 if (database[e.item][PHONE])
1381                         fprintf(out, "TEL;HOME:%s\n", database[e.item][PHONE]);
1382                 if (database[e.item][WORKPHONE])
1383                         fprintf(out, "TEL;WORK:%s\n", database[e.item][WORKPHONE]);
1384                 if (database[e.item][FAX])
1385                         fprintf(out, "TEL;FAX:%s\n", database[e.item][FAX]);
1386                 if (database[e.item][MOBILEPHONE])
1387                         fprintf(out, "TEL;CELL:%s\n", database[e.item][MOBILEPHONE]);
1388
1389                 if ( database[e.item][EMAIL] ) {
1390                         split_emailstr(e.item, emails);
1391                         for(j=0; j < MAX_EMAILS ; j++) {
1392                                 if ( *emails[j] ) 
1393                                         fprintf(out, "EMAIL;INTERNET:%s\n",
1394                                                 emails[j]);
1395                         }
1396                 }
1397                 
1398                 if ( database[e.item][NOTES] ) 
1399                         fprintf(out, "NOTE:%s\n", database[e.item][NOTES]);
1400                 if (database[e.item][URL])
1401                         fprintf(out, "URL:%s\n",  database[e.item][URL]);
1402
1403                 fprintf(out, "END:VCARD\n\n");
1404                 
1405         }
1406
1407         return 0;
1408 }
1409
1410 /*
1411  * end of GnomeCard export filter
1412  */
1413
1414
1415 /*
1416  * mutt alias export filter
1417  */
1418
1419 static char *
1420 mutt_alias_genalias(int i)
1421 {
1422         char *tmp, *pos;
1423         
1424         if(database[i][NICK])
1425                 return strdup(database[i][NICK]);
1426
1427         tmp = strdup(database[i][NAME]);
1428
1429         if( ( pos = strchr(tmp, ' ') ) )
1430                 *pos = 0;
1431
1432         strlower(tmp);
1433
1434         return tmp;     
1435 }
1436
1437 static int
1438 mutt_alias_export(FILE *out, struct db_enumerator e)
1439 {
1440         char email[MAX_EMAIL_LEN];
1441         char *alias = NULL;
1442
1443         db_enumerate_items(e) {
1444                 alias = mutt_alias_genalias(e.item);
1445
1446                 get_first_email(email, e.item);
1447                 fprintf(out, *email ? "alias %s %s <%s>\n": "alias %s %s%s\n",
1448                                 alias,
1449                                 database[e.item][NAME],
1450                                 email);
1451                 my_free(alias);
1452         }
1453
1454         return 0;
1455 }
1456
1457 /*
1458  * end of mutt alias export filter
1459  */
1460
1461
1462 /*
1463  * printable export filter
1464  */
1465
1466
1467 static void
1468 text_write_address_us(FILE *out, int i) {
1469         fprintf(out, "\n%s", database[i][ADDRESS]);
1470
1471         if (database[i][ADDRESS2])
1472                 fprintf(out, "\n%s", database[i][ADDRESS2]);
1473
1474         if (database[i][CITY])
1475                 fprintf(out, "\n%s", database[i][CITY]);
1476                 
1477         if (database[i][STATE] || database[i][ZIP]) {
1478                 fputc('\n', out);
1479                 
1480                 if(database[i][STATE]) {
1481                         fprintf(out, "%s", database[i][STATE]);
1482                         if(database[i][ZIP])
1483                                 fputc(' ', out);
1484                 }
1485
1486                 if(database[i][ZIP])
1487                         fprintf(out, "%s", database[i][ZIP]);
1488         }
1489
1490         if (database[i][COUNTRY])
1491                 fprintf(out, "\n%s", database[i][COUNTRY]);
1492 }
1493
1494
1495 static void
1496 text_write_address_uk(FILE *out, int i) {
1497         int j;
1498
1499         for (j = ADDRESS; j <= COUNTRY; j++)
1500                 if (database[i][j])
1501                         fprintf(out, "\n%s", database[i][j]);
1502 }
1503
1504 static void
1505 text_write_address_eu(FILE *out, int i) {
1506         fprintf(out, "\n%s", database[i][ADDRESS]);
1507
1508         if (database[i][ADDRESS2])
1509                 fprintf(out, "\n%s", database[i][ADDRESS2]);
1510
1511         if (database[i][ZIP] || database[i][CITY]) {
1512                 fputc('\n', out);
1513
1514                 if(database[i][ZIP]) {
1515                         fprintf(out, "%s", database[i][ZIP]);
1516                         if(database[i][CITY])
1517                                 fputc(' ', out);
1518                 }
1519
1520                 if(database[i][CITY])
1521                         fprintf(out, "%s", database[i][CITY]);
1522         }
1523         
1524         if (database[i][STATE])
1525                 fprintf(out, "\n%s", database[i][STATE]);
1526
1527         if (database[i][COUNTRY])
1528                 fprintf(out, "\n%s", database[i][COUNTRY]);
1529 }
1530
1531 static int
1532 text_export_database(FILE * out, struct db_enumerator e)
1533 {
1534         char emails[MAX_EMAILS][MAX_EMAIL_LEN];
1535         int j;
1536         char *realname = get_real_name();
1537         char *style = opt_get_str(STR_ADDRESS_STYLE);
1538
1539         fprintf(out,
1540                 "-----------------------------------------\n%s's address book\n"
1541                 "-----------------------------------------\n\n\n",
1542                 realname);
1543         free(realname);
1544
1545         db_enumerate_items(e) {
1546                 fprintf(out,
1547                         "-----------------------------------------\n\n");
1548                 fprintf(out, "%s", database[e.item][NAME]);
1549                 if (database[e.item][NICK] && *database[e.item][NICK])
1550                         fprintf(out, "\n(%s)", database[e.item][NICK]);
1551                 fprintf(out, "\n");
1552
1553                 if (*database[e.item][EMAIL]) {
1554                         fprintf(out, "\n");
1555                         split_emailstr(e.item, emails);
1556                         for (j = 0; j < MAX_EMAILS; j++)
1557                                 if (*emails[j])
1558                                         fprintf(out, "%s\n", emails[j]);
1559                 }
1560                 /* Print address */
1561                 if (database[e.item][ADDRESS]) {
1562                         if (!safe_strcmp(style, "us"))  /* US like */
1563                                 text_write_address_us(out, e.item);
1564                         else if (!safe_strcmp(style, "uk"))     /* UK like */
1565                                 text_write_address_uk(out, e.item);
1566                         else    /* EU like */
1567                                 text_write_address_eu(out, e.item);
1568
1569                         fprintf(out, "\n");
1570                 }
1571
1572                 if ((database[e.item][PHONE]) ||
1573                         (database[e.item][WORKPHONE]) ||
1574                         (database[e.item][FAX]) ||
1575                         (database[e.item][MOBILEPHONE])) {
1576                         fprintf(out, "\n");
1577                         for (j = PHONE; j <= MOBILEPHONE; j++)
1578                                 if (database[e.item][j])
1579                                         fprintf(out, "%s: %s\n",
1580                                                 abook_fields[j].name,
1581                                                 database[e.item][j]);
1582                 }
1583
1584                 if (database[e.item][URL])
1585                         fprintf(out, "\n%s\n", database[e.item][URL]);
1586                 if (database[e.item][NOTES])
1587                         fprintf(out, "\n%s\n", database[e.item][NOTES]);
1588
1589                 fprintf(out, "\n");
1590         }
1591
1592         fprintf(out, "-----------------------------------------\n");
1593
1594         return 0;
1595 }
1596
1597 /*
1598  * end of printable export filter
1599  */
1600
1601 /*
1602  * elm alias export filter
1603  */
1604
1605 static int
1606 elm_alias_export(FILE *out, struct db_enumerator e)
1607 {
1608         char email[MAX_EMAIL_LEN];
1609         char *alias = NULL;
1610
1611         db_enumerate_items(e) {
1612                 alias = mutt_alias_genalias(e.item);
1613                 get_first_email(email, e.item);
1614                 fprintf(out, "%s = %s = %s\n",
1615                                 alias,
1616                                 database[e.item][NAME],
1617                                 email);
1618                 my_free(alias);
1619         }
1620
1621         return 0;
1622 }
1623
1624 /*
1625  * end of elm alias export filter
1626  */
1627
1628
1629 /*
1630  * Spruce export filter
1631  */
1632
1633 static int
1634 spruce_export_database (FILE *out, struct db_enumerator e)
1635 {
1636         char email[MAX_EMAIL_LEN];
1637
1638         fprintf (out, "# This is a generated file made by abook for the Spruce e-mail client.\n\n");
1639
1640         db_enumerate_items(e) {
1641                 if(strcmp (safe_str(database[e.item][EMAIL]), "")) {
1642                         get_first_email(email, e.item);
1643                         fprintf(out, "# Address %d\nName: %s\nEmail: %s\nMemo: %s\n\n",
1644                                         e.item,
1645                                         database[e.item][NAME],
1646                                         email,
1647                                         safe_str(database[e.item][NOTES])
1648                                         );
1649                 }
1650         }
1651
1652         fprintf (out, "# End of address book file.\n");
1653
1654         return 0;
1655 }
1656
1657 /*
1658  * end of Spruce export filter
1659  */
1660