]> git.deb.at Git - pkg/abook.git/blob - filter.c
Import vCard file format.
[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 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ctype.h>
14 #include <pwd.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include "abook_curses.h"
18 #include "filter.h"
19 #include "abook.h"
20 #include "database.h"
21 #include "edit.h"
22 #include "gettext.h"
23 #include "list.h"
24 #include "misc.h"
25 #include "options.h"
26 #include "ui.h"
27 #include "xmalloc.h"
28 #include <assert.h>
29
30 extern abook_field_list *fields_list;
31 extern int fields_count;
32
33 /*
34  * function declarations
35  */
36
37 /*
38  * import filter prototypes
39  */
40
41 static int      ldif_parse_file(FILE *handle);
42 static int      mutt_parse_file(FILE *in);
43 static int      pine_parse_file(FILE *in);
44 static int      csv_parse_file(FILE *in);
45 static int      allcsv_parse_file(FILE *in);
46 static int      palmcsv_parse_file(FILE *in);
47 static int      vcard_parse_file(FILE *in);
48
49 /*
50  * export filter prototypes
51  */
52
53 static int      ldif_export_database(FILE *out, struct db_enumerator e);
54 static int      html_export_database(FILE *out, struct db_enumerator e);
55 static int      pine_export_database(FILE *out, struct db_enumerator e);
56 static int      csv_export_database(FILE *out, struct db_enumerator e);
57 static int      allcsv_export_database(FILE *out, struct db_enumerator e);
58 static int      palm_export_database(FILE *out, struct db_enumerator e);
59 static int      gcrd_export_database(FILE *out, struct db_enumerator e);
60 static int      mutt_alias_export(FILE *out, struct db_enumerator e);
61 static int      elm_alias_export(FILE *out, struct db_enumerator e);
62 static int      text_export_database(FILE *out, struct db_enumerator e);
63 static int      spruce_export_database(FILE *out, struct db_enumerator e);
64 static int      wl_export_database(FILE *out, struct db_enumerator e);
65 static int      bsdcal_export_database(FILE *out, struct db_enumerator e);
66
67 /*
68  * end of function declarations
69  */
70
71 struct abook_input_filter i_filters[] = {
72         { "abook", N_("abook native format"), parse_database },
73         { "ldif", N_("ldif / Netscape addressbook"), ldif_parse_file },
74         { "mutt", N_("mutt alias"), mutt_parse_file },
75         { "pine", N_("pine addressbook"), pine_parse_file },
76         { "csv", N_("comma separated values"), csv_parse_file },
77         { "allcsv", N_("comma separated values (all fields)"), allcsv_parse_file },
78         { "palmcsv", N_("Palm comma separated values"), palmcsv_parse_file },
79         { "vcard", N_("vCard file"), vcard_parse_file },
80         { "\0", NULL, NULL }
81 };
82
83 struct abook_output_filter e_filters[] = {
84         { "abook", N_("abook native format"), write_database },
85         { "ldif", N_("ldif / Netscape addressbook (.4ld)"), ldif_export_database },
86         { "mutt", N_("mutt alias"), mutt_alias_export },
87         { "html", N_("html document"), html_export_database },
88         { "pine", N_("pine addressbook"), pine_export_database },
89         { "gcrd", N_("GnomeCard (VCard) addressbook"), gcrd_export_database },
90         { "csv", N_("comma separated values"), csv_export_database },
91         { "allcsv", N_("comma separated values (all fields)"), allcsv_export_database },
92         { "palmcsv", N_("Palm comma separated values"), palm_export_database},
93         { "elm", N_("elm alias"), elm_alias_export },
94         { "text", N_("plain text"), text_export_database },
95         { "wl", N_("Wanderlust address book"), wl_export_database },
96         { "spruce", N_("Spruce address book"), spruce_export_database },
97         { "bsdcal", N_("BSD calendar"), bsdcal_export_database },
98         { "\0", NULL, NULL }
99 };
100
101 /*
102  * common functions
103  */
104
105 void
106 print_filters()
107 {
108         int i;
109
110         puts(_("input:"));
111         for(i=0; *i_filters[i].filtname ; i++)
112                 printf("\t%s\t%s\n", i_filters[i].filtname,
113                         gettext(i_filters[i].desc));
114
115         putchar('\n');
116
117         puts(_("output:"));
118         for(i=0; *e_filters[i].filtname ; i++)
119                 printf("\t%s\t%s\n", e_filters[i].filtname,
120                         gettext(e_filters[i].desc));
121
122         putchar('\n');
123 }
124
125 static int
126 number_of_output_filters()
127 {
128         int i;
129
130         for(i=0; *e_filters[i].filtname ; i++)
131                 ;
132
133         return i;
134 }
135
136 static int
137 number_of_input_filters()
138 {
139         int i;
140
141         for(i=0; *i_filters[i].filtname ; i++)
142                 ;
143
144         return i;
145 }
146
147 static char *
148 get_real_name()
149 {
150         char *username = getenv("USER");
151         struct passwd *pwent;
152         int rtn;
153         char *tmp;
154
155         pwent = getpwnam(username);
156
157         if((tmp = xstrdup(pwent->pw_gecos)) == NULL)
158                 return xstrdup(username);
159
160         rtn = sscanf(pwent->pw_gecos, "%[^,]", tmp);
161         if (rtn == EOF || rtn == 0) {
162                 free(tmp);
163                 return xstrdup(username);
164         } else
165                 return tmp;
166 }
167
168 /*
169  * import
170  */
171
172 static int              i_read_file(char *filename, int (*func) (FILE *in));
173
174 static void
175 import_screen()
176 {
177         int i;
178
179         clear();
180
181         refresh_statusline();
182         headerline(_("import database"));
183
184         mvaddstr(3, 1, _("please select a filter"));
185
186
187         for(i=0; *i_filters[i].filtname ; i++)
188                 mvprintw(5 + i, 6, "%c -\t%s\t%s\n", 'a' + i,
189                         i_filters[i].filtname,
190                         gettext(i_filters[i].desc));
191
192         mvprintw(6 + i, 6, _("x -\tcancel"));
193 }
194
195 int
196 import_database()
197 {
198         int filter;
199         char *filename;
200         int tmp = db_n_items();
201
202         import_screen();
203
204         filter = getch() - 'a';
205         if(filter == 'x' - 'a' ||
206                 filter >= number_of_input_filters() || filter < 0) {
207                 refresh_screen();
208                 return 1;
209         }
210
211         mvaddstr(5+filter, 2, "->");
212
213         filename = ask_filename(_("Filename: "));
214         if(!filename) {
215                 refresh_screen();
216                 return 2;
217         }
218
219         if(i_read_file(filename, i_filters[filter].func ))
220                 statusline_msg(_("Error occured while opening the file"));
221         else if(tmp == db_n_items())
222                 statusline_msg(_("File does not seem to be a valid addressbook"));
223
224         refresh_screen();
225         free(filename);
226
227         return 0;
228 }
229
230
231
232 static int
233 i_read_file(char *filename, int (*func) (FILE *in))
234 {
235         FILE *in;
236         int ret = 0;
237
238         if( (in = abook_fopen( filename, "r" )) == NULL )
239                 return 1;
240
241         ret = (*func) (in);
242
243         fclose(in);
244
245         return ret;
246 }
247
248 int
249 import_file(char filtname[FILTNAME_LEN], char *filename)
250 {
251         int i;
252         int tmp = db_n_items();
253         int ret = 0;
254
255         for(i=0;; i++) {
256                 if(! strncasecmp(i_filters[i].filtname, filtname,
257                                         FILTNAME_LEN) )
258                         break;
259                 if(! *i_filters[i].filtname) {
260                         i = -1;
261                         break;
262                 }
263         }
264
265         if(i < 0)
266                 return -1;
267
268         if(!strcmp(filename, "-")) {
269                 struct stat s;
270                 if((fstat(fileno(stdin), &s)) == -1 || S_ISDIR(s.st_mode))
271                         ret = 1;
272                 else
273                         ret = (*i_filters[i].func) (stdin);
274         } else
275                 ret =  i_read_file(filename, i_filters[i].func);
276
277         if(tmp == db_n_items())
278                 ret = 1;
279
280         return ret;
281 }
282
283 /*
284  * export
285  */
286
287 static int e_write_file(char *filename,
288                 int (*func) (FILE *in, struct db_enumerator e), int mode);
289
290 static void
291 export_screen()
292 {
293         int i;
294
295         clear();
296
297
298         refresh_statusline();
299         headerline(_("export database"));
300
301         mvaddstr(3, 1, _("please select a filter"));
302
303
304         for(i = 0; *e_filters[i].filtname ; i++)
305                 mvprintw(5 + i, 6, "%c -\t%s\t%s\n", 'a' + i,
306                         e_filters[i].filtname,
307                         gettext(e_filters[i].desc));
308
309         mvprintw(6 + i, 6, _("x -\tcancel"));
310 }
311
312 int
313 export_database()
314 {
315         int filter;
316         int enum_mode = ENUM_ALL;
317         char *filename;
318
319         export_screen();
320
321         filter = getch() - 'a';
322         if(filter == 'x' - 'a' ||
323                 filter >= number_of_output_filters() || filter < 0) {
324                 refresh_screen();
325                 return 1;
326         }
327
328         mvaddstr(5 + filter, 2, "->");
329
330         if(selected_items()) {
331                 switch(statusline_askchoice(
332                         _("Export <a>ll, export <s>elected, or <c>ancel?"),
333                         S_("keybindings:all/selected/cancel|asc"), 3)) {
334                         case 1:
335                                 break;
336                         case 2:
337                                 enum_mode = ENUM_SELECTED;
338                                 break;
339                         case 0:
340                         case 3:
341                                 refresh_screen();
342                                 return 1;
343                 }
344                 clear_statusline();
345         }
346
347         filename = ask_filename(_("Filename: "));
348         if(!filename) {
349                 refresh_screen();
350                 return 2;
351         }
352
353         if( e_write_file(filename, e_filters[filter].func, enum_mode))
354                 statusline_msg(_("Error occured while exporting"));
355
356         refresh_screen();
357         free(filename);
358
359         return 0;
360 }
361
362 static int
363 e_write_file(char *filename, int (*func) (FILE *in, struct db_enumerator e),
364                 int mode)
365 {
366         FILE *out;
367         int ret = 0;
368         struct db_enumerator enumerator = init_db_enumerator(mode);
369
370         if((out = fopen(filename, "a")) == NULL)
371                 return 1;
372
373         if(ftell(out))
374                 return 1;
375
376         ret = (*func) (out, enumerator);
377
378         fclose(out);
379
380         return ret;
381 }
382
383 int
384 fexport(char filtname[FILTNAME_LEN], FILE *handle, int enum_mode)
385 {
386         int i;
387         struct db_enumerator e = init_db_enumerator(enum_mode);
388
389         for(i=0;; i++) {
390                 if(!strncasecmp(e_filters[i].filtname, filtname,
391                                         FILTNAME_LEN))
392                         break;
393                 if(!*e_filters[i].filtname) {
394                         i = -1;
395                         break;
396                 }
397         }
398
399         return (e_filters[i].func) (handle, e);
400 }
401
402
403
404 int
405 export_file(char filtname[FILTNAME_LEN], char *filename)
406 {
407         const int mode = ENUM_ALL;
408         int i;
409         int ret = 0;
410         struct db_enumerator e = init_db_enumerator(mode);
411
412         for(i=0;; i++) {
413                 if(!strncasecmp(e_filters[i].filtname, filtname,
414                                         FILTNAME_LEN))
415                         break;
416                 if(!*e_filters[i].filtname) {
417                         i = -1;
418                         break;
419                 }
420         }
421
422         if(i < 0)
423                 return -1;
424
425         if(!strcmp(filename, "-"))
426                 ret = (e_filters[i].func) (stdout, e);
427         else
428                 ret =  e_write_file(filename, e_filters[i].func, mode);
429
430         return ret;
431 }
432
433 /*
434  * end of common functions
435  */
436
437 /*
438  * ldif import
439  */
440
441 #include "ldif.h"
442
443 static void     ldif_fix_string(char *str);
444
445 #define LDIF_ITEM_FIELDS        16
446
447 typedef char *ldif_item[LDIF_ITEM_FIELDS];
448
449 static ldif_item ldif_field_names = {
450         "cn",
451         "mail",
452         "streetaddress",
453         "streetaddress2",
454         "locality",
455         "st",
456         "postalcode",
457         "countryname",
458         "homephone",
459         "description",
460         "homeurl",
461         "facsimiletelephonenumber",
462         "cellphone",
463         "xmozillaanyphone",
464         "xmozillanickname",
465         "objectclass", /* this must be the last entry */
466 };
467
468 static int ldif_conv_table[LDIF_ITEM_FIELDS] = {
469         NAME,           /* "cn" */
470         EMAIL,          /* "mail" */
471         ADDRESS,        /* "streetaddress" */
472         ADDRESS2,       /* "streetaddress2" */
473         CITY,           /* "locality" */
474         STATE,          /* "st" */
475         ZIP,            /* "postalcode" */
476         COUNTRY,        /* "countryname" */
477         PHONE,          /* "homephone" */
478         NOTES,          /* "description" */
479         URL,            /* "homeurl" */
480         FAX,            /* "facsimiletelephonenumber" */
481         MOBILEPHONE,    /* "cellphone" */
482         WORKPHONE,      /* "xmozillaanyphone" */
483         NICK,           /* "xmozillanickname" */
484         -1,             /* "objectclass" */ /* this must be the last entry */
485 };
486
487
488 static char *
489 ldif_read_line(FILE *in)
490 {
491         char *buf = NULL;
492         char *ptr, *tmp;
493         long pos;
494         int i;
495
496         for(i = 1;;i++) {
497                 char *line;
498
499                 pos = ftell(in);
500                 line = getaline(in);
501
502                 if(feof(in) || !line)
503                         break;
504
505                 if(i == 1) {
506                         buf = line;
507                         continue;
508                 }
509
510                 if(*line != ' ') {
511                         fseek(in, pos, SEEK_SET); /* fixme ! */
512                         free(line);
513                         break;
514                 }
515
516                 ptr = line;
517                 while( *ptr == ' ')
518                         ptr++;
519
520                 tmp = buf;
521                 buf = strconcat(buf, ptr, NULL);
522                 free(tmp);
523                 free(line);
524         }
525
526         if(buf && *buf == '#' ) {
527                 free(buf);
528                 return NULL;
529         }
530
531         return buf;
532 }
533
534 static void
535 ldif_add_item(ldif_item li)
536 {
537         list_item item;
538         int i;
539
540         item = item_create();
541
542         if(!li[LDIF_ITEM_FIELDS -1])
543                 goto bail_out;
544
545
546         for(i=0; i < LDIF_ITEM_FIELDS; i++) {
547                 if(ldif_conv_table[i] >= 0 && li[i] && *li[i])
548                         item_fput(item,ldif_conv_table[i],xstrdup(li[i]));
549         }
550
551         add_item2database(item);
552
553 bail_out:
554         for(i=0; i < LDIF_ITEM_FIELDS; i++)
555                 xfree(li[i]);
556         item_free(&item);
557
558 }
559
560 static void
561 ldif_convert(ldif_item item, char *type, char *value)
562 {
563         int i;
564
565         if(!strcmp(type, "dn")) {
566                 ldif_add_item(item);
567                 return;
568         }
569
570         for(i=0; i < LDIF_ITEM_FIELDS; i++) {
571                 if(!safe_strcmp(ldif_field_names[i], type) && *value) {
572                         if(i == LDIF_ITEM_FIELDS - 1) /* this is a dirty hack */
573                                 if(safe_strcmp("person", value))
574                                         break;
575
576                         if(item_fget(item, i))
577                                 free(item_fget(item, i));
578
579                         item_fput(item, i, xstrdup(value));
580                 }
581         }
582 }
583
584 static int
585 ldif_parse_file(FILE *handle)
586 {
587         char *line = NULL;
588         char *type, *value;
589         int vlen;
590         ldif_item item;
591
592         memset(item, 0, sizeof(item));
593
594         do {
595                 if( !(line = ldif_read_line(handle)) )
596                         continue;
597
598                 if(-1 == (str_parse_line(line, &type, &value, &vlen))) {
599                         xfree(line);
600                         continue; /* just skip the errors */
601                 }
602
603                 ldif_fix_string(value);
604
605                 ldif_convert(item, type, value);
606
607                 xfree(line);
608         } while ( !feof(handle) );
609
610         ldif_convert(item, "dn", "");
611
612         return 0;
613 }
614
615 static void
616 ldif_fix_string(char *str)
617 {
618         int i, j;
619
620         for(i = 0, j = 0; j < (int)strlen(str); i++, j++)
621                 str[i] = ( str[j] == (char)0xc3 ?
622                                 (char) str[++j] + (char) 0x40 :
623                                 str[j] );
624
625         str[i] = 0;
626 }
627
628 /*
629  * end of ldif import
630  */
631
632 /*
633  * mutt alias import filter
634  */
635
636 #include "getname.h"
637
638 static int
639 mutt_read_line(FILE *in, char **alias, char **rest)
640 {
641         char *line, *ptr, *tmp;
642         size_t alias_len;
643
644         if( !(line = ptr = getaline(in)) )
645                 return 1; /* error / EOF */
646
647         SKIPWS(ptr);
648
649         if(strncmp("alias", ptr, 5)) {
650                 free(line);
651                 return 1;
652         }
653
654         ptr += 5;
655
656         SKIPWS(ptr);
657
658         tmp = ptr;
659
660         while( ! ISSPACE(*ptr) )
661                 ptr++;
662
663         alias_len = (size_t)(ptr - tmp);
664
665         if(alias)
666                 *alias = xmalloc_inc(alias_len, 1);
667
668         strncpy(*alias, tmp, alias_len);
669         *(*alias + alias_len) = 0;
670
671         SKIPWS(ptr);
672
673         *rest = xstrdup(ptr);
674
675         free(line);
676         return 0;
677 }
678
679 static void
680 mutt_fix_quoting(char *p)
681 {
682         char *escape = 0;
683
684         for(; *p; p++) {
685                 switch(*p) {
686                         case '\"':
687                                 if(escape)
688                                         *escape = ' ';
689                                 break;
690                         case '\\':
691                                 escape = p;
692                                 break;
693                         default:
694                                 escape = 0;
695                 }
696         }
697 }
698
699 static void
700 mutt_parse_email(list_item item)
701 {
702         char *line = item_fget(item, NAME);
703         char *tmp;
704         char *name, *email;
705 #if 0
706         char *start = line;
707         int i = 0;
708 #endif
709
710         mutt_fix_quoting(line);
711         tmp = strconcat("From: ", line, NULL);
712         getname(tmp, &name, &email);
713         free(tmp);
714
715         if(name)
716                 item_fput(item, NAME, name);
717         else
718                 return;
719
720         if(email)
721                 item_fput(item, EMAIL, email);
722         else
723                 return;
724
725         /*
726          * this is completely broken
727          */
728 #if 0
729         while( (start = strchr(start, ',')) && i++ < MAX_EMAILS - 1) {
730                 tmp = strconcat("From: ", ++start, NULL);
731                 getname(tmp, &name, &email);
732                 free(tmp);
733                 free(name);
734                 if(email) {
735                         if(*email) {
736                                 tmp = strconcat(item[EMAIL], ",", email, NULL);
737                                 free(item[EMAIL]);
738                                 item[EMAIL] = tmp;
739                         } else {
740                                 xfree(email);
741                         }
742                 }
743         }
744 #endif
745 }
746
747 static int
748 mutt_parse_file(FILE *in)
749 {
750         list_item item = item_create();
751
752         for(;;) {
753                 memset(item, 0, fields_count * sizeof(char *));
754
755                 if(!mutt_read_line(in,
756                                         (field_id(NICK) != -1) ?
757                                         &item[field_id(NICK)] : NULL,
758                                         &item[field_id(NAME)]))
759                         mutt_parse_email(item);
760
761                 if(feof(in)) {
762                         item_empty(item);
763                         break;
764                 }
765
766                 add_item2database(item);
767         }
768         item_free(&item);
769
770         return 0;
771 }
772
773 /*
774  * end of mutt alias import filter
775  */
776
777
778 /*
779  * ldif export filter
780  */
781
782 static void
783 ldif_fput_type_and_value(FILE *out,char *type, char *value )
784 {
785         char *tmp;
786
787         tmp = ldif_type_and_value(type, value, strlen(value));
788
789         fputs(tmp, out);
790
791         free(tmp);
792 }
793
794 static int
795 ldif_export_database(FILE *out, struct db_enumerator e)
796 {
797         char email[MAX_EMAILSTR_LEN];
798
799         fprintf(out, "version: 1\n");
800
801         db_enumerate_items(e) {
802                 char *tmp;
803                 int j;
804                 get_first_email(email, e.item);
805
806                 tmp = strdup_printf("cn=%s,mail=%s",db_name_get(e.item),email);
807
808                 ldif_fput_type_and_value(out, "dn", tmp);
809                 free(tmp);
810
811                 for(j = 0; j < LDIF_ITEM_FIELDS; j++) {
812                         if(ldif_conv_table[j] >= 0) {
813                                 if(ldif_conv_table[j] == EMAIL)
814                                         ldif_fput_type_and_value(out,
815                                                 ldif_field_names[j], email);
816                                 else if(db_fget(e.item,ldif_conv_table[j]))
817                                         ldif_fput_type_and_value(out,
818                                                 ldif_field_names[j],
819                                                 db_fget(e.item,
820                                                         ldif_conv_table[j]));
821                         }
822                 }
823
824                 fprintf(out, "objectclass: top\n"
825                                 "objectclass: person\n\n");
826         }
827
828         return 0;
829 }
830
831 /*
832  * end of ldif export filter
833  */
834
835 /*
836  * html export filter
837  */
838
839 static void            html_export_write_head(FILE *out);
840 static void            html_export_write_tail(FILE *out);
841
842 extern struct index_elem *index_elements;
843
844 static void
845 html_print_emails(FILE *out, struct list_field *f)
846 {
847         abook_list *l = csv_to_abook_list(f->data);
848
849         for(; l; l = l->next) {
850                 fprintf(out, "<a href=\"mailto:%s\">%s</a>", l->data, l->data);
851                 if(l->next)
852                         fprintf(out, ", ");
853         }
854
855         abook_list_free(&l);
856 }
857
858 static int
859 html_export_database(FILE *out, struct db_enumerator e)
860 {
861         struct list_field f;
862         struct index_elem *cur;
863
864         if(list_is_empty())
865                 return 2;
866
867         init_index();
868
869         html_export_write_head(out);
870
871         db_enumerate_items(e) {
872                 fprintf(out, "<tr>");
873                 for(cur = index_elements; cur; cur = cur->next) {
874                         if(cur->type != INDEX_FIELD)
875                                 continue;
876
877                         get_list_field(e.item, cur, &f);
878
879                         if(f.type == FIELD_EMAILS) {
880                                 fprintf(out, "<td>");
881                                 html_print_emails(out, &f);
882                                 fprintf(out, "</td>");
883                                 continue;
884                         } else {
885                                 fprintf(out, "<td>%s</td>", safe_str(f.data));
886                         }
887                 }
888                 fprintf(out, "</tr>\n");
889         }
890
891         html_export_write_tail(out);
892
893         return 0;
894 }
895
896 static void
897 html_export_write_head(FILE *out)
898 {
899         char *realname = get_real_name(), *str;
900         struct index_elem *cur;
901
902         fprintf(out, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n");
903         fprintf(out, "<html>\n<head>\n <title>%s's addressbook</title>",
904                         realname );
905         fprintf(out, "\n</head>\n<body>\n");
906         fprintf(out, "\n<h2>%s's addressbook</h2>\n", realname );
907         fprintf(out, "<br><br>\n\n");
908
909         fprintf(out, "<table border=\"1\" align=\"center\">\n<tr>");
910         for(cur = index_elements; cur; cur = cur->next) {
911                 if(cur->type != INDEX_FIELD)
912                         continue;
913
914                 get_field_info(cur->d.field.id, NULL, &str, NULL);
915                 fprintf(out, "<th>%s</th>", str);
916         }
917         fprintf(out, "</tr>\n\n");
918
919         free(realname);
920 }
921
922 static void
923 html_export_write_tail(FILE *out)
924 {
925         fprintf(out, "\n</table>\n");
926         fprintf(out, "\n</body>\n</html>\n");
927 }
928
929 /*
930  * end of html export filter
931  */
932
933
934 /*
935  * pine addressbook import filter
936  */
937
938 #define PINE_BUF_SIZE 2048
939
940 static void
941 pine_fixbuf(char *buf)
942 {
943         int i,j;
944
945         for(i = 0,j = 0; j < (int)strlen(buf); i++, j++)
946                 buf[i] = buf[j] == '\n' ? buf[++j] : buf[j];
947 }
948
949 static void
950 pine_convert_emails(char *s)
951 {
952         int i;
953         char *tmp;
954
955         if(s == NULL || *s != '(')
956                 return;
957
958         for(i = 0; s[i]; i++)
959                 s[i] = s[i + 1];
960
961         if( ( tmp = strchr(s,')')) )
962                 *tmp = '\0';
963
964         for(i = 1; ( tmp = strchr(s, ',') ) != NULL ; i++, s = tmp + 1)
965                 if(i > MAX_LIST_ITEMS - 1) {
966                         *tmp = '\0';
967                         break;
968                 }
969
970 }
971
972 static void
973 pine_parse_buf(char *buf)
974 {
975         list_item item;
976         char *start = buf;
977         char *end;
978         char tmp[PINE_BUF_SIZE];
979         int i, len, last;
980         int pine_conv_table[]= {NICK, NAME, EMAIL, -1, NOTES};
981
982         item = item_create();
983
984         for(i=0, last=0; !last ; i++) {
985                 if( !(end = strchr(start, '\t')) )
986                         last=1;
987
988                 len = last ? strlen(start) : (int) (end-start);
989                 len = min(len, PINE_BUF_SIZE - 1);
990
991                 if(i < (int)(sizeof(pine_conv_table) / sizeof(*pine_conv_table))
992                                 && pine_conv_table[i] >= 0) {
993                         strncpy(tmp, start, len);
994                         tmp[len] = 0;
995                         if(*tmp)
996                                 item_fput(item, pine_conv_table[i],
997                                                 xstrdup(tmp));
998                 }
999                 start = end + 1;
1000         }
1001
1002         pine_convert_emails(item_fget(item, EMAIL));
1003         add_item2database(item);
1004         item_free(&item);
1005 }
1006
1007
1008 #define LINESIZE        1024
1009
1010 static int
1011 pine_parse_file(FILE *in)
1012 {
1013         char line[LINESIZE];
1014         char *buf = NULL;
1015         char *ptr;
1016         int i;
1017
1018         fgets(line, LINESIZE, in);
1019
1020         while(!feof(in)) {
1021                 for(i = 2;;i++) {
1022                         buf = xrealloc(buf, i*LINESIZE);
1023                         if(i == 2)
1024                                 strcpy(buf, line);
1025                         fgets(line, LINESIZE, in);
1026                         ptr=(char *)&line;
1027                         if(*ptr != ' ' || feof(in))
1028                                 break;
1029                         else
1030                                 while(*ptr == ' ')
1031                                         ptr++;
1032
1033                         strcat(buf, ptr);
1034                 }
1035                 if(*buf == '#') {
1036                         xfree(buf);
1037                         continue;
1038                 }
1039                 pine_fixbuf(buf);
1040
1041                 pine_parse_buf(buf);
1042
1043                 xfree(buf);
1044         }
1045
1046         return 0;
1047 }
1048
1049 /*
1050  * end of pine addressbook import filter
1051  */
1052
1053
1054 /*
1055  * pine addressbook export filter
1056  *
1057  *  filter doesn't wrap the lines as it should but Pine seems to handle
1058  *  created files without problems - JH
1059  */
1060
1061 static int
1062 pine_export_database(FILE *out, struct db_enumerator e)
1063 {
1064         char *emails;
1065
1066         db_enumerate_items(e) {
1067                 emails = db_email_get(e.item);
1068                 fprintf(out, strchr(emails, ',') /* multiple addresses? */ ?
1069                                 "%s\t%s\t(%s)\t\t%s\n" : "%s\t%s\t%s\t\t%s\n",
1070                                 safe_str(db_fget(e.item, NICK)),
1071                                 safe_str(db_name_get(e.item)),
1072                                 emails,
1073                                 safe_str(db_fget(e.item, NOTES))
1074                                 );
1075                 free(emails);
1076         }
1077
1078         return 0;
1079 }
1080
1081 /*
1082  * end of pine addressbook export filter
1083  */
1084
1085
1086 /*
1087  * csv import filter
1088  */
1089
1090 /* FIXME
1091  * these files should be parsed according to a certain
1092  * lay out, or the default if layout is not given, at
1093  * the moment only default is done...
1094  */
1095
1096 #define CSV_COMMENT_CHAR        '#'
1097 #define CSV_DUPLICATE_SEPARATOR " "
1098 #define CSV_TABLE_SIZE(t)       (sizeof (t) / sizeof *(t))
1099
1100 static int csv_conv_table[] = {
1101         NAME,
1102         EMAIL,
1103         PHONE,
1104         NOTES,
1105         NICK
1106 };
1107
1108 static int allcsv_conv_table[] = {
1109         NAME,
1110         EMAIL,
1111         ADDRESS,
1112         ADDRESS2,
1113         CITY,
1114         STATE,
1115         ZIP,
1116         COUNTRY,
1117         PHONE,
1118         WORKPHONE,
1119         FAX,
1120         MOBILEPHONE,
1121         NICK,
1122         URL,
1123         NOTES,
1124         ANNIVERSARY
1125 };
1126
1127 static int palmcsv_conv_table[] = {
1128         NAME,           /* Last name */
1129         NAME,           /* First name */
1130         NOTES,          /* Title */
1131         NICK,           /* Company */
1132         WORKPHONE,
1133         PHONE,
1134         FAX,
1135         MOBILEPHONE,
1136         EMAIL,
1137         ADDRESS,
1138         CITY,
1139         STATE,
1140         ZIP,
1141         COUNTRY,
1142         ANNIVERSARY,
1143 };
1144
1145 static void
1146 csv_convert_emails(char *s)
1147 {
1148         int i;
1149         char *tmp;
1150
1151         if(s == NULL)
1152                 return;
1153
1154         for(i = 1; ( tmp = strchr(s, ',') ) != NULL ; i++, s = tmp + 1)
1155                 if(i > MAX_LIST_ITEMS - 1) {
1156                         *tmp = 0;
1157                         break;
1158                 }
1159
1160 }
1161
1162 static char *
1163 csv_remove_quotes(char *s)
1164 {
1165         char *copy, *trimmed;
1166         int len;
1167
1168         copy = trimmed = xstrdup(s);
1169         strtrim(trimmed);
1170
1171         len = strlen(trimmed);
1172         if(trimmed[len - 1] == '\"' && *trimmed == '\"') {
1173                 if(len < 3) {
1174                         xfree(copy);
1175                         return NULL;
1176                 }
1177                 trimmed[len - 1] = 0;
1178                 trimmed++;
1179                 trimmed = xstrdup(trimmed);
1180                 free(copy);
1181                 return trimmed;
1182         }
1183
1184         xfree(copy);
1185         return xstrdup(s);
1186 }
1187
1188 static int
1189 csv_field_to_item(int *table_base, size_t table_size, int field)
1190 {
1191         if(field < table_size)
1192                 return field_id(table_base[field]);
1193
1194         return -1;
1195 }
1196
1197 static void
1198 csv_store_item(list_item item, int i, char *s)
1199 {
1200         char *newstr = NULL;
1201
1202         if(!s || !*s)
1203                 return;
1204
1205         if( !(newstr = csv_remove_quotes(s)) )
1206                 return;
1207
1208         if(i >= 0) {
1209                 if (item[i] != NULL) {
1210                         char *oldstr = item[i];
1211
1212                         item[i] = strconcat(newstr, CSV_DUPLICATE_SEPARATOR,
1213                                 oldstr, NULL);
1214                         xfree(newstr);
1215                         xfree(oldstr);
1216                 } else {
1217                         item[i] = newstr;
1218                 }
1219         } else {
1220                 xfree(newstr);
1221         }
1222 }
1223
1224 static int
1225 csv_is_valid_quote_end(char *p)
1226 {
1227         if(*p != '\"')
1228                 return FALSE;
1229
1230         for(p++; *p; p++) {
1231                 if(*p == ',')
1232                         return TRUE;
1233                 else if(!ISSPACE(*p))
1234                         return FALSE;
1235         }
1236
1237         return TRUE;
1238 }
1239
1240 static int
1241 csv_is_valid_quote_start(char *p)
1242 {
1243         for(; *p; p++) {
1244                 if(*p == '\"')
1245                         return TRUE;
1246                 else if(!ISSPACE(*p))
1247                         return FALSE;
1248         }
1249
1250         return FALSE;
1251 }
1252
1253 static void
1254 csv_parse_line(char *line, int *table_base, size_t table_size)
1255 {
1256         char *p, *start;
1257         int field;
1258         bool in_quote = FALSE;
1259         list_item item;
1260
1261         item = item_create();
1262
1263         for(p = start = line, field = 0; *p; p++) {
1264                 if(in_quote) {
1265                         if(csv_is_valid_quote_end(p))
1266                                 in_quote = FALSE;
1267                 } else {
1268                         if ( (((p - start) / sizeof (char)) < 2 ) &&
1269                                 csv_is_valid_quote_start(p) )
1270                                 in_quote = TRUE;
1271                 }
1272
1273                 if(*p == ',' && !in_quote) {
1274                         *p = 0;
1275                         csv_store_item(item,
1276                                 csv_field_to_item(table_base,table_size,field),
1277                                 start);
1278                         field++;
1279                         start = p + 1;
1280                 }
1281         }
1282         /*
1283          * store last field
1284          */
1285         csv_store_item(item, csv_field_to_item(table_base, table_size, field),
1286                 start);
1287
1288         csv_convert_emails(item_fget(item, EMAIL));
1289         add_item2database(item);
1290         item_free(&item);
1291 }
1292
1293 static int
1294 csv_parse_file_common(FILE *in, int *conv_table, size_t table_size)
1295 {
1296         char *line = NULL;
1297
1298         while(!feof(in)) {
1299                 line = getaline(in);
1300
1301                 if(line && *line && *line != CSV_COMMENT_CHAR)
1302                         csv_parse_line(line, conv_table, table_size);
1303
1304                 xfree(line);
1305         }
1306
1307         return 0;
1308 }
1309
1310 static int
1311 csv_parse_file(FILE *in)
1312 {
1313         return csv_parse_file_common(in, csv_conv_table,
1314                 CSV_TABLE_SIZE(csv_conv_table));
1315 }
1316
1317 static int
1318 allcsv_parse_file(FILE *in)
1319 {
1320         return csv_parse_file_common(in, allcsv_conv_table,
1321                 CSV_TABLE_SIZE(allcsv_conv_table));
1322 }
1323
1324 static int
1325 palmcsv_parse_file(FILE *in)
1326 {
1327         return csv_parse_file_common(in, palmcsv_conv_table,
1328                 CSV_TABLE_SIZE(palmcsv_conv_table));
1329 }
1330
1331 /*
1332  * end of csv import filter
1333  */
1334
1335 /*
1336  * vCard import filter
1337  */
1338
1339 static char *vcard_fields[] = {
1340         "FN",                   /* NAME */
1341         "EMAIL",                /* EMAIL */
1342         "ADR",                  /* ADDRESS */
1343         "ADR",                  /* ADDRESS2 - not used */
1344         "ADR",                  /* CITY */
1345         "ADR",                  /* STATE */
1346         "ADR",                  /* ZIP */
1347         "ADR",                  /* COUNTRY */
1348         "TEL",                  /* PHONE */
1349         "TEL",                  /* WORKPHONE */
1350         "TEL",                  /* FAX */
1351         "TEL",                  /* MOBILEPHONE */
1352         "NICKNAME",             /* NICK */
1353         "URL",                  /* URL */
1354         "NOTE",                 /* NOTES */
1355         NULL                    /* not implemented: ANNIVERSARY, ITEM_FIELDS */
1356 };
1357
1358 /*
1359  * mappings between vCard ADR field and abook's ADDRESS
1360  * see rfc2426 section 3.2.1
1361  */
1362 static int vcard_address_fields[] = {
1363         -1,                     /* vCard(post office box) - not used */
1364         -1,                     /* vCard(the extended address) - not used */
1365         2,                      /* vCard(the street address) - ADDRESS */
1366         4,                      /* vCard(the locality) - CITY */
1367         5,                      /* vCard(the region) - STATE */
1368         6,                      /* vCard(the postal code) - ZIP */
1369         7                       /* vCard(the country name) - COUNTRY */
1370 };
1371
1372 enum {
1373         VCARD_KEY = 0,
1374         VCARD_KEY_ATTRIBUTE,
1375         VCARD_VALUE,
1376 };
1377
1378 static char *
1379 vcard_get_line_element(char *line, int element)
1380 {
1381         int i;
1382         char *line_copy = 0;
1383         char *result = 0;
1384         char *key = 0;
1385         char *key_attr = 0;
1386         char *value = 0;
1387
1388         line_copy = xstrdup(line);
1389
1390         /* make newline characters if exist end of string */
1391         for(i=0; line_copy[i]; i++) {
1392                 if(line_copy[i] == '\r' || line_copy[i] == '\n') {
1393                         line_copy[i] = '\0';
1394                         break;
1395                 }
1396         }
1397
1398         /* separate key from value */
1399         for(i=0; line_copy[i]; i++) {
1400                 if(line_copy[i] == ':') {
1401                         line_copy[i] = '\0';
1402                         key = line_copy;
1403                         value = &line_copy[i+1];
1404                         break;
1405                 }
1406         }
1407
1408         /* separate key from key attributes */
1409         if (key) {
1410                 for(i=0; key[i]; i++) {
1411                         if(key[i] == ';') {
1412                                 key[i] = '\0';
1413                                 key_attr = &key[i+1];
1414                                 break;
1415                         }
1416                 }
1417         }
1418
1419         switch(element) {
1420         case VCARD_KEY:
1421                 if(key)
1422                         result = xstrdup(key);
1423                 break;
1424         case VCARD_KEY_ATTRIBUTE:
1425                 if(key_attr)
1426                         result = xstrdup(key_attr);
1427                 break;
1428         case VCARD_VALUE:
1429                 if(value)
1430                         result = xstrdup(value);
1431                 break;
1432         }
1433
1434         xfree(line_copy);
1435         return result;
1436 }
1437
1438 static void
1439 vcard_parse_email(list_item item, char *line)
1440 {
1441         char *email;
1442
1443         email = vcard_get_line_element(line, VCARD_VALUE);
1444
1445         if(item[1]) {
1446                 item[1] = strconcat(item[1], ",", email, 0);
1447                 xfree(email);
1448         }
1449         else {
1450                 item[1] = email;
1451         }
1452 }
1453
1454 static void
1455 vcard_parse_address(list_item item, char *line)
1456 {
1457         int i;
1458         int k;
1459         char *value;
1460         char *address_field;
1461
1462         value = vcard_get_line_element(line, VCARD_VALUE);
1463         if(!value)
1464                 return;
1465
1466         address_field = value;
1467         for(i=k=0; value[i]; i++) {
1468                 if(value[i] == ';') {
1469                         value[i] = '\0';
1470                         if(vcard_address_fields[k] >= 0) {
1471                                 item[vcard_address_fields[k]] = xstrdup(address_field);
1472                         }
1473                         address_field = &value[i+1];
1474                         k++;
1475                         if((k+1)==(sizeof(vcard_address_fields)/sizeof(*vcard_address_fields)))
1476                                 break;
1477                 }
1478         }
1479         item[vcard_address_fields[k]] = xstrdup(address_field);
1480         xfree(value);
1481 }
1482
1483 static void
1484 vcard_parse_phone(list_item item, char *line)
1485 {
1486         int index = 8;
1487         char *type = vcard_get_line_element(line, VCARD_KEY_ATTRIBUTE);
1488         char *value = vcard_get_line_element(line, VCARD_VALUE);
1489
1490         /* set the standard number */
1491         if (!type) {
1492                 item[index] = value;
1493         }
1494
1495         /*
1496          * see rfc2426 section 3.3.1
1497          */
1498         else if (strstr(type, "TYPE=") == type){
1499                 if (strcasestr(type, "home")) {
1500                         item[index] = xstrdup(value);
1501                 }
1502                 if (strcasestr(type, "work")) {
1503                         item[index+1] = xstrdup(value);
1504                 }
1505                 if (strcasestr(type, "fax")) {
1506                         item[index+2] = xstrdup(value);
1507                 }
1508                 if (strcasestr(type, "cell")) {
1509                         item[index+3] = xstrdup(value);
1510                 }
1511
1512                 xfree(type);
1513                 xfree(value);
1514         }
1515 }
1516
1517 static void
1518 vcard_parse_line(list_item item, char *line)
1519 {
1520         int i;
1521         char *key;
1522
1523         for(i=0; vcard_fields[i]; i++) {
1524                 key = vcard_fields[i];
1525
1526                 if(!strncmp(key, line, strlen(key))) {
1527                         if(i == 1) {
1528                                 vcard_parse_email(item, line);
1529                         }
1530                         else if(i == 2) {
1531                                 vcard_parse_address(item, line);
1532                         }
1533                         else if(i == 8) {
1534                                 vcard_parse_phone(item, line);
1535                         }
1536                         else {
1537                                 item[i] = vcard_get_line_element(line, VCARD_VALUE);
1538                         }
1539                         break;
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  * GnomeCard (VCard) addressbook export filter
1782  */
1783
1784 static int
1785 gcrd_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 GnomeCard 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