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