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