]> git.deb.at Git - pkg/abook.git/blob - filter.c
96fa9c207e5b6d58788c8cda616a7f309c7f73f4
[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 #define _GNU_SOURCE
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <ctype.h>
16 #include <pwd.h>
17 #include <sys/stat.h>
18 #include <sys/types.h>
19 #include "abook_curses.h"
20 #include "filter.h"
21 #include "abook.h"
22 #include "database.h"
23 #include "edit.h"
24 #include "gettext.h"
25 #include "list.h"
26 #include "misc.h"
27 #include "options.h"
28 #include "ui.h"
29 #include "xmalloc.h"
30 #include <assert.h>
31
32 extern abook_field_list *fields_list;
33 extern int fields_count;
34
35 /*
36  * function declarations
37  */
38
39 /*
40  * import filter prototypes
41  */
42
43 static int      ldif_parse_file(FILE *handle);
44 static int      mutt_parse_file(FILE *in);
45 static int      pine_parse_file(FILE *in);
46 static int      csv_parse_file(FILE *in);
47 static int      allcsv_parse_file(FILE *in);
48 static int      palmcsv_parse_file(FILE *in);
49 static int      vcard_parse_file(FILE *in);
50
51 /*
52  * export filter prototypes
53  */
54
55 static int      ldif_export_database(FILE *out, struct db_enumerator e);
56 static int      html_export_database(FILE *out, struct db_enumerator e);
57 static int      pine_export_database(FILE *out, struct db_enumerator e);
58 static int      csv_export_database(FILE *out, struct db_enumerator e);
59 static int      allcsv_export_database(FILE *out, struct db_enumerator e);
60 static int      palm_export_database(FILE *out, struct db_enumerator e);
61 static int      vcard_export_database(FILE *out, struct db_enumerator e);
62 static int      mutt_alias_export(FILE *out, struct db_enumerator e);
63 static int      mutt_query_export_database(FILE *out, struct db_enumerator e);
64 static int      elm_alias_export(FILE *out, struct db_enumerator e);
65 static int      text_export_database(FILE *out, struct db_enumerator e);
66 static int      spruce_export_database(FILE *out, struct db_enumerator e);
67 static int      wl_export_database(FILE *out, struct db_enumerator e);
68 static int      bsdcal_export_database(FILE *out, struct db_enumerator e);
69
70 /*
71  * end of function declarations
72  */
73
74 struct abook_input_filter i_filters[] = {
75         { "abook", N_("abook native format"), parse_database },
76         { "ldif", N_("ldif / Netscape addressbook"), ldif_parse_file },
77         { "mutt", N_("mutt alias"), mutt_parse_file },
78         { "pine", N_("pine addressbook"), pine_parse_file },
79         { "csv", N_("comma separated values"), csv_parse_file },
80         { "allcsv", N_("comma separated values (all fields)"), allcsv_parse_file },
81         { "palmcsv", N_("Palm comma separated values"), palmcsv_parse_file },
82         { "vcard", N_("vCard file"), vcard_parse_file },
83         { "\0", NULL, NULL }
84 };
85
86 struct abook_output_filter e_filters[] = {
87         { "abook", N_("abook native format"), write_database },
88         { "ldif", N_("ldif / Netscape addressbook (.4ld)"), ldif_export_database },
89         { "vcard", N_("vCard 2 file"), vcard_export_database },
90         { "mutt", N_("mutt alias"), mutt_alias_export },
91         { "muttq", N_("mutt query format (internal use)"), mutt_query_export_database },
92         { "html", N_("html document"), html_export_database },
93         { "pine", N_("pine addressbook"), pine_export_database },
94         { "csv", N_("comma separated values"), csv_export_database },
95         { "allcsv", N_("comma separated values (all fields)"), allcsv_export_database },
96         { "palmcsv", N_("Palm comma separated values"), palm_export_database},
97         { "elm", N_("elm alias"), elm_alias_export },
98         { "text", N_("plain text"), text_export_database },
99         { "wl", N_("Wanderlust address book"), wl_export_database },
100         { "spruce", N_("Spruce address book"), spruce_export_database },
101         { "bsdcal", N_("BSD calendar"), bsdcal_export_database },
102         { "\0", NULL, NULL }
103 };
104
105 struct abook_output_item_filter u_filters[] = {
106         { "\0", NULL }
107 };
108
109 /*
110  * common functions
111  */
112
113 void
114 print_filters()
115 {
116         int i;
117
118         puts(_("input:"));
119         for(i=0; *i_filters[i].filtname ; i++)
120                 printf("\t%s\t%s\n", i_filters[i].filtname,
121                         gettext(i_filters[i].desc));
122
123         putchar('\n');
124
125         puts(_("output:"));
126         for(i=0; *e_filters[i].filtname ; i++)
127                 printf("\t%s\t%s\n", e_filters[i].filtname,
128                         gettext(e_filters[i].desc));
129
130         putchar('\n');
131
132         puts(_("output (with query):"));
133         for(i=0; *u_filters[i].filtname ; i++)
134                 printf("\t%s\t%s\n", u_filters[i].filtname,
135                         gettext(u_filters[i].desc));
136
137         putchar('\n');
138 }
139
140 static int
141 number_of_output_filters()
142 {
143         int i;
144
145         for(i=0; *e_filters[i].filtname ; i++)
146                 ;
147
148         return i;
149 }
150
151 static int
152 number_of_input_filters()
153 {
154         int i;
155
156         for(i=0; *i_filters[i].filtname ; i++)
157                 ;
158
159         return i;
160 }
161
162 static char *
163 get_real_name()
164 {
165         char *username = getenv("USER");
166         struct passwd *pwent;
167         int rtn;
168         char *tmp;
169
170         pwent = getpwnam(username);
171
172         if((tmp = xstrdup(pwent->pw_gecos)) == NULL)
173                 return xstrdup(username);
174
175         rtn = sscanf(pwent->pw_gecos, "%[^,]", tmp);
176         if (rtn == EOF || rtn == 0) {
177                 free(tmp);
178                 return xstrdup(username);
179         } else
180                 return tmp;
181 }
182
183 /*
184  * import
185  */
186
187 static int              i_read_file(char *filename, int (*func) (FILE *in));
188
189 static void
190 import_screen()
191 {
192         int i;
193
194         clear();
195
196         refresh_statusline();
197         headerline(_("import database"));
198
199         mvaddstr(3, 1, _("please select a filter"));
200
201
202         for(i=0; *i_filters[i].filtname ; i++)
203                 mvprintw(5 + i, 6, "%c -\t%s\t%s\n", 'a' + i,
204                         i_filters[i].filtname,
205                         gettext(i_filters[i].desc));
206
207         mvprintw(6 + i, 6, _("x -\tcancel"));
208 }
209
210 int
211 import_database()
212 {
213         int filter;
214         char *filename;
215         int tmp = db_n_items();
216
217         import_screen();
218
219         filter = getch() - 'a';
220         if(filter == 'x' - 'a' ||
221                 filter >= number_of_input_filters() || filter < 0) {
222                 refresh_screen();
223                 return 1;
224         }
225
226         mvaddstr(5+filter, 2, "->");
227
228         filename = ask_filename(_("Filename: "));
229         if(!filename) {
230                 refresh_screen();
231                 return 2;
232         }
233
234         if(i_read_file(filename, i_filters[filter].func ))
235                 statusline_msg(_("Error occured while opening the file"));
236         else if(tmp == db_n_items())
237                 statusline_msg(_("File does not seem to be a valid addressbook"));
238
239         refresh_screen();
240         free(filename);
241
242         return 0;
243 }
244
245
246
247 static int
248 i_read_file(char *filename, int (*func) (FILE *in))
249 {
250         FILE *in;
251         int ret = 0;
252
253         if( (in = abook_fopen( filename, "r" )) == NULL )
254                 return 1;
255
256         ret = (*func) (in);
257
258         fclose(in);
259
260         return ret;
261 }
262
263 int
264 import_file(char filtname[FILTNAME_LEN], char *filename)
265 {
266         int i;
267         int tmp = db_n_items();
268         int ret = 0;
269
270         for(i=0;; i++) {
271                 if(! strncasecmp(i_filters[i].filtname, filtname,
272                                         FILTNAME_LEN) )
273                         break;
274                 if(! *i_filters[i].filtname) {
275                         i = -1;
276                         break;
277                 }
278         }
279
280         if(i < 0)
281                 return -1;
282
283         if(!strcmp(filename, "-")) {
284                 struct stat s;
285                 if((fstat(fileno(stdin), &s)) == -1 || S_ISDIR(s.st_mode))
286                         ret = 1;
287                 else
288                         ret = (*i_filters[i].func) (stdin);
289         } else
290                 ret =  i_read_file(filename, i_filters[i].func);
291
292         if(tmp == db_n_items())
293                 ret = 1;
294
295         return ret;
296 }
297
298 /*
299  * export
300  */
301
302 static int e_write_file(char *filename,
303                 int (*func) (FILE *in, struct db_enumerator e), int mode);
304
305 static void
306 export_screen()
307 {
308         int i;
309
310         clear();
311
312
313         refresh_statusline();
314         headerline(_("export database"));
315
316         mvaddstr(3, 1, _("please select a filter"));
317
318
319         for(i = 0; *e_filters[i].filtname ; i++)
320                 mvprintw(5 + i, 6, "%c -\t%s\t%s\n", 'a' + i,
321                         e_filters[i].filtname,
322                         gettext(e_filters[i].desc));
323
324         mvprintw(6 + i, 6, _("x -\tcancel"));
325 }
326
327 int
328 export_database()
329 {
330         int filter;
331         int enum_mode = ENUM_ALL;
332         char *filename;
333
334         export_screen();
335
336         filter = getch() - 'a';
337         if(filter == 'x' - 'a' ||
338                 filter >= number_of_output_filters() || filter < 0) {
339                 refresh_screen();
340                 return 1;
341         }
342
343         mvaddstr(5 + filter, 2, "->");
344
345         if(selected_items()) {
346                 switch(statusline_askchoice(
347                         _("Export <a>ll, export <s>elected, or <c>ancel?"),
348                         S_("keybindings:all/selected/cancel|asc"), 3)) {
349                         case 1:
350                                 break;
351                         case 2:
352                                 enum_mode = ENUM_SELECTED;
353                                 break;
354                         case 0:
355                         case 3:
356                                 refresh_screen();
357                                 return 1;
358                 }
359                 clear_statusline();
360         }
361
362         filename = ask_filename(_("Filename: "));
363         if(!filename) {
364                 refresh_screen();
365                 return 2;
366         }
367
368         if( e_write_file(filename, e_filters[filter].func, enum_mode))
369                 statusline_msg(_("Error occured while exporting"));
370
371         refresh_screen();
372         free(filename);
373
374         return 0;
375 }
376
377 struct abook_output_item_filter select_output_item_filter(char filtname[FILTNAME_LEN]) {
378         int i;
379         for(i=0;; i++) {
380                 if(!strncasecmp(u_filters[i].filtname, filtname, FILTNAME_LEN))
381                   break;
382                 if(!*u_filters[i].filtname) {
383                   i = -1;
384                   break;
385                 }
386         }
387         return u_filters[i];
388 }
389
390 void
391 e_write_item(FILE *out, int item, void (*func) (FILE *in, int item))
392 {
393   (*func) (out, item);
394 }
395
396 static int
397 e_write_file(char *filename, int (*func) (FILE *in, struct db_enumerator e),
398                 int mode)
399 {
400         FILE *out;
401         int ret = 0;
402         struct db_enumerator enumerator = init_db_enumerator(mode);
403
404         if((out = fopen(filename, "a")) == NULL)
405                 return 1;
406
407         if(ftell(out))
408                 return 1;
409
410         ret = (*func) (out, enumerator);
411
412         fclose(out);
413
414         return ret;
415 }
416
417 int
418 fexport(char filtname[FILTNAME_LEN], FILE *handle, int enum_mode)
419 {
420         int i;
421         struct db_enumerator e = init_db_enumerator(enum_mode);
422
423         for(i=0;; i++) {
424                 if(!strncasecmp(e_filters[i].filtname, filtname,
425                                         FILTNAME_LEN))
426                         break;
427                 if(!*e_filters[i].filtname) {
428                         i = -1;
429                         break;
430                 }
431         }
432
433         return (e_filters[i].func) (handle, e);
434 }
435
436
437
438 int
439 export_file(char filtname[FILTNAME_LEN], char *filename)
440 {
441         const int mode = ENUM_ALL;
442         int i;
443         int ret = 0;
444         struct db_enumerator e = init_db_enumerator(mode);
445
446         for(i=0;; i++) {
447                 if(!strncasecmp(e_filters[i].filtname, filtname,
448                                         FILTNAME_LEN))
449                         break;
450                 if(!*e_filters[i].filtname) {
451                         i = -1;
452                         break;
453                 }
454         }
455
456         if(i < 0)
457                 return -1;
458
459         if(!strcmp(filename, "-"))
460                 ret = (e_filters[i].func) (stdout, e);
461         else
462                 ret =  e_write_file(filename, e_filters[i].func, mode);
463
464         return ret;
465 }
466
467 /*
468  * end of common functions
469  */
470
471 /*
472  * ldif import
473  */
474
475 #include "ldif.h"
476
477 static void     ldif_fix_string(char *str);
478
479 #define LDIF_ITEM_FIELDS        16
480
481 typedef char *ldif_item[LDIF_ITEM_FIELDS];
482
483 static ldif_item ldif_field_names = {
484         "cn",
485         "mail",
486         "streetaddress",
487         "streetaddress2",
488         "locality",
489         "st",
490         "postalcode",
491         "countryname",
492         "homephone",
493         "description",
494         "homeurl",
495         "facsimiletelephonenumber",
496         "cellphone",
497         "xmozillaanyphone",
498         "xmozillanickname",
499         "objectclass", /* this must be the last entry */
500 };
501
502 static int ldif_conv_table[LDIF_ITEM_FIELDS] = {
503         NAME,           /* "cn" */
504         EMAIL,          /* "mail" */
505         ADDRESS,        /* "streetaddress" */
506         ADDRESS2,       /* "streetaddress2" */
507         CITY,           /* "locality" */
508         STATE,          /* "st" */
509         ZIP,            /* "postalcode" */
510         COUNTRY,        /* "countryname" */
511         PHONE,          /* "homephone" */
512         NOTES,          /* "description" */
513         URL,            /* "homeurl" */
514         FAX,            /* "facsimiletelephonenumber" */
515         MOBILEPHONE,    /* "cellphone" */
516         WORKPHONE,      /* "xmozillaanyphone" */
517         NICK,           /* "xmozillanickname" */
518         -1,             /* "objectclass" */ /* this must be the last entry */
519 };
520
521
522 static char *
523 ldif_read_line(FILE *in)
524 {
525         char *buf = NULL;
526         char *ptr, *tmp;
527         long pos;
528         int i;
529
530         for(i = 1;;i++) {
531                 char *line;
532
533                 pos = ftell(in);
534                 line = getaline(in);
535
536                 if(feof(in) || !line)
537                         break;
538
539                 if(i == 1) {
540                         buf = line;
541                         continue;
542                 }
543
544                 if(*line != ' ') {
545                         fseek(in, pos, SEEK_SET); /* fixme ! */
546                         free(line);
547                         break;
548                 }
549
550                 ptr = line;
551                 while( *ptr == ' ')
552                         ptr++;
553
554                 tmp = buf;
555                 buf = strconcat(buf, ptr, NULL);
556                 free(tmp);
557                 free(line);
558         }
559
560         if(buf && *buf == '#' ) {
561                 free(buf);
562                 return NULL;
563         }
564
565         return buf;
566 }
567
568 static void
569 ldif_add_item(ldif_item li)
570 {
571         list_item item;
572         int i;
573
574         item = item_create();
575
576         if(!li[LDIF_ITEM_FIELDS -1])
577                 goto bail_out;
578
579
580         for(i=0; i < LDIF_ITEM_FIELDS; i++) {
581                 if(ldif_conv_table[i] >= 0 && li[i] && *li[i])
582                         item_fput(item,ldif_conv_table[i],xstrdup(li[i]));
583         }
584
585         add_item2database(item);
586
587 bail_out:
588         for(i=0; i < LDIF_ITEM_FIELDS; i++)
589                 xfree(li[i]);
590         item_free(&item);
591
592 }
593
594 static void
595 ldif_convert(ldif_item item, char *type, char *value)
596 {
597         int i;
598
599         if(!strcmp(type, "dn")) {
600                 ldif_add_item(item);
601                 return;
602         }
603
604         for(i=0; i < LDIF_ITEM_FIELDS; i++) {
605                 if(!safe_strcmp(ldif_field_names[i], type) && *value) {
606                         if(i == LDIF_ITEM_FIELDS - 1) /* this is a dirty hack */
607                                 if(safe_strcmp("person", value))
608                                         break;
609
610                         if(item_fget(item, i))
611                                 free(item_fget(item, i));
612
613                         item_fput(item, i, xstrdup(value));
614                 }
615         }
616 }
617
618 static int
619 ldif_parse_file(FILE *handle)
620 {
621         char *line = NULL;
622         char *type, *value;
623         int vlen;
624         ldif_item item;
625
626         memset(item, 0, sizeof(item));
627
628         do {
629                 if( !(line = ldif_read_line(handle)) )
630                         continue;
631
632                 if(-1 == (str_parse_line(line, &type, &value, &vlen))) {
633                         xfree(line);
634                         continue; /* just skip the errors */
635                 }
636
637                 ldif_fix_string(value);
638
639                 ldif_convert(item, type, value);
640
641                 xfree(line);
642         } while ( !feof(handle) );
643
644         ldif_convert(item, "dn", "");
645
646         return 0;
647 }
648
649 static void
650 ldif_fix_string(char *str)
651 {
652         int i, j;
653
654         for(i = 0, j = 0; j < (int)strlen(str); i++, j++)
655                 str[i] = ( str[j] == (char)0xc3 ?
656                                 (char) str[++j] + (char) 0x40 :
657                                 str[j] );
658
659         str[i] = 0;
660 }
661
662 /*
663  * end of ldif import
664  */
665
666 /*
667  * mutt alias import filter
668  */
669
670 #include "getname.h"
671
672 static int
673 mutt_read_line(FILE *in, char **groups, char **alias, char **rest)
674 {
675         char *line, *ptr;
676         char *start, *end;
677         abook_list *glist = NULL;
678
679         if( !(line = ptr = getaline(in)) )
680                 return 1; /* error / EOF */
681
682         SKIPWS(ptr);
683
684         if(strncmp("alias", ptr, 5)) {
685                 free(line);
686                 return 1;
687         }
688
689         ptr += 5;
690         SKIPWS(ptr);
691
692         /* If the group option is used, save the groups */
693         *groups = NULL;
694         start = ptr;
695         int n_groups;
696         for(n_groups = 0; 0 == strncmp("-group", ptr, 6); n_groups++) {
697                 ptr += 6;
698                 SKIPWS(ptr);
699                 start = ptr;
700                 SKIPNONWS(ptr);
701                 end = ptr;
702                 abook_list_append(&glist,xstrndup(start, end - start));
703                 SKIPWS(ptr);
704         }
705
706         if(n_groups && groups)
707                 *groups = abook_list_to_csv(glist);
708
709         abook_list_free(&glist);        
710
711         /* alias */
712         start = ptr;
713         SKIPNONWS(ptr);
714         end = ptr;
715         SKIPWS(ptr);
716         if(alias)
717                 *alias = xstrndup(start, end - start);
718
719         /* rest (email) */
720         *rest = xstrdup(ptr);
721
722         xfree(line);
723         return 0;
724 }
725
726 static void
727 mutt_fix_quoting(char *p)
728 {
729         char *escape = 0;
730
731         for(; *p; p++) {
732                 switch(*p) {
733                         case '\"':
734                                 if(escape)
735                                         *escape = ' ';
736                                 break;
737                         case '\\':
738                                 escape = p;
739                                 break;
740                         default:
741                                 escape = 0;
742                 }
743         }
744 }
745
746 static void
747 mutt_parse_email(list_item item)
748 {
749         char *line = item_fget(item, NAME);
750         char *tmp;
751         char *name, *email;
752 #if 0
753         char *start = line;
754         int i = 0;
755 #endif
756
757         mutt_fix_quoting(line);
758         tmp = strconcat("From: ", line, NULL);
759         getname(tmp, &name, &email);
760         free(tmp);
761
762         if(name)
763                 item_fput(item, NAME, name);
764         else
765                 return;
766
767         if(email)
768                 item_fput(item, EMAIL, email);
769         else
770                 return;
771
772         /*
773          * this is completely broken
774          */
775 #if 0
776         while( (start = strchr(start, ',')) && i++ < MAX_EMAILS - 1) {
777                 tmp = strconcat("From: ", ++start, NULL);
778                 getname(tmp, &name, &email);
779                 free(tmp);
780                 free(name);
781                 if(email) {
782                         if(*email) {
783                                 tmp = strconcat(item[EMAIL], ",", email, NULL);
784                                 free(item[EMAIL]);
785                                 item[EMAIL] = tmp;
786                         } else {
787                                 xfree(email);
788                         }
789                 }
790         }
791 #endif
792 }
793
794 static int
795 mutt_parse_file(FILE *in)
796 {
797         list_item item = item_create();
798
799         for(;;) {
800                 memset(item, 0, fields_count * sizeof(char *));
801
802                 if(!mutt_read_line(in,
803                         (field_id(GROUPS) != -1) ? &item[field_id(GROUPS)] : NULL,
804                         (field_id(NICK) != -1) ? &item[field_id(NICK)] : NULL,
805                         &item[field_id(NAME)]) )
806                         mutt_parse_email(item);
807
808                 if(feof(in)) {
809                         item_empty(item);
810                         break;
811                 }
812
813                 add_item2database(item);
814         }
815         item_free(&item);
816
817         return 0;
818 }
819
820 /*
821  * end of mutt alias import filter
822  */
823
824
825 /*
826  * ldif export filter
827  */
828
829 static void
830 ldif_fput_type_and_value(FILE *out,char *type, char *value )
831 {
832         char *tmp;
833
834         tmp = ldif_type_and_value(type, value, strlen(value));
835
836         fputs(tmp, out);
837
838         free(tmp);
839 }
840
841 static int
842 ldif_export_database(FILE *out, struct db_enumerator e)
843 {
844         char email[MAX_EMAILSTR_LEN];
845
846         fprintf(out, "version: 1\n");
847
848         db_enumerate_items(e) {
849                 char *tmp;
850                 int j;
851                 get_first_email(email, e.item);
852
853                 tmp = strdup_printf("cn=%s,mail=%s",db_name_get(e.item),email);
854
855                 ldif_fput_type_and_value(out, "dn", tmp);
856                 free(tmp);
857
858                 for(j = 0; j < LDIF_ITEM_FIELDS; j++) {
859                         if(ldif_conv_table[j] >= 0) {
860                                 if(ldif_conv_table[j] == EMAIL)
861                                         ldif_fput_type_and_value(out,
862                                                 ldif_field_names[j], email);
863                                 else if(db_fget(e.item,ldif_conv_table[j]))
864                                         ldif_fput_type_and_value(out,
865                                                 ldif_field_names[j],
866                                                 db_fget(e.item,
867                                                         ldif_conv_table[j]));
868                         }
869                 }
870
871                 fprintf(out, "objectclass: top\n"
872                                 "objectclass: person\n\n");
873         }
874
875         return 0;
876 }
877
878 /*
879  * end of ldif export filter
880  */
881
882 /*
883  * html export filter
884  */
885
886 static void            html_export_write_head(FILE *out);
887 static void            html_export_write_tail(FILE *out);
888
889 extern struct index_elem *index_elements;
890
891 static void
892 html_print_emails(FILE *out, struct list_field *f)
893 {
894         abook_list *l = csv_to_abook_list(f->data);
895
896         for(; l; l = l->next) {
897                 fprintf(out, "<a href=\"mailto:%s\">%s</a>", l->data, l->data);
898                 if(l->next)
899                         fprintf(out, ", ");
900         }
901
902         abook_list_free(&l);
903 }
904
905 static int
906 html_export_database(FILE *out, struct db_enumerator e)
907 {
908         struct list_field f;
909         struct index_elem *cur;
910
911         if(list_is_empty())
912                 return 2;
913
914         init_index();
915
916         html_export_write_head(out);
917
918         db_enumerate_items(e) {
919                 fprintf(out, "<tr>");
920                 for(cur = index_elements; cur; cur = cur->next) {
921                         if(cur->type != INDEX_FIELD)
922                                 continue;
923
924                         get_list_field(e.item, cur, &f);
925
926                         if(f.type == FIELD_EMAILS) {
927                                 fprintf(out, "<td>");
928                                 html_print_emails(out, &f);
929                                 fprintf(out, "</td>");
930                                 continue;
931                         } else {
932                                 fprintf(out, "<td>%s</td>", safe_str(f.data));
933                         }
934                 }
935                 fprintf(out, "</tr>\n");
936         }
937
938         html_export_write_tail(out);
939
940         return 0;
941 }
942
943 static void
944 html_export_write_head(FILE *out)
945 {
946         char *realname = get_real_name(), *str;
947         struct index_elem *cur;
948
949         fprintf(out, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n");
950         fprintf(out, "<html>\n<head>\n <title>%s's addressbook</title>",
951                         realname );
952         fprintf(out, "\n</head>\n<body>\n");
953         fprintf(out, "\n<h2>%s's addressbook</h2>\n", realname );
954         fprintf(out, "<br><br>\n\n");
955
956         fprintf(out, "<table border=\"1\" align=\"center\">\n<tr>");
957         for(cur = index_elements; cur; cur = cur->next) {
958                 if(cur->type != INDEX_FIELD)
959                         continue;
960
961                 get_field_info(cur->d.field.id, NULL, &str, NULL);
962                 fprintf(out, "<th>%s</th>", str);
963         }
964         fprintf(out, "</tr>\n\n");
965
966         free(realname);
967 }
968
969 static void
970 html_export_write_tail(FILE *out)
971 {
972         fprintf(out, "\n</table>\n");
973         fprintf(out, "\n</body>\n</html>\n");
974 }
975
976 /*
977  * end of html export filter
978  */
979
980
981 /*
982  * pine addressbook import filter
983  */
984
985 #define PINE_BUF_SIZE 2048
986
987 static void
988 pine_fixbuf(char *buf)
989 {
990         int i,j;
991
992         for(i = 0,j = 0; j < (int)strlen(buf); i++, j++)
993                 buf[i] = buf[j] == '\n' ? buf[++j] : buf[j];
994 }
995
996 static void
997 pine_convert_emails(char *s)
998 {
999         int i;
1000         char *tmp;
1001
1002         if(s == NULL || *s != '(')
1003                 return;
1004
1005         for(i = 0; s[i]; i++)
1006                 s[i] = s[i + 1];
1007
1008         if( ( tmp = strchr(s,')')) )
1009                 *tmp = '\0';
1010
1011         for(i = 1; ( tmp = strchr(s, ',') ) != NULL ; i++, s = tmp + 1)
1012                 if(i > MAX_LIST_ITEMS - 1) {
1013                         *tmp = '\0';
1014                         break;
1015                 }
1016
1017 }
1018
1019 static void
1020 pine_parse_buf(char *buf)
1021 {
1022         list_item item;
1023         char *start = buf;
1024         char *end;
1025         char tmp[PINE_BUF_SIZE];
1026         int i, len, last;
1027         int pine_conv_table[]= {NICK, NAME, EMAIL, -1, NOTES};
1028
1029         item = item_create();
1030
1031         for(i=0, last=0; !last ; i++) {
1032                 if( !(end = strchr(start, '\t')) )
1033                         last=1;
1034
1035                 len = last ? strlen(start) : (int) (end-start);
1036                 len = min(len, PINE_BUF_SIZE - 1);
1037
1038                 if(i < (int)(sizeof(pine_conv_table) / sizeof(*pine_conv_table))
1039                                 && pine_conv_table[i] >= 0) {
1040                         strncpy(tmp, start, len);
1041                         tmp[len] = 0;
1042                         if(*tmp)
1043                                 item_fput(item, pine_conv_table[i],
1044                                                 xstrdup(tmp));
1045                 }
1046                 start = end + 1;
1047         }
1048
1049         pine_convert_emails(item_fget(item, EMAIL));
1050         add_item2database(item);
1051         item_free(&item);
1052 }
1053
1054
1055 #define LINESIZE        1024
1056
1057 static int
1058 pine_parse_file(FILE *in)
1059 {
1060         char line[LINESIZE];
1061         char *buf = NULL;
1062         char *ptr;
1063         int i;
1064
1065         fgets(line, LINESIZE, in);
1066
1067         while(!feof(in)) {
1068                 for(i = 2;;i++) {
1069                         buf = xrealloc(buf, i*LINESIZE);
1070                         if(i == 2)
1071                                 strcpy(buf, line);
1072                         fgets(line, LINESIZE, in);
1073                         ptr=(char *)&line;
1074                         if(*ptr != ' ' || feof(in))
1075                                 break;
1076                         else
1077                                 while(*ptr == ' ')
1078                                         ptr++;
1079
1080                         strcat(buf, ptr);
1081                 }
1082                 if(*buf == '#') {
1083                         xfree(buf);
1084                         continue;
1085                 }
1086                 pine_fixbuf(buf);
1087
1088                 pine_parse_buf(buf);
1089
1090                 xfree(buf);
1091         }
1092
1093         return 0;
1094 }
1095
1096 /*
1097  * end of pine addressbook import filter
1098  */
1099
1100
1101 /*
1102  * pine addressbook export filter
1103  *
1104  *  filter doesn't wrap the lines as it should but Pine seems to handle
1105  *  created files without problems - JH
1106  */
1107
1108 static int
1109 pine_export_database(FILE *out, struct db_enumerator e)
1110 {
1111         char *emails;
1112
1113         db_enumerate_items(e) {
1114                 emails = db_email_get(e.item);
1115                 fprintf(out, strchr(emails, ',') /* multiple addresses? */ ?
1116                                 "%s\t%s\t(%s)\t\t%s\n" : "%s\t%s\t%s\t\t%s\n",
1117                                 safe_str(db_fget(e.item, NICK)),
1118                                 safe_str(db_name_get(e.item)),
1119                                 emails,
1120                                 safe_str(db_fget(e.item, NOTES))
1121                                 );
1122                 free(emails);
1123         }
1124
1125         return 0;
1126 }
1127
1128 /*
1129  * end of pine addressbook export filter
1130  */
1131
1132
1133 /*
1134  * csv import filter
1135  */
1136
1137 /* FIXME
1138  * these files should be parsed according to a certain
1139  * lay out, or the default if layout is not given, at
1140  * the moment only default is done...
1141  */
1142
1143 #define CSV_COMMENT_CHAR        '#'
1144 #define CSV_DUPLICATE_SEPARATOR " "
1145 #define CSV_TABLE_SIZE(t)       (sizeof (t) / sizeof *(t))
1146
1147 static int csv_conv_table[] = {
1148         NAME,
1149         EMAIL,
1150         PHONE,
1151         NOTES,
1152         NICK
1153 };
1154
1155 static int allcsv_conv_table[] = {
1156         NAME,
1157         EMAIL,
1158         ADDRESS,
1159         ADDRESS2,
1160         CITY,
1161         STATE,
1162         ZIP,
1163         COUNTRY,
1164         PHONE,
1165         WORKPHONE,
1166         FAX,
1167         MOBILEPHONE,
1168         NICK,
1169         URL,
1170         NOTES,
1171         ANNIVERSARY
1172 };
1173
1174 static int palmcsv_conv_table[] = {
1175         NAME,           /* Last name */
1176         NAME,           /* First name */
1177         NOTES,          /* Title */
1178         NICK,           /* Company */
1179         WORKPHONE,
1180         PHONE,
1181         FAX,
1182         MOBILEPHONE,
1183         EMAIL,
1184         ADDRESS,
1185         CITY,
1186         STATE,
1187         ZIP,
1188         COUNTRY,
1189         ANNIVERSARY,
1190 };
1191
1192 static void
1193 csv_convert_emails(char *s)
1194 {
1195         int i;
1196         char *tmp;
1197
1198         if(s == NULL)
1199                 return;
1200
1201         for(i = 1; ( tmp = strchr(s, ',') ) != NULL ; i++, s = tmp + 1)
1202                 if(i > MAX_LIST_ITEMS - 1) {
1203                         *tmp = 0;
1204                         break;
1205                 }
1206
1207 }
1208
1209 static char *
1210 csv_remove_quotes(char *s)
1211 {
1212         char *copy, *trimmed;
1213         int len;
1214
1215         copy = trimmed = xstrdup(s);
1216         strtrim(trimmed);
1217
1218         len = strlen(trimmed);
1219         if(trimmed[len - 1] == '\"' && *trimmed == '\"') {
1220                 if(len < 3) {
1221                         xfree(copy);
1222                         return NULL;
1223                 }
1224                 trimmed[len - 1] = 0;
1225                 trimmed++;
1226                 trimmed = xstrdup(trimmed);
1227                 free(copy);
1228                 return trimmed;
1229         }
1230
1231         xfree(copy);
1232         return xstrdup(s);
1233 }
1234
1235 static int
1236 csv_field_to_item(int *table_base, size_t table_size, int field)
1237 {
1238         if(field < table_size)
1239                 return field_id(table_base[field]);
1240
1241         return -1;
1242 }
1243
1244 static void
1245 csv_store_item(list_item item, int i, char *s)
1246 {
1247         char *newstr = NULL;
1248
1249         if(!s || !*s)
1250                 return;
1251
1252         if( !(newstr = csv_remove_quotes(s)) )
1253                 return;
1254
1255         if(i >= 0) {
1256                 if (item[i] != NULL) {
1257                         char *oldstr = item[i];
1258
1259                         item[i] = strconcat(newstr, CSV_DUPLICATE_SEPARATOR,
1260                                 oldstr, NULL);
1261                         xfree(newstr);
1262                         xfree(oldstr);
1263                 } else {
1264                         item[i] = newstr;
1265                 }
1266         } else {
1267                 xfree(newstr);
1268         }
1269 }
1270
1271 static int
1272 csv_is_valid_quote_end(char *p)
1273 {
1274         if(*p != '\"')
1275                 return FALSE;
1276
1277         for(p++; *p; p++) {
1278                 if(*p == ',')
1279                         return TRUE;
1280                 else if(!ISSPACE(*p))
1281                         return FALSE;
1282         }
1283
1284         return TRUE;
1285 }
1286
1287 static int
1288 csv_is_valid_quote_start(char *p)
1289 {
1290         for(; *p; p++) {
1291                 if(*p == '\"')
1292                         return TRUE;
1293                 else if(!ISSPACE(*p))
1294                         return FALSE;
1295         }
1296
1297         return FALSE;
1298 }
1299
1300 static void
1301 csv_parse_line(char *line, int *table_base, size_t table_size)
1302 {
1303         char *p, *start;
1304         int field;
1305         bool in_quote = FALSE;
1306         list_item item;
1307
1308         item = item_create();
1309
1310         for(p = start = line, field = 0; *p; p++) {
1311                 if(in_quote) {
1312                         if(csv_is_valid_quote_end(p))
1313                                 in_quote = FALSE;
1314                 } else {
1315                         if ( (((p - start) / sizeof (char)) < 2 ) &&
1316                                 csv_is_valid_quote_start(p) )
1317                                 in_quote = TRUE;
1318                 }
1319
1320                 if(*p == ',' && !in_quote) {
1321                         *p = 0;
1322                         csv_store_item(item,
1323                                 csv_field_to_item(table_base,table_size,field),
1324                                 start);
1325                         field++;
1326                         start = p + 1;
1327                 }
1328         }
1329         /*
1330          * store last field
1331          */
1332         csv_store_item(item, csv_field_to_item(table_base, table_size, field),
1333                 start);
1334
1335         csv_convert_emails(item_fget(item, EMAIL));
1336         add_item2database(item);
1337         item_free(&item);
1338 }
1339
1340 static int
1341 csv_parse_file_common(FILE *in, int *conv_table, size_t table_size)
1342 {
1343         char *line = NULL;
1344
1345         while(!feof(in)) {
1346                 line = getaline(in);
1347
1348                 if(line && *line && *line != CSV_COMMENT_CHAR)
1349                         csv_parse_line(line, conv_table, table_size);
1350
1351                 xfree(line);
1352         }
1353
1354         return 0;
1355 }
1356
1357 static int
1358 csv_parse_file(FILE *in)
1359 {
1360         return csv_parse_file_common(in, csv_conv_table,
1361                 CSV_TABLE_SIZE(csv_conv_table));
1362 }
1363
1364 static int
1365 allcsv_parse_file(FILE *in)
1366 {
1367         return csv_parse_file_common(in, allcsv_conv_table,
1368                 CSV_TABLE_SIZE(allcsv_conv_table));
1369 }
1370
1371 static int
1372 palmcsv_parse_file(FILE *in)
1373 {
1374         return csv_parse_file_common(in, palmcsv_conv_table,
1375                 CSV_TABLE_SIZE(palmcsv_conv_table));
1376 }
1377
1378 /*
1379  * end of csv import filter
1380  */
1381
1382 /*
1383  * vCard import filter
1384  */
1385
1386 static char *vcard_fields[] = {
1387         "FN",                   /* FORMATTED NAME */
1388         "EMAIL",                /* EMAIL */
1389         "ADR",                  /* ADDRESS */
1390         "ADR",                  /* ADDRESS2 - not used */
1391         "ADR",                  /* CITY */
1392         "ADR",                  /* STATE */
1393         "ADR",                  /* ZIP */
1394         "ADR",                  /* COUNTRY */
1395         "TEL",                  /* PHONE */
1396         "TEL",                  /* WORKPHONE */
1397         "TEL",                  /* FAX */
1398         "TEL",                  /* MOBILEPHONE */
1399         "NICKNAME",             /* NICK */
1400         "URL",                  /* URL */
1401         "NOTE",                 /* NOTES */
1402         "N",                    /* NAME: special case/mapping in vcard_parse_line() */
1403         NULL                    /* not implemented: ANNIVERSARY, ITEM_FIELDS */
1404 };
1405
1406 /*
1407  * mappings between vCard ADR field and abook's ADDRESS
1408  * see rfc2426 section 3.2.1
1409  */
1410 static int vcard_address_fields[] = {
1411         -1,                     /* vCard(post office box) - not used */
1412         -1,                     /* vCard(the extended address) - not used */
1413         2,                      /* vCard(the street address) - ADDRESS */
1414         4,                      /* vCard(the locality) - CITY */
1415         5,                      /* vCard(the region) - STATE */
1416         6,                      /* vCard(the postal code) - ZIP */
1417         7                       /* vCard(the country name) - COUNTRY */
1418 };
1419
1420 enum {
1421         VCARD_KEY = 0,
1422         VCARD_KEY_ATTRIBUTE,
1423         VCARD_VALUE,
1424 };
1425
1426 static char *
1427 vcard_get_line_element(char *line, int element)
1428 {
1429         int i;
1430         char *line_copy = 0;
1431         char *result = 0;
1432         char *key = 0;
1433         char *key_attr = 0;
1434         char *value = 0;
1435
1436         line_copy = xstrdup(line);
1437
1438         /* change newline characters, if present, to end of string */
1439         for(i=0; line_copy[i]; i++) {
1440                 if(line_copy[i] == '\r' || line_copy[i] == '\n') {
1441                         line_copy[i] = '\0';
1442                         break;
1443                 }
1444         }
1445
1446         /* separate key from value */
1447         for(i=0; line_copy[i]; i++) {
1448                 if(line_copy[i] == ':') {
1449                         line_copy[i] = '\0';
1450                         key = line_copy;
1451                         value = &line_copy[i+1];
1452                         break;
1453                 }
1454         }
1455
1456         /* separate key from key attributes */
1457         /* works for vCard 2 as well (automagically) */
1458         if (key) {
1459                 for(i=0; key[i]; i++) {
1460                         if(key[i] == ';') {
1461                                 key[i] = '\0';
1462                                 key_attr = &key[i+1];
1463                                 break;
1464                         }
1465                 }
1466         }
1467
1468         switch(element) {
1469         case VCARD_KEY:
1470                 if(key)
1471                         result = xstrdup(key);
1472                 break;
1473         case VCARD_KEY_ATTRIBUTE:
1474                 if(key_attr)
1475                         result = xstrdup(key_attr);
1476                 break;
1477         case VCARD_VALUE:
1478                 if(value)
1479                         result = xstrdup(value);
1480                 break;
1481         }
1482
1483         xfree(line_copy);
1484         return result;
1485 }
1486
1487 static void
1488 vcard_parse_email(list_item item, char *line)
1489 {
1490         char *email;
1491
1492         email = vcard_get_line_element(line, VCARD_VALUE);
1493
1494         if(item[1]) {
1495                 item[1] = strconcat(item[1], ",", email, 0);
1496                 xfree(email);
1497         }
1498         else {
1499                 item[1] = email;
1500         }
1501 }
1502
1503 static void
1504 vcard_parse_address(list_item item, char *line)
1505 {
1506         int i;
1507         int k;
1508         char *value;
1509         char *address_field;
1510
1511         value = vcard_get_line_element(line, VCARD_VALUE);
1512         if(!value)
1513                 return;
1514
1515         address_field = value;
1516         for(i=k=0; value[i]; i++) {
1517                 if(value[i] == ';') {
1518                         value[i] = '\0';
1519                         if(vcard_address_fields[k] >= 0) {
1520                                 item[vcard_address_fields[k]] = xstrdup(address_field);
1521                         }
1522                         address_field = &value[i+1];
1523                         k++;
1524                         if((k+1)==(sizeof(vcard_address_fields)/sizeof(*vcard_address_fields)))
1525                                 break;
1526                 }
1527         }
1528         item[vcard_address_fields[k]] = xstrdup(address_field);
1529         xfree(value);
1530 }
1531
1532 static void
1533 vcard_parse_name(list_item item, char *line)
1534 {
1535         // store the "N" field into "NAME" *if* no "FN:"
1536         // value has already been stored here
1537         if(item[0]) return;
1538
1539         int i = -1;
1540         item[0] = vcard_get_line_element(line, VCARD_VALUE);
1541         // "N:" can be multivalued => replace ';' separators by ' '
1542         while(item[0][++i]) if(item[0][i] == ';') item[0][i] = ' ';
1543
1544         // http://www.daniweb.com/software-development/c/code/216919
1545         char *original = item[0], *p = original;
1546         int trimmed = 0;
1547         do {
1548           if (*original != ' ' || trimmed) {
1549             trimmed = 1; *p++ = *original;
1550           }
1551         } while(*original++);
1552 }
1553
1554 static void
1555 vcard_parse_phone(list_item item, char *line)
1556 {
1557         char *type = vcard_get_line_element(line, VCARD_KEY_ATTRIBUTE);
1558         char *value = vcard_get_line_element(line, VCARD_VALUE);
1559
1560         /* set the standard number */
1561         if (!type) item_fput(item, PHONE, value);
1562
1563         /*
1564          * see rfc2426 section 3.3.1
1565          * Note: we probably support both vCard 2 and 3
1566          */
1567         else {
1568                 if (strcasestr(type, "home") != NULL)
1569                         item_fput(item, PHONE, xstrdup(value));
1570                 else if (strcasestr(type, "work") != NULL)
1571                         item_fput(item, WORKPHONE, xstrdup(value));
1572                 else if (strcasestr(type, "fax") != NULL)
1573                         item_fput(item, FAX, xstrdup(value));
1574                 else if (strcasestr(type, "cell") != NULL)
1575                         item_fput(item, MOBILEPHONE, xstrdup(value));
1576
1577                 xfree(type);
1578                 xfree(value);
1579         }
1580 }
1581
1582 static void
1583 vcard_parse_line(list_item item, char *line)
1584 {
1585         int i;
1586         char *key;
1587
1588         for(i=0; vcard_fields[i]; i++) {
1589                 key = vcard_fields[i];
1590
1591                 if(0 == strncmp(key, line, strlen(key))) {
1592                         if(0 == strcmp(key, "EMAIL"))
1593                                 vcard_parse_email(item, line);
1594                         else if(i == 2)
1595                                 vcard_parse_address(item, line);
1596                         else if(0 == strcmp(key, "TEL"))
1597                                 vcard_parse_phone(item, line);
1598                         else if(0 == strcmp(key, "N"))
1599                                 vcard_parse_name(item, line);
1600                         else
1601                                 item[i] = vcard_get_line_element(line, VCARD_VALUE);
1602                         return;
1603                 }
1604         }
1605 }
1606
1607 static void
1608 vcard_parse_item(FILE *in)
1609 {
1610         char *line = NULL;
1611         list_item item = item_create();
1612
1613         while(!feof(in)) {
1614                 line = getaline(in);
1615
1616                 if(line && !strncmp("END:VCARD", line, 9)) {
1617                         xfree(line);
1618                         break;
1619                 }
1620                 else if(line) {
1621                         vcard_parse_line(item, line);
1622                         xfree(line);
1623                 }
1624         }
1625
1626         add_item2database(item);
1627         item_free(&item);
1628 }
1629
1630 static int
1631 vcard_parse_file(FILE *in)
1632 {
1633         char *line = NULL;
1634
1635         while(!feof(in)) {
1636                 line = getaline(in);
1637
1638                 if(line && !strncmp("BEGIN:VCARD", line, 11)) {
1639                         xfree(line);
1640                         vcard_parse_item(in);
1641                 }
1642                 else if(line) {
1643                         xfree(line);
1644                 }
1645         }
1646
1647         return 0;
1648 }
1649
1650 /*
1651  * end of vCard import filter
1652  */
1653
1654 /*
1655  * csv addressbook export filters
1656  */
1657
1658 #define CSV_LAST                (-1)
1659 #define CSV_UNDEFINED           (-2)
1660 #define CSV_SPECIAL(X)          (-3 - (X))
1661 #define CSV_IS_SPECIAL(X)       ((X) <= -3)
1662
1663 static int
1664 csv_export_common(FILE *out, struct db_enumerator e,
1665                 int fields[], void (*special_func)(FILE *, int, int))
1666 {
1667         int i;
1668
1669         db_enumerate_items(e) {
1670                 for(i = 0; fields[i] != CSV_LAST; i++) {
1671                         if(fields[i] == CSV_UNDEFINED)
1672                                 fprintf(out, "\"\"");
1673                         else if(CSV_IS_SPECIAL(fields[i])) {
1674                                 if(special_func)
1675                                         (*special_func)(out, e.item, fields[i]);
1676                         } else
1677                                 /*fprintf(out,(
1678                         strchr(safe_str(database[e.item][field_idx(fields[i])]), ',') ||
1679                         strchr(safe_str(database[e.item][field_idx(fields[i])]), '\"')) ?
1680                                 "\"%s\"" : "%s",
1681                                 safe_str(database[e.item][field_idx(fields[i])])
1682                                 );*/
1683                                 fprintf(out, "\"%s\"",
1684                                         safe_str(db_fget(e.item,fields[i])));
1685
1686                         if(fields[i + 1] != CSV_LAST)
1687                                 fputc(',', out);
1688                 }
1689                 fputc('\n', out);
1690         }
1691
1692         return 0;
1693 }
1694
1695 static int
1696 csv_export_database(FILE *out, struct db_enumerator e)
1697 {
1698         int csv_export_fields[] = {
1699                 NAME,
1700                 EMAIL,
1701                 PHONE,
1702                 NOTES,
1703                 NICK,
1704                 CSV_LAST
1705         };
1706
1707         csv_export_common(out, e, csv_export_fields, NULL);
1708
1709         return 0;
1710 }
1711
1712 static int
1713 allcsv_export_database(FILE *out, struct db_enumerator e)
1714 {
1715         /*
1716          * TODO: Should get these atomatically from abook_fileds
1717          *  - JH
1718          */
1719         int allcsv_export_fields[] = {
1720                 NAME,
1721                 EMAIL,
1722                 ADDRESS,
1723                 ADDRESS2,
1724                 CITY,
1725                 STATE,
1726                 ZIP,
1727                 COUNTRY,
1728                 PHONE,
1729                 WORKPHONE,
1730                 FAX,
1731                 MOBILEPHONE,
1732                 NICK,
1733                 URL,
1734                 NOTES,
1735                 ANNIVERSARY,
1736                 GROUPS,
1737                 CSV_LAST
1738         };
1739
1740         fprintf(out, "#");
1741         fprintf(out, "\"NAME\",");
1742         fprintf(out, "\"EMAIL\",");
1743         fprintf(out, "\"ADDRESS\",");
1744         fprintf(out, "\"ADDRESS2\",");
1745         fprintf(out, "\"CITY\",");
1746         fprintf(out, "\"STATE\",");
1747         fprintf(out, "\"ZIP\",");
1748         fprintf(out, "\"COUNTRY\",");
1749         fprintf(out, "\"PHONE\",");
1750         fprintf(out, "\"WORKPHONE\",");
1751         fprintf(out, "\"FAX\",");
1752         fprintf(out, "\"MOBILEPHONE\",");
1753         fprintf(out, "\"NICK\",");
1754         fprintf(out, "\"URL\",");
1755         fprintf(out, "\"NOTES\",");
1756         fprintf(out, "\"ANNIVERSARY\",");
1757         fprintf(out, "\"GROUPS\"\n");
1758
1759         csv_export_common(out, e, allcsv_export_fields, NULL);
1760
1761         return 0;
1762 }
1763
1764 /*
1765  * palm csv
1766  */
1767
1768 #define PALM_CSV_NAME   CSV_SPECIAL(0)
1769 #define PALM_CSV_END    CSV_SPECIAL(1)
1770 #define PALM_CSV_CAT    CSV_SPECIAL(2)
1771
1772 static void
1773 palm_split_and_write_name(FILE *out, char *name)
1774 {
1775         char *p;
1776
1777         assert(name);
1778
1779         if ( (p = strchr(name, ' ')) ) {
1780                 /*
1781                  * last name first
1782                  */
1783                 fprintf(out, "\"%s\",\"" , p + 1);
1784                 fwrite((void *)name, p - name, sizeof(char), out);
1785                 fputc('\"', out);
1786         } else {
1787                 fprintf(out, "\"%s\"", safe_str(name));
1788         }
1789 }
1790
1791 static void
1792 palm_csv_handle_specials(FILE *out, int item, int field)
1793 {
1794         switch(field) {
1795                 case PALM_CSV_NAME:
1796                         palm_split_and_write_name(out, db_name_get(item));
1797                         break;
1798                 case PALM_CSV_CAT:
1799                         fprintf(out, "\"abook\"");
1800                         break;
1801                 case PALM_CSV_END:
1802                         fprintf(out, "\"0\"");
1803                         break;
1804                 default:
1805                         assert(0);
1806         }
1807 }
1808
1809 static int
1810 palm_export_database(FILE *out, struct db_enumerator e)
1811 {
1812         int palm_export_fields[] = {
1813                 PALM_CSV_NAME,          /* LASTNAME, FIRSTNAME  */
1814                 CSV_UNDEFINED,          /* TITLE                */
1815                 CSV_UNDEFINED,          /* COMPANY              */
1816                 WORKPHONE,              /* WORK PHONE           */
1817                 PHONE,                  /* HOME PHONE           */
1818                 FAX,                    /* FAX                  */
1819                 MOBILEPHONE,            /* OTHER                */
1820                 EMAIL,                  /* EMAIL                */
1821                 ADDRESS,                /* ADDRESS              */
1822                 CITY,                   /* CITY                 */
1823                 STATE,                  /* STATE                */
1824                 ZIP,                    /* ZIP                  */
1825                 COUNTRY,                /* COUNTRY              */
1826                 NICK,                   /* DEFINED 1            */
1827                 URL,                    /* DEFINED 2            */
1828                 CSV_UNDEFINED,          /* DEFINED 3            */
1829                 CSV_UNDEFINED,          /* DEFINED 4            */
1830                 NOTES,                  /* NOTE                 */
1831                 PALM_CSV_END,           /* "0"                  */
1832                 PALM_CSV_CAT,           /* CATEGORY             */
1833                 CSV_LAST
1834         };
1835
1836         csv_export_common(out, e, palm_export_fields, palm_csv_handle_specials);
1837
1838         return 0;
1839 }
1840
1841 /*
1842  * end of csv export filters
1843  */
1844
1845 /*
1846  * vCard 2 addressbook export filter
1847  */
1848
1849 static int
1850 vcard_export_database(FILE *out, struct db_enumerator e)
1851 {
1852         int j;
1853         char *name, *tmp;
1854         abook_list *emails, *em;
1855
1856         db_enumerate_items(e) {
1857                 fprintf(out, "BEGIN:VCARD\r\nFN:%s\r\n",
1858                                 safe_str(db_name_get(e.item)));
1859
1860                 name = get_surname(db_name_get(e.item));
1861                 for( j = strlen(db_name_get(e.item)) - 1; j >= 0; j-- ) {
1862                         if((db_name_get(e.item))[j] == ' ')
1863                                 break;
1864                 }
1865                 fprintf(out, "N:%s;%.*s\r\n",
1866                         safe_str(name),
1867                         j,
1868                         safe_str(db_name_get(e.item))
1869                         );
1870
1871                 free(name);
1872
1873                 if(db_fget(e.item, ADDRESS))
1874                         fprintf(out, "ADR:;;%s;%s;%s;%s;%s;%s\r\n",
1875                                 safe_str(db_fget(e.item, ADDRESS)),
1876                                 safe_str(db_fget(e.item, ADDRESS2)),
1877                                 safe_str(db_fget(e.item, CITY)),
1878                                 safe_str(db_fget(e.item, STATE)),
1879                                 safe_str(db_fget(e.item, ZIP)),
1880                                 safe_str(db_fget(e.item, COUNTRY))
1881                                 );
1882
1883                 if(db_fget(e.item, PHONE))
1884                         fprintf(out, "TEL;HOME:%s\r\n",
1885                                         db_fget(e.item, PHONE));
1886                 if(db_fget(e.item, WORKPHONE))
1887                         fprintf(out, "TEL;WORK:%s\r\n",
1888                                         db_fget(e.item, WORKPHONE));
1889                 if(db_fget(e.item, FAX))
1890                         fprintf(out, "TEL;FAX:%s\r\n",
1891                                         db_fget(e.item, FAX));
1892                 if(db_fget(e.item, MOBILEPHONE))
1893                         fprintf(out, "TEL;CELL:%s\r\n",
1894                                         db_fget(e.item, MOBILEPHONE));
1895
1896                 tmp = db_email_get(e.item);
1897                 if(*tmp) {
1898                         emails = csv_to_abook_list(tmp);
1899
1900                         for(em = emails; em; em = em->next)
1901                                 fprintf(out, "EMAIL;INTERNET:%s\r\n", em->data);
1902
1903                         abook_list_free(&emails);
1904                 }
1905                 free(tmp);
1906
1907                 if(db_fget(e.item, NOTES))
1908                         fprintf(out, "NOTE:%s\r\n",
1909                                         db_fget(e.item, NOTES));
1910                 if(db_fget(e.item, URL))
1911                         fprintf(out, "URL:%s\r\n",
1912                                         db_fget(e.item, URL));
1913
1914                 fprintf(out, "END:VCARD\r\n\r\n");
1915
1916         }
1917
1918         return 0;
1919 }
1920
1921 /*
1922  * end of vCard export filter
1923  */
1924
1925
1926 /*
1927  * mutt alias export filter
1928  */
1929
1930 static char *
1931 mutt_alias_genalias(int i)
1932 {
1933         char *tmp, *pos;
1934
1935         if(db_fget(i, NICK))
1936                 return xstrdup(db_fget(i, NICK));
1937
1938         tmp = xstrdup(db_name_get(i));
1939
1940         if( ( pos = strchr(tmp, ' ') ) )
1941                 *pos = 0;
1942
1943         strlower(tmp);
1944
1945         return tmp;
1946 }
1947
1948 /*
1949  * This function is a variant of abook_list_to_csv
1950  * */
1951 static char *
1952 mutt_alias_gengroups(int i)
1953 {
1954         char *groups, *res = NULL;
1955         char groupstr[7] = "-group ";
1956         abook_list *list, *tmp;
1957
1958         groups = db_fget(i, GROUPS);
1959
1960         if(!groups)
1961                 return NULL;
1962
1963         list = csv_to_abook_list(groups);
1964         for(tmp = list; tmp; tmp = tmp->next) {
1965                 if(tmp == list) {
1966                         res = xmalloc(strlen(groupstr)+strlen(tmp->data)+1);
1967                         res = strcpy(res, groupstr);
1968                 } else {
1969                         res = xrealloc(res, strlen(res)+1+strlen(groupstr)+strlen(tmp->data)+1);
1970                         strcat(res, " ");
1971                         strcat(res, groupstr);
1972                 }
1973                 strcat(res, tmp->data);
1974         }
1975         abook_list_free(&list);
1976         xfree(groups);
1977
1978         return res;
1979 }
1980
1981 static int
1982 mutt_alias_export(FILE *out, struct db_enumerator e)
1983 {
1984         char email[MAX_EMAIL_LEN];
1985         char *alias = NULL;
1986         char *groups = NULL;
1987         int email_addresses;
1988         char *ptr;
1989
1990         db_enumerate_items(e) {
1991                 alias = (field_id(NICK) != -1) ? mutt_alias_genalias(e.item) : NULL;
1992                 groups = (field_id(GROUPS) != -1) ?  mutt_alias_gengroups(e.item) : NULL;
1993                 get_first_email(email, e.item);
1994
1995                 /* do not output contacts without email address */
1996                 /* cause this does not make sense in mutt aliases */
1997                 if (*email) {
1998
1999                         /* output first email address */
2000                         fprintf(out,"alias ");
2001                         if(groups)
2002                                 fprintf(out, "%s ", groups);
2003                         if(alias)
2004                                 fprintf(out, "%s ", alias);
2005                         fprintf(out, "%s <%s>\n",
2006                                         db_name_get(e.item),
2007                                         email);
2008
2009                         /* number of email addresses */
2010                         email_addresses = 1;
2011                         ptr = db_email_get(e.item);
2012                         while (*ptr != '\0') {
2013                                 if (*ptr == ',') {
2014                                         email_addresses++;
2015                                 }
2016                                 ptr++;
2017                         }
2018
2019                         /* output other email addresses */
2020                         while (email_addresses-- > 1) {
2021                                 roll_emails(e.item, ROTATE_RIGHT);
2022                                 get_first_email(email, e.item);
2023                                 fprintf(out,"alias ");
2024                                 if( groups )
2025                                         fprintf(out, "%s ", groups);
2026                                 if(alias)
2027                                         fprintf(out, "%s__%s ", alias, email);
2028                                 else
2029                                         fprintf(out, "%s__%s ", db_name_get(e.item), email);
2030                                 fprintf(out, "%s <%s>\n",
2031                                                 db_name_get(e.item),
2032                                                 email);
2033                         }
2034                         roll_emails(e.item, ROTATE_RIGHT);
2035                         xfree(alias);
2036                         xfree(groups);
2037                 }
2038         }
2039
2040         return 0;
2041 }
2042
2043 void muttq_print_item(FILE *file, int item)
2044 {
2045         abook_list *emails, *e;
2046         char *tmp = db_email_get(item);
2047
2048         emails = csv_to_abook_list(tmp);
2049         free(tmp);
2050
2051         for(e = emails; e; e = e->next) {
2052                 fprintf(file, "%s\t%s\t%s\n", e->data, db_name_get(item),
2053                                 !db_fget(item, NOTES) ?" " :db_fget(item, NOTES)
2054                                 );
2055                 if(!opt_get_bool(BOOL_MUTT_RETURN_ALL_EMAILS))
2056                         break;
2057         }
2058         abook_list_free(&emails);
2059 }
2060
2061 static int
2062 mutt_query_export_database(FILE *out, struct db_enumerator e)
2063 {
2064   fprintf(out, "All items\n");
2065   db_enumerate_items(e)
2066     muttq_print_item(out, e.item);
2067   return 0;
2068 }
2069
2070 /*
2071  * end of mutt alias export filter
2072  */
2073
2074
2075 /*
2076  * printable export filter
2077  */
2078
2079
2080 static void
2081 text_write_address_us(FILE *out, int i) {
2082         fprintf(out, "\n%s", db_fget(i, ADDRESS));
2083
2084         if(db_fget(i, ADDRESS2))
2085                 fprintf(out, "\n%s", db_fget(i, ADDRESS2));
2086
2087         if(db_fget(i, CITY))
2088                 fprintf(out, "\n%s", db_fget(i, CITY));
2089
2090         if(db_fget(i, STATE) || db_fget(i, ZIP)) {
2091                 fputc('\n', out);
2092
2093                 if(db_fget(i, STATE)) {
2094                         fprintf(out, "%s", db_fget(i, STATE));
2095                         if(db_fget(i, ZIP))
2096                                 fputc(' ', out);
2097                 }
2098
2099                 if(db_fget(i, ZIP))
2100                         fprintf(out, "%s", db_fget(i, ZIP));
2101         }
2102
2103         if(db_fget(i, COUNTRY))
2104                 fprintf(out, "\n%s", db_fget(i, COUNTRY));
2105 }
2106
2107
2108 static void
2109 text_write_address_uk(FILE *out, int i) {
2110         int j;
2111
2112         for(j = ADDRESS; j <= COUNTRY; j++)
2113                 if(db_fget(i, j))
2114                         fprintf(out, "\n%s", db_fget(i, j));
2115 }
2116
2117 static void
2118 text_write_address_eu(FILE *out, int i) {
2119         fprintf(out, "\n%s", db_fget(i, ADDRESS));
2120
2121         if(db_fget(i, ADDRESS2))
2122                 fprintf(out, "\n%s", db_fget(i, ADDRESS2));
2123
2124         if(db_fget(i, ZIP) || db_fget(i, CITY)) {
2125                 fputc('\n', out);
2126
2127                 if(db_fget(i, ZIP)) {
2128                         fprintf(out, "%s", db_fget(i, ZIP));
2129                         if(db_fget(i, CITY))
2130                                 fputc(' ', out);
2131                 }
2132
2133                 fprintf(out, "%s", safe_str(db_fget(i, CITY)));
2134         }
2135
2136         if(db_fget(i, STATE))
2137                 fprintf(out, "\n%s", db_fget(i, STATE));
2138
2139         if(db_fget(i, COUNTRY))
2140                 fprintf(out, "\n%s", db_fget(i, COUNTRY));
2141 }
2142
2143 static int
2144 text_export_database(FILE * out, struct db_enumerator e)
2145 {
2146         abook_list *emails, *em;
2147         int j;
2148         char *realname = get_real_name(), *str = NULL, *tmp;
2149         char *style = opt_get_str(STR_ADDRESS_STYLE);
2150
2151         fprintf(out,
2152                 "-----------------------------------------\n%s's address book\n"
2153                 "-----------------------------------------\n\n\n",
2154                 realname);
2155         free(realname);
2156
2157         db_enumerate_items(e) {
2158                 fprintf(out,
2159                         "-----------------------------------------\n\n");
2160                 fprintf(out, "%s", db_name_get(e.item));
2161                 if(db_fget(e.item, NICK) && *db_fget(e.item, NICK))
2162                         fprintf(out, "\n(%s)", db_fget(e.item, NICK));
2163                 fprintf(out, "\n");
2164
2165                 tmp = db_email_get(e.item);
2166                 if(*tmp) {
2167                         emails = csv_to_abook_list(tmp);
2168
2169                         fprintf(out, "\n");
2170                         for(em = emails; em; em = em->next)
2171                                 fprintf(out, "%s\n", em->data);
2172
2173                         abook_list_free(&emails);
2174                 }
2175                 free(tmp);
2176                 /* Print address */
2177                 if(db_fget(e.item, ADDRESS)) {
2178                         if(!safe_strcmp(style, "us"))   /* US like */
2179                                 text_write_address_us(out, e.item);
2180                         else if(!safe_strcmp(style, "uk"))      /* UK like */
2181                                 text_write_address_uk(out, e.item);
2182                         else    /* EU like */
2183                                 text_write_address_eu(out, e.item);
2184
2185                         fprintf(out, "\n");
2186                 }
2187
2188                 if((db_fget(e.item, PHONE)) ||
2189                         (db_fget(e.item, WORKPHONE)) ||
2190                         (db_fget(e.item, FAX)) ||
2191                         (db_fget(e.item, MOBILEPHONE))) {
2192                         fprintf(out, "\n");
2193                         for(j = PHONE; j <= MOBILEPHONE; j++)
2194                                 if(db_fget(e.item, j)) {
2195                                         get_field_info(field_id(j),
2196                                                         NULL, &str, NULL);
2197                                         fprintf(out, "%s: %s\n", str,
2198                                                 db_fget(e.item, j));
2199                                 }
2200                 }
2201
2202                 if(db_fget(e.item, URL))
2203                         fprintf(out, "\n%s\n", db_fget(e.item, URL));
2204                 if(db_fget(e.item, NOTES))
2205                         fprintf(out, "\n%s\n", db_fget(e.item, NOTES));
2206
2207                 fprintf(out, "\n");
2208         }
2209
2210         fprintf(out, "-----------------------------------------\n");
2211
2212         return 0;
2213 }
2214
2215 /*
2216  * end of printable export filter
2217  */
2218
2219 /*
2220  * elm alias export filter
2221  */
2222
2223 static int
2224 elm_alias_export(FILE *out, struct db_enumerator e)
2225 {
2226         char email[MAX_EMAIL_LEN];
2227         char *alias = NULL;
2228
2229         db_enumerate_items(e) {
2230                 alias = mutt_alias_genalias(e.item);
2231                 get_first_email(email, e.item);
2232                 fprintf(out, "%s = %s = %s\n",alias,db_name_get(e.item),email);
2233                 xfree(alias);
2234         }
2235
2236         return 0;
2237 }
2238
2239 /*
2240  * end of elm alias export filter
2241  */
2242
2243
2244 /*
2245  * Spruce export filter
2246  */
2247
2248 static int
2249 spruce_export_database (FILE *out, struct db_enumerator e)
2250 {
2251         char email[MAX_EMAIL_LEN];
2252
2253         fprintf(out, "# This is a generated file made by abook for the Spruce e-mail client.\n\n");
2254
2255         db_enumerate_items(e) {
2256                 get_first_email(email, e.item);
2257                 if(strcmp(email, "")) {
2258                         fprintf(out, "# Address %d\nName: %s\nEmail: %s\nMemo: %s\n\n",
2259                                         e.item,
2260                                         db_name_get(e.item),
2261                                         email,
2262                                         safe_str(db_fget(e.item, NOTES))
2263                                         );
2264                 }
2265         }
2266
2267         fprintf (out, "# End of address book file.\n");
2268
2269         return 0;
2270 }
2271
2272 /*
2273  * end of Spruce export filter
2274  */
2275
2276 /*
2277  * wanderlust addressbook export filter
2278  */
2279
2280 static int
2281 wl_export_database(FILE *out, struct db_enumerator e)
2282 {
2283         char email[MAX_EMAIL_LEN];
2284
2285         fprintf(out, "# Wanderlust address book written by %s\n\n", PACKAGE);
2286         db_enumerate_items(e) {
2287                 get_first_email(email, e.item);
2288                 if(*email) {
2289                         fprintf(out,
2290                                 "%s\t\"%s\"\t\"%s\"\n",
2291                                 email,
2292                                 safe_str(db_fget(e.item, NICK)),
2293                                 safe_str(db_name_get(e.item))
2294                         );
2295                 }
2296         }
2297
2298         fprintf (out, "\n# End of address book file.\n");
2299
2300         return 0;
2301 }
2302
2303 /*
2304  * end of wanderlust addressbook export filter
2305  */
2306
2307 /*
2308  * BSD calendar export filter
2309  */
2310
2311 static int
2312 bsdcal_export_database(FILE *out, struct db_enumerator e)
2313 {
2314         db_enumerate_items(e) {
2315                 int year, month = 0, day = 0;
2316                 char *anniversary = db_fget(e.item, ANNIVERSARY);
2317
2318                 if(anniversary) {
2319                         if(!parse_date_string(anniversary, &day, &month, &year))
2320                                 continue;
2321
2322                         fprintf(out,
2323                                 _("%02d/%02d\tAnniversary of %s\n"),
2324                                 month,
2325                                 day,
2326                                 safe_str(db_name_get(e.item))
2327                         );
2328                 }
2329         }
2330
2331         return 0;
2332 }
2333
2334 /*
2335  * end of BSD calendar export filter
2336  */
2337