]> git.deb.at Git - pkg/abook.git/blob - filter.c
880213a7d00a352d5ae08a55b8b7388991dfd6e9
[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 = (char *)malloc(strlen(pwent->pw_gecos) +1)) == 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
622         if( !(line = ptr = getaline(in)) )
623                 return 1; /* error / EOF */
624
625         while( ISSPACE(*ptr) )
626                 ptr++;
627
628         if( strncmp("alias", ptr, 5) ) {
629                 free(line);
630                 return 1;
631         }
632
633         ptr += 5;
634
635         while( ISSPACE(*ptr) )
636                 ptr++;
637
638         tmp = ptr;
639
640         while( ! ISSPACE(*ptr) )
641                 ptr++;
642
643         if( (*alias = (char *)malloc(ptr-tmp+1)) == NULL) {
644                 free(line);
645                 return 1;
646         }
647
648         strncpy(*alias, tmp, ptr-tmp);
649         *(*alias + (ptr - tmp)) = 0;
650
651         while( ISSPACE(*ptr) )
652                 ptr++;
653
654         *rest = strdup(ptr);    
655
656         free(line);
657         return 0;
658 }
659
660 static void
661 mutt_parse_email(list_item item)
662 {
663         char *line = item[NAME];
664         char *start = line, *tmp;
665         char *name, *email;
666         int i = 0;
667
668         tmp = strconcat("From: ", line, NULL);
669         getname(tmp, &name, &email);
670         free(tmp);
671
672         if(name)
673                 item[NAME] = name;
674         else
675                 return;
676         if(email)
677                 item[EMAIL] = email;
678         else
679                 return;
680
681         while( (start = strchr(start, ',')) && i++ < MAX_EMAILS - 1) {
682                 tmp = strconcat("From: ", ++start, NULL);
683                 getname(tmp, &name, &email);
684                 free(tmp);
685                 free(name);
686                 if(email) {
687                         if(*email) {
688                                 tmp = strconcat(item[EMAIL], ",", email, NULL);
689                                 free(item[EMAIL]);
690                                 item[EMAIL] = tmp;
691                         } else {
692                                 my_free(email);
693                         }
694                 }
695         }
696 }
697
698 static int
699 mutt_parse_file(FILE *in)
700 {
701         list_item item;
702
703         for(;;) {
704                 memset(item, 0, sizeof(item));
705
706                 if( !mutt_read_line(in, &item[NICK],
707                                 &item[NAME]) )
708                         mutt_parse_email(item);
709
710                 if( feof(in) ) {
711                         free_list_item(item);
712                         break;
713                 }
714
715                 add_item2database(item);
716         }
717
718         return 0;
719 }
720
721 /*
722  * end of mutt alias import filter
723  */
724
725
726 /*
727  * ldif export filter
728  */
729
730 static void
731 ldif_fput_type_and_value(FILE *out,char *type, char *value )
732 {
733         char *tmp;
734
735         tmp = ldif_type_and_value(type, value, strlen(value));
736
737         fputs(tmp, out);
738
739         free(tmp);
740 }
741
742 static int
743 ldif_export_database(FILE *out, struct db_enumerator e)
744 {
745         char email[MAX_EMAILSTR_LEN];
746
747         fprintf(out, "version: 1\n");
748
749         db_enumerate_items(e) {
750                 char *tmp;
751                 int j;
752                 get_first_email(email, e.item);
753
754                 tmp = mkstr("cn=%s,mail=%s", database[e.item][NAME], email);
755                 ldif_fput_type_and_value(out, "dn", tmp);
756                 free(tmp);
757
758                 for(j=0; j < LDIF_ITEM_FIELDS; j++) {
759                         if(ldif_conv_table[j] >= 0) {
760                                 if(ldif_conv_table[j] == EMAIL)
761                                         ldif_fput_type_and_value(out,
762                                                 ldif_field_names[j], email);
763                                 else if(database[e.item][ldif_conv_table[j]])
764                                         ldif_fput_type_and_value(out,
765                                                 ldif_field_names[j],
766                                                 database[e.item][ldif_conv_table[j]]);
767                         }
768                 }
769
770                 fprintf(out, "objectclass: top\n"
771                                 "objectclass: person\n\n");
772         }
773
774         return 0;
775 }
776
777 /*
778  * end of ldif export filter
779  */
780
781 /*
782  * html export filter
783  */
784
785 static void            html_export_write_head(FILE *out, int extra_column);
786 static void            html_export_write_tail(FILE *out);
787
788 extern int extra_column;
789
790 static int
791 html_export_database(FILE *out, struct db_enumerator e)
792 {
793         char tmp[MAX_EMAILSTR_LEN];
794
795         if( items < 1 )
796                 return 2;
797
798         extra_column = (extra_column > 2 && extra_column < ITEM_FIELDS) ?
799                 extra_column : PHONE;
800
801         html_export_write_head(out, extra_column);
802
803         db_enumerate_items(e) {
804                 get_first_email(tmp, e.item);
805                 if (*tmp)
806                     fprintf(out, "<tr>\n<td><a href=\"mailto:%s\">%s</a>\n",
807                             tmp,
808                             database[e.item][NAME] );
809                 else
810                     fprintf(out, "<tr>\n<td>%s\n",
811                             database[e.item][NAME] );
812
813                 fprintf(out, "<td>%s\n<td>%s\n",
814                                 database[e.item][EMAIL],
815                                 safe_str(database[e.item][extra_column]) );
816                 fprintf(out, "</tr>\n\n");
817         }
818
819         html_export_write_tail(out);
820
821         return 0;
822 }
823
824
825 static void
826 html_export_write_head(FILE *out, int extra_column)
827 {
828         char *realname = get_real_name();
829
830         fprintf(out, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n");
831         fprintf(out, "<html>\n<head>\n <title>%s's addressbook</title>", realname );
832         fprintf(out, "\n</head>\n<body>\n");
833         fprintf(out, "\n<h2>%s's addressbook</h2>\n", realname );
834         fprintf(out, "<br><br>\n\n");
835
836         fprintf(out, "<table border=\"1\" align=\"center\">\n");
837         fprintf(out, "\n<tr><th>Name<th>E-mail address(es)<th>%s</tr>\n\n",
838                         abook_fields[extra_column].name);
839
840         free(realname);
841 }
842
843 static void
844 html_export_write_tail(FILE *out)
845 {
846         fprintf(out, "\n</table>\n");
847         fprintf(out, "\n</body>\n</html>\n");
848 }
849         
850 /*
851  * end of html export filter
852  */
853
854
855 /*
856  * pine addressbook import filter
857  */
858
859 #define PINE_BUF_SIZE 2048
860
861 static void
862 pine_fixbuf(char *buf)
863 {
864         int i,j;
865
866         for(i=0,j=0; j < (int)strlen(buf); i++, j++)
867                 buf[i] = buf[j] == '\n' ? buf[++j] : buf[j];
868 }
869
870 static void
871 pine_convert_emails(char *s)
872 {
873         int i;
874         char *tmp;
875
876         if( s == NULL || *s != '(' )
877                 return;
878
879         for(i=0; s[i]; i++ )
880                 s[i] = s[i+1];
881
882         if( ( tmp = strchr(s,')')) )
883                 *tmp=0;
884
885         for(i=1; ( tmp = strchr(s, ',') ) != NULL ; i++, s=tmp+1 )
886                 if( i > MAX_EMAILS - 1 ) {
887                         *tmp = 0;
888                         break;  
889                 }
890
891 }
892
893 static void
894 pine_parse_buf(char *buf)
895 {
896         list_item item;
897         char *start = buf;
898         char *end;
899         char tmp[PINE_BUF_SIZE];
900         int i, len, last;
901         int pine_conv_table[]= {NICK, NAME, EMAIL, -1, NOTES};
902
903         memset(&item, 0, sizeof(item) );
904         
905         for(i=0, last=0; !last ; i++) {
906                 if( ! (end = strchr(start, '\t')) )
907                         last=1;
908
909                 len = last ? strlen(start) : (int) (end-start);
910                 len = min(len, PINE_BUF_SIZE - 1);
911
912                 if(i < (int)(sizeof(pine_conv_table) / sizeof(*pine_conv_table))
913                                 && pine_conv_table[i] >= 0) {
914                         strncpy(tmp, start, len);
915                         tmp[len] = 0;
916                         if(*tmp)
917                                 item[pine_conv_table[i]] = strdup(tmp);
918                 }
919                 start = end + 1;
920         }
921
922         pine_convert_emails(item[EMAIL]);
923         add_item2database(item);
924 }
925
926
927 #define LINESIZE        1024
928
929 static int
930 pine_parse_file(FILE *in)
931 {
932         char line[LINESIZE];
933         char *buf = NULL;
934         char *ptr;
935         int i;
936
937         fgets(line, LINESIZE, in);      
938
939         while(!feof(in)) {
940                 for(i = 2;;i++) {
941                         buf = (char *) realloc(buf, i*LINESIZE);
942                         if(i == 2)
943                                 strcpy(buf, line);
944                         fgets(line, LINESIZE, in);
945                         ptr=(char *)&line;
946                         if(*ptr != ' ' || feof(in) )
947                                 break;
948                         else
949                                 while( *ptr == ' ')
950                                         ptr++;
951
952                         strcat(buf, ptr);
953                 }
954                 if( *buf == '#' ) {
955                         my_free(buf);
956                         continue;
957                 }
958                 pine_fixbuf(buf);
959
960                 pine_parse_buf(buf);
961
962                 my_free(buf);
963         }
964
965         return 0;
966 }
967
968 /*
969  * end of pine addressbook import filter
970  */
971
972
973 /*
974  * pine addressbook export filter
975  *
976  *  filter doesn't wrap the lines as it should but Pine seems to handle
977  *  created files without problems - JH
978  */
979
980 static int
981 pine_export_database(FILE *out, struct db_enumerator e)
982 {
983         db_enumerate_items(e) {
984                 fprintf(out, have_multiple_emails(e.item) ?
985                                 "%s\t%s\t(%s)\t\t%s\n" : "%s\t%s\t%s\t\t%s\n",
986                                 safe_str(database[e.item][NICK]),
987                                 safe_str(database[e.item][NAME]),
988                                 safe_str(database[e.item][EMAIL]),
989                                 safe_str(database[e.item][NOTES])
990                                 );
991         }
992
993         return 0;
994 }
995
996 /*
997  * end of pine addressbook export filter
998  */
999
1000
1001 /*
1002  * csv import filter
1003  */
1004
1005 /* FIXME
1006  * these files should be parsed according to a certain
1007  * lay out, or the default if layout is not given, at 
1008  * the moment only default is done...
1009  */ 
1010
1011 #define CSV_COMMENT_CHAR        '#'
1012
1013 static int csv_conv_table[] = {
1014         NAME,
1015         EMAIL,
1016         PHONE,
1017         NOTES,
1018         NICK
1019 };
1020
1021 static void
1022 csv_convert_emails(char *s)
1023 {
1024         int i;
1025         char *tmp;
1026
1027         if( s == NULL )
1028                 return;
1029
1030         for(i=1; ( tmp = strchr(s, ',') ) != NULL ; i++, s = tmp + 1 )
1031                 if( i > MAX_EMAILS - 1 ) {
1032                         *tmp = 0;
1033                         break;  
1034                 }
1035
1036 }
1037
1038 static char *
1039 csv_remove_quotes(char *s)
1040 {
1041         char *copy, *trimmed;
1042         int len;
1043
1044         copy = trimmed = strdup(s);
1045         strtrim(trimmed);
1046
1047         len = strlen(trimmed);
1048         if(trimmed[len - 1] == '\"' && *trimmed == '\"') {
1049                 if(len < 3) {
1050                         my_free(copy);
1051                         return NULL;
1052                 }
1053                 trimmed[len - 1] = 0;
1054                 trimmed++;
1055                 trimmed = strdup(trimmed);
1056                 free(copy);
1057                 return trimmed;
1058         }
1059
1060         my_free(copy);
1061         return strdup(s);
1062 }
1063
1064 static void
1065 csv_store_field(list_item item, char *s, int field)
1066 {
1067         char *newstr = NULL;
1068
1069         if(!s || !*s)
1070                 return;
1071
1072         if( !(newstr = csv_remove_quotes(s)) )
1073                 return;
1074
1075         if(field < (int)(sizeof(csv_conv_table) / sizeof(*csv_conv_table))
1076                         && csv_conv_table[field] >= 0) {
1077                 item[csv_conv_table[field]] = newstr;
1078         } else {
1079                 my_free(newstr);
1080         }
1081 }
1082
1083 static int
1084 csv_is_valid_quote_end(char *p)
1085 {
1086         if(*p != '\"')
1087                 return FALSE;
1088
1089         for(p++; *p; p++) {
1090                 if(*p == ',')
1091                         return TRUE;
1092                 else if(!ISSPACE(*p))
1093                         return FALSE;
1094         }
1095
1096         return TRUE;
1097 }
1098
1099 static int
1100 csv_is_valid_quote_start(char *p)
1101 {
1102         for(; *p; p++) {
1103                 if(*p == '\"')
1104                         return TRUE;
1105                 else if(!ISSPACE(*p))
1106                         return FALSE;
1107         }
1108
1109         return FALSE;
1110 }
1111
1112 static void
1113 csv_parse_line(char *line)
1114 {
1115         char *p, *start;
1116         int field;
1117         bool in_quote = FALSE;
1118         list_item item;
1119
1120         memset(item, 0, sizeof(item));
1121
1122         for(p = start = line, field = 0; *p; p++) {
1123                 if(in_quote) {
1124                         if(csv_is_valid_quote_end(p))
1125                                 in_quote = FALSE;
1126                 } else {
1127                         if ( (((p - start) / sizeof (char)) < 2 ) &&
1128                                 csv_is_valid_quote_start(p) )
1129                                 in_quote = TRUE;
1130                 }
1131
1132                 if( *p == ',' && !in_quote) {
1133                         *p = 0;
1134                         csv_store_field(item, start, field);
1135                         field++;
1136                         start = p + 1;
1137                 }
1138         }
1139         /*
1140          * store last field
1141          */
1142         csv_store_field(item, start, field);
1143
1144         csv_convert_emails(item[EMAIL]);
1145         add_item2database(item);
1146 }
1147
1148
1149 static int
1150 csv_parse_file(FILE *in)
1151 {
1152         char *line = NULL;
1153
1154         while(!feof(in)) {
1155                 line = getaline(in);
1156
1157                 if(line && *line && *line != CSV_COMMENT_CHAR)
1158                         csv_parse_line(line);
1159
1160                 my_free(line);
1161         }
1162
1163         return 0;
1164 }
1165
1166 /*
1167  * end of csv import filter
1168  */
1169
1170 /*
1171  * csv addressbook export filters
1172  */
1173
1174 #define CSV_LAST                (-1)
1175 #define CSV_UNDEFINED           (-2)
1176 #define CSV_SPECIAL(X)          (-3 - (X))
1177 #define CSV_IS_SPECIAL(X)       ((X) <= -3)
1178
1179 static int
1180 csv_export_common(FILE *out, struct db_enumerator e,
1181                 int fields[], void (*special_func)(FILE *, int, int))
1182 {
1183         int i;
1184
1185         db_enumerate_items(e) {
1186                 for(i = 0; fields[i] != CSV_LAST; i++) {
1187                         if(fields[i] == CSV_UNDEFINED)
1188                                 fprintf(out, "\"\"");
1189                         else if(CSV_IS_SPECIAL(fields[i])) {
1190                                 if(special_func)
1191                                         (*special_func)(out, e.item, fields[i]);
1192                         } else
1193                                 /*fprintf(out,(
1194                         strchr(safe_str(database[e.item][fields[i]]), ',') ||
1195                         strchr(safe_str(database[e.item][fields[i]]), '\"')) ?
1196                                 "\"%s\"" : "%s",
1197                                 safe_str(database[e.item][fields[i]])
1198                                 );*/
1199                                 fprintf(out, "\"%s\"",
1200                                         safe_str(database[e.item][fields[i]]));
1201
1202                         if(fields[i + 1] != CSV_LAST)
1203                                 fputc(',', out);
1204                 }
1205                 fputc('\n', out);
1206         }
1207
1208         return 0;
1209 }
1210
1211 static int
1212 csv_export_database(FILE *out, struct db_enumerator e)
1213 {
1214         int csv_export_fields[] = {
1215                 NAME,
1216                 EMAIL,
1217                 PHONE,
1218                 NOTES,
1219                 NICK,
1220                 CSV_LAST
1221         };
1222
1223         csv_export_common(out, e, csv_export_fields, NULL);
1224         
1225         return 0;
1226 }
1227
1228 /*
1229  * palm csv
1230  */
1231
1232 #define PALM_CSV_NAME   CSV_SPECIAL(0)
1233 #define PALM_CSV_END    CSV_SPECIAL(1)
1234 #define PALM_CSV_CAT    CSV_SPECIAL(2)
1235
1236 static void 
1237 palm_split_and_write_name(FILE *out, char *name)
1238 {
1239         char *p;
1240
1241         assert(name);
1242
1243         if ( (p = strchr(name, ' ')) ) {
1244                 /*
1245                  * last name first
1246                  */
1247                 fprintf(out, "\"%s\",\"" , p + 1);
1248                 fwrite((void *)name, p - name, sizeof(char), out);
1249                 fputc('\"', out);
1250         } else {
1251                 fprintf(out, "\"%s\"", safe_str(name));
1252         }
1253 }
1254
1255 static void 
1256 palm_csv_handle_specials(FILE *out, int item, int field)
1257 {
1258         switch(field) {
1259                 case PALM_CSV_NAME:
1260                         palm_split_and_write_name(out, database[item][NAME]);
1261                         break;
1262                 case PALM_CSV_CAT:
1263                         fprintf(out, "\"abook\"");
1264                         break;
1265                 case PALM_CSV_END:
1266                         fprintf(out, "\"0\"");
1267                         break;
1268                 default:
1269                         assert(0);
1270         }
1271 }
1272
1273 static int
1274 palm_export_database(FILE *out, struct db_enumerator e)
1275 {
1276         int palm_export_fields[] = {
1277                 PALM_CSV_NAME,          /* LASTNAME, FIRSTNAME  */
1278                 CSV_UNDEFINED,          /* TITLE                */
1279                 CSV_UNDEFINED,          /* COMPANY              */
1280                 WORKPHONE,              /* WORK PHONE           */
1281                 PHONE,                  /* HOME PHONE           */
1282                 FAX,                    /* FAX                  */
1283                 MOBILEPHONE,            /* OTHER                */
1284                 EMAIL,                  /* EMAIL                */
1285                 ADDRESS,                /* ADDRESS              */ 
1286                 CITY,                   /* CITY                 */
1287                 STATE,                  /* STATE                */
1288                 ZIP,                    /* ZIP                  */
1289                 COUNTRY,                /* COUNTRY              */
1290                 NICK,                   /* DEFINED 1            */
1291                 URL,                    /* DEFINED 2            */
1292                 CSV_UNDEFINED,          /* DEFINED 3            */
1293                 CSV_UNDEFINED,          /* DEFINED 4            */
1294                 NOTES,                  /* NOTE                 */
1295                 PALM_CSV_END,           /* "0"                  */
1296                 PALM_CSV_CAT,           /* CATEGORY             */
1297                 CSV_LAST
1298         };
1299
1300         csv_export_common(out, e, palm_export_fields, palm_csv_handle_specials);
1301
1302         return 0;
1303 }
1304
1305 /*
1306  * end of csv export filters
1307  */
1308
1309 /*
1310  * GnomeCard (VCard) addressbook export filter
1311  */
1312
1313 static int
1314 gcrd_export_database(FILE *out, struct db_enumerator e)
1315 {
1316         char emails[MAX_EMAILS][MAX_EMAIL_LEN];
1317         int j;
1318         char *name;
1319
1320         db_enumerate_items(e) {
1321                 fprintf(out, "BEGIN:VCARD\nFN:%s\n",
1322                                 safe_str(database[e.item][NAME]));
1323
1324                 name = get_surname(database[e.item][NAME]);
1325                 for( j = strlen(database[e.item][NAME]) - 1; j >= 0; j-- ) {
1326                         if(database[e.item][NAME][j] == ' ')
1327                                 break;
1328                 } 
1329                 fprintf(out, "N:%s;%.*s\n",
1330                         safe_str(name),
1331                         j,
1332                         safe_str(database[e.item][NAME])
1333                         ); 
1334
1335                 free(name);
1336
1337                 if ( database[e.item][ADDRESS] )
1338                         fprintf(out, "ADR:;;%s;%s;%s;%s;%s;%s\n",
1339                                 safe_str(database[e.item][ADDRESS]),
1340                                 safe_str(database[e.item][ADDRESS2]),                           
1341                                 safe_str(database[e.item][CITY]),
1342                                 safe_str(database[e.item][STATE]),
1343                                 safe_str(database[e.item][ZIP]),
1344                                 safe_str(database[e.item][COUNTRY])
1345                                 );
1346                 
1347                 if (database[e.item][PHONE])
1348                         fprintf(out, "TEL;HOME:%s\n", database[e.item][PHONE]);
1349                 if (database[e.item][WORKPHONE])
1350                         fprintf(out, "TEL;WORK:%s\n", database[e.item][WORKPHONE]);
1351                 if (database[e.item][FAX])
1352                         fprintf(out, "TEL;FAX:%s\n", database[e.item][FAX]);
1353                 if (database[e.item][MOBILEPHONE])
1354                         fprintf(out, "TEL;CELL:%s\n", database[e.item][MOBILEPHONE]);
1355
1356                 if ( database[e.item][EMAIL] ) {
1357                         split_emailstr(e.item, emails);
1358                         for(j=0; j < MAX_EMAILS ; j++) {
1359                                 if ( *emails[j] ) 
1360                                         fprintf(out, "EMAIL;INTERNET:%s\n",
1361                                                 emails[j]);
1362                         }
1363                 }
1364                 
1365                 if ( database[e.item][NOTES] ) 
1366                         fprintf(out, "NOTE:%s\n", database[e.item][NOTES]);
1367                 if (database[e.item][URL])
1368                         fprintf(out, "URL:%s\n",  database[e.item][URL]);
1369
1370                 fprintf(out, "END:VCARD\n\n");
1371                 
1372         }
1373
1374         return 0;
1375 }
1376
1377 /*
1378  * end of GnomeCard export filter
1379  */
1380
1381
1382 /*
1383  * mutt alias export filter
1384  */
1385
1386 static char *
1387 mutt_alias_genalias(int i)
1388 {
1389         char *tmp, *pos;
1390         
1391         if(database[i][NICK])
1392                 return strdup(database[i][NICK]);
1393
1394         tmp = strdup(database[i][NAME]);
1395
1396         if( ( pos = strchr(tmp, ' ') ) )
1397                 *pos = 0;
1398
1399         strlower(tmp);
1400
1401         return tmp;     
1402 }
1403
1404 static int
1405 mutt_alias_export(FILE *out, struct db_enumerator e)
1406 {
1407         char email[MAX_EMAIL_LEN];
1408         char *alias = NULL;
1409
1410         db_enumerate_items(e) {
1411                 alias = mutt_alias_genalias(e.item);
1412
1413                 get_first_email(email, e.item);
1414                 fprintf(out, *email ? "alias %s %s <%s>\n": "alias %s %s%s\n",
1415                                 alias,
1416                                 database[e.item][NAME],
1417                                 email);
1418                 my_free(alias);
1419         }
1420
1421         return 0;
1422 }
1423
1424 /*
1425  * end of mutt alias export filter
1426  */
1427
1428
1429 /*
1430  * printable export filter
1431  */
1432
1433
1434 static void
1435 text_write_address_us(FILE *out, int i) {
1436         fprintf(out, "\n%s", database[i][ADDRESS]);
1437
1438         if (database[i][ADDRESS2])
1439                 fprintf(out, "\n%s", database[i][ADDRESS2]);
1440
1441         if (database[i][CITY])
1442                 fprintf(out, "\n%s", database[i][CITY]);
1443                 
1444         if (database[i][STATE] || database[i][ZIP]) {
1445                 fputc('\n', out);
1446                 
1447                 if(database[i][STATE]) {
1448                         fprintf(out, "%s", database[i][STATE]);
1449                         if(database[i][ZIP])
1450                                 fputc(' ', out);
1451                 }
1452
1453                 if(database[i][ZIP])
1454                         fprintf(out, "%s", database[i][ZIP]);
1455         }
1456
1457         if (database[i][COUNTRY])
1458                 fprintf(out, "\n%s", database[i][COUNTRY]);
1459 }
1460
1461
1462 static void
1463 text_write_address_uk(FILE *out, int i) {
1464         int j;
1465
1466         for (j = ADDRESS; j <= COUNTRY; j++)
1467                 if (database[i][j])
1468                         fprintf(out, "\n%s", database[i][j]);
1469 }
1470
1471 static void
1472 text_write_address_eu(FILE *out, int i) {
1473         fprintf(out, "\n%s", database[i][ADDRESS]);
1474
1475         if (database[i][ADDRESS2])
1476                 fprintf(out, "\n%s", database[i][ADDRESS2]);
1477
1478         if (database[i][ZIP] || database[i][CITY]) {
1479                 fputc('\n', out);
1480
1481                 if(database[i][ZIP]) {
1482                         fprintf(out, "%s", database[i][ZIP]);
1483                         if(database[i][CITY])
1484                                 fputc(' ', out);
1485                 }
1486
1487                 if(database[i][CITY])
1488                         fprintf(out, "%s", database[i][CITY]);
1489         }
1490         
1491         if (database[i][STATE])
1492                 fprintf(out, "\n%s", database[i][STATE]);
1493
1494         if (database[i][COUNTRY])
1495                 fprintf(out, "\n%s", database[i][COUNTRY]);
1496 }
1497
1498 static int
1499 text_export_database(FILE * out, struct db_enumerator e)
1500 {
1501         char emails[MAX_EMAILS][MAX_EMAIL_LEN];
1502         int j;
1503         char *realname = get_real_name();
1504         char *style = opt_get_str(STR_ADDRESS_STYLE);
1505
1506         fprintf(out,
1507                 "-----------------------------------------\n%s's address book\n"
1508                 "-----------------------------------------\n\n\n",
1509                 realname);
1510         free(realname);
1511
1512         db_enumerate_items(e) {
1513                 fprintf(out,
1514                         "-----------------------------------------\n\n");
1515                 fprintf(out, "%s", database[e.item][NAME]);
1516                 if (database[e.item][NICK] && *database[e.item][NICK])
1517                         fprintf(out, "\n(%s)", database[e.item][NICK]);
1518                 fprintf(out, "\n");
1519
1520                 if (*database[e.item][EMAIL]) {
1521                         fprintf(out, "\n");
1522                         split_emailstr(e.item, emails);
1523                         for (j = 0; j < MAX_EMAILS; j++)
1524                                 if (*emails[j])
1525                                         fprintf(out, "%s\n", emails[j]);
1526                 }
1527                 /* Print address */
1528                 if (database[e.item][ADDRESS]) {
1529                         if (!safe_strcmp(style, "us"))  /* US like */
1530                                 text_write_address_us(out, e.item);
1531                         else if (!safe_strcmp(style, "uk"))     /* UK like */
1532                                 text_write_address_uk(out, e.item);
1533                         else    /* EU like */
1534                                 text_write_address_eu(out, e.item);
1535
1536                         fprintf(out, "\n");
1537                 }
1538
1539                 if ((database[e.item][PHONE]) ||
1540                         (database[e.item][WORKPHONE]) ||
1541                         (database[e.item][FAX]) ||
1542                         (database[e.item][MOBILEPHONE])) {
1543                         fprintf(out, "\n");
1544                         for (j = PHONE; j <= MOBILEPHONE; j++)
1545                                 if (database[e.item][j])
1546                                         fprintf(out, "%s: %s\n",
1547                                                 abook_fields[j].name,
1548                                                 database[e.item][j]);
1549                 }
1550
1551                 if (database[e.item][URL])
1552                         fprintf(out, "\n%s\n", database[e.item][URL]);
1553                 if (database[e.item][NOTES])
1554                         fprintf(out, "\n%s\n", database[e.item][NOTES]);
1555
1556                 fprintf(out, "\n");
1557         }
1558
1559         fprintf(out, "-----------------------------------------\n");
1560
1561         return 0;
1562 }
1563
1564 /*
1565  * end of printable export filter
1566  */
1567
1568 /*
1569  * elm alias export filter
1570  */
1571
1572 static int
1573 elm_alias_export(FILE *out, struct db_enumerator e)
1574 {
1575         char email[MAX_EMAIL_LEN];
1576         char *alias = NULL;
1577
1578         db_enumerate_items(e) {
1579                 alias = mutt_alias_genalias(e.item);
1580                 get_first_email(email, e.item);
1581                 fprintf(out, "%s = %s = %s\n",
1582                                 alias,
1583                                 database[e.item][NAME],
1584                                 email);
1585                 my_free(alias);
1586         }
1587
1588         return 0;
1589 }
1590
1591 /*
1592  * end of elm alias export filter
1593  */
1594
1595
1596 /*
1597  * Spruce export filter
1598  */
1599
1600 static int
1601 spruce_export_database (FILE *out, struct db_enumerator e)
1602 {
1603         char email[MAX_EMAIL_LEN];
1604
1605         fprintf (out, "# This is a generated file made by abook for the Spruce e-mail client.\n\n");
1606
1607         db_enumerate_items(e) {
1608                 if(strcmp (safe_str(database[e.item][EMAIL]), "")) {
1609                         get_first_email(email, e.item);
1610                         fprintf(out, "# Address %d\nName: %s\nEmail: %s\nMemo: %s\n\n",
1611                                         e.item,
1612                                         database[e.item][NAME],
1613                                         email,
1614                                         safe_str(database[e.item][NOTES])
1615                                         );
1616                 }
1617         }
1618
1619         fprintf (out, "# End of address book file.\n");
1620
1621         return 0;
1622 }
1623
1624 /*
1625  * end of Spruce export filter
1626  */
1627