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