5 * by JH <jheinonen@users.sourceforge.net>
7 * Copyright (C) Jaakko Heinonen
18 #include <sys/types.h>
19 #include "abook_curses.h"
36 extern abook_field_list *fields_list;
37 extern int fields_count;
40 * function declarations
44 * import filter prototypes
47 static int ldif_parse_file(FILE *handle);
48 static int mutt_parse_file(FILE *in);
49 static int pine_parse_file(FILE *in);
50 static int csv_parse_file(FILE *in);
51 static int allcsv_parse_file(FILE *in);
52 static int palmcsv_parse_file(FILE *in);
53 static int vcard_parse_file(FILE *in);
56 * export filter prototypes
59 static int ldif_export_database(FILE *out, struct db_enumerator e);
60 static int html_export_database(FILE *out, struct db_enumerator e);
61 static int pine_export_database(FILE *out, struct db_enumerator e);
62 static int csv_export_database(FILE *out, struct db_enumerator e);
63 static int allcsv_export_database(FILE *out, struct db_enumerator e);
64 static int palm_export_database(FILE *out, struct db_enumerator e);
65 static int vcard_export_database(FILE *out, struct db_enumerator e);
66 static int mutt_alias_export(FILE *out, struct db_enumerator e);
67 static int mutt_query_export_database(FILE *out, struct db_enumerator e);
68 static int elm_alias_export(FILE *out, struct db_enumerator e);
69 static int text_export_database(FILE *out, struct db_enumerator e);
70 static int spruce_export_database(FILE *out, struct db_enumerator e);
71 static int wl_export_database(FILE *out, struct db_enumerator e);
72 static int bsdcal_export_database(FILE *out, struct db_enumerator e);
73 static int custom_export_database(FILE *out, struct db_enumerator e);
76 * export filter item prototypes
79 void vcard_export_item(FILE *out, int item);
80 void muttq_print_item(FILE *file, int item);
81 void custom_print_item(FILE *out, int item);
84 * end of function declarations
87 struct abook_input_filter i_filters[] = {
88 { "abook", N_("abook native format"), parse_database },
89 { "ldif", N_("ldif / Netscape addressbook"), ldif_parse_file },
90 { "mutt", N_("mutt alias"), mutt_parse_file },
91 { "pine", N_("pine addressbook"), pine_parse_file },
92 { "csv", N_("comma separated values"), csv_parse_file },
93 { "allcsv", N_("comma separated values (all fields)"), allcsv_parse_file },
94 { "palmcsv", N_("Palm comma separated values"), palmcsv_parse_file },
95 { "vcard", N_("vCard file"), vcard_parse_file },
99 struct abook_output_filter e_filters[] = {
100 { "abook", N_("abook native format"), write_database },
101 { "ldif", N_("ldif / Netscape addressbook (.4ld)"), ldif_export_database },
102 { "vcard", N_("vCard 2 file"), vcard_export_database },
103 { "mutt", N_("mutt alias"), mutt_alias_export },
104 { "muttq", N_("mutt query format (internal use)"), mutt_query_export_database },
105 { "html", N_("html document"), html_export_database },
106 { "pine", N_("pine addressbook"), pine_export_database },
107 { "csv", N_("comma separated values"), csv_export_database },
108 { "allcsv", N_("comma separated values (all fields)"), allcsv_export_database },
109 { "palmcsv", N_("Palm comma separated values"), palm_export_database},
110 { "elm", N_("elm alias"), elm_alias_export },
111 { "text", N_("plain text"), text_export_database },
112 { "wl", N_("Wanderlust address book"), wl_export_database },
113 { "spruce", N_("Spruce address book"), spruce_export_database },
114 { "bsdcal", N_("BSD calendar"), bsdcal_export_database },
115 { "custom", N_("Custom format"), custom_export_database },
119 struct abook_output_item_filter u_filters[] = {
120 { "vcard", N_("vCard 2 file"), vcard_export_item },
121 { "muttq", N_("mutt alias"), muttq_print_item },
122 { "custom", N_("Custom format"), custom_print_item },
135 puts(_("input formats:"));
136 for(i=0; *i_filters[i].filtname ; i++)
137 printf("\t%s\t%s\n", i_filters[i].filtname,
138 gettext(i_filters[i].desc));
142 puts(_("output formats:"));
143 for(i=0; *e_filters[i].filtname ; i++)
144 printf("\t%s\t%s\n", e_filters[i].filtname,
145 gettext(e_filters[i].desc));
149 puts(_("query-compatible output formats:"));
150 for(i=0; *u_filters[i].filtname ; i++)
151 printf("\t%s\t%s\n", u_filters[i].filtname,
152 gettext(u_filters[i].desc));
158 number_of_output_filters()
162 for(i=0; *e_filters[i].filtname ; i++)
169 number_of_input_filters()
173 for(i=0; *i_filters[i].filtname ; i++)
182 char *username = getenv("USER");
183 struct passwd *pwent;
187 pwent = getpwnam(username);
189 if((tmp = xstrdup(pwent->pw_gecos)) == NULL)
190 return xstrdup(username);
192 rtn = sscanf(pwent->pw_gecos, "%[^,]", tmp);
193 if (rtn == EOF || rtn == 0) {
195 return xstrdup(username);
204 static int i_read_file(char *filename, int (*func) (FILE *in));
213 refresh_statusline();
214 headerline(_("import database"));
216 mvaddstr(3, 1, _("please select a filter"));
219 for(i=0; *i_filters[i].filtname ; i++)
220 mvprintw(5 + i, 6, "%c -\t%s\t%s\n", 'a' + i,
221 i_filters[i].filtname,
222 gettext(i_filters[i].desc));
224 mvprintw(6 + i, 6, _("x -\tcancel"));
232 int tmp = db_n_items();
236 filter = getch() - 'a';
237 if(filter == 'x' - 'a' ||
238 filter >= number_of_input_filters() || filter < 0) {
243 mvaddstr(5+filter, 2, "->");
245 filename = ask_filename(_("Filename: "));
251 if(i_read_file(filename, i_filters[filter].func ))
252 statusline_msg(_("Error occured while opening the file"));
253 else if(tmp == db_n_items())
254 statusline_msg(_("File does not seem to be a valid addressbook"));
265 i_read_file(char *filename, int (*func) (FILE *in))
270 if( (in = abook_fopen( filename, "r" )) == NULL )
281 import_file(char filtname[FILTNAME_LEN], char *filename)
284 int tmp = db_n_items();
288 if(! strncasecmp(i_filters[i].filtname, filtname,
291 if(! *i_filters[i].filtname) {
301 // this is a special case for
302 // libvformat whose API expects a filename
303 if(!strcmp(filtname, "vcard")) {
304 if(!strcmp(filename, "-"))
305 ret = vcard_parse_file_libvformat("/dev/stdin");
307 ret = vcard_parse_file_libvformat(filename);
312 if(!strcmp(filename, "-")) {
314 if((fstat(fileno(stdin), &s)) == -1 || S_ISDIR(s.st_mode))
317 ret = (*i_filters[i].func) (stdin);
319 ret = i_read_file(filename, i_filters[i].func);
321 if(tmp == db_n_items())
331 static int e_write_file(char *filename,
332 int (*func) (FILE *in, struct db_enumerator e), int mode);
342 refresh_statusline();
343 headerline(_("export database"));
345 mvaddstr(3, 1, _("please select a filter"));
348 for(i = 0; *e_filters[i].filtname ; i++)
349 mvprintw(5 + i, 6, "%c -\t%s\t%s\n", 'a' + i,
350 e_filters[i].filtname,
351 gettext(e_filters[i].desc));
353 mvprintw(6 + i, 6, _("x -\tcancel"));
360 int enum_mode = ENUM_ALL;
365 filter = getch() - 'a';
366 if(filter == 'x' - 'a' ||
367 filter >= number_of_output_filters() || filter < 0) {
372 mvaddstr(5 + filter, 2, "->");
374 if(selected_items()) {
375 switch(statusline_askchoice(
376 _("Export <a>ll, export <s>elected, or <c>ancel?"),
377 S_("keybindings:all/selected/cancel|asc"), 3)) {
381 enum_mode = ENUM_SELECTED;
391 filename = ask_filename(_("Filename: "));
397 if( e_write_file(filename, e_filters[filter].func, enum_mode))
398 statusline_msg(_("Error occured while exporting"));
406 struct abook_output_item_filter select_output_item_filter(char filtname[FILTNAME_LEN]) {
409 if(!strncasecmp(u_filters[i].filtname, filtname, FILTNAME_LEN))
411 if(!*u_filters[i].filtname) {
420 e_write_item(FILE *out, int item, void (*func) (FILE *in, int item))
426 e_write_file(char *filename, int (*func) (FILE *in, struct db_enumerator e),
431 struct db_enumerator enumerator = init_db_enumerator(mode);
433 if((out = fopen(filename, "a")) == NULL)
439 ret = (*func) (out, enumerator);
447 fexport(char filtname[FILTNAME_LEN], FILE *handle, int enum_mode)
450 struct db_enumerator e = init_db_enumerator(enum_mode);
453 if(!strncasecmp(e_filters[i].filtname, filtname,
456 if(!*e_filters[i].filtname) {
462 return (e_filters[i].func) (handle, e);
468 export_file(char filtname[FILTNAME_LEN], char *filename)
470 const int mode = ENUM_ALL;
473 struct db_enumerator e = init_db_enumerator(mode);
476 if(!strncasecmp(e_filters[i].filtname, filtname,
479 if(!*e_filters[i].filtname) {
488 if(!strcmp(filename, "-"))
489 ret = (e_filters[i].func) (stdout, e);
491 ret = e_write_file(filename, e_filters[i].func, mode);
497 * end of common functions
506 static void ldif_fix_string(char *str);
508 #define LDIF_ITEM_FIELDS 16
510 typedef char *ldif_item[LDIF_ITEM_FIELDS];
512 static ldif_item ldif_field_names = {
524 "facsimiletelephonenumber",
528 "objectclass", /* this must be the last entry */
531 static int ldif_conv_table[LDIF_ITEM_FIELDS] = {
534 ADDRESS, /* "streetaddress" */
535 ADDRESS2, /* "streetaddress2" */
536 CITY, /* "locality" */
538 ZIP, /* "postalcode" */
539 COUNTRY, /* "countryname" */
540 PHONE, /* "homephone" */
541 NOTES, /* "description" */
543 FAX, /* "facsimiletelephonenumber" */
544 MOBILEPHONE, /* "cellphone" */
545 WORKPHONE, /* "xmozillaanyphone" */
546 NICK, /* "xmozillanickname" */
547 -1, /* "objectclass" */ /* this must be the last entry */
552 ldif_read_line(FILE *in)
565 if(feof(in) || !line)
574 fseek(in, pos, SEEK_SET); /* fixme ! */
584 buf = strconcat(buf, ptr, NULL);
589 if(buf && *buf == '#' ) {
598 ldif_add_item(ldif_item li)
603 item = item_create();
605 if(!li[LDIF_ITEM_FIELDS -1])
609 for(i=0; i < LDIF_ITEM_FIELDS; i++) {
610 if(ldif_conv_table[i] >= 0 && li[i] && *li[i])
611 item_fput(item,ldif_conv_table[i],xstrdup(li[i]));
614 add_item2database(item);
617 for(i=0; i < LDIF_ITEM_FIELDS; i++)
624 ldif_convert(ldif_item item, char *type, char *value)
628 if(!strcmp(type, "dn")) {
633 for(i=0; i < LDIF_ITEM_FIELDS; i++) {
634 if(!strcasecmp(ldif_field_names[i], type) && *value) {
635 if(i == LDIF_ITEM_FIELDS - 1) /* this is a dirty hack */
636 if(safe_strcmp("person", value))
639 if(item_fget(item, i))
640 free(item_fget(item, i));
642 item_fput(item, i, xstrdup(value));
649 ldif_parse_file(FILE *handle)
656 memset(item, 0, sizeof(item));
659 if( !(line = ldif_read_line(handle)) )
662 if(-1 == (str_parse_line(line, &type, &value, &vlen))) {
664 continue; /* just skip the errors */
667 ldif_fix_string(value);
669 ldif_convert(item, type, value);
672 } while ( !feof(handle) );
674 ldif_convert(item, "dn", "");
680 ldif_fix_string(char *str)
684 for(i = 0, j = 0; j < (int)strlen(str); i++, j++)
685 str[i] = ( str[j] == (char)0xc3 ?
686 (char) str[++j] + (char) 0x40 :
697 * mutt alias import filter
703 mutt_read_line(FILE *in, char **groups, char **alias, char **rest)
707 abook_list *glist = NULL;
709 if( !(line = ptr = getaline(in)) )
710 return 1; /* error / EOF */
714 if(strncmp("alias", ptr, 5)) {
722 /* If the group option is used, save the groups */
726 for(n_groups = 0; 0 == strncmp("-group", ptr, 6); n_groups++) {
732 abook_list_append(&glist,xstrndup(start, end - start));
736 if(n_groups && groups)
737 *groups = abook_list_to_csv(glist);
739 abook_list_free(&glist);
747 *alias = xstrndup(start, end - start);
750 *rest = xstrdup(ptr);
757 mutt_fix_quoting(char *p)
777 mutt_parse_email(list_item item)
779 char *line = item_fget(item, NAME);
787 mutt_fix_quoting(line);
788 tmp = strconcat("From: ", line, NULL);
789 getname(tmp, &name, &email);
793 item_fput(item, NAME, name);
798 item_fput(item, EMAIL, email);
803 * this is completely broken
806 while( (start = strchr(start, ',')) && i++ < MAX_EMAILS - 1) {
807 tmp = strconcat("From: ", ++start, NULL);
808 getname(tmp, &name, &email);
813 tmp = strconcat(item[EMAIL], ",", email, NULL);
825 mutt_parse_file(FILE *in)
827 list_item item = item_create();
830 memset(item, 0, fields_count * sizeof(char *));
832 if(!mutt_read_line(in,
833 (field_id(GROUPS) != -1) ? &item[field_id(GROUPS)] : NULL,
834 (field_id(NICK) != -1) ? &item[field_id(NICK)] : NULL,
835 &item[field_id(NAME)]) )
836 mutt_parse_email(item);
843 add_item2database(item);
851 * end of mutt alias import filter
860 ldif_fput_type_and_value(FILE *out,char *type, char *value )
864 tmp = ldif_type_and_value(type, value, strlen(value));
872 ldif_export_database(FILE *out, struct db_enumerator e)
874 char email[MAX_EMAILSTR_LEN];
876 fprintf(out, "version: 1\n");
878 db_enumerate_items(e) {
881 get_first_email(email, e.item);
883 tmp = strdup_printf("cn=%s,mail=%s",db_name_get(e.item),email);
885 ldif_fput_type_and_value(out, "dn", tmp);
888 for(j = 0; j < LDIF_ITEM_FIELDS; j++) {
889 if(ldif_conv_table[j] >= 0) {
890 if(ldif_conv_table[j] == EMAIL)
891 ldif_fput_type_and_value(out,
892 ldif_field_names[j], email);
893 else if(db_fget(e.item,ldif_conv_table[j]))
894 ldif_fput_type_and_value(out,
897 ldif_conv_table[j]));
901 fprintf(out, "objectclass: top\n"
902 "objectclass: person\n\n");
909 * end of ldif export filter
916 static void html_export_write_head(FILE *out);
917 static void html_export_write_tail(FILE *out);
919 extern struct index_elem *index_elements;
922 html_print_emails(FILE *out, struct list_field *f)
924 abook_list *l = csv_to_abook_list(f->data);
926 for(; l; l = l->next) {
927 fprintf(out, "<a href=\"mailto:%s\">%s</a>", l->data, l->data);
936 html_export_database(FILE *out, struct db_enumerator e)
939 struct index_elem *cur;
946 html_export_write_head(out);
948 db_enumerate_items(e) {
949 fprintf(out, "<tr>");
950 for(cur = index_elements; cur; cur = cur->next) {
951 if(cur->type != INDEX_FIELD)
954 get_list_field(e.item, cur, &f);
956 if(f.type == FIELD_EMAILS) {
957 fprintf(out, "<td>");
958 html_print_emails(out, &f);
959 fprintf(out, "</td>");
962 fprintf(out, "<td>%s</td>", safe_str(f.data));
965 fprintf(out, "</tr>\n");
968 html_export_write_tail(out);
974 html_export_write_head(FILE *out)
976 char *realname = get_real_name(), *str;
977 struct index_elem *cur;
979 fprintf(out, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n");
980 fprintf(out, "<html>\n<head>\n <title>%s's addressbook</title>",
982 fprintf(out, "\n</head>\n<body>\n");
983 fprintf(out, "\n<h2>%s's addressbook</h2>\n", realname );
984 fprintf(out, "<br><br>\n\n");
986 fprintf(out, "<table border=\"1\" align=\"center\">\n<tr>");
987 for(cur = index_elements; cur; cur = cur->next) {
988 if(cur->type != INDEX_FIELD)
991 get_field_info(cur->d.field.id, NULL, &str, NULL);
992 fprintf(out, "<th>%s</th>", str);
994 fprintf(out, "</tr>\n\n");
1000 html_export_write_tail(FILE *out)
1002 fprintf(out, "\n</table>\n");
1003 fprintf(out, "\n</body>\n</html>\n");
1007 * end of html export filter
1012 * pine addressbook import filter
1015 #define PINE_BUF_SIZE 2048
1018 pine_fixbuf(char *buf)
1022 for(i = 0,j = 0; j < (int)strlen(buf); i++, j++)
1023 buf[i] = buf[j] == '\n' ? buf[++j] : buf[j];
1027 pine_convert_emails(char *s)
1032 if(s == NULL || *s != '(')
1035 for(i = 0; s[i]; i++)
1038 if( ( tmp = strchr(s,')')) )
1041 for(i = 1; ( tmp = strchr(s, ',') ) != NULL ; i++, s = tmp + 1)
1042 if(i > MAX_LIST_ITEMS - 1) {
1050 pine_parse_buf(char *buf)
1055 char tmp[PINE_BUF_SIZE];
1057 int pine_conv_table[]= {NICK, NAME, EMAIL, -1, NOTES};
1059 item = item_create();
1061 for(i=0, last=0; !last ; i++) {
1062 if( !(end = strchr(start, '\t')) )
1065 len = last ? strlen(start) : (int) (end-start);
1066 len = min(len, PINE_BUF_SIZE - 1);
1068 if(i < (int)(sizeof(pine_conv_table) / sizeof(*pine_conv_table))
1069 && pine_conv_table[i] >= 0) {
1070 strncpy(tmp, start, len);
1073 item_fput(item, pine_conv_table[i],
1079 pine_convert_emails(item_fget(item, EMAIL));
1080 add_item2database(item);
1085 #define LINESIZE 1024
1088 pine_parse_file(FILE *in)
1090 char line[LINESIZE];
1095 fgets(line, LINESIZE, in);
1099 buf = xrealloc(buf, i*LINESIZE);
1102 fgets(line, LINESIZE, in);
1104 if(*ptr != ' ' || feof(in))
1118 pine_parse_buf(buf);
1127 * end of pine addressbook import filter
1132 * pine addressbook export filter
1134 * filter doesn't wrap the lines as it should but Pine seems to handle
1135 * created files without problems - JH
1139 pine_export_database(FILE *out, struct db_enumerator e)
1143 db_enumerate_items(e) {
1144 emails = db_email_get(e.item);
1145 fprintf(out, strchr(emails, ',') /* multiple addresses? */ ?
1146 "%s\t%s\t(%s)\t\t%s\n" : "%s\t%s\t%s\t\t%s\n",
1147 safe_str(db_fget(e.item, NICK)),
1148 safe_str(db_name_get(e.item)),
1150 safe_str(db_fget(e.item, NOTES))
1159 * end of pine addressbook export filter
1168 * these files should be parsed according to a certain
1169 * lay out, or the default if layout is not given, at
1170 * the moment only default is done...
1173 #define CSV_COMMENT_CHAR '#'
1174 #define CSV_DUPLICATE_SEPARATOR " "
1175 #define CSV_TABLE_SIZE(t) (sizeof (t) / sizeof *(t))
1177 static int csv_conv_table[] = {
1185 static int allcsv_conv_table[] = {
1204 static int palmcsv_conv_table[] = {
1205 NAME, /* Last name */
1206 NAME, /* First name */
1223 csv_convert_emails(char *s)
1231 for(i = 1; ( tmp = strchr(s, ',') ) != NULL ; i++, s = tmp + 1)
1232 if(i > MAX_LIST_ITEMS - 1) {
1240 csv_remove_quotes(char *s)
1242 char *copy, *trimmed;
1245 copy = trimmed = xstrdup(s);
1248 len = strlen(trimmed);
1249 if(trimmed[len - 1] == '\"' && *trimmed == '\"') {
1254 trimmed[len - 1] = 0;
1256 trimmed = xstrdup(trimmed);
1266 csv_field_to_item(int *table_base, size_t table_size, int field)
1268 if(field < table_size)
1269 return field_id(table_base[field]);
1275 csv_store_item(list_item item, int i, char *s)
1277 char *newstr = NULL;
1282 if( !(newstr = csv_remove_quotes(s)) )
1286 if (item[i] != NULL) {
1287 char *oldstr = item[i];
1289 item[i] = strconcat(newstr, CSV_DUPLICATE_SEPARATOR,
1302 csv_is_valid_quote_end(char *p)
1310 else if(!ISSPACE(*p))
1318 csv_is_valid_quote_start(char *p)
1323 else if(!ISSPACE(*p))
1331 csv_parse_line(char *line, int *table_base, size_t table_size)
1335 bool in_quote = FALSE;
1338 item = item_create();
1340 for(p = start = line, field = 0; *p; p++) {
1342 if(csv_is_valid_quote_end(p))
1345 if ( (((p - start) / sizeof (char)) < 2 ) &&
1346 csv_is_valid_quote_start(p) )
1350 if(*p == ',' && !in_quote) {
1352 csv_store_item(item,
1353 csv_field_to_item(table_base,table_size,field),
1362 csv_store_item(item, csv_field_to_item(table_base, table_size, field),
1365 csv_convert_emails(item_fget(item, EMAIL));
1366 add_item2database(item);
1371 csv_parse_file_common(FILE *in, int *conv_table, size_t table_size)
1376 line = getaline(in);
1378 if(line && *line && *line != CSV_COMMENT_CHAR)
1379 csv_parse_line(line, conv_table, table_size);
1388 csv_parse_file(FILE *in)
1390 return csv_parse_file_common(in, csv_conv_table,
1391 CSV_TABLE_SIZE(csv_conv_table));
1395 allcsv_parse_file(FILE *in)
1397 return csv_parse_file_common(in, allcsv_conv_table,
1398 CSV_TABLE_SIZE(allcsv_conv_table));
1402 palmcsv_parse_file(FILE *in)
1404 return csv_parse_file_common(in, palmcsv_conv_table,
1405 CSV_TABLE_SIZE(palmcsv_conv_table));
1409 * end of csv import filter
1413 * vCard import filter
1416 static char *vcard_fields[] = {
1417 "FN", /* FORMATTED NAME */
1418 "EMAIL", /* EMAIL */
1419 "ADR", /* ADDRESS */
1420 "ADR", /* ADDRESS2 - not used */
1424 "ADR", /* COUNTRY */
1426 "TEL", /* WORKPHONE */
1428 "TEL", /* MOBILEPHONE */
1429 "NICKNAME", /* NICK */
1432 "N", /* NAME: special case/mapping in vcard_parse_line() */
1433 NULL /* not implemented: ANNIVERSARY, ITEM_FIELDS */
1437 * mappings between vCard ADR field and abook's ADDRESS
1438 * see rfc2426 section 3.2.1
1440 static int vcard_address_fields[] = {
1441 -1, /* vCard(post office box) - not used */
1442 -1, /* vCard(the extended address) - not used */
1443 2, /* vCard(the street address) - ADDRESS */
1444 4, /* vCard(the locality) - CITY */
1445 5, /* vCard(the region) - STATE */
1446 6, /* vCard(the postal code) - ZIP */
1447 7 /* vCard(the country name) - COUNTRY */
1452 VCARD_KEY_ATTRIBUTE,
1457 vcard_get_line_element(char *line, int element)
1460 char *line_copy = 0;
1466 line_copy = xstrdup(line);
1468 /* change newline characters, if present, to end of string */
1469 for(i=0; line_copy[i]; i++) {
1470 if(line_copy[i] == '\r' || line_copy[i] == '\n') {
1471 line_copy[i] = '\0';
1476 /* separate key from value */
1477 for(i=0; line_copy[i]; i++) {
1478 if(line_copy[i] == ':') {
1479 line_copy[i] = '\0';
1481 value = &line_copy[i+1];
1486 /* separate key from key attributes */
1487 /* works for vCard 2 as well (automagically) */
1489 for(i=0; key[i]; i++) {
1492 key_attr = &key[i+1];
1501 result = xstrdup(key);
1503 case VCARD_KEY_ATTRIBUTE:
1505 result = xstrdup(key_attr);
1509 result = xstrdup(value);
1518 vcard_parse_email(list_item item, char *line)
1522 email = vcard_get_line_element(line, VCARD_VALUE);
1525 item[1] = strconcat(item[1], ",", email, 0);
1534 vcard_parse_address(list_item item, char *line)
1539 char *address_field;
1541 value = vcard_get_line_element(line, VCARD_VALUE);
1545 address_field = value;
1546 for(i=k=0; value[i]; i++) {
1547 if(value[i] == ';') {
1549 if(vcard_address_fields[k] >= 0) {
1550 item[vcard_address_fields[k]] = xstrdup(address_field);
1552 address_field = &value[i+1];
1554 if((k+1)==(sizeof(vcard_address_fields)/sizeof(*vcard_address_fields)))
1558 item[vcard_address_fields[k]] = xstrdup(address_field);
1563 vcard_parse_name(list_item item, char *line)
1565 // store the "N" field into "NAME" *if* no "FN:"
1566 // value has already been stored here
1570 item[0] = vcard_get_line_element(line, VCARD_VALUE);
1571 // "N:" can be multivalued => replace ';' separators by ' '
1572 while(item[0][++i]) if(item[0][i] == ';') item[0][i] = ' ';
1574 // http://www.daniweb.com/software-development/c/code/216919
1575 char *original = item[0], *p = original;
1578 if (*original != ' ' || trimmed) {
1579 trimmed = 1; *p++ = *original;
1581 } while(*original++);
1585 vcard_parse_phone(list_item item, char *line)
1587 char *type = vcard_get_line_element(line, VCARD_KEY_ATTRIBUTE);
1588 char *value = vcard_get_line_element(line, VCARD_VALUE);
1590 /* set the standard number */
1591 if (!type) item_fput(item, PHONE, value);
1594 * see rfc2426 section 3.3.1
1595 * Note: we probably support both vCard 2 and 3
1598 if (strcasestr(type, "home") != NULL)
1599 item_fput(item, PHONE, xstrdup(value));
1600 else if (strcasestr(type, "work") != NULL)
1601 item_fput(item, WORKPHONE, xstrdup(value));
1602 else if (strcasestr(type, "fax") != NULL)
1603 item_fput(item, FAX, xstrdup(value));
1604 else if (strcasestr(type, "cell") != NULL)
1605 item_fput(item, MOBILEPHONE, xstrdup(value));
1613 vcard_parse_line(list_item item, char *line)
1618 for(i=0; vcard_fields[i]; i++) {
1619 key = vcard_fields[i];
1621 if(0 == strncmp(key, line, strlen(key))) {
1622 if(0 == strcmp(key, "EMAIL"))
1623 vcard_parse_email(item, line);
1625 vcard_parse_address(item, line);
1626 else if(0 == strcmp(key, "TEL"))
1627 vcard_parse_phone(item, line);
1628 else if(0 == strcmp(key, "N"))
1629 vcard_parse_name(item, line);
1631 item[i] = vcard_get_line_element(line, VCARD_VALUE);
1638 vcard_parse_item(FILE *in)
1641 list_item item = item_create();
1644 line = getaline(in);
1646 if(line && !strncmp("END:VCARD", line, 9)) {
1651 vcard_parse_line(item, line);
1656 add_item2database(item);
1661 vcard_parse_file(FILE *in)
1666 line = getaline(in);
1668 if(line && !strncmp("BEGIN:VCARD", line, 11)) {
1670 vcard_parse_item(in);
1681 * end of vCard import filter
1685 * csv addressbook export filters
1688 #define CSV_LAST (-1)
1689 #define CSV_UNDEFINED (-2)
1690 #define CSV_SPECIAL(X) (-3 - (X))
1691 #define CSV_IS_SPECIAL(X) ((X) <= -3)
1694 csv_export_common(FILE *out, struct db_enumerator e,
1695 int fields[], void (*special_func)(FILE *, int, int))
1699 db_enumerate_items(e) {
1700 for(i = 0; fields[i] != CSV_LAST; i++) {
1701 if(fields[i] == CSV_UNDEFINED)
1702 fprintf(out, "\"\"");
1703 else if(CSV_IS_SPECIAL(fields[i])) {
1705 (*special_func)(out, e.item, fields[i]);
1708 strchr(safe_str(database[e.item][field_idx(fields[i])]), ',') ||
1709 strchr(safe_str(database[e.item][field_idx(fields[i])]), '\"')) ?
1711 safe_str(database[e.item][field_idx(fields[i])])
1713 fprintf(out, "\"%s\"",
1714 safe_str(db_fget(e.item,fields[i])));
1716 if(fields[i + 1] != CSV_LAST)
1726 csv_export_database(FILE *out, struct db_enumerator e)
1728 int csv_export_fields[] = {
1737 csv_export_common(out, e, csv_export_fields, NULL);
1743 allcsv_export_database(FILE *out, struct db_enumerator e)
1746 * TODO: Should get these atomatically from abook_fileds
1749 int allcsv_export_fields[] = {
1771 fprintf(out, "\"NAME\",");
1772 fprintf(out, "\"EMAIL\",");
1773 fprintf(out, "\"ADDRESS\",");
1774 fprintf(out, "\"ADDRESS2\",");
1775 fprintf(out, "\"CITY\",");
1776 fprintf(out, "\"STATE\",");
1777 fprintf(out, "\"ZIP\",");
1778 fprintf(out, "\"COUNTRY\",");
1779 fprintf(out, "\"PHONE\",");
1780 fprintf(out, "\"WORKPHONE\",");
1781 fprintf(out, "\"FAX\",");
1782 fprintf(out, "\"MOBILEPHONE\",");
1783 fprintf(out, "\"NICK\",");
1784 fprintf(out, "\"URL\",");
1785 fprintf(out, "\"NOTES\",");
1786 fprintf(out, "\"ANNIVERSARY\",");
1787 fprintf(out, "\"GROUPS\"\n");
1789 csv_export_common(out, e, allcsv_export_fields, NULL);
1798 #define PALM_CSV_NAME CSV_SPECIAL(0)
1799 #define PALM_CSV_END CSV_SPECIAL(1)
1800 #define PALM_CSV_CAT CSV_SPECIAL(2)
1803 palm_split_and_write_name(FILE *out, char *name)
1809 if ( (p = strchr(name, ' ')) ) {
1813 fprintf(out, "\"%s\",\"" , p + 1);
1814 fwrite((void *)name, p - name, sizeof(char), out);
1817 fprintf(out, "\"%s\"", safe_str(name));
1822 palm_csv_handle_specials(FILE *out, int item, int field)
1826 palm_split_and_write_name(out, db_name_get(item));
1829 fprintf(out, "\"abook\"");
1832 fprintf(out, "\"0\"");
1840 palm_export_database(FILE *out, struct db_enumerator e)
1842 int palm_export_fields[] = {
1843 PALM_CSV_NAME, /* LASTNAME, FIRSTNAME */
1844 CSV_UNDEFINED, /* TITLE */
1845 CSV_UNDEFINED, /* COMPANY */
1846 WORKPHONE, /* WORK PHONE */
1847 PHONE, /* HOME PHONE */
1849 MOBILEPHONE, /* OTHER */
1851 ADDRESS, /* ADDRESS */
1855 COUNTRY, /* COUNTRY */
1856 NICK, /* DEFINED 1 */
1857 URL, /* DEFINED 2 */
1858 CSV_UNDEFINED, /* DEFINED 3 */
1859 CSV_UNDEFINED, /* DEFINED 4 */
1861 PALM_CSV_END, /* "0" */
1862 PALM_CSV_CAT, /* CATEGORY */
1866 csv_export_common(out, e, palm_export_fields, palm_csv_handle_specials);
1872 * end of csv export filters
1876 * vCard 2 addressbook export filter
1880 vcard_export_database(FILE *out, struct db_enumerator e)
1882 db_enumerate_items(e)
1883 vcard_export_item(out, e.item);
1888 vcard_export_item(FILE *out, int item)
1892 abook_list *emails, *em;
1893 fprintf(out, "BEGIN:VCARD\r\nFN:%s\r\n",
1894 safe_str(db_name_get(item)));
1896 name = get_surname(db_name_get(item));
1897 for( j = strlen(db_name_get(item)) - 1; j >= 0; j-- ) {
1898 if((db_name_get(item))[j] == ' ')
1901 fprintf(out, "N:%s;%.*s\r\n",
1904 safe_str(db_name_get(item))
1909 if(db_fget(item, ADDRESS))
1910 fprintf(out, "ADR:;;%s;%s;%s;%s;%s;%s\r\n",
1911 safe_str(db_fget(item, ADDRESS)),
1912 safe_str(db_fget(item, ADDRESS2)),
1913 safe_str(db_fget(item, CITY)),
1914 safe_str(db_fget(item, STATE)),
1915 safe_str(db_fget(item, ZIP)),
1916 safe_str(db_fget(item, COUNTRY))
1919 if(db_fget(item, PHONE))
1920 fprintf(out, "TEL;HOME:%s\r\n",
1921 db_fget(item, PHONE));
1922 if(db_fget(item, WORKPHONE))
1923 fprintf(out, "TEL;WORK:%s\r\n",
1924 db_fget(item, WORKPHONE));
1925 if(db_fget(item, FAX))
1926 fprintf(out, "TEL;FAX:%s\r\n",
1927 db_fget(item, FAX));
1928 if(db_fget(item, MOBILEPHONE))
1929 fprintf(out, "TEL;CELL:%s\r\n",
1930 db_fget(item, MOBILEPHONE));
1932 tmp = db_email_get(item);
1934 emails = csv_to_abook_list(tmp);
1936 for(em = emails; em; em = em->next)
1937 fprintf(out, "EMAIL;INTERNET:%s\r\n", em->data);
1939 abook_list_free(&emails);
1943 if(db_fget(item, NOTES))
1944 fprintf(out, "NOTE:%s\r\n",
1945 db_fget(item, NOTES));
1946 if(db_fget(item, URL))
1947 fprintf(out, "URL:%s\r\n",
1948 db_fget(item, URL));
1950 fprintf(out, "END:VCARD\r\n\r\n");
1955 * end of vCard export filter
1960 * mutt alias export filter
1964 mutt_alias_genalias(int i)
1968 if(db_fget(i, NICK))
1969 return xstrdup(db_fget(i, NICK));
1971 tmp = xstrdup(db_name_get(i));
1973 if( ( pos = strchr(tmp, ' ') ) )
1982 * This function is a variant of abook_list_to_csv
1985 mutt_alias_gengroups(int i)
1987 char *groups, *res = NULL;
1988 char groupstr[7] = "-group ";
1989 abook_list *list, *tmp;
1991 groups = db_fget(i, GROUPS);
1996 list = csv_to_abook_list(groups);
1997 for(tmp = list; tmp; tmp = tmp->next) {
1999 res = xmalloc(strlen(groupstr)+strlen(tmp->data)+1);
2000 res = strcpy(res, groupstr);
2002 res = xrealloc(res, strlen(res)+1+strlen(groupstr)+strlen(tmp->data)+1);
2004 strcat(res, groupstr);
2006 strcat(res, tmp->data);
2008 abook_list_free(&list);
2015 mutt_alias_export(FILE *out, struct db_enumerator e)
2017 char email[MAX_EMAIL_LEN];
2019 char *groups = NULL;
2020 int email_addresses;
2023 db_enumerate_items(e) {
2024 alias = (field_id(NICK) != -1) ? mutt_alias_genalias(e.item) : NULL;
2025 groups = (field_id(GROUPS) != -1) ? mutt_alias_gengroups(e.item) : NULL;
2026 get_first_email(email, e.item);
2028 /* do not output contacts without email address */
2029 /* cause this does not make sense in mutt aliases */
2032 /* output first email address */
2033 fprintf(out,"alias ");
2035 fprintf(out, "%s ", groups);
2037 fprintf(out, "%s ", alias);
2038 fprintf(out, "%s <%s>\n",
2039 db_name_get(e.item),
2042 /* number of email addresses */
2043 email_addresses = 1;
2044 ptr = db_email_get(e.item);
2045 while (*ptr != '\0') {
2052 /* output other email addresses */
2053 while (email_addresses-- > 1) {
2054 roll_emails(e.item, ROTATE_RIGHT);
2055 get_first_email(email, e.item);
2056 fprintf(out,"alias ");
2058 fprintf(out, "%s ", groups);
2060 fprintf(out, "%s__%s ", alias, email);
2062 fprintf(out, "%s__%s ", db_name_get(e.item), email);
2063 fprintf(out, "%s <%s>\n",
2064 db_name_get(e.item),
2067 roll_emails(e.item, ROTATE_RIGHT);
2076 void muttq_print_item(FILE *file, int item)
2078 abook_list *emails, *e;
2079 char *tmp = db_email_get(item);
2081 emails = csv_to_abook_list(tmp);
2084 for(e = emails; e; e = e->next) {
2085 fprintf(file, "%s\t%s\t%s\n", e->data, db_name_get(item),
2086 !db_fget(item, NOTES) ?" " :db_fget(item, NOTES)
2088 if(!opt_get_bool(BOOL_MUTT_RETURN_ALL_EMAILS))
2091 abook_list_free(&emails);
2095 mutt_query_export_database(FILE *out, struct db_enumerator e)
2097 fprintf(out, "All items\n");
2098 db_enumerate_items(e)
2099 muttq_print_item(out, e.item);
2104 * end of mutt alias export filter
2109 * printable export filter
2114 text_write_address_us(FILE *out, int i) {
2115 fprintf(out, "\n%s", db_fget(i, ADDRESS));
2117 if(db_fget(i, ADDRESS2))
2118 fprintf(out, "\n%s", db_fget(i, ADDRESS2));
2120 if(db_fget(i, CITY))
2121 fprintf(out, "\n%s", db_fget(i, CITY));
2123 if(db_fget(i, STATE) || db_fget(i, ZIP)) {
2126 if(db_fget(i, STATE)) {
2127 fprintf(out, "%s", db_fget(i, STATE));
2133 fprintf(out, "%s", db_fget(i, ZIP));
2136 if(db_fget(i, COUNTRY))
2137 fprintf(out, "\n%s", db_fget(i, COUNTRY));
2142 text_write_address_uk(FILE *out, int i) {
2145 for(j = ADDRESS; j <= COUNTRY; j++)
2147 fprintf(out, "\n%s", db_fget(i, j));
2151 text_write_address_eu(FILE *out, int i) {
2152 fprintf(out, "\n%s", db_fget(i, ADDRESS));
2154 if(db_fget(i, ADDRESS2))
2155 fprintf(out, "\n%s", db_fget(i, ADDRESS2));
2157 if(db_fget(i, ZIP) || db_fget(i, CITY)) {
2160 if(db_fget(i, ZIP)) {
2161 fprintf(out, "%s", db_fget(i, ZIP));
2162 if(db_fget(i, CITY))
2166 fprintf(out, "%s", safe_str(db_fget(i, CITY)));
2169 if(db_fget(i, STATE))
2170 fprintf(out, "\n%s", db_fget(i, STATE));
2172 if(db_fget(i, COUNTRY))
2173 fprintf(out, "\n%s", db_fget(i, COUNTRY));
2177 text_export_database(FILE * out, struct db_enumerator e)
2179 abook_list *emails, *em;
2181 char *realname = get_real_name(), *str = NULL, *tmp;
2182 char *style = opt_get_str(STR_ADDRESS_STYLE);
2185 "-----------------------------------------\n%s's address book\n"
2186 "-----------------------------------------\n\n\n",
2190 db_enumerate_items(e) {
2192 "-----------------------------------------\n\n");
2193 fprintf(out, "%s", db_name_get(e.item));
2194 if(db_fget(e.item, NICK) && *db_fget(e.item, NICK))
2195 fprintf(out, "\n(%s)", db_fget(e.item, NICK));
2198 tmp = db_email_get(e.item);
2200 emails = csv_to_abook_list(tmp);
2203 for(em = emails; em; em = em->next)
2204 fprintf(out, "%s\n", em->data);
2206 abook_list_free(&emails);
2210 if(db_fget(e.item, ADDRESS)) {
2211 if(!safe_strcmp(style, "us")) /* US like */
2212 text_write_address_us(out, e.item);
2213 else if(!safe_strcmp(style, "uk")) /* UK like */
2214 text_write_address_uk(out, e.item);
2216 text_write_address_eu(out, e.item);
2221 if((db_fget(e.item, PHONE)) ||
2222 (db_fget(e.item, WORKPHONE)) ||
2223 (db_fget(e.item, FAX)) ||
2224 (db_fget(e.item, MOBILEPHONE))) {
2226 for(j = PHONE; j <= MOBILEPHONE; j++)
2227 if(db_fget(e.item, j)) {
2228 get_field_info(field_id(j),
2230 fprintf(out, "%s: %s\n", str,
2231 db_fget(e.item, j));
2235 if(db_fget(e.item, URL))
2236 fprintf(out, "\n%s\n", db_fget(e.item, URL));
2237 if(db_fget(e.item, NOTES))
2238 fprintf(out, "\n%s\n", db_fget(e.item, NOTES));
2243 fprintf(out, "-----------------------------------------\n");
2249 * end of printable export filter
2253 * elm alias export filter
2257 elm_alias_export(FILE *out, struct db_enumerator e)
2259 char email[MAX_EMAIL_LEN];
2262 db_enumerate_items(e) {
2263 alias = mutt_alias_genalias(e.item);
2264 get_first_email(email, e.item);
2265 fprintf(out, "%s = %s = %s\n",alias,db_name_get(e.item),email);
2273 * end of elm alias export filter
2278 * Spruce export filter
2282 spruce_export_database (FILE *out, struct db_enumerator e)
2284 char email[MAX_EMAIL_LEN];
2286 fprintf(out, "# This is a generated file made by abook for the Spruce e-mail client.\n\n");
2288 db_enumerate_items(e) {
2289 get_first_email(email, e.item);
2290 if(strcmp(email, "")) {
2291 fprintf(out, "# Address %d\nName: %s\nEmail: %s\nMemo: %s\n\n",
2293 db_name_get(e.item),
2295 safe_str(db_fget(e.item, NOTES))
2300 fprintf (out, "# End of address book file.\n");
2306 * end of Spruce export filter
2310 * wanderlust addressbook export filter
2314 wl_export_database(FILE *out, struct db_enumerator e)
2316 char email[MAX_EMAIL_LEN];
2318 fprintf(out, "# Wanderlust address book written by %s\n\n", PACKAGE);
2319 db_enumerate_items(e) {
2320 get_first_email(email, e.item);
2323 "%s\t\"%s\"\t\"%s\"\n",
2325 safe_str(db_fget(e.item, NICK)),
2326 safe_str(db_name_get(e.item))
2331 fprintf (out, "\n# End of address book file.\n");
2337 * end of wanderlust addressbook export filter
2341 * BSD calendar export filter
2345 bsdcal_export_database(FILE *out, struct db_enumerator e)
2347 db_enumerate_items(e) {
2348 int year, month = 0, day = 0;
2349 char *anniversary = db_fget(e.item, ANNIVERSARY);
2352 if(!parse_date_string(anniversary, &day, &month, &year))
2356 _("%02d/%02d\tAnniversary of %s\n"),
2359 safe_str(db_name_get(e.item))
2367 // see enum field_types @database.h
2368 static char *conv_table[] = {
2389 find_field_enum(char *s) {
2391 while (conv_table[i]) {
2392 if(!safe_strcmp(conv_table[i], s))
2400 /* Convert a string with named placeholders to
2401 a *printf() compatible string.
2402 Stores the abook field values into ft. */
2404 parse_custom_format(char *s, char *fmt_string, enum field_types *ft)
2406 if(! fmt_string || ! ft) {
2407 fprintf(stderr, _("parse_custom_format: fmt_string or ft not allocated\n"));
2411 char *p, *start, *field_name = NULL;
2417 p = strchr(start, '}');
2419 fprintf(stderr, _("parse_custom_format: invalid format\n"));
2422 strcat(fmt_string, "%s");
2423 field_name = strndup(start, (size_t)(p-start));
2424 *ft = find_field_enum(field_name);
2426 fprintf(stderr, _("parse_custom_format: invalid placeholder: {%s}\n"), field_name);
2434 p = strchr(start, '{');
2436 strncat(fmt_string, start, (size_t)(p-start));
2440 strncat( fmt_string,
2442 FORMAT_STRING_LEN - strlen(fmt_string) - 1 );
2451 custom_export_item(FILE *out, int item, char *s, enum field_types *ft);
2454 // used to store the format string from --outformatstr when "custom" format is used
2455 // default value overriden in export_file()
2456 extern char *parsed_custom_format;
2457 extern enum field_types *custom_format_fields;
2459 /* wrapper for custom_export_item:
2460 1) avoid messing with extern pointer
2462 3) follow the prototype needed for an abook_output_item_filter entry */
2464 custom_print_item(FILE *out, int item)
2467 if(custom_export_item(out, item, parsed_custom_format, custom_format_fields) == 0)
2472 custom_export_item(FILE *out, int item, char *fmt, enum field_types *ft)
2476 // if the first character is '!':
2477 // we first check that all fields exist before continuing
2479 enum field_types *ftp = ft;
2481 if(! db_fget(item, *ft) )
2490 if(!strncmp(fmt, "%s", 2)) {
2491 fprintf(out, "%s", safe_str(db_fget(item, *ft)));
2494 } else if (*ft == 66) {
2495 fprintf(out, "%s", fmt);
2498 p = strchr(fmt, '%');
2500 q = strndup(fmt, (size_t)(p-fmt));
2501 fprintf(out, "%s", q);
2506 fprintf(out, "%s", fmt);
2515 // used to store the format string from --outformatstr when "custom" format is used
2516 // default value overriden from abook.c
2517 extern char custom_format[FORMAT_STRING_LEN];
2520 custom_export_database(FILE *out, struct db_enumerator e)
2522 char *format_string =
2523 (char *)malloc(FORMAT_STRING_LEN * sizeof(char*));
2525 enum field_types *ft =
2526 (enum field_types *)malloc(FORMAT_STRING_MAX_FIELDS * sizeof(enum field_types *));
2528 parse_custom_format(custom_format, format_string, ft);
2530 db_enumerate_items(e) {
2531 if(custom_export_item(out, e.item, format_string, ft) == 0)
2538 * end of BSD calendar export filter