Initialize with abook-0.6.0pre2
[abook.git] / filter.c
blobf13d0995943dbbba872a5c70b5f924c302c28bb1
2 /*
3 * $Id: filter.c,v 1.55 2006/09/06 02:46:44 cduval Exp $
5 * by JH <jheinonen@users.sourceforge.net>
7 * Copyright (C) Jaakko Heinonen
8 */
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>
30 extern abook_field_list *fields_list;
31 extern int fields_count;
34 * function declarations
38 * import filter prototypes
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);
49 * export filter prototypes
52 static int ldif_export_database(FILE *out, struct db_enumerator e);
53 static int html_export_database(FILE *out, struct db_enumerator e);
54 static int pine_export_database(FILE *out, struct db_enumerator e);
55 static int csv_export_database(FILE *out, struct db_enumerator e);
56 static int allcsv_export_database(FILE *out, struct db_enumerator e);
57 static int palm_export_database(FILE *out, struct db_enumerator e);
58 static int gcrd_export_database(FILE *out, struct db_enumerator e);
59 static int mutt_alias_export(FILE *out, struct db_enumerator e);
60 static int elm_alias_export(FILE *out, struct db_enumerator e);
61 static int text_export_database(FILE *out, struct db_enumerator e);
62 static int spruce_export_database(FILE *out, struct db_enumerator e);
63 static int wl_export_database(FILE *out, struct db_enumerator e);
64 static int bsdcal_export_database(FILE *out, struct db_enumerator e);
67 * end of function declarations
70 struct abook_input_filter i_filters[] = {
71 { "abook", N_("abook native format"), parse_database },
72 { "ldif", N_("ldif / Netscape addressbook"), ldif_parse_file },
73 { "mutt", N_("mutt alias"), mutt_parse_file },
74 { "pine", N_("pine addressbook"), pine_parse_file },
75 { "csv", N_("comma separated values"), csv_parse_file },
76 { "allcsv", N_("comma separated values (all fields)"), allcsv_parse_file },
77 { "palmcsv", N_("Palm comma separated values"), palmcsv_parse_file },
78 { "\0", NULL, NULL }
81 struct abook_output_filter e_filters[] = {
82 { "abook", N_("abook native format"), write_database },
83 { "ldif", N_("ldif / Netscape addressbook (.4ld)"), ldif_export_database },
84 { "mutt", N_("mutt alias"), mutt_alias_export },
85 { "html", N_("html document"), html_export_database },
86 { "pine", N_("pine addressbook"), pine_export_database },
87 { "gcrd", N_("GnomeCard (VCard) addressbook"), gcrd_export_database },
88 { "csv", N_("comma separated values"), csv_export_database },
89 { "allcsv", N_("comma separated values (all fields)"), allcsv_export_database },
90 { "palmcsv", N_("Palm comma separated values"), palm_export_database},
91 { "elm", N_("elm alias"), elm_alias_export },
92 { "text", N_("plain text"), text_export_database },
93 { "wl", N_("Wanderlust address book"), wl_export_database },
94 { "spruce", N_("Spruce address book"), spruce_export_database },
95 { "bsdcal", N_("BSD calendar"), bsdcal_export_database },
96 { "\0", NULL, NULL }
100 * common functions
103 void
104 print_filters()
106 int i;
108 puts(_("input:"));
109 for(i=0; *i_filters[i].filtname ; i++)
110 printf("\t%s\t%s\n", i_filters[i].filtname,
111 gettext(i_filters[i].desc));
113 putchar('\n');
115 puts(_("output:"));
116 for(i=0; *e_filters[i].filtname ; i++)
117 printf("\t%s\t%s\n", e_filters[i].filtname,
118 gettext(e_filters[i].desc));
120 putchar('\n');
123 static int
124 number_of_output_filters()
126 int i;
128 for(i=0; *e_filters[i].filtname ; i++)
131 return i;
134 static int
135 number_of_input_filters()
137 int i;
139 for(i=0; *i_filters[i].filtname ; i++)
142 return i;
145 static char *
146 get_real_name()
148 char *username = getenv("USER");
149 struct passwd *pwent;
150 int rtn;
151 char *tmp;
153 pwent = getpwnam(username);
155 if((tmp = xstrdup(pwent->pw_gecos)) == NULL)
156 return xstrdup(username);
158 rtn = sscanf(pwent->pw_gecos, "%[^,]", tmp);
159 if (rtn == EOF || rtn == 0) {
160 free(tmp);
161 return xstrdup(username);
162 } else
163 return tmp;
167 * import
170 static int i_read_file(char *filename, int (*func) (FILE *in));
172 static void
173 import_screen()
175 int i;
177 clear();
179 refresh_statusline();
180 headerline(_("import database"));
182 mvaddstr(3, 1, _("please select a filter"));
185 for(i=0; *i_filters[i].filtname ; i++)
186 mvprintw(5 + i, 6, "%c -\t%s\t%s\n", 'a' + i,
187 i_filters[i].filtname,
188 gettext(i_filters[i].desc));
190 mvprintw(6 + i, 6, _("x -\tcancel"));
194 import_database()
196 int filter;
197 char *filename;
198 int tmp = db_n_items();
200 import_screen();
202 filter = getch() - 'a';
203 if(filter == 'x' - 'a' ||
204 filter >= number_of_input_filters() || filter < 0) {
205 refresh_screen();
206 return 1;
209 mvaddstr(5+filter, 2, "->");
211 filename = ask_filename(_("Filename: "));
212 if(!filename) {
213 refresh_screen();
214 return 2;
217 if(i_read_file(filename, i_filters[filter].func ))
218 statusline_msg(_("Error occured while opening the file"));
219 else if(tmp == db_n_items())
220 statusline_msg(_("File does not seem to be a valid addressbook"));
222 refresh_screen();
223 free(filename);
225 return 0;
230 static int
231 i_read_file(char *filename, int (*func) (FILE *in))
233 FILE *in;
234 int ret = 0;
236 if( (in = abook_fopen( filename, "r" )) == NULL )
237 return 1;
239 ret = (*func) (in);
241 fclose(in);
243 return ret;
247 import_file(char filtname[FILTNAME_LEN], char *filename)
249 int i;
250 int tmp = db_n_items();
251 int ret = 0;
253 for(i=0;; i++) {
254 if(! strncasecmp(i_filters[i].filtname, filtname,
255 FILTNAME_LEN) )
256 break;
257 if(! *i_filters[i].filtname) {
258 i = -1;
259 break;
263 if(i < 0)
264 return -1;
266 if(!strcmp(filename, "-")) {
267 struct stat s;
268 if((fstat(fileno(stdin), &s)) == -1 || S_ISDIR(s.st_mode))
269 ret = 1;
270 else
271 ret = (*i_filters[i].func) (stdin);
272 } else
273 ret = i_read_file(filename, i_filters[i].func);
275 if(tmp == db_n_items())
276 ret = 1;
278 return ret;
282 * export
285 static int e_write_file(char *filename,
286 int (*func) (FILE *in, struct db_enumerator e), int mode);
288 static void
289 export_screen()
291 int i;
293 clear();
296 refresh_statusline();
297 headerline(_("export database"));
299 mvaddstr(3, 1, _("please select a filter"));
302 for(i = 0; *e_filters[i].filtname ; i++)
303 mvprintw(5 + i, 6, "%c -\t%s\t%s\n", 'a' + i,
304 e_filters[i].filtname,
305 gettext(e_filters[i].desc));
307 mvprintw(6 + i, 6, _("x -\tcancel"));
311 export_database()
313 int filter;
314 int enum_mode = ENUM_ALL;
315 char *filename;
317 export_screen();
319 filter = getch() - 'a';
320 if(filter == 'x' - 'a' ||
321 filter >= number_of_output_filters() || filter < 0) {
322 refresh_screen();
323 return 1;
326 mvaddstr(5 + filter, 2, "->");
328 if(selected_items()) {
329 switch(statusline_askchoice(
330 _("Export <a>ll, export <s>elected, or <c>ancel?"),
331 S_("keybindings:all/selected/cancel|asc"), 3)) {
332 case 1:
333 break;
334 case 2:
335 enum_mode = ENUM_SELECTED;
336 break;
337 case 0:
338 case 3:
339 refresh_screen();
340 return 1;
342 clear_statusline();
345 filename = ask_filename(_("Filename: "));
346 if(!filename) {
347 refresh_screen();
348 return 2;
351 if( e_write_file(filename, e_filters[filter].func, enum_mode))
352 statusline_msg(_("Error occured while exporting"));
354 refresh_screen();
355 free(filename);
357 return 0;
360 static int
361 e_write_file(char *filename, int (*func) (FILE *in, struct db_enumerator e),
362 int mode)
364 FILE *out;
365 int ret = 0;
366 struct db_enumerator enumerator = init_db_enumerator(mode);
368 if((out = fopen(filename, "a")) == NULL)
369 return 1;
371 if(ftell(out))
372 return 1;
374 ret = (*func) (out, enumerator);
376 fclose(out);
378 return ret;
382 fexport(char filtname[FILTNAME_LEN], FILE *handle, int enum_mode)
384 int i;
385 struct db_enumerator e = init_db_enumerator(enum_mode);
387 for(i=0;; i++) {
388 if(!strncasecmp(e_filters[i].filtname, filtname,
389 FILTNAME_LEN))
390 break;
391 if(!*e_filters[i].filtname) {
392 i = -1;
393 break;
397 return (e_filters[i].func) (handle, e);
403 export_file(char filtname[FILTNAME_LEN], char *filename)
405 const int mode = ENUM_ALL;
406 int i;
407 int ret = 0;
408 struct db_enumerator e = init_db_enumerator(mode);
410 for(i=0;; i++) {
411 if(!strncasecmp(e_filters[i].filtname, filtname,
412 FILTNAME_LEN))
413 break;
414 if(!*e_filters[i].filtname) {
415 i = -1;
416 break;
420 if(i < 0)
421 return -1;
423 if(!strcmp(filename, "-"))
424 ret = (e_filters[i].func) (stdout, e);
425 else
426 ret = e_write_file(filename, e_filters[i].func, mode);
428 return ret;
432 * end of common functions
436 * ldif import
439 #include "ldif.h"
441 static void ldif_fix_string(char *str);
443 #define LDIF_ITEM_FIELDS 16
445 typedef char *ldif_item[LDIF_ITEM_FIELDS];
447 static ldif_item ldif_field_names = {
448 "cn",
449 "mail",
450 "streetaddress",
451 "streetaddress2",
452 "locality",
453 "st",
454 "postalcode",
455 "countryname",
456 "homephone",
457 "description",
458 "homeurl",
459 "facsimiletelephonenumber",
460 "cellphone",
461 "xmozillaanyphone",
462 "xmozillanickname",
463 "objectclass", /* this must be the last entry */
466 static int ldif_conv_table[LDIF_ITEM_FIELDS] = {
467 NAME, /* "cn" */
468 EMAIL, /* "mail" */
469 ADDRESS, /* "streetaddress" */
470 ADDRESS2, /* "streetaddress2" */
471 CITY, /* "locality" */
472 STATE, /* "st" */
473 ZIP, /* "postalcode" */
474 COUNTRY, /* "countryname" */
475 PHONE, /* "homephone" */
476 NOTES, /* "description" */
477 URL, /* "homeurl" */
478 FAX, /* "facsimiletelephonenumber" */
479 MOBILEPHONE, /* "cellphone" */
480 WORKPHONE, /* "xmozillaanyphone" */
481 NICK, /* "xmozillanickname" */
482 -1, /* "objectclass" */ /* this must be the last entry */
486 static char *
487 ldif_read_line(FILE *in)
489 char *buf = NULL;
490 char *ptr, *tmp;
491 long pos;
492 int i;
494 for(i = 1;;i++) {
495 char *line;
497 pos = ftell(in);
498 line = getaline(in);
500 if(feof(in) || !line)
501 break;
503 if(i == 1) {
504 buf = line;
505 continue;
508 if(*line != ' ') {
509 fseek(in, pos, SEEK_SET); /* fixme ! */
510 free(line);
511 break;
514 ptr = line;
515 while( *ptr == ' ')
516 ptr++;
518 tmp = buf;
519 buf = strconcat(buf, ptr, NULL);
520 free(tmp);
521 free(line);
524 if(buf && *buf == '#' ) {
525 free(buf);
526 return NULL;
529 return buf;
532 static void
533 ldif_add_item(ldif_item li)
535 list_item item;
536 int i;
538 item = item_create();
540 if(!li[LDIF_ITEM_FIELDS -1])
541 goto bail_out;
544 for(i=0; i < LDIF_ITEM_FIELDS; i++) {
545 if(ldif_conv_table[i] >= 0 && li[i] && *li[i])
546 item_fput(item,ldif_conv_table[i],xstrdup(li[i]));
549 add_item2database(item);
551 bail_out:
552 for(i=0; i < LDIF_ITEM_FIELDS; i++)
553 xfree(li[i]);
554 item_free(&item);
558 static void
559 ldif_convert(ldif_item item, char *type, char *value)
561 int i;
563 if(!strcmp(type, "dn")) {
564 ldif_add_item(item);
565 return;
568 for(i=0; i < LDIF_ITEM_FIELDS; i++) {
569 if(!safe_strcmp(ldif_field_names[i], type) && *value) {
570 if(i == LDIF_ITEM_FIELDS - 1) /* this is a dirty hack */
571 if(safe_strcmp("person", value))
572 break;
574 if(item_fget(item, i))
575 free(item_fget(item, i));
577 item_fput(item, i, xstrdup(value));
582 static int
583 ldif_parse_file(FILE *handle)
585 char *line = NULL;
586 char *type, *value;
587 int vlen;
588 ldif_item item;
590 memset(item, 0, sizeof(item));
592 do {
593 if( !(line = ldif_read_line(handle)) )
594 continue;
596 if(-1 == (str_parse_line(line, &type, &value, &vlen))) {
597 xfree(line);
598 continue; /* just skip the errors */
601 ldif_fix_string(value);
603 ldif_convert(item, type, value);
605 xfree(line);
606 } while ( !feof(handle) );
608 ldif_convert(item, "dn", "");
610 return 0;
613 static void
614 ldif_fix_string(char *str)
616 int i, j;
618 for(i = 0, j = 0; j < (int)strlen(str); i++, j++)
619 str[i] = ( str[j] == (char)0xc3 ?
620 (char) str[++j] + (char) 0x40 :
621 str[j] );
623 str[i] = 0;
627 * end of ldif import
631 * mutt alias import filter
634 #include "getname.h"
636 static int
637 mutt_read_line(FILE *in, char **alias, char **rest)
639 char *line, *ptr, *tmp;
640 size_t alias_len;
642 if( !(line = ptr = getaline(in)) )
643 return 1; /* error / EOF */
645 SKIPWS(ptr);
647 if(strncmp("alias", ptr, 5)) {
648 free(line);
649 return 1;
652 ptr += 5;
654 SKIPWS(ptr);
656 tmp = ptr;
658 while( ! ISSPACE(*ptr) )
659 ptr++;
661 alias_len = (size_t)(ptr - tmp);
663 if(alias)
664 *alias = xmalloc_inc(alias_len, 1);
666 strncpy(*alias, tmp, alias_len);
667 *(*alias + alias_len) = 0;
669 SKIPWS(ptr);
671 *rest = xstrdup(ptr);
673 free(line);
674 return 0;
677 static void
678 mutt_fix_quoting(char *p)
680 char *escape = 0;
682 for(; *p; p++) {
683 switch(*p) {
684 case '\"':
685 if(escape)
686 *escape = ' ';
687 break;
688 case '\\':
689 escape = p;
690 break;
691 default:
692 escape = 0;
697 static void
698 mutt_parse_email(list_item item)
700 char *line = item_fget(item, NAME);
701 char *tmp;
702 char *name, *email;
703 #if 0
704 char *start = line;
705 int i = 0;
706 #endif
708 mutt_fix_quoting(line);
709 tmp = strconcat("From: ", line, NULL);
710 getname(tmp, &name, &email);
711 free(tmp);
713 if(name)
714 item_fput(item, NAME, name);
715 else
716 return;
718 if(email)
719 item_fput(item, EMAIL, email);
720 else
721 return;
724 * this is completely broken
726 #if 0
727 while( (start = strchr(start, ',')) && i++ < MAX_EMAILS - 1) {
728 tmp = strconcat("From: ", ++start, NULL);
729 getname(tmp, &name, &email);
730 free(tmp);
731 free(name);
732 if(email) {
733 if(*email) {
734 tmp = strconcat(item[EMAIL], ",", email, NULL);
735 free(item[EMAIL]);
736 item[EMAIL] = tmp;
737 } else {
738 xfree(email);
742 #endif
745 static int
746 mutt_parse_file(FILE *in)
748 list_item item = item_create();
750 for(;;) {
751 memset(item, 0, fields_count * sizeof(char *));
753 if(!mutt_read_line(in,
754 (field_id(NICK) != -1) ?
755 &item[field_id(NICK)] : NULL,
756 &item[field_id(NAME)]))
757 mutt_parse_email(item);
759 if(feof(in)) {
760 item_empty(item);
761 break;
764 add_item2database(item);
766 item_free(&item);
768 return 0;
772 * end of mutt alias import filter
777 * ldif export filter
780 static void
781 ldif_fput_type_and_value(FILE *out,char *type, char *value )
783 char *tmp;
785 tmp = ldif_type_and_value(type, value, strlen(value));
787 fputs(tmp, out);
789 free(tmp);
792 static int
793 ldif_export_database(FILE *out, struct db_enumerator e)
795 char email[MAX_EMAILSTR_LEN];
797 fprintf(out, "version: 1\n");
799 db_enumerate_items(e) {
800 char *tmp;
801 int j;
802 get_first_email(email, e.item);
804 tmp = strdup_printf("cn=%s,mail=%s",db_name_get(e.item),email);
806 ldif_fput_type_and_value(out, "dn", tmp);
807 free(tmp);
809 for(j = 0; j < LDIF_ITEM_FIELDS; j++) {
810 if(ldif_conv_table[j] >= 0) {
811 if(ldif_conv_table[j] == EMAIL)
812 ldif_fput_type_and_value(out,
813 ldif_field_names[j], email);
814 else if(db_fget(e.item,ldif_conv_table[j]))
815 ldif_fput_type_and_value(out,
816 ldif_field_names[j],
817 db_fget(e.item,
818 ldif_conv_table[j]));
822 fprintf(out, "objectclass: top\n"
823 "objectclass: person\n\n");
826 return 0;
830 * end of ldif export filter
834 * html export filter
837 static void html_export_write_head(FILE *out);
838 static void html_export_write_tail(FILE *out);
840 extern struct index_elem *index_elements;
842 static void
843 html_print_emails(FILE *out, struct list_field *f)
845 abook_list *l = csv_to_abook_list(f->data);
847 for(; l; l = l->next) {
848 fprintf(out, "<a href=\"mailto:%s\">%s</a>", l->data, l->data);
849 if(l->next)
850 fprintf(out, ", ");
853 abook_list_free(&l);
856 static int
857 html_export_database(FILE *out, struct db_enumerator e)
859 struct list_field f;
860 struct index_elem *cur;
862 if(list_is_empty())
863 return 2;
865 init_index();
867 html_export_write_head(out);
869 db_enumerate_items(e) {
870 fprintf(out, "<tr>");
871 for(cur = index_elements; cur; cur = cur->next) {
872 if(cur->type != INDEX_FIELD)
873 continue;
875 get_list_field(e.item, cur, &f);
877 if(f.type == FIELD_EMAILS) {
878 fprintf(out, "<td>");
879 html_print_emails(out, &f);
880 fprintf(out, "</td>");
881 continue;
882 } else {
883 fprintf(out, "<td>%s</td>", safe_str(f.data));
886 fprintf(out, "</tr>\n");
889 html_export_write_tail(out);
891 return 0;
894 static void
895 html_export_write_head(FILE *out)
897 char *realname = get_real_name(), *str;
898 struct index_elem *cur;
900 fprintf(out, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n");
901 fprintf(out, "<html>\n<head>\n <title>%s's addressbook</title>",
902 realname );
903 fprintf(out, "\n</head>\n<body>\n");
904 fprintf(out, "\n<h2>%s's addressbook</h2>\n", realname );
905 fprintf(out, "<br><br>\n\n");
907 fprintf(out, "<table border=\"1\" align=\"center\">\n<tr>");
908 for(cur = index_elements; cur; cur = cur->next) {
909 if(cur->type != INDEX_FIELD)
910 continue;
912 get_field_info(cur->d.field.id, NULL, &str, NULL);
913 fprintf(out, "<th>%s</th>", str);
915 fprintf(out, "</tr>\n\n");
917 free(realname);
920 static void
921 html_export_write_tail(FILE *out)
923 fprintf(out, "\n</table>\n");
924 fprintf(out, "\n</body>\n</html>\n");
928 * end of html export filter
933 * pine addressbook import filter
936 #define PINE_BUF_SIZE 2048
938 static void
939 pine_fixbuf(char *buf)
941 int i,j;
943 for(i = 0,j = 0; j < (int)strlen(buf); i++, j++)
944 buf[i] = buf[j] == '\n' ? buf[++j] : buf[j];
947 static void
948 pine_convert_emails(char *s)
950 int i;
951 char *tmp;
953 if(s == NULL || *s != '(')
954 return;
956 for(i = 0; s[i]; i++)
957 s[i] = s[i + 1];
959 if( ( tmp = strchr(s,')')) )
960 *tmp = '\0';
962 for(i = 1; ( tmp = strchr(s, ',') ) != NULL ; i++, s = tmp + 1)
963 if(i > MAX_LIST_ITEMS - 1) {
964 *tmp = '\0';
965 break;
970 static void
971 pine_parse_buf(char *buf)
973 list_item item;
974 char *start = buf;
975 char *end;
976 char tmp[PINE_BUF_SIZE];
977 int i, len, last;
978 int pine_conv_table[]= {NICK, NAME, EMAIL, -1, NOTES};
980 item = item_create();
982 for(i=0, last=0; !last ; i++) {
983 if( !(end = strchr(start, '\t')) )
984 last=1;
986 len = last ? strlen(start) : (int) (end-start);
987 len = min(len, PINE_BUF_SIZE - 1);
989 if(i < (int)(sizeof(pine_conv_table) / sizeof(*pine_conv_table))
990 && pine_conv_table[i] >= 0) {
991 strncpy(tmp, start, len);
992 tmp[len] = 0;
993 if(*tmp)
994 item_fput(item, pine_conv_table[i],
995 xstrdup(tmp));
997 start = end + 1;
1000 pine_convert_emails(item_fget(item, EMAIL));
1001 add_item2database(item);
1002 item_free(&item);
1006 #define LINESIZE 1024
1008 static int
1009 pine_parse_file(FILE *in)
1011 char line[LINESIZE];
1012 char *buf = NULL;
1013 char *ptr;
1014 int i;
1016 fgets(line, LINESIZE, in);
1018 while(!feof(in)) {
1019 for(i = 2;;i++) {
1020 buf = xrealloc(buf, i*LINESIZE);
1021 if(i == 2)
1022 strcpy(buf, line);
1023 fgets(line, LINESIZE, in);
1024 ptr=(char *)&line;
1025 if(*ptr != ' ' || feof(in))
1026 break;
1027 else
1028 while(*ptr == ' ')
1029 ptr++;
1031 strcat(buf, ptr);
1033 if(*buf == '#') {
1034 xfree(buf);
1035 continue;
1037 pine_fixbuf(buf);
1039 pine_parse_buf(buf);
1041 xfree(buf);
1044 return 0;
1048 * end of pine addressbook import filter
1053 * pine addressbook export filter
1055 * filter doesn't wrap the lines as it should but Pine seems to handle
1056 * created files without problems - JH
1059 static int
1060 pine_export_database(FILE *out, struct db_enumerator e)
1062 char *emails;
1064 db_enumerate_items(e) {
1065 emails = db_email_get(e.item);
1066 fprintf(out, strchr(emails, ',') /* multiple addresses? */ ?
1067 "%s\t%s\t(%s)\t\t%s\n" : "%s\t%s\t%s\t\t%s\n",
1068 safe_str(db_fget(e.item, NICK)),
1069 safe_str(db_name_get(e.item)),
1070 emails,
1071 safe_str(db_fget(e.item, NOTES))
1073 free(emails);
1076 return 0;
1080 * end of pine addressbook export filter
1085 * csv import filter
1088 /* FIXME
1089 * these files should be parsed according to a certain
1090 * lay out, or the default if layout is not given, at
1091 * the moment only default is done...
1094 #define CSV_COMMENT_CHAR '#'
1095 #define CSV_DUPLICATE_SEPARATOR " "
1096 #define CSV_TABLE_SIZE(t) (sizeof (t) / sizeof *(t))
1098 static int csv_conv_table[] = {
1099 NAME,
1100 EMAIL,
1101 PHONE,
1102 NOTES,
1103 NICK
1106 static int allcsv_conv_table[] = {
1107 NAME,
1108 EMAIL,
1109 ADDRESS,
1110 ADDRESS2,
1111 CITY,
1112 STATE,
1113 ZIP,
1114 COUNTRY,
1115 PHONE,
1116 WORKPHONE,
1117 FAX,
1118 MOBILEPHONE,
1119 NICK,
1120 URL,
1121 NOTES,
1122 ANNIVERSARY
1125 static int palmcsv_conv_table[] = {
1126 NAME, /* Last name */
1127 NAME, /* First name */
1128 NOTES, /* Title */
1129 NICK, /* Company */
1130 WORKPHONE,
1131 PHONE,
1132 FAX,
1133 MOBILEPHONE,
1134 EMAIL,
1135 ADDRESS,
1136 CITY,
1137 STATE,
1138 ZIP,
1139 COUNTRY,
1140 ANNIVERSARY,
1143 static void
1144 csv_convert_emails(char *s)
1146 int i;
1147 char *tmp;
1149 if(s == NULL)
1150 return;
1152 for(i = 1; ( tmp = strchr(s, ',') ) != NULL ; i++, s = tmp + 1)
1153 if(i > MAX_LIST_ITEMS - 1) {
1154 *tmp = 0;
1155 break;
1160 static char *
1161 csv_remove_quotes(char *s)
1163 char *copy, *trimmed;
1164 int len;
1166 copy = trimmed = xstrdup(s);
1167 strtrim(trimmed);
1169 len = strlen(trimmed);
1170 if(trimmed[len - 1] == '\"' && *trimmed == '\"') {
1171 if(len < 3) {
1172 xfree(copy);
1173 return NULL;
1175 trimmed[len - 1] = 0;
1176 trimmed++;
1177 trimmed = xstrdup(trimmed);
1178 free(copy);
1179 return trimmed;
1182 xfree(copy);
1183 return xstrdup(s);
1186 static int
1187 csv_field_to_item(int *table_base, size_t table_size, int field)
1189 if(field < table_size)
1190 return field_id(table_base[field]);
1192 return -1;
1195 static void
1196 csv_store_item(list_item item, int i, char *s)
1198 char *newstr = NULL;
1200 if(!s || !*s)
1201 return;
1203 if( !(newstr = csv_remove_quotes(s)) )
1204 return;
1206 if(i >= 0) {
1207 if (item[i] != NULL) {
1208 char *oldstr = item[i];
1210 item[i] = strconcat(newstr, CSV_DUPLICATE_SEPARATOR,
1211 oldstr, NULL);
1212 xfree(newstr);
1213 xfree(oldstr);
1214 } else {
1215 item[i] = newstr;
1217 } else {
1218 xfree(newstr);
1222 static int
1223 csv_is_valid_quote_end(char *p)
1225 if(*p != '\"')
1226 return FALSE;
1228 for(p++; *p; p++) {
1229 if(*p == ',')
1230 return TRUE;
1231 else if(!ISSPACE(*p))
1232 return FALSE;
1235 return TRUE;
1238 static int
1239 csv_is_valid_quote_start(char *p)
1241 for(; *p; p++) {
1242 if(*p == '\"')
1243 return TRUE;
1244 else if(!ISSPACE(*p))
1245 return FALSE;
1248 return FALSE;
1251 static void
1252 csv_parse_line(char *line, int *table_base, size_t table_size)
1254 char *p, *start;
1255 int field;
1256 bool in_quote = FALSE;
1257 list_item item;
1259 item = item_create();
1261 for(p = start = line, field = 0; *p; p++) {
1262 if(in_quote) {
1263 if(csv_is_valid_quote_end(p))
1264 in_quote = FALSE;
1265 } else {
1266 if ( (((p - start) / sizeof (char)) < 2 ) &&
1267 csv_is_valid_quote_start(p) )
1268 in_quote = TRUE;
1271 if(*p == ',' && !in_quote) {
1272 *p = 0;
1273 csv_store_item(item,
1274 csv_field_to_item(table_base,table_size,field),
1275 start);
1276 field++;
1277 start = p + 1;
1281 * store last field
1283 csv_store_item(item, csv_field_to_item(table_base, table_size, field),
1284 start);
1286 csv_convert_emails(item_fget(item, EMAIL));
1287 add_item2database(item);
1288 item_free(&item);
1291 static int
1292 csv_parse_file_common(FILE *in, int *conv_table, size_t table_size)
1294 char *line = NULL;
1296 while(!feof(in)) {
1297 line = getaline(in);
1299 if(line && *line && *line != CSV_COMMENT_CHAR)
1300 csv_parse_line(line, conv_table, table_size);
1302 xfree(line);
1305 return 0;
1308 static int
1309 csv_parse_file(FILE *in)
1311 return csv_parse_file_common(in, csv_conv_table,
1312 CSV_TABLE_SIZE(csv_conv_table));
1315 static int
1316 allcsv_parse_file(FILE *in)
1318 return csv_parse_file_common(in, allcsv_conv_table,
1319 CSV_TABLE_SIZE(allcsv_conv_table));
1322 static int
1323 palmcsv_parse_file(FILE *in)
1325 return csv_parse_file_common(in, palmcsv_conv_table,
1326 CSV_TABLE_SIZE(palmcsv_conv_table));
1330 * end of csv import filter
1334 * csv addressbook export filters
1337 #define CSV_LAST (-1)
1338 #define CSV_UNDEFINED (-2)
1339 #define CSV_SPECIAL(X) (-3 - (X))
1340 #define CSV_IS_SPECIAL(X) ((X) <= -3)
1342 static int
1343 csv_export_common(FILE *out, struct db_enumerator e,
1344 int fields[], void (*special_func)(FILE *, int, int))
1346 int i;
1348 db_enumerate_items(e) {
1349 for(i = 0; fields[i] != CSV_LAST; i++) {
1350 if(fields[i] == CSV_UNDEFINED)
1351 fprintf(out, "\"\"");
1352 else if(CSV_IS_SPECIAL(fields[i])) {
1353 if(special_func)
1354 (*special_func)(out, e.item, fields[i]);
1355 } else
1356 /*fprintf(out,(
1357 strchr(safe_str(database[e.item][field_idx(fields[i])]), ',') ||
1358 strchr(safe_str(database[e.item][field_idx(fields[i])]), '\"')) ?
1359 "\"%s\"" : "%s",
1360 safe_str(database[e.item][field_idx(fields[i])])
1361 );*/
1362 fprintf(out, "\"%s\"",
1363 safe_str(db_fget(e.item,fields[i])));
1365 if(fields[i + 1] != CSV_LAST)
1366 fputc(',', out);
1368 fputc('\n', out);
1371 return 0;
1374 static int
1375 csv_export_database(FILE *out, struct db_enumerator e)
1377 int csv_export_fields[] = {
1378 NAME,
1379 EMAIL,
1380 PHONE,
1381 NOTES,
1382 NICK,
1383 CSV_LAST
1386 csv_export_common(out, e, csv_export_fields, NULL);
1388 return 0;
1391 static int
1392 allcsv_export_database(FILE *out, struct db_enumerator e)
1395 * TODO: Should get these atomatically from abook_fileds
1396 * - JH
1398 int allcsv_export_fields[] = {
1399 NAME,
1400 EMAIL,
1401 ADDRESS,
1402 ADDRESS2,
1403 CITY,
1404 STATE,
1405 ZIP,
1406 COUNTRY,
1407 PHONE,
1408 WORKPHONE,
1409 FAX,
1410 MOBILEPHONE,
1411 NICK,
1412 URL,
1413 NOTES,
1414 ANNIVERSARY,
1415 CSV_LAST
1418 fprintf(out, "#");
1419 fprintf(out, "\"NAME\",");
1420 fprintf(out, "\"EMAIL\",");
1421 fprintf(out, "\"ADDRESS\",");
1422 fprintf(out, "\"ADDRESS2\",");
1423 fprintf(out, "\"CITY\",");
1424 fprintf(out, "\"STATE\",");
1425 fprintf(out, "\"ZIP\",");
1426 fprintf(out, "\"COUNTRY\",");
1427 fprintf(out, "\"PHONE\",");
1428 fprintf(out, "\"WORKPHONE\",");
1429 fprintf(out, "\"FAX\",");
1430 fprintf(out, "\"MOBILEPHONE\",");
1431 fprintf(out, "\"NICK\",");
1432 fprintf(out, "\"URL\",");
1433 fprintf(out, "\"NOTES\",");
1434 fprintf(out, "\"ANNIVERSARY\"\n");
1436 csv_export_common(out, e, allcsv_export_fields, NULL);
1438 return 0;
1442 * palm csv
1445 #define PALM_CSV_NAME CSV_SPECIAL(0)
1446 #define PALM_CSV_END CSV_SPECIAL(1)
1447 #define PALM_CSV_CAT CSV_SPECIAL(2)
1449 static void
1450 palm_split_and_write_name(FILE *out, char *name)
1452 char *p;
1454 assert(name);
1456 if ( (p = strchr(name, ' ')) ) {
1458 * last name first
1460 fprintf(out, "\"%s\",\"" , p + 1);
1461 fwrite((void *)name, p - name, sizeof(char), out);
1462 fputc('\"', out);
1463 } else {
1464 fprintf(out, "\"%s\"", safe_str(name));
1468 static void
1469 palm_csv_handle_specials(FILE *out, int item, int field)
1471 switch(field) {
1472 case PALM_CSV_NAME:
1473 palm_split_and_write_name(out, db_name_get(item));
1474 break;
1475 case PALM_CSV_CAT:
1476 fprintf(out, "\"abook\"");
1477 break;
1478 case PALM_CSV_END:
1479 fprintf(out, "\"0\"");
1480 break;
1481 default:
1482 assert(0);
1486 static int
1487 palm_export_database(FILE *out, struct db_enumerator e)
1489 int palm_export_fields[] = {
1490 PALM_CSV_NAME, /* LASTNAME, FIRSTNAME */
1491 CSV_UNDEFINED, /* TITLE */
1492 CSV_UNDEFINED, /* COMPANY */
1493 WORKPHONE, /* WORK PHONE */
1494 PHONE, /* HOME PHONE */
1495 FAX, /* FAX */
1496 MOBILEPHONE, /* OTHER */
1497 EMAIL, /* EMAIL */
1498 ADDRESS, /* ADDRESS */
1499 CITY, /* CITY */
1500 STATE, /* STATE */
1501 ZIP, /* ZIP */
1502 COUNTRY, /* COUNTRY */
1503 NICK, /* DEFINED 1 */
1504 URL, /* DEFINED 2 */
1505 CSV_UNDEFINED, /* DEFINED 3 */
1506 CSV_UNDEFINED, /* DEFINED 4 */
1507 NOTES, /* NOTE */
1508 PALM_CSV_END, /* "0" */
1509 PALM_CSV_CAT, /* CATEGORY */
1510 CSV_LAST
1513 csv_export_common(out, e, palm_export_fields, palm_csv_handle_specials);
1515 return 0;
1519 * end of csv export filters
1523 * GnomeCard (VCard) addressbook export filter
1526 static int
1527 gcrd_export_database(FILE *out, struct db_enumerator e)
1529 int j;
1530 char *name, *tmp;
1531 abook_list *emails, *em;
1533 db_enumerate_items(e) {
1534 fprintf(out, "BEGIN:VCARD\r\nFN:%s\r\n",
1535 safe_str(db_name_get(e.item)));
1537 name = get_surname(db_name_get(e.item));
1538 for( j = strlen(db_name_get(e.item)) - 1; j >= 0; j-- ) {
1539 if((db_name_get(e.item))[j] == ' ')
1540 break;
1542 fprintf(out, "N:%s;%.*s\r\n",
1543 safe_str(name),
1545 safe_str(db_name_get(e.item))
1548 free(name);
1550 if(db_fget(e.item, ADDRESS))
1551 fprintf(out, "ADR:;;%s;%s;%s;%s;%s;%s\r\n",
1552 safe_str(db_fget(e.item, ADDRESS)),
1553 safe_str(db_fget(e.item, ADDRESS2)),
1554 safe_str(db_fget(e.item, CITY)),
1555 safe_str(db_fget(e.item, STATE)),
1556 safe_str(db_fget(e.item, ZIP)),
1557 safe_str(db_fget(e.item, COUNTRY))
1560 if(db_fget(e.item, PHONE))
1561 fprintf(out, "TEL;HOME:%s\r\n",
1562 db_fget(e.item, PHONE));
1563 if(db_fget(e.item, WORKPHONE))
1564 fprintf(out, "TEL;WORK:%s\r\n",
1565 db_fget(e.item, WORKPHONE));
1566 if(db_fget(e.item, FAX))
1567 fprintf(out, "TEL;FAX:%s\r\n",
1568 db_fget(e.item, FAX));
1569 if(db_fget(e.item, MOBILEPHONE))
1570 fprintf(out, "TEL;CELL:%s\r\n",
1571 db_fget(e.item, MOBILEPHONE));
1573 tmp = db_email_get(e.item);
1574 if(*tmp) {
1575 emails = csv_to_abook_list(tmp);
1577 for(em = emails; em; em = em->next)
1578 fprintf(out, "EMAIL;INTERNET:%s\r\n", em->data);
1580 abook_list_free(&emails);
1582 free(tmp);
1584 if(db_fget(e.item, NOTES))
1585 fprintf(out, "NOTE:%s\r\n",
1586 db_fget(e.item, NOTES));
1587 if(db_fget(e.item, URL))
1588 fprintf(out, "URL:%s\r\n",
1589 db_fget(e.item, URL));
1591 fprintf(out, "END:VCARD\r\n\r\n");
1595 return 0;
1599 * end of GnomeCard export filter
1604 * mutt alias export filter
1607 static char *
1608 mutt_alias_genalias(int i)
1610 char *tmp, *pos;
1612 if(db_fget(i, NICK))
1613 return xstrdup(db_fget(i, NICK));
1615 tmp = xstrdup(db_name_get(i));
1617 if( ( pos = strchr(tmp, ' ') ) )
1618 *pos = 0;
1620 strlower(tmp);
1622 return tmp;
1625 static int
1626 mutt_alias_export(FILE *out, struct db_enumerator e)
1628 char email[MAX_EMAIL_LEN];
1629 char *alias = NULL;
1631 db_enumerate_items(e) {
1632 alias = mutt_alias_genalias(e.item);
1633 get_first_email(email, e.item);
1634 fprintf(out, *email ? "alias %s %s <%s>\n": "alias %s %s%s\n",
1635 alias,
1636 db_name_get(e.item),
1637 email);
1638 xfree(alias);
1641 return 0;
1645 * end of mutt alias export filter
1650 * printable export filter
1654 static void
1655 text_write_address_us(FILE *out, int i) {
1656 fprintf(out, "\n%s", db_fget(i, ADDRESS));
1658 if(db_fget(i, ADDRESS2))
1659 fprintf(out, "\n%s", db_fget(i, ADDRESS2));
1661 if(db_fget(i, CITY))
1662 fprintf(out, "\n%s", db_fget(i, CITY));
1664 if(db_fget(i, STATE) || db_fget(i, ZIP)) {
1665 fputc('\n', out);
1667 if(db_fget(i, STATE)) {
1668 fprintf(out, "%s", db_fget(i, STATE));
1669 if(db_fget(i, ZIP))
1670 fputc(' ', out);
1673 if(db_fget(i, ZIP))
1674 fprintf(out, "%s", db_fget(i, ZIP));
1677 if(db_fget(i, COUNTRY))
1678 fprintf(out, "\n%s", db_fget(i, COUNTRY));
1682 static void
1683 text_write_address_uk(FILE *out, int i) {
1684 int j;
1686 for(j = ADDRESS; j <= COUNTRY; j++)
1687 if(db_fget(i, j))
1688 fprintf(out, "\n%s", db_fget(i, j));
1691 static void
1692 text_write_address_eu(FILE *out, int i) {
1693 fprintf(out, "\n%s", db_fget(i, ADDRESS));
1695 if(db_fget(i, ADDRESS2))
1696 fprintf(out, "\n%s", db_fget(i, ADDRESS2));
1698 if(db_fget(i, ZIP) || db_fget(i, CITY)) {
1699 fputc('\n', out);
1701 if(db_fget(i, ZIP)) {
1702 fprintf(out, "%s", db_fget(i, ZIP));
1703 if(db_fget(i, CITY))
1704 fputc(' ', out);
1707 fprintf(out, "%s", safe_str(db_fget(i, CITY)));
1710 if(db_fget(i, STATE))
1711 fprintf(out, "\n%s", db_fget(i, STATE));
1713 if(db_fget(i, COUNTRY))
1714 fprintf(out, "\n%s", db_fget(i, COUNTRY));
1717 static int
1718 text_export_database(FILE * out, struct db_enumerator e)
1720 abook_list *emails, *em;
1721 int j;
1722 char *realname = get_real_name(), *str = NULL, *tmp;
1723 char *style = opt_get_str(STR_ADDRESS_STYLE);
1725 fprintf(out,
1726 "-----------------------------------------\n%s's address book\n"
1727 "-----------------------------------------\n\n\n",
1728 realname);
1729 free(realname);
1731 db_enumerate_items(e) {
1732 fprintf(out,
1733 "-----------------------------------------\n\n");
1734 fprintf(out, "%s", db_name_get(e.item));
1735 if(db_fget(e.item, NICK) && *db_fget(e.item, NICK))
1736 fprintf(out, "\n(%s)", db_fget(e.item, NICK));
1737 fprintf(out, "\n");
1739 tmp = db_email_get(e.item);
1740 if(*tmp) {
1741 emails = csv_to_abook_list(tmp);
1743 fprintf(out, "\n");
1744 for(em = emails; em; em = em->next)
1745 fprintf(out, "%s\n", em->data);
1747 abook_list_free(&emails);
1749 free(tmp);
1750 /* Print address */
1751 if(db_fget(e.item, ADDRESS)) {
1752 if(!safe_strcmp(style, "us")) /* US like */
1753 text_write_address_us(out, e.item);
1754 else if(!safe_strcmp(style, "uk")) /* UK like */
1755 text_write_address_uk(out, e.item);
1756 else /* EU like */
1757 text_write_address_eu(out, e.item);
1759 fprintf(out, "\n");
1762 if((db_fget(e.item, PHONE)) ||
1763 (db_fget(e.item, WORKPHONE)) ||
1764 (db_fget(e.item, FAX)) ||
1765 (db_fget(e.item, MOBILEPHONE))) {
1766 fprintf(out, "\n");
1767 for(j = PHONE; j <= MOBILEPHONE; j++)
1768 if(db_fget(e.item, j)) {
1769 get_field_info(field_id(j),
1770 NULL, &str, NULL);
1771 fprintf(out, "%s: %s\n", str,
1772 db_fget(e.item, j));
1776 if(db_fget(e.item, URL))
1777 fprintf(out, "\n%s\n", db_fget(e.item, URL));
1778 if(db_fget(e.item, NOTES))
1779 fprintf(out, "\n%s\n", db_fget(e.item, NOTES));
1781 fprintf(out, "\n");
1784 fprintf(out, "-----------------------------------------\n");
1786 return 0;
1790 * end of printable export filter
1794 * elm alias export filter
1797 static int
1798 elm_alias_export(FILE *out, struct db_enumerator e)
1800 char email[MAX_EMAIL_LEN];
1801 char *alias = NULL;
1803 db_enumerate_items(e) {
1804 alias = mutt_alias_genalias(e.item);
1805 get_first_email(email, e.item);
1806 fprintf(out, "%s = %s = %s\n",alias,db_name_get(e.item),email);
1807 xfree(alias);
1810 return 0;
1814 * end of elm alias export filter
1819 * Spruce export filter
1822 static int
1823 spruce_export_database (FILE *out, struct db_enumerator e)
1825 char email[MAX_EMAIL_LEN];
1827 fprintf(out, "# This is a generated file made by abook for the Spruce e-mail client.\n\n");
1829 db_enumerate_items(e) {
1830 get_first_email(email, e.item);
1831 if(strcmp(email, "")) {
1832 fprintf(out, "# Address %d\nName: %s\nEmail: %s\nMemo: %s\n\n",
1833 e.item,
1834 db_name_get(e.item),
1835 email,
1836 safe_str(db_fget(e.item, NOTES))
1841 fprintf (out, "# End of address book file.\n");
1843 return 0;
1847 * end of Spruce export filter
1851 * wanderlust addressbook export filter
1854 static int
1855 wl_export_database(FILE *out, struct db_enumerator e)
1857 char email[MAX_EMAIL_LEN];
1859 fprintf(out, "# Wanderlust address book written by %s\n\n", PACKAGE);
1860 db_enumerate_items(e) {
1861 get_first_email(email, e.item);
1862 if(*email) {
1863 fprintf(out,
1864 "%s\t\"%s\"\t\"%s\"\n",
1865 email,
1866 safe_str(db_fget(e.item, NICK)),
1867 safe_str(db_name_get(e.item))
1872 fprintf (out, "\n# End of address book file.\n");
1874 return 0;
1878 * end of wanderlust addressbook export filter
1882 * BSD calendar export filter
1885 static int
1886 bsdcal_export_database(FILE *out, struct db_enumerator e)
1888 db_enumerate_items(e) {
1889 int year, month = 0, day = 0;
1890 char *anniversary = db_fget(e.item, ANNIVERSARY);
1892 if(anniversary) {
1893 parse_date_string(anniversary, &day, &month, &year);
1895 fprintf(out,
1896 _("%02d/%02d\tAnniversary of %s\n"),
1897 month,
1898 day,
1899 safe_str(db_name_get(e.item))
1904 return 0;
1908 * end of BSD calendar export filter