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