]> git.deb.at Git - pkg/abook.git/blob - filter.c
7dcfa329c42392141090b77c9d3928d578affe4f
[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);
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                         item[pine_conv_table[i]] = strdup(tmp);
917                 }
918                 start = end + 1;
919         }
920
921         pine_convert_emails(item[EMAIL]);
922         add_item2database(item);
923 }
924
925
926 #define LINESIZE        1024
927
928 static int
929 pine_parse_file(FILE *in)
930 {
931         char line[LINESIZE];
932         char *buf = NULL;
933         char *ptr;
934         int i;
935
936         fgets(line, LINESIZE, in);      
937
938         while(!feof(in)) {
939                 for(i = 2;;i++) {
940                         buf = (char *) realloc(buf, i*LINESIZE);
941                         if(i == 2)
942                                 strcpy(buf, line);
943                         fgets(line, LINESIZE, in);
944                         ptr=(char *)&line;
945                         if(*ptr != ' ' || feof(in) )
946                                 break;
947                         else
948                                 while( *ptr == ' ')
949                                         ptr++;
950
951                         strcat(buf, ptr);
952                 }
953                 if( *buf == '#' ) {
954                         my_free(buf);
955                         continue;
956                 }
957                 pine_fixbuf(buf);
958
959                 pine_parse_buf(buf);
960
961                 my_free(buf);
962         }
963
964         return 0;
965 }
966
967 /*
968  * end of pine addressbook import filter
969  */
970
971
972 /*
973  * pine addressbook export filter
974  *
975  *  filter doesn't wrap the lines as it should but Pine seems to handle
976  *  created files without problems - JH
977  */
978
979 static int
980 pine_export_database(FILE *out, struct db_enumerator e)
981 {
982         db_enumerate_items(e) {
983                 fprintf(out, have_multiple_emails(e.item) ?
984                                 "%s\t%s\t(%s)\t\t%s\n" : "%s\t%s\t%s\t\t%s\n",
985                                 safe_str(database[e.item][NICK]),
986                                 safe_str(database[e.item][NAME]),
987                                 safe_str(database[e.item][EMAIL]),
988                                 safe_str(database[e.item][NOTES])
989                                 );
990         }
991
992         return 0;
993 }
994
995 /*
996  * end of pine addressbook export filter
997  */
998
999
1000 /*
1001  * csv import filter
1002  */
1003
1004 /* FIXME
1005  * these files should be parsed according to a certain
1006  * lay out, or the default if layout is not given, at 
1007  * the moment only default is done...
1008  */ 
1009
1010 #define CSV_COMMENT_CHAR        '#'
1011
1012 static int csv_conv_table[] = {
1013         NAME,
1014         EMAIL,
1015         PHONE,
1016         NOTES,
1017         NICK
1018 };
1019
1020 static void
1021 csv_convert_emails(char *s)
1022 {
1023         int i;
1024         char *tmp;
1025
1026         if( s == NULL )
1027                 return;
1028
1029         for(i=1; ( tmp = strchr(s, ',') ) != NULL ; i++, s = tmp + 1 )
1030                 if( i > MAX_EMAILS - 1 ) {
1031                         *tmp = 0;
1032                         break;  
1033                 }
1034
1035 }
1036
1037 static char *
1038 csv_remove_quotes(char *s)
1039 {
1040         char *copy, *trimmed;
1041         int len;
1042
1043         copy = trimmed = strdup(s);
1044         strtrim(trimmed);
1045
1046         len = strlen(trimmed);
1047         if(trimmed[len - 1] == '\"' && *trimmed == '\"') {
1048                 if(len < 3) {
1049                         my_free(copy);
1050                         return NULL;
1051                 }
1052                 trimmed[len - 1] = 0;
1053                 trimmed++;
1054                 trimmed = strdup(trimmed);
1055                 free(copy);
1056                 return trimmed;
1057         }
1058
1059         my_free(copy);
1060         return strdup(s);
1061 }
1062
1063 static void
1064 csv_store_field(list_item item, char *s, int field)
1065 {
1066         char *newstr = NULL;
1067
1068         if(!s || !*s)
1069                 return;
1070
1071         if( !(newstr = csv_remove_quotes(s)) )
1072                 return;
1073
1074         if(field < (int)(sizeof(csv_conv_table) / sizeof(*csv_conv_table))
1075                         && csv_conv_table[field] >= 0) {
1076                 item[csv_conv_table[field]] = newstr;
1077         } else {
1078                 my_free(newstr);
1079         }
1080 }
1081
1082 static int
1083 csv_is_valid_quote_end(char *p)
1084 {
1085         if(*p != '\"')
1086                 return FALSE;
1087
1088         for(p++; *p; p++) {
1089                 if(*p == ',')
1090                         return TRUE;
1091                 else if(!ISSPACE(*p))
1092                         return FALSE;
1093         }
1094
1095         return TRUE;
1096 }
1097
1098 static int
1099 csv_is_valid_quote_start(char *p)
1100 {
1101         for(; *p; p++) {
1102                 if(*p == '\"')
1103                         return TRUE;
1104                 else if(!ISSPACE(*p))
1105                         return FALSE;
1106         }
1107
1108         return FALSE;
1109 }
1110
1111 static void
1112 csv_parse_line(char *line)
1113 {
1114         char *p, *start;
1115         int field;
1116         bool in_quote = FALSE;
1117         list_item item;
1118
1119         memset(item, 0, sizeof(item));
1120
1121         for(p = start = line, field = 0; *p; p++) {
1122                 if(in_quote) {
1123                         if(csv_is_valid_quote_end(p))
1124                                 in_quote = FALSE;
1125                 } else {
1126                         if ( (((p - start) / sizeof (char)) < 2 ) &&
1127                                 csv_is_valid_quote_start(p) )
1128                                 in_quote = TRUE;
1129                 }
1130
1131                 if( *p == ',' && !in_quote) {
1132                         *p = 0;
1133                         csv_store_field(item, start, field);
1134                         field++;
1135                         start = p + 1;
1136                 }
1137         }
1138         /*
1139          * store last field
1140          */
1141         csv_store_field(item, start, field);
1142
1143         csv_convert_emails(item[EMAIL]);
1144         add_item2database(item);
1145 }
1146
1147
1148 static int
1149 csv_parse_file(FILE *in)
1150 {
1151         char *line = NULL;
1152
1153         while(!feof(in)) {
1154                 line = getaline(in);
1155
1156                 if(line && *line && *line != CSV_COMMENT_CHAR)
1157                         csv_parse_line(line);
1158
1159                 my_free(line);
1160         }
1161
1162         return 0;
1163 }
1164
1165 /*
1166  * end of csv import filter
1167  */
1168
1169 /*
1170  * csv addressbook export filters
1171  */
1172
1173 #define CSV_LAST                (-1)
1174 #define CSV_UNDEFINED           (-2)
1175 #define CSV_SPECIAL(X)          (-3 - (X))
1176 #define CSV_IS_SPECIAL(X)       ((X) <= -3)
1177
1178 static int
1179 csv_export_common(FILE *out, struct db_enumerator e,
1180                 int fields[], void (*special_func)(FILE *, int, int))
1181 {
1182         int i;
1183
1184         db_enumerate_items(e) {
1185                 for(i = 0; fields[i] != CSV_LAST; i++) {
1186                         if(fields[i] == CSV_UNDEFINED)
1187                                 fprintf(out, "\"\"");
1188                         else if(CSV_IS_SPECIAL(fields[i])) {
1189                                 if(special_func)
1190                                         (*special_func)(out, e.item, fields[i]);
1191                         } else
1192                                 /*fprintf(out,(
1193                         strchr(safe_str(database[e.item][fields[i]]), ',') ||
1194                         strchr(safe_str(database[e.item][fields[i]]), '\"')) ?
1195                                 "\"%s\"" : "%s",
1196                                 safe_str(database[e.item][fields[i]])
1197                                 );*/
1198                                 fprintf(out, "\"%s\"",
1199                                         safe_str(database[e.item][fields[i]]));
1200
1201                         if(fields[i + 1] != CSV_LAST)
1202                                 fputc(',', out);
1203                 }
1204                 fputc('\n', out);
1205         }
1206
1207         return 0;
1208 }
1209
1210 static int
1211 csv_export_database(FILE *out, struct db_enumerator e)
1212 {
1213         int csv_export_fields[] = {
1214                 NAME,
1215                 EMAIL,
1216                 PHONE,
1217                 NOTES,
1218                 NICK,
1219                 CSV_LAST
1220         };
1221
1222         csv_export_common(out, e, csv_export_fields, NULL);
1223         
1224         return 0;
1225 }
1226
1227 /*
1228  * palm csv
1229  */
1230
1231 #define PALM_CSV_NAME   CSV_SPECIAL(0)
1232 #define PALM_CSV_END    CSV_SPECIAL(1)
1233 #define PALM_CSV_CAT    CSV_SPECIAL(2)
1234
1235 static void 
1236 palm_split_and_write_name(FILE *out, char *name)
1237 {
1238         char *p;
1239
1240         assert(name);
1241
1242         if ( (p = strchr(name, ' ')) ) {
1243                 /*
1244                  * last name first
1245                  */
1246                 fprintf(out, "\"%s\",\"" , p + 1);
1247                 fwrite((void *)name, p - name, sizeof(char), out);
1248                 fputc('\"', out);
1249         } else {
1250                 fprintf(out, "\"%s\"", safe_str(name));
1251         }
1252 }
1253
1254 static void 
1255 palm_csv_handle_specials(FILE *out, int item, int field)
1256 {
1257         switch(field) {
1258                 case PALM_CSV_NAME:
1259                         palm_split_and_write_name(out, database[item][NAME]);
1260                         break;
1261                 case PALM_CSV_CAT:
1262                         fprintf(out, "\"abook\"");
1263                         break;
1264                 case PALM_CSV_END:
1265                         fprintf(out, "\"0\"");
1266                         break;
1267                 default:
1268                         assert(0);
1269         }
1270 }
1271
1272 static int
1273 palm_export_database(FILE *out, struct db_enumerator e)
1274 {
1275         int palm_export_fields[] = {
1276                 PALM_CSV_NAME,          /* LASTNAME, FIRSTNAME  */
1277                 CSV_UNDEFINED,          /* TITLE                */
1278                 CSV_UNDEFINED,          /* COMPANY              */
1279                 WORKPHONE,              /* WORK PHONE           */
1280                 PHONE,                  /* HOME PHONE           */
1281                 FAX,                    /* FAX                  */
1282                 MOBILEPHONE,            /* OTHER                */
1283                 EMAIL,                  /* EMAIL                */
1284                 ADDRESS,                /* ADDRESS              */ 
1285                 CITY,                   /* CITY                 */
1286                 STATE,                  /* STATE                */
1287                 ZIP,                    /* ZIP                  */
1288                 COUNTRY,                /* COUNTRY              */
1289                 NICK,                   /* DEFINED 1            */
1290                 URL,                    /* DEFINED 2            */
1291                 CSV_UNDEFINED,          /* DEFINED 3            */
1292                 CSV_UNDEFINED,          /* DEFINED 4            */
1293                 NOTES,                  /* NOTE                 */
1294                 PALM_CSV_END,           /* "0"                  */
1295                 PALM_CSV_CAT,           /* CATEGORY             */
1296                 CSV_LAST
1297         };
1298
1299         csv_export_common(out, e, palm_export_fields, palm_csv_handle_specials);
1300
1301         return 0;
1302 }
1303
1304 /*
1305  * end of csv export filters
1306  */
1307
1308 /*
1309  * GnomeCard (VCard) addressbook export filter
1310  */
1311
1312 static int
1313 gcrd_export_database(FILE *out, struct db_enumerator e)
1314 {
1315         char emails[MAX_EMAILS][MAX_EMAIL_LEN];
1316         int j;
1317         char *name;
1318
1319         db_enumerate_items(e) {
1320                 fprintf(out, "BEGIN:VCARD\nFN:%s\n",
1321                                 safe_str(database[e.item][NAME]));
1322
1323                 name = get_surname(database[e.item][NAME]);
1324                 for( j = strlen(database[e.item][NAME]) - 1; j >= 0; j-- ) {
1325                         if(database[e.item][NAME][j] == ' ')
1326                                 break;
1327                 } 
1328                 fprintf(out, "N:%s;%.*s\n",
1329                         safe_str(name),
1330                         j,
1331                         safe_str(database[e.item][NAME])
1332                         ); 
1333
1334                 free(name);
1335
1336                 if ( database[e.item][ADDRESS] )
1337                         fprintf(out, "ADR:;;%s;%s;%s;%s;%s;%s\n",
1338                                 safe_str(database[e.item][ADDRESS]),
1339                                 safe_str(database[e.item][ADDRESS2]),                           
1340                                 safe_str(database[e.item][CITY]),
1341                                 safe_str(database[e.item][STATE]),
1342                                 safe_str(database[e.item][ZIP]),
1343                                 safe_str(database[e.item][COUNTRY])
1344                                 );
1345                 
1346                 if (database[e.item][PHONE])
1347                         fprintf(out, "TEL;HOME:%s\n", database[e.item][PHONE]);
1348                 if (database[e.item][WORKPHONE])
1349                         fprintf(out, "TEL;WORK:%s\n", database[e.item][WORKPHONE]);
1350                 if (database[e.item][FAX])
1351                         fprintf(out, "TEL;FAX:%s\n", database[e.item][FAX]);
1352                 if (database[e.item][MOBILEPHONE])
1353                         fprintf(out, "TEL;CELL:%s\n", database[e.item][MOBILEPHONE]);
1354
1355                 if ( database[e.item][EMAIL] ) {
1356                         split_emailstr(e.item, emails);
1357                         for(j=0; j < MAX_EMAILS ; j++) {
1358                                 if ( *emails[j] ) 
1359                                         fprintf(out, "EMAIL;INTERNET:%s\n",
1360                                                 emails[j]);
1361                         }
1362                 }
1363                 
1364                 if ( database[e.item][NOTES] ) 
1365                         fprintf(out, "NOTE:%s\n", database[e.item][NOTES]);
1366                 if (database[e.item][URL])
1367                         fprintf(out, "URL:%s\n",  database[e.item][URL]);
1368
1369                 fprintf(out, "END:VCARD\n\n");
1370                 
1371         }
1372
1373         return 0;
1374 }
1375
1376 /*
1377  * end of GnomeCard export filter
1378  */
1379
1380
1381 /*
1382  * mutt alias export filter
1383  */
1384
1385 static char *
1386 mutt_alias_genalias(int i)
1387 {
1388         char *tmp, *pos;
1389         
1390         if(database[i][NICK])
1391                 return strdup(database[i][NICK]);
1392
1393         tmp = strdup(database[i][NAME]);
1394
1395         if( ( pos = strchr(tmp, ' ') ) )
1396                 *pos = 0;
1397
1398         strlower(tmp);
1399
1400         return tmp;     
1401 }
1402
1403 static int
1404 mutt_alias_export(FILE *out, struct db_enumerator e)
1405 {
1406         char email[MAX_EMAIL_LEN];
1407         char *alias = NULL;
1408
1409         db_enumerate_items(e) {
1410                 alias = mutt_alias_genalias(e.item);
1411
1412                 get_first_email(email, e.item);
1413                 fprintf(out, *email ? "alias %s %s <%s>\n": "alias %s %s%s\n",
1414                                 alias,
1415                                 database[e.item][NAME],
1416                                 email);
1417                 my_free(alias);
1418         }
1419
1420         return 0;
1421 }
1422
1423 /*
1424  * end of mutt alias export filter
1425  */
1426
1427
1428 /*
1429  * printable export filter
1430  */
1431
1432
1433 static void
1434 text_write_address_us(FILE *out, int i) {
1435         fprintf(out, "\n%s", database[i][ADDRESS]);
1436
1437         if (database[i][ADDRESS2])
1438                 fprintf(out, "\n%s", database[i][ADDRESS2]);
1439
1440         if (database[i][CITY])
1441                 fprintf(out, "\n%s", database[i][CITY]);
1442                 
1443         if (database[i][STATE] || database[i][ZIP]) {
1444                 fputc('\n', out);
1445                 
1446                 if(database[i][STATE]) {
1447                         fprintf(out, "%s", database[i][STATE]);
1448                         if(database[i][ZIP])
1449                                 fputc(' ', out);
1450                 }
1451
1452                 if(database[i][ZIP])
1453                         fprintf(out, "%s", database[i][ZIP]);
1454         }
1455
1456         if (database[i][COUNTRY])
1457                 fprintf(out, "\n%s", database[i][COUNTRY]);
1458 }
1459
1460
1461 static void
1462 text_write_address_uk(FILE *out, int i) {
1463         int j;
1464
1465         for (j = ADDRESS; j <= COUNTRY; j++)
1466                 if (database[i][j])
1467                         fprintf(out, "\n%s", database[i][j]);
1468 }
1469
1470 static void
1471 text_write_address_eu(FILE *out, int i) {
1472         fprintf(out, "\n%s", database[i][ADDRESS]);
1473
1474         if (database[i][ADDRESS2])
1475                 fprintf(out, "\n%s", database[i][ADDRESS2]);
1476
1477         if (database[i][ZIP] || database[i][CITY]) {
1478                 fputc('\n', out);
1479
1480                 if(database[i][ZIP]) {
1481                         fprintf(out, "%s", database[i][ZIP]);
1482                         if(database[i][CITY])
1483                                 fputc(' ', out);
1484                 }
1485
1486                 if(database[i][CITY])
1487                         fprintf(out, "%s", database[i][CITY]);
1488         }
1489         
1490         if (database[i][STATE])
1491                 fprintf(out, "\n%s", database[i][STATE]);
1492
1493         if (database[i][COUNTRY])
1494                 fprintf(out, "\n%s", database[i][COUNTRY]);
1495 }
1496
1497 static int
1498 text_export_database(FILE * out, struct db_enumerator e)
1499 {
1500         char emails[MAX_EMAILS][MAX_EMAIL_LEN];
1501         int j;
1502         char *realname = get_real_name();
1503         char *style = opt_get_str(STR_ADDRESS_STYLE);
1504
1505         fprintf(out,
1506                 "-----------------------------------------\n%s's address book\n"
1507                 "-----------------------------------------\n\n\n",
1508                 realname);
1509         free(realname);
1510
1511         db_enumerate_items(e) {
1512                 fprintf(out,
1513                         "-----------------------------------------\n\n");
1514                 fprintf(out, "%s", database[e.item][NAME]);
1515                 if (database[e.item][NICK])
1516                         fprintf(out, "\n(%s)", database[e.item][NICK]);
1517                 fprintf(out, "\n");
1518
1519                 if (*database[e.item][EMAIL]) {
1520                         fprintf(out, "\n");
1521                         split_emailstr(e.item, emails);
1522                         for (j = 0; j < MAX_EMAILS; j++)
1523                                 if (*emails[j])
1524                                         fprintf(out, "%s\n", emails[j]);
1525                 }
1526                 /* Print address */
1527                 if (database[e.item][ADDRESS]) {
1528                         if (!safe_strcmp(style, "us"))  /* US like */
1529                                 text_write_address_us(out, e.item);
1530                         else if (!safe_strcmp(style, "uk"))     /* UK like */
1531                                 text_write_address_uk(out, e.item);
1532                         else    /* EU like */
1533                                 text_write_address_eu(out, e.item);
1534
1535                         fprintf(out, "\n");
1536                 }
1537
1538                 if ((database[e.item][PHONE]) ||
1539                         (database[e.item][WORKPHONE]) ||
1540                         (database[e.item][FAX]) ||
1541                         (database[e.item][MOBILEPHONE])) {
1542                         fprintf(out, "\n");
1543                         for (j = PHONE; j <= MOBILEPHONE; j++)
1544                                 if (database[e.item][j])
1545                                         fprintf(out, "%s: %s\n",
1546                                                 abook_fields[j].name,
1547                                                 database[e.item][j]);
1548                 }
1549
1550                 if (database[e.item][URL])
1551                         fprintf(out, "\n%s\n", database[e.item][URL]);
1552                 if (database[e.item][NOTES])
1553                         fprintf(out, "\n%s\n", database[e.item][NOTES]);
1554
1555                 fprintf(out, "\n");
1556         }
1557
1558         fprintf(out, "-----------------------------------------\n");
1559
1560         return 0;
1561 }
1562
1563 /*
1564  * end of printable export filter
1565  */
1566
1567 /*
1568  * elm alias export filter
1569  */
1570
1571 static int
1572 elm_alias_export(FILE *out, struct db_enumerator e)
1573 {
1574         char email[MAX_EMAIL_LEN];
1575         char *alias = NULL;
1576
1577         db_enumerate_items(e) {
1578                 alias = mutt_alias_genalias(e.item);
1579                 get_first_email(email, e.item);
1580                 fprintf(out, "%s = %s = %s\n",
1581                                 alias,
1582                                 database[e.item][NAME],
1583                                 email);
1584                 my_free(alias);
1585         }
1586
1587         return 0;
1588 }
1589
1590 /*
1591  * end of elm alias export filter
1592  */
1593
1594
1595 /*
1596  * Spruce export filter
1597  */
1598
1599 static int
1600 spruce_export_database (FILE *out, struct db_enumerator e)
1601 {
1602         char email[MAX_EMAIL_LEN];
1603
1604         fprintf (out, "# This is a generated file made by abook for the Spruce e-mail client.\n\n");
1605
1606         db_enumerate_items(e) {
1607                 if(strcmp (safe_str(database[e.item][EMAIL]), "")) {
1608                         get_first_email(email, e.item);
1609                         fprintf(out, "# Address %d\nName: %s\nEmail: %s\nMemo: %s\n\n",
1610                                         e.item,
1611                                         database[e.item][NAME],
1612                                         email,
1613                                         safe_str(database[e.item][NOTES])
1614                                         );
1615                 }
1616         }
1617
1618         fprintf (out, "# End of address book file.\n");
1619
1620         return 0;
1621 }
1622
1623 /*
1624  * end of Spruce export filter
1625  */
1626