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