]> git.deb.at Git - pkg/abook.git/blob - filter.c
Fix the inclusion of strcasestr() used by the vCard parser.
[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",                   /* 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         NULL                    /* not implemented: ANNIVERSARY, ITEM_FIELDS */
1358 };
1359
1360 /*
1361  * mappings between vCard ADR field and abook's ADDRESS
1362  * see rfc2426 section 3.2.1
1363  */
1364 static int vcard_address_fields[] = {
1365         -1,                     /* vCard(post office box) - not used */
1366         -1,                     /* vCard(the extended address) - not used */
1367         2,                      /* vCard(the street address) - ADDRESS */
1368         4,                      /* vCard(the locality) - CITY */
1369         5,                      /* vCard(the region) - STATE */
1370         6,                      /* vCard(the postal code) - ZIP */
1371         7                       /* vCard(the country name) - COUNTRY */
1372 };
1373
1374 enum {
1375         VCARD_KEY = 0,
1376         VCARD_KEY_ATTRIBUTE,
1377         VCARD_VALUE,
1378 };
1379
1380 static char *
1381 vcard_get_line_element(char *line, int element)
1382 {
1383         int i;
1384         char *line_copy = 0;
1385         char *result = 0;
1386         char *key = 0;
1387         char *key_attr = 0;
1388         char *value = 0;
1389
1390         line_copy = xstrdup(line);
1391
1392         /* change newline characters, if present, to end of string */
1393         for(i=0; line_copy[i]; i++) {
1394                 if(line_copy[i] == '\r' || line_copy[i] == '\n') {
1395                         line_copy[i] = '\0';
1396                         break;
1397                 }
1398         }
1399
1400         /* separate key from value */
1401         for(i=0; line_copy[i]; i++) {
1402                 if(line_copy[i] == ':') {
1403                         line_copy[i] = '\0';
1404                         key = line_copy;
1405                         value = &line_copy[i+1];
1406                         break;
1407                 }
1408         }
1409
1410         /* separate key from key attributes */
1411         /* works for vCard 2 as well (automagically) */
1412         if (key) {
1413                 for(i=0; key[i]; i++) {
1414                         if(key[i] == ';') {
1415                                 key[i] = '\0';
1416                                 key_attr = &key[i+1];
1417                                 break;
1418                         }
1419                 }
1420         }
1421
1422         switch(element) {
1423         case VCARD_KEY:
1424                 if(key)
1425                         result = xstrdup(key);
1426                 break;
1427         case VCARD_KEY_ATTRIBUTE:
1428                 if(key_attr)
1429                         result = xstrdup(key_attr);
1430                 break;
1431         case VCARD_VALUE:
1432                 if(value)
1433                         result = xstrdup(value);
1434                 break;
1435         }
1436
1437         xfree(line_copy);
1438         return result;
1439 }
1440
1441 static void
1442 vcard_parse_email(list_item item, char *line)
1443 {
1444         char *email;
1445
1446         email = vcard_get_line_element(line, VCARD_VALUE);
1447
1448         if(item[1]) {
1449                 item[1] = strconcat(item[1], ",", email, 0);
1450                 xfree(email);
1451         }
1452         else {
1453                 item[1] = email;
1454         }
1455 }
1456
1457 static void
1458 vcard_parse_address(list_item item, char *line)
1459 {
1460         int i;
1461         int k;
1462         char *value;
1463         char *address_field;
1464
1465         value = vcard_get_line_element(line, VCARD_VALUE);
1466         if(!value)
1467                 return;
1468
1469         address_field = value;
1470         for(i=k=0; value[i]; i++) {
1471                 if(value[i] == ';') {
1472                         value[i] = '\0';
1473                         if(vcard_address_fields[k] >= 0) {
1474                                 item[vcard_address_fields[k]] = xstrdup(address_field);
1475                         }
1476                         address_field = &value[i+1];
1477                         k++;
1478                         if((k+1)==(sizeof(vcard_address_fields)/sizeof(*vcard_address_fields)))
1479                                 break;
1480                 }
1481         }
1482         item[vcard_address_fields[k]] = xstrdup(address_field);
1483         xfree(value);
1484 }
1485
1486 static void
1487 vcard_parse_phone(list_item item, char *line)
1488 {
1489         int index = 8;
1490         char *type = vcard_get_line_element(line, VCARD_KEY_ATTRIBUTE);
1491         char *value = vcard_get_line_element(line, VCARD_VALUE);
1492
1493         /* set the standard number */
1494         if (!type) {
1495                 item[index] = value;
1496         }
1497
1498         /*
1499          * see rfc2426 section 3.3.1
1500          * Note: we probably support both vCard 2 and 3
1501          */
1502         else {
1503                 if (strcasestr(type, "home") != NULL) {
1504                         item[index] = xstrdup(value);
1505                 }
1506                 if (strcasestr(type, "work") != NULL) {
1507                         item[index+1] = xstrdup(value);
1508                 }
1509                 if (strcasestr(type, "fax") != NULL) {
1510                         item[index+2] = xstrdup(value);
1511                 }
1512                 if (strcasestr(type, "cell") != NULL) {
1513                         item[index+3] = xstrdup(value);
1514                 }
1515
1516                 xfree(type);
1517                 xfree(value);
1518         }
1519 }
1520
1521 static void
1522 vcard_parse_line(list_item item, char *line)
1523 {
1524         int i;
1525         char *key;
1526
1527         for(i=0; vcard_fields[i]; i++) {
1528                 key = vcard_fields[i];
1529
1530                 if(0 == strncmp(key, line, strlen(key))) {
1531                         if(0 == strcmp(key, "EMAIL"))
1532                                 vcard_parse_email(item, line);
1533                         else if(i == 2)
1534                                 vcard_parse_address(item, line);
1535                         else if(0 == strcmp(key, "TEL"))
1536                                 vcard_parse_phone(item, line);
1537                         else
1538                                 item[i] = vcard_get_line_element(line, VCARD_VALUE);
1539                         return;
1540                 }
1541         }
1542 }
1543
1544 static void
1545 vcard_parse_item(FILE *in)
1546 {
1547         char *line = NULL;
1548         list_item item = item_create();
1549
1550         while(!feof(in)) {
1551                 line = getaline(in);
1552
1553                 if(line && !strncmp("END:VCARD", line, 9)) {
1554                         xfree(line);
1555                         break;
1556                 }
1557                 else if(line) {
1558                         vcard_parse_line(item, line);
1559                         xfree(line);
1560                 }
1561         }
1562
1563         add_item2database(item);
1564         item_free(&item);
1565 }
1566
1567 static int
1568 vcard_parse_file(FILE *in)
1569 {
1570         char *line = NULL;
1571
1572         while(!feof(in)) {
1573                 line = getaline(in);
1574
1575                 if(line && !strncmp("BEGIN:VCARD", line, 11)) {
1576                         xfree(line);
1577                         vcard_parse_item(in);
1578                 }
1579                 else if(line) {
1580                         xfree(line);
1581                 }
1582         }
1583
1584         return 0;
1585 }
1586
1587 /*
1588  * end of vCard import filter
1589  */
1590
1591 /*
1592  * csv addressbook export filters
1593  */
1594
1595 #define CSV_LAST                (-1)
1596 #define CSV_UNDEFINED           (-2)
1597 #define CSV_SPECIAL(X)          (-3 - (X))
1598 #define CSV_IS_SPECIAL(X)       ((X) <= -3)
1599
1600 static int
1601 csv_export_common(FILE *out, struct db_enumerator e,
1602                 int fields[], void (*special_func)(FILE *, int, int))
1603 {
1604         int i;
1605
1606         db_enumerate_items(e) {
1607                 for(i = 0; fields[i] != CSV_LAST; i++) {
1608                         if(fields[i] == CSV_UNDEFINED)
1609                                 fprintf(out, "\"\"");
1610                         else if(CSV_IS_SPECIAL(fields[i])) {
1611                                 if(special_func)
1612                                         (*special_func)(out, e.item, fields[i]);
1613                         } else
1614                                 /*fprintf(out,(
1615                         strchr(safe_str(database[e.item][field_idx(fields[i])]), ',') ||
1616                         strchr(safe_str(database[e.item][field_idx(fields[i])]), '\"')) ?
1617                                 "\"%s\"" : "%s",
1618                                 safe_str(database[e.item][field_idx(fields[i])])
1619                                 );*/
1620                                 fprintf(out, "\"%s\"",
1621                                         safe_str(db_fget(e.item,fields[i])));
1622
1623                         if(fields[i + 1] != CSV_LAST)
1624                                 fputc(',', out);
1625                 }
1626                 fputc('\n', out);
1627         }
1628
1629         return 0;
1630 }
1631
1632 static int
1633 csv_export_database(FILE *out, struct db_enumerator e)
1634 {
1635         int csv_export_fields[] = {
1636                 NAME,
1637                 EMAIL,
1638                 PHONE,
1639                 NOTES,
1640                 NICK,
1641                 CSV_LAST
1642         };
1643
1644         csv_export_common(out, e, csv_export_fields, NULL);
1645
1646         return 0;
1647 }
1648
1649 static int
1650 allcsv_export_database(FILE *out, struct db_enumerator e)
1651 {
1652         /*
1653          * TODO: Should get these atomatically from abook_fileds
1654          *  - JH
1655          */
1656         int allcsv_export_fields[] = {
1657                 NAME,
1658                 EMAIL,
1659                 ADDRESS,
1660                 ADDRESS2,
1661                 CITY,
1662                 STATE,
1663                 ZIP,
1664                 COUNTRY,
1665                 PHONE,
1666                 WORKPHONE,
1667                 FAX,
1668                 MOBILEPHONE,
1669                 NICK,
1670                 URL,
1671                 NOTES,
1672                 ANNIVERSARY,
1673                 CSV_LAST
1674         };
1675
1676         fprintf(out, "#");
1677         fprintf(out, "\"NAME\",");
1678         fprintf(out, "\"EMAIL\",");
1679         fprintf(out, "\"ADDRESS\",");
1680         fprintf(out, "\"ADDRESS2\",");
1681         fprintf(out, "\"CITY\",");
1682         fprintf(out, "\"STATE\",");
1683         fprintf(out, "\"ZIP\",");
1684         fprintf(out, "\"COUNTRY\",");
1685         fprintf(out, "\"PHONE\",");
1686         fprintf(out, "\"WORKPHONE\",");
1687         fprintf(out, "\"FAX\",");
1688         fprintf(out, "\"MOBILEPHONE\",");
1689         fprintf(out, "\"NICK\",");
1690         fprintf(out, "\"URL\",");
1691         fprintf(out, "\"NOTES\",");
1692         fprintf(out, "\"ANNIVERSARY\"\n");
1693
1694         csv_export_common(out, e, allcsv_export_fields, NULL);
1695
1696         return 0;
1697 }
1698
1699 /*
1700  * palm csv
1701  */
1702
1703 #define PALM_CSV_NAME   CSV_SPECIAL(0)
1704 #define PALM_CSV_END    CSV_SPECIAL(1)
1705 #define PALM_CSV_CAT    CSV_SPECIAL(2)
1706
1707 static void
1708 palm_split_and_write_name(FILE *out, char *name)
1709 {
1710         char *p;
1711
1712         assert(name);
1713
1714         if ( (p = strchr(name, ' ')) ) {
1715                 /*
1716                  * last name first
1717                  */
1718                 fprintf(out, "\"%s\",\"" , p + 1);
1719                 fwrite((void *)name, p - name, sizeof(char), out);
1720                 fputc('\"', out);
1721         } else {
1722                 fprintf(out, "\"%s\"", safe_str(name));
1723         }
1724 }
1725
1726 static void
1727 palm_csv_handle_specials(FILE *out, int item, int field)
1728 {
1729         switch(field) {
1730                 case PALM_CSV_NAME:
1731                         palm_split_and_write_name(out, db_name_get(item));
1732                         break;
1733                 case PALM_CSV_CAT:
1734                         fprintf(out, "\"abook\"");
1735                         break;
1736                 case PALM_CSV_END:
1737                         fprintf(out, "\"0\"");
1738                         break;
1739                 default:
1740                         assert(0);
1741         }
1742 }
1743
1744 static int
1745 palm_export_database(FILE *out, struct db_enumerator e)
1746 {
1747         int palm_export_fields[] = {
1748                 PALM_CSV_NAME,          /* LASTNAME, FIRSTNAME  */
1749                 CSV_UNDEFINED,          /* TITLE                */
1750                 CSV_UNDEFINED,          /* COMPANY              */
1751                 WORKPHONE,              /* WORK PHONE           */
1752                 PHONE,                  /* HOME PHONE           */
1753                 FAX,                    /* FAX                  */
1754                 MOBILEPHONE,            /* OTHER                */
1755                 EMAIL,                  /* EMAIL                */
1756                 ADDRESS,                /* ADDRESS              */
1757                 CITY,                   /* CITY                 */
1758                 STATE,                  /* STATE                */
1759                 ZIP,                    /* ZIP                  */
1760                 COUNTRY,                /* COUNTRY              */
1761                 NICK,                   /* DEFINED 1            */
1762                 URL,                    /* DEFINED 2            */
1763                 CSV_UNDEFINED,          /* DEFINED 3            */
1764                 CSV_UNDEFINED,          /* DEFINED 4            */
1765                 NOTES,                  /* NOTE                 */
1766                 PALM_CSV_END,           /* "0"                  */
1767                 PALM_CSV_CAT,           /* CATEGORY             */
1768                 CSV_LAST
1769         };
1770
1771         csv_export_common(out, e, palm_export_fields, palm_csv_handle_specials);
1772
1773         return 0;
1774 }
1775
1776 /*
1777  * end of csv export filters
1778  */
1779
1780 /*
1781  * vCard 2 addressbook export filter
1782  */
1783
1784 static int
1785 vcard_export_database(FILE *out, struct db_enumerator e)
1786 {
1787         int j;
1788         char *name, *tmp;
1789         abook_list *emails, *em;
1790
1791         db_enumerate_items(e) {
1792                 fprintf(out, "BEGIN:VCARD\r\nFN:%s\r\n",
1793                                 safe_str(db_name_get(e.item)));
1794
1795                 name = get_surname(db_name_get(e.item));
1796                 for( j = strlen(db_name_get(e.item)) - 1; j >= 0; j-- ) {
1797                         if((db_name_get(e.item))[j] == ' ')
1798                                 break;
1799                 }
1800                 fprintf(out, "N:%s;%.*s\r\n",
1801                         safe_str(name),
1802                         j,
1803                         safe_str(db_name_get(e.item))
1804                         );
1805
1806                 free(name);
1807
1808                 if(db_fget(e.item, ADDRESS))
1809                         fprintf(out, "ADR:;;%s;%s;%s;%s;%s;%s\r\n",
1810                                 safe_str(db_fget(e.item, ADDRESS)),
1811                                 safe_str(db_fget(e.item, ADDRESS2)),
1812                                 safe_str(db_fget(e.item, CITY)),
1813                                 safe_str(db_fget(e.item, STATE)),
1814                                 safe_str(db_fget(e.item, ZIP)),
1815                                 safe_str(db_fget(e.item, COUNTRY))
1816                                 );
1817
1818                 if(db_fget(e.item, PHONE))
1819                         fprintf(out, "TEL;HOME:%s\r\n",
1820                                         db_fget(e.item, PHONE));
1821                 if(db_fget(e.item, WORKPHONE))
1822                         fprintf(out, "TEL;WORK:%s\r\n",
1823                                         db_fget(e.item, WORKPHONE));
1824                 if(db_fget(e.item, FAX))
1825                         fprintf(out, "TEL;FAX:%s\r\n",
1826                                         db_fget(e.item, FAX));
1827                 if(db_fget(e.item, MOBILEPHONE))
1828                         fprintf(out, "TEL;CELL:%s\r\n",
1829                                         db_fget(e.item, MOBILEPHONE));
1830
1831                 tmp = db_email_get(e.item);
1832                 if(*tmp) {
1833                         emails = csv_to_abook_list(tmp);
1834
1835                         for(em = emails; em; em = em->next)
1836                                 fprintf(out, "EMAIL;INTERNET:%s\r\n", em->data);
1837
1838                         abook_list_free(&emails);
1839                 }
1840                 free(tmp);
1841
1842                 if(db_fget(e.item, NOTES))
1843                         fprintf(out, "NOTE:%s\r\n",
1844                                         db_fget(e.item, NOTES));
1845                 if(db_fget(e.item, URL))
1846                         fprintf(out, "URL:%s\r\n",
1847                                         db_fget(e.item, URL));
1848
1849                 fprintf(out, "END:VCARD\r\n\r\n");
1850
1851         }
1852
1853         return 0;
1854 }
1855
1856 /*
1857  * end of vCard export filter
1858  */
1859
1860
1861 /*
1862  * mutt alias export filter
1863  */
1864
1865 static char *
1866 mutt_alias_genalias(int i)
1867 {
1868         char *tmp, *pos;
1869
1870         if(db_fget(i, NICK))
1871                 return xstrdup(db_fget(i, NICK));
1872
1873         tmp = xstrdup(db_name_get(i));
1874
1875         if( ( pos = strchr(tmp, ' ') ) )
1876                 *pos = 0;
1877
1878         strlower(tmp);
1879
1880         return tmp;
1881 }
1882
1883 static int
1884 mutt_alias_export(FILE *out, struct db_enumerator e)
1885 {
1886         char email[MAX_EMAIL_LEN];
1887         char *alias = NULL;
1888         int email_addresses;
1889         char *ptr;
1890
1891         db_enumerate_items(e) {
1892                 alias = mutt_alias_genalias(e.item);
1893                 get_first_email(email, e.item);
1894
1895                 /* do not output contacts without email address */
1896                 /* cause this does not make sense in mutt aliases */
1897                 if (*email) {
1898
1899                         /* output first email address */
1900                         fprintf(out, "alias %s %s <%s>\n",
1901                                         alias,
1902                                         db_name_get(e.item),
1903                                         email);
1904
1905                         /* number of email addresses */
1906                         email_addresses = 1;
1907                         ptr = db_email_get(e.item);
1908                         while (*ptr != '\0') {
1909                                 if (*ptr == ',') {
1910                                         email_addresses++;
1911                                 }
1912                                 ptr++;
1913                         }
1914
1915                         /* output other email addresses */
1916                         while (email_addresses-- > 1) {
1917                                 roll_emails(e.item, ROTATE_RIGHT);
1918                                 get_first_email(email, e.item);
1919                                 fprintf(out, "alias %s__%s %s <%s>\n",
1920                                                 alias,
1921                                                 email,
1922                                                 db_name_get(e.item),
1923                                                 email);
1924                         }
1925                         roll_emails(e.item, ROTATE_RIGHT);
1926                         xfree(alias);
1927                 }
1928         }
1929
1930         return 0;
1931 }
1932
1933 /*
1934  * end of mutt alias export filter
1935  */
1936
1937
1938 /*
1939  * printable export filter
1940  */
1941
1942
1943 static void
1944 text_write_address_us(FILE *out, int i) {
1945         fprintf(out, "\n%s", db_fget(i, ADDRESS));
1946
1947         if(db_fget(i, ADDRESS2))
1948                 fprintf(out, "\n%s", db_fget(i, ADDRESS2));
1949
1950         if(db_fget(i, CITY))
1951                 fprintf(out, "\n%s", db_fget(i, CITY));
1952
1953         if(db_fget(i, STATE) || db_fget(i, ZIP)) {
1954                 fputc('\n', out);
1955
1956                 if(db_fget(i, STATE)) {
1957                         fprintf(out, "%s", db_fget(i, STATE));
1958                         if(db_fget(i, ZIP))
1959                                 fputc(' ', out);
1960                 }
1961
1962                 if(db_fget(i, ZIP))
1963                         fprintf(out, "%s", db_fget(i, ZIP));
1964         }
1965
1966         if(db_fget(i, COUNTRY))
1967                 fprintf(out, "\n%s", db_fget(i, COUNTRY));
1968 }
1969
1970
1971 static void
1972 text_write_address_uk(FILE *out, int i) {
1973         int j;
1974
1975         for(j = ADDRESS; j <= COUNTRY; j++)
1976                 if(db_fget(i, j))
1977                         fprintf(out, "\n%s", db_fget(i, j));
1978 }
1979
1980 static void
1981 text_write_address_eu(FILE *out, int i) {
1982         fprintf(out, "\n%s", db_fget(i, ADDRESS));
1983
1984         if(db_fget(i, ADDRESS2))
1985                 fprintf(out, "\n%s", db_fget(i, ADDRESS2));
1986
1987         if(db_fget(i, ZIP) || db_fget(i, CITY)) {
1988                 fputc('\n', out);
1989
1990                 if(db_fget(i, ZIP)) {
1991                         fprintf(out, "%s", db_fget(i, ZIP));
1992                         if(db_fget(i, CITY))
1993                                 fputc(' ', out);
1994                 }
1995
1996                 fprintf(out, "%s", safe_str(db_fget(i, CITY)));
1997         }
1998
1999         if(db_fget(i, STATE))
2000                 fprintf(out, "\n%s", db_fget(i, STATE));
2001
2002         if(db_fget(i, COUNTRY))
2003                 fprintf(out, "\n%s", db_fget(i, COUNTRY));
2004 }
2005
2006 static int
2007 text_export_database(FILE * out, struct db_enumerator e)
2008 {
2009         abook_list *emails, *em;
2010         int j;
2011         char *realname = get_real_name(), *str = NULL, *tmp;
2012         char *style = opt_get_str(STR_ADDRESS_STYLE);
2013
2014         fprintf(out,
2015                 "-----------------------------------------\n%s's address book\n"
2016                 "-----------------------------------------\n\n\n",
2017                 realname);
2018         free(realname);
2019
2020         db_enumerate_items(e) {
2021                 fprintf(out,
2022                         "-----------------------------------------\n\n");
2023                 fprintf(out, "%s", db_name_get(e.item));
2024                 if(db_fget(e.item, NICK) && *db_fget(e.item, NICK))
2025                         fprintf(out, "\n(%s)", db_fget(e.item, NICK));
2026                 fprintf(out, "\n");
2027
2028                 tmp = db_email_get(e.item);
2029                 if(*tmp) {
2030                         emails = csv_to_abook_list(tmp);
2031
2032                         fprintf(out, "\n");
2033                         for(em = emails; em; em = em->next)
2034                                 fprintf(out, "%s\n", em->data);
2035
2036                         abook_list_free(&emails);
2037                 }
2038                 free(tmp);
2039                 /* Print address */
2040                 if(db_fget(e.item, ADDRESS)) {
2041                         if(!safe_strcmp(style, "us"))   /* US like */
2042                                 text_write_address_us(out, e.item);
2043                         else if(!safe_strcmp(style, "uk"))      /* UK like */
2044                                 text_write_address_uk(out, e.item);
2045                         else    /* EU like */
2046                                 text_write_address_eu(out, e.item);
2047
2048                         fprintf(out, "\n");
2049                 }
2050
2051                 if((db_fget(e.item, PHONE)) ||
2052                         (db_fget(e.item, WORKPHONE)) ||
2053                         (db_fget(e.item, FAX)) ||
2054                         (db_fget(e.item, MOBILEPHONE))) {
2055                         fprintf(out, "\n");
2056                         for(j = PHONE; j <= MOBILEPHONE; j++)
2057                                 if(db_fget(e.item, j)) {
2058                                         get_field_info(field_id(j),
2059                                                         NULL, &str, NULL);
2060                                         fprintf(out, "%s: %s\n", str,
2061                                                 db_fget(e.item, j));
2062                                 }
2063                 }
2064
2065                 if(db_fget(e.item, URL))
2066                         fprintf(out, "\n%s\n", db_fget(e.item, URL));
2067                 if(db_fget(e.item, NOTES))
2068                         fprintf(out, "\n%s\n", db_fget(e.item, NOTES));
2069
2070                 fprintf(out, "\n");
2071         }
2072
2073         fprintf(out, "-----------------------------------------\n");
2074
2075         return 0;
2076 }
2077
2078 /*
2079  * end of printable export filter
2080  */
2081
2082 /*
2083  * elm alias export filter
2084  */
2085
2086 static int
2087 elm_alias_export(FILE *out, struct db_enumerator e)
2088 {
2089         char email[MAX_EMAIL_LEN];
2090         char *alias = NULL;
2091
2092         db_enumerate_items(e) {
2093                 alias = mutt_alias_genalias(e.item);
2094                 get_first_email(email, e.item);
2095                 fprintf(out, "%s = %s = %s\n",alias,db_name_get(e.item),email);
2096                 xfree(alias);
2097         }
2098
2099         return 0;
2100 }
2101
2102 /*
2103  * end of elm alias export filter
2104  */
2105
2106
2107 /*
2108  * Spruce export filter
2109  */
2110
2111 static int
2112 spruce_export_database (FILE *out, struct db_enumerator e)
2113 {
2114         char email[MAX_EMAIL_LEN];
2115
2116         fprintf(out, "# This is a generated file made by abook for the Spruce e-mail client.\n\n");
2117
2118         db_enumerate_items(e) {
2119                 get_first_email(email, e.item);
2120                 if(strcmp(email, "")) {
2121                         fprintf(out, "# Address %d\nName: %s\nEmail: %s\nMemo: %s\n\n",
2122                                         e.item,
2123                                         db_name_get(e.item),
2124                                         email,
2125                                         safe_str(db_fget(e.item, NOTES))
2126                                         );
2127                 }
2128         }
2129
2130         fprintf (out, "# End of address book file.\n");
2131
2132         return 0;
2133 }
2134
2135 /*
2136  * end of Spruce export filter
2137  */
2138
2139 /*
2140  * wanderlust addressbook export filter
2141  */
2142
2143 static int
2144 wl_export_database(FILE *out, struct db_enumerator e)
2145 {
2146         char email[MAX_EMAIL_LEN];
2147
2148         fprintf(out, "# Wanderlust address book written by %s\n\n", PACKAGE);
2149         db_enumerate_items(e) {
2150                 get_first_email(email, e.item);
2151                 if(*email) {
2152                         fprintf(out,
2153                                 "%s\t\"%s\"\t\"%s\"\n",
2154                                 email,
2155                                 safe_str(db_fget(e.item, NICK)),
2156                                 safe_str(db_name_get(e.item))
2157                         );
2158                 }
2159         }
2160
2161         fprintf (out, "\n# End of address book file.\n");
2162
2163         return 0;
2164 }
2165
2166 /*
2167  * end of wanderlust addressbook export filter
2168  */
2169
2170 /*
2171  * BSD calendar export filter
2172  */
2173
2174 static int
2175 bsdcal_export_database(FILE *out, struct db_enumerator e)
2176 {
2177         db_enumerate_items(e) {
2178                 int year, month = 0, day = 0;
2179                 char *anniversary = db_fget(e.item, ANNIVERSARY);
2180
2181                 if(anniversary) {
2182                         if(!parse_date_string(anniversary, &day, &month, &year))
2183                                 continue;
2184
2185                         fprintf(out,
2186                                 _("%02d/%02d\tAnniversary of %s\n"),
2187                                 month,
2188                                 day,
2189                                 safe_str(db_name_get(e.item))
2190                         );
2191                 }
2192         }
2193
2194         return 0;
2195 }
2196
2197 /*
2198  * end of BSD calendar export filter
2199  */
2200