5 * by JH <jheinonen@users.sourceforge.net>
7 * Copyright (C) Jaakko Heinonen
18 #include <sys/types.h>
19 #include "abook_curses.h"
32 extern abook_field_list *fields_list;
33 extern int fields_count;
36 * function declarations
40 * import filter prototypes
43 static int ldif_parse_file(FILE *handle);
44 static int mutt_parse_file(FILE *in);
45 static int pine_parse_file(FILE *in);
46 static int csv_parse_file(FILE *in);
47 static int allcsv_parse_file(FILE *in);
48 static int palmcsv_parse_file(FILE *in);
49 static int vcard_parse_file(FILE *in);
52 * export filter prototypes
55 static int ldif_export_database(FILE *out, struct db_enumerator e);
56 static int html_export_database(FILE *out, struct db_enumerator e);
57 static int pine_export_database(FILE *out, struct db_enumerator e);
58 static int csv_export_database(FILE *out, struct db_enumerator e);
59 static int allcsv_export_database(FILE *out, struct db_enumerator e);
60 static int palm_export_database(FILE *out, struct db_enumerator e);
61 static int vcard_export_database(FILE *out, struct db_enumerator e);
62 static int mutt_alias_export(FILE *out, struct db_enumerator e);
63 static int elm_alias_export(FILE *out, struct db_enumerator e);
64 static int text_export_database(FILE *out, struct db_enumerator e);
65 static int spruce_export_database(FILE *out, struct db_enumerator e);
66 static int wl_export_database(FILE *out, struct db_enumerator e);
67 static int bsdcal_export_database(FILE *out, struct db_enumerator e);
70 * end of function declarations
73 struct abook_input_filter i_filters[] = {
74 { "abook", N_("abook native format"), parse_database },
75 { "ldif", N_("ldif / Netscape addressbook"), ldif_parse_file },
76 { "mutt", N_("mutt alias"), mutt_parse_file },
77 { "pine", N_("pine addressbook"), pine_parse_file },
78 { "csv", N_("comma separated values"), csv_parse_file },
79 { "allcsv", N_("comma separated values (all fields)"), allcsv_parse_file },
80 { "palmcsv", N_("Palm comma separated values"), palmcsv_parse_file },
81 { "vcard", N_("vCard file"), vcard_parse_file },
85 struct abook_output_filter e_filters[] = {
86 { "abook", N_("abook native format"), write_database },
87 { "ldif", N_("ldif / Netscape addressbook (.4ld)"), ldif_export_database },
88 { "vcard", N_("vCard 2 file"), vcard_export_database },
89 { "mutt", N_("mutt alias"), mutt_alias_export },
90 { "html", N_("html document"), html_export_database },
91 { "pine", N_("pine addressbook"), pine_export_database },
92 { "csv", N_("comma separated values"), csv_export_database },
93 { "allcsv", N_("comma separated values (all fields)"), allcsv_export_database },
94 { "palmcsv", N_("Palm comma separated values"), palm_export_database},
95 { "elm", N_("elm alias"), elm_alias_export },
96 { "text", N_("plain text"), text_export_database },
97 { "wl", N_("Wanderlust address book"), wl_export_database },
98 { "spruce", N_("Spruce address book"), spruce_export_database },
99 { "bsdcal", N_("BSD calendar"), bsdcal_export_database },
113 for(i=0; *i_filters[i].filtname ; i++)
114 printf("\t%s\t%s\n", i_filters[i].filtname,
115 gettext(i_filters[i].desc));
120 for(i=0; *e_filters[i].filtname ; i++)
121 printf("\t%s\t%s\n", e_filters[i].filtname,
122 gettext(e_filters[i].desc));
128 number_of_output_filters()
132 for(i=0; *e_filters[i].filtname ; i++)
139 number_of_input_filters()
143 for(i=0; *i_filters[i].filtname ; i++)
152 char *username = getenv("USER");
153 struct passwd *pwent;
157 pwent = getpwnam(username);
159 if((tmp = xstrdup(pwent->pw_gecos)) == NULL)
160 return xstrdup(username);
162 rtn = sscanf(pwent->pw_gecos, "%[^,]", tmp);
163 if (rtn == EOF || rtn == 0) {
165 return xstrdup(username);
174 static int i_read_file(char *filename, int (*func) (FILE *in));
183 refresh_statusline();
184 headerline(_("import database"));
186 mvaddstr(3, 1, _("please select a filter"));
189 for(i=0; *i_filters[i].filtname ; i++)
190 mvprintw(5 + i, 6, "%c -\t%s\t%s\n", 'a' + i,
191 i_filters[i].filtname,
192 gettext(i_filters[i].desc));
194 mvprintw(6 + i, 6, _("x -\tcancel"));
202 int tmp = db_n_items();
206 filter = getch() - 'a';
207 if(filter == 'x' - 'a' ||
208 filter >= number_of_input_filters() || filter < 0) {
213 mvaddstr(5+filter, 2, "->");
215 filename = ask_filename(_("Filename: "));
221 if(i_read_file(filename, i_filters[filter].func ))
222 statusline_msg(_("Error occured while opening the file"));
223 else if(tmp == db_n_items())
224 statusline_msg(_("File does not seem to be a valid addressbook"));
235 i_read_file(char *filename, int (*func) (FILE *in))
240 if( (in = abook_fopen( filename, "r" )) == NULL )
251 import_file(char filtname[FILTNAME_LEN], char *filename)
254 int tmp = db_n_items();
258 if(! strncasecmp(i_filters[i].filtname, filtname,
261 if(! *i_filters[i].filtname) {
270 if(!strcmp(filename, "-")) {
272 if((fstat(fileno(stdin), &s)) == -1 || S_ISDIR(s.st_mode))
275 ret = (*i_filters[i].func) (stdin);
277 ret = i_read_file(filename, i_filters[i].func);
279 if(tmp == db_n_items())
289 static int e_write_file(char *filename,
290 int (*func) (FILE *in, struct db_enumerator e), int mode);
300 refresh_statusline();
301 headerline(_("export database"));
303 mvaddstr(3, 1, _("please select a filter"));
306 for(i = 0; *e_filters[i].filtname ; i++)
307 mvprintw(5 + i, 6, "%c -\t%s\t%s\n", 'a' + i,
308 e_filters[i].filtname,
309 gettext(e_filters[i].desc));
311 mvprintw(6 + i, 6, _("x -\tcancel"));
318 int enum_mode = ENUM_ALL;
323 filter = getch() - 'a';
324 if(filter == 'x' - 'a' ||
325 filter >= number_of_output_filters() || filter < 0) {
330 mvaddstr(5 + filter, 2, "->");
332 if(selected_items()) {
333 switch(statusline_askchoice(
334 _("Export <a>ll, export <s>elected, or <c>ancel?"),
335 S_("keybindings:all/selected/cancel|asc"), 3)) {
339 enum_mode = ENUM_SELECTED;
349 filename = ask_filename(_("Filename: "));
355 if( e_write_file(filename, e_filters[filter].func, enum_mode))
356 statusline_msg(_("Error occured while exporting"));
365 e_write_file(char *filename, int (*func) (FILE *in, struct db_enumerator e),
370 struct db_enumerator enumerator = init_db_enumerator(mode);
372 if((out = fopen(filename, "a")) == NULL)
378 ret = (*func) (out, enumerator);
386 fexport(char filtname[FILTNAME_LEN], FILE *handle, int enum_mode)
389 struct db_enumerator e = init_db_enumerator(enum_mode);
392 if(!strncasecmp(e_filters[i].filtname, filtname,
395 if(!*e_filters[i].filtname) {
401 return (e_filters[i].func) (handle, e);
407 export_file(char filtname[FILTNAME_LEN], char *filename)
409 const int mode = ENUM_ALL;
412 struct db_enumerator e = init_db_enumerator(mode);
415 if(!strncasecmp(e_filters[i].filtname, filtname,
418 if(!*e_filters[i].filtname) {
427 if(!strcmp(filename, "-"))
428 ret = (e_filters[i].func) (stdout, e);
430 ret = e_write_file(filename, e_filters[i].func, mode);
436 * end of common functions
445 static void ldif_fix_string(char *str);
447 #define LDIF_ITEM_FIELDS 16
449 typedef char *ldif_item[LDIF_ITEM_FIELDS];
451 static ldif_item ldif_field_names = {
463 "facsimiletelephonenumber",
467 "objectclass", /* this must be the last entry */
470 static int ldif_conv_table[LDIF_ITEM_FIELDS] = {
473 ADDRESS, /* "streetaddress" */
474 ADDRESS2, /* "streetaddress2" */
475 CITY, /* "locality" */
477 ZIP, /* "postalcode" */
478 COUNTRY, /* "countryname" */
479 PHONE, /* "homephone" */
480 NOTES, /* "description" */
482 FAX, /* "facsimiletelephonenumber" */
483 MOBILEPHONE, /* "cellphone" */
484 WORKPHONE, /* "xmozillaanyphone" */
485 NICK, /* "xmozillanickname" */
486 -1, /* "objectclass" */ /* this must be the last entry */
491 ldif_read_line(FILE *in)
504 if(feof(in) || !line)
513 fseek(in, pos, SEEK_SET); /* fixme ! */
523 buf = strconcat(buf, ptr, NULL);
528 if(buf && *buf == '#' ) {
537 ldif_add_item(ldif_item li)
542 item = item_create();
544 if(!li[LDIF_ITEM_FIELDS -1])
548 for(i=0; i < LDIF_ITEM_FIELDS; i++) {
549 if(ldif_conv_table[i] >= 0 && li[i] && *li[i])
550 item_fput(item,ldif_conv_table[i],xstrdup(li[i]));
553 add_item2database(item);
556 for(i=0; i < LDIF_ITEM_FIELDS; i++)
563 ldif_convert(ldif_item item, char *type, char *value)
567 if(!strcmp(type, "dn")) {
572 for(i=0; i < LDIF_ITEM_FIELDS; i++) {
573 if(!safe_strcmp(ldif_field_names[i], type) && *value) {
574 if(i == LDIF_ITEM_FIELDS - 1) /* this is a dirty hack */
575 if(safe_strcmp("person", value))
578 if(item_fget(item, i))
579 free(item_fget(item, i));
581 item_fput(item, i, xstrdup(value));
587 ldif_parse_file(FILE *handle)
594 memset(item, 0, sizeof(item));
597 if( !(line = ldif_read_line(handle)) )
600 if(-1 == (str_parse_line(line, &type, &value, &vlen))) {
602 continue; /* just skip the errors */
605 ldif_fix_string(value);
607 ldif_convert(item, type, value);
610 } while ( !feof(handle) );
612 ldif_convert(item, "dn", "");
618 ldif_fix_string(char *str)
622 for(i = 0, j = 0; j < (int)strlen(str); i++, j++)
623 str[i] = ( str[j] == (char)0xc3 ?
624 (char) str[++j] + (char) 0x40 :
635 * mutt alias import filter
641 mutt_read_line(FILE *in, char **groups, char **alias, char **rest)
645 abook_list *glist = NULL;
647 if( !(line = ptr = getaline(in)) )
648 return 1; /* error / EOF */
652 if(strncmp("alias", ptr, 5)) {
660 /* If the group option is used, save the groups */
664 for(n_groups = 0; 0 == strncmp("-group", ptr, 6); n_groups++) {
670 abook_list_append(&glist,xstrndup(start, end - start));
674 if(n_groups && groups)
675 *groups = abook_list_to_csv(glist);
677 abook_list_free(&glist);
685 *alias = xstrndup(start, end - start);
688 *rest = xstrdup(ptr);
695 mutt_fix_quoting(char *p)
715 mutt_parse_email(list_item item)
717 char *line = item_fget(item, NAME);
725 mutt_fix_quoting(line);
726 tmp = strconcat("From: ", line, NULL);
727 getname(tmp, &name, &email);
731 item_fput(item, NAME, name);
736 item_fput(item, EMAIL, email);
741 * this is completely broken
744 while( (start = strchr(start, ',')) && i++ < MAX_EMAILS - 1) {
745 tmp = strconcat("From: ", ++start, NULL);
746 getname(tmp, &name, &email);
751 tmp = strconcat(item[EMAIL], ",", email, NULL);
763 mutt_parse_file(FILE *in)
765 list_item item = item_create();
768 memset(item, 0, fields_count * sizeof(char *));
770 if(!mutt_read_line(in,
771 (field_id(GROUPS) != -1) ? &item[field_id(GROUPS)] : NULL,
772 (field_id(NICK) != -1) ? &item[field_id(NICK)] : NULL,
773 &item[field_id(NAME)]) )
774 mutt_parse_email(item);
781 add_item2database(item);
789 * end of mutt alias import filter
798 ldif_fput_type_and_value(FILE *out,char *type, char *value )
802 tmp = ldif_type_and_value(type, value, strlen(value));
810 ldif_export_database(FILE *out, struct db_enumerator e)
812 char email[MAX_EMAILSTR_LEN];
814 fprintf(out, "version: 1\n");
816 db_enumerate_items(e) {
819 get_first_email(email, e.item);
821 tmp = strdup_printf("cn=%s,mail=%s",db_name_get(e.item),email);
823 ldif_fput_type_and_value(out, "dn", tmp);
826 for(j = 0; j < LDIF_ITEM_FIELDS; j++) {
827 if(ldif_conv_table[j] >= 0) {
828 if(ldif_conv_table[j] == EMAIL)
829 ldif_fput_type_and_value(out,
830 ldif_field_names[j], email);
831 else if(db_fget(e.item,ldif_conv_table[j]))
832 ldif_fput_type_and_value(out,
835 ldif_conv_table[j]));
839 fprintf(out, "objectclass: top\n"
840 "objectclass: person\n\n");
847 * end of ldif export filter
854 static void html_export_write_head(FILE *out);
855 static void html_export_write_tail(FILE *out);
857 extern struct index_elem *index_elements;
860 html_print_emails(FILE *out, struct list_field *f)
862 abook_list *l = csv_to_abook_list(f->data);
864 for(; l; l = l->next) {
865 fprintf(out, "<a href=\"mailto:%s\">%s</a>", l->data, l->data);
874 html_export_database(FILE *out, struct db_enumerator e)
877 struct index_elem *cur;
884 html_export_write_head(out);
886 db_enumerate_items(e) {
887 fprintf(out, "<tr>");
888 for(cur = index_elements; cur; cur = cur->next) {
889 if(cur->type != INDEX_FIELD)
892 get_list_field(e.item, cur, &f);
894 if(f.type == FIELD_EMAILS) {
895 fprintf(out, "<td>");
896 html_print_emails(out, &f);
897 fprintf(out, "</td>");
900 fprintf(out, "<td>%s</td>", safe_str(f.data));
903 fprintf(out, "</tr>\n");
906 html_export_write_tail(out);
912 html_export_write_head(FILE *out)
914 char *realname = get_real_name(), *str;
915 struct index_elem *cur;
917 fprintf(out, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n");
918 fprintf(out, "<html>\n<head>\n <title>%s's addressbook</title>",
920 fprintf(out, "\n</head>\n<body>\n");
921 fprintf(out, "\n<h2>%s's addressbook</h2>\n", realname );
922 fprintf(out, "<br><br>\n\n");
924 fprintf(out, "<table border=\"1\" align=\"center\">\n<tr>");
925 for(cur = index_elements; cur; cur = cur->next) {
926 if(cur->type != INDEX_FIELD)
929 get_field_info(cur->d.field.id, NULL, &str, NULL);
930 fprintf(out, "<th>%s</th>", str);
932 fprintf(out, "</tr>\n\n");
938 html_export_write_tail(FILE *out)
940 fprintf(out, "\n</table>\n");
941 fprintf(out, "\n</body>\n</html>\n");
945 * end of html export filter
950 * pine addressbook import filter
953 #define PINE_BUF_SIZE 2048
956 pine_fixbuf(char *buf)
960 for(i = 0,j = 0; j < (int)strlen(buf); i++, j++)
961 buf[i] = buf[j] == '\n' ? buf[++j] : buf[j];
965 pine_convert_emails(char *s)
970 if(s == NULL || *s != '(')
973 for(i = 0; s[i]; i++)
976 if( ( tmp = strchr(s,')')) )
979 for(i = 1; ( tmp = strchr(s, ',') ) != NULL ; i++, s = tmp + 1)
980 if(i > MAX_LIST_ITEMS - 1) {
988 pine_parse_buf(char *buf)
993 char tmp[PINE_BUF_SIZE];
995 int pine_conv_table[]= {NICK, NAME, EMAIL, -1, NOTES};
997 item = item_create();
999 for(i=0, last=0; !last ; i++) {
1000 if( !(end = strchr(start, '\t')) )
1003 len = last ? strlen(start) : (int) (end-start);
1004 len = min(len, PINE_BUF_SIZE - 1);
1006 if(i < (int)(sizeof(pine_conv_table) / sizeof(*pine_conv_table))
1007 && pine_conv_table[i] >= 0) {
1008 strncpy(tmp, start, len);
1011 item_fput(item, pine_conv_table[i],
1017 pine_convert_emails(item_fget(item, EMAIL));
1018 add_item2database(item);
1023 #define LINESIZE 1024
1026 pine_parse_file(FILE *in)
1028 char line[LINESIZE];
1033 fgets(line, LINESIZE, in);
1037 buf = xrealloc(buf, i*LINESIZE);
1040 fgets(line, LINESIZE, in);
1042 if(*ptr != ' ' || feof(in))
1056 pine_parse_buf(buf);
1065 * end of pine addressbook import filter
1070 * pine addressbook export filter
1072 * filter doesn't wrap the lines as it should but Pine seems to handle
1073 * created files without problems - JH
1077 pine_export_database(FILE *out, struct db_enumerator e)
1081 db_enumerate_items(e) {
1082 emails = db_email_get(e.item);
1083 fprintf(out, strchr(emails, ',') /* multiple addresses? */ ?
1084 "%s\t%s\t(%s)\t\t%s\n" : "%s\t%s\t%s\t\t%s\n",
1085 safe_str(db_fget(e.item, NICK)),
1086 safe_str(db_name_get(e.item)),
1088 safe_str(db_fget(e.item, NOTES))
1097 * end of pine addressbook export filter
1106 * these files should be parsed according to a certain
1107 * lay out, or the default if layout is not given, at
1108 * the moment only default is done...
1111 #define CSV_COMMENT_CHAR '#'
1112 #define CSV_DUPLICATE_SEPARATOR " "
1113 #define CSV_TABLE_SIZE(t) (sizeof (t) / sizeof *(t))
1115 static int csv_conv_table[] = {
1123 static int allcsv_conv_table[] = {
1142 static int palmcsv_conv_table[] = {
1143 NAME, /* Last name */
1144 NAME, /* First name */
1161 csv_convert_emails(char *s)
1169 for(i = 1; ( tmp = strchr(s, ',') ) != NULL ; i++, s = tmp + 1)
1170 if(i > MAX_LIST_ITEMS - 1) {
1178 csv_remove_quotes(char *s)
1180 char *copy, *trimmed;
1183 copy = trimmed = xstrdup(s);
1186 len = strlen(trimmed);
1187 if(trimmed[len - 1] == '\"' && *trimmed == '\"') {
1192 trimmed[len - 1] = 0;
1194 trimmed = xstrdup(trimmed);
1204 csv_field_to_item(int *table_base, size_t table_size, int field)
1206 if(field < table_size)
1207 return field_id(table_base[field]);
1213 csv_store_item(list_item item, int i, char *s)
1215 char *newstr = NULL;
1220 if( !(newstr = csv_remove_quotes(s)) )
1224 if (item[i] != NULL) {
1225 char *oldstr = item[i];
1227 item[i] = strconcat(newstr, CSV_DUPLICATE_SEPARATOR,
1240 csv_is_valid_quote_end(char *p)
1248 else if(!ISSPACE(*p))
1256 csv_is_valid_quote_start(char *p)
1261 else if(!ISSPACE(*p))
1269 csv_parse_line(char *line, int *table_base, size_t table_size)
1273 bool in_quote = FALSE;
1276 item = item_create();
1278 for(p = start = line, field = 0; *p; p++) {
1280 if(csv_is_valid_quote_end(p))
1283 if ( (((p - start) / sizeof (char)) < 2 ) &&
1284 csv_is_valid_quote_start(p) )
1288 if(*p == ',' && !in_quote) {
1290 csv_store_item(item,
1291 csv_field_to_item(table_base,table_size,field),
1300 csv_store_item(item, csv_field_to_item(table_base, table_size, field),
1303 csv_convert_emails(item_fget(item, EMAIL));
1304 add_item2database(item);
1309 csv_parse_file_common(FILE *in, int *conv_table, size_t table_size)
1314 line = getaline(in);
1316 if(line && *line && *line != CSV_COMMENT_CHAR)
1317 csv_parse_line(line, conv_table, table_size);
1326 csv_parse_file(FILE *in)
1328 return csv_parse_file_common(in, csv_conv_table,
1329 CSV_TABLE_SIZE(csv_conv_table));
1333 allcsv_parse_file(FILE *in)
1335 return csv_parse_file_common(in, allcsv_conv_table,
1336 CSV_TABLE_SIZE(allcsv_conv_table));
1340 palmcsv_parse_file(FILE *in)
1342 return csv_parse_file_common(in, palmcsv_conv_table,
1343 CSV_TABLE_SIZE(palmcsv_conv_table));
1347 * end of csv import filter
1351 * vCard import filter
1354 static char *vcard_fields[] = {
1355 "FN", /* FORMATTED NAME */
1356 "EMAIL", /* EMAIL */
1357 "ADR", /* ADDRESS */
1358 "ADR", /* ADDRESS2 - not used */
1362 "ADR", /* COUNTRY */
1364 "TEL", /* WORKPHONE */
1366 "TEL", /* MOBILEPHONE */
1367 "NICKNAME", /* NICK */
1370 "N", /* NAME: special case/mapping in vcard_parse_line() */
1371 NULL /* not implemented: ANNIVERSARY, ITEM_FIELDS */
1375 * mappings between vCard ADR field and abook's ADDRESS
1376 * see rfc2426 section 3.2.1
1378 static int vcard_address_fields[] = {
1379 -1, /* vCard(post office box) - not used */
1380 -1, /* vCard(the extended address) - not used */
1381 2, /* vCard(the street address) - ADDRESS */
1382 4, /* vCard(the locality) - CITY */
1383 5, /* vCard(the region) - STATE */
1384 6, /* vCard(the postal code) - ZIP */
1385 7 /* vCard(the country name) - COUNTRY */
1390 VCARD_KEY_ATTRIBUTE,
1395 vcard_get_line_element(char *line, int element)
1398 char *line_copy = 0;
1404 line_copy = xstrdup(line);
1406 /* change newline characters, if present, to end of string */
1407 for(i=0; line_copy[i]; i++) {
1408 if(line_copy[i] == '\r' || line_copy[i] == '\n') {
1409 line_copy[i] = '\0';
1414 /* separate key from value */
1415 for(i=0; line_copy[i]; i++) {
1416 if(line_copy[i] == ':') {
1417 line_copy[i] = '\0';
1419 value = &line_copy[i+1];
1424 /* separate key from key attributes */
1425 /* works for vCard 2 as well (automagically) */
1427 for(i=0; key[i]; i++) {
1430 key_attr = &key[i+1];
1439 result = xstrdup(key);
1441 case VCARD_KEY_ATTRIBUTE:
1443 result = xstrdup(key_attr);
1447 result = xstrdup(value);
1456 vcard_parse_email(list_item item, char *line)
1460 email = vcard_get_line_element(line, VCARD_VALUE);
1463 item[1] = strconcat(item[1], ",", email, 0);
1472 vcard_parse_address(list_item item, char *line)
1477 char *address_field;
1479 value = vcard_get_line_element(line, VCARD_VALUE);
1483 address_field = value;
1484 for(i=k=0; value[i]; i++) {
1485 if(value[i] == ';') {
1487 if(vcard_address_fields[k] >= 0) {
1488 item[vcard_address_fields[k]] = xstrdup(address_field);
1490 address_field = &value[i+1];
1492 if((k+1)==(sizeof(vcard_address_fields)/sizeof(*vcard_address_fields)))
1496 item[vcard_address_fields[k]] = xstrdup(address_field);
1501 vcard_parse_name(list_item item, char *line)
1503 // store the "N" field into "NAME" *if* no "FN:"
1504 // value has already been stored here
1508 item[0] = vcard_get_line_element(line, VCARD_VALUE);
1509 // "N:" can be multivalued => replace ';' separators by ' '
1510 while(item[0][++i]) if(item[0][i] == ';') item[0][i] = ' ';
1512 // http://www.daniweb.com/software-development/c/code/216919
1513 char *original = item[0], *p = original;
1516 if (*original != ' ' || trimmed) {
1517 trimmed = 1; *p++ = *original;
1519 } while(*original++);
1523 vcard_parse_phone(list_item item, char *line)
1525 char *type = vcard_get_line_element(line, VCARD_KEY_ATTRIBUTE);
1526 char *value = vcard_get_line_element(line, VCARD_VALUE);
1528 /* set the standard number */
1529 if (!type) item_fput(item, PHONE, value);
1532 * see rfc2426 section 3.3.1
1533 * Note: we probably support both vCard 2 and 3
1536 if (strcasestr(type, "home") != NULL)
1537 item_fput(item, PHONE, xstrdup(value));
1538 else if (strcasestr(type, "work") != NULL)
1539 item_fput(item, WORKPHONE, xstrdup(value));
1540 else if (strcasestr(type, "fax") != NULL)
1541 item_fput(item, FAX, xstrdup(value));
1542 else if (strcasestr(type, "cell") != NULL)
1543 item_fput(item, MOBILEPHONE, xstrdup(value));
1551 vcard_parse_line(list_item item, char *line)
1556 for(i=0; vcard_fields[i]; i++) {
1557 key = vcard_fields[i];
1559 if(0 == strncmp(key, line, strlen(key))) {
1560 if(0 == strcmp(key, "EMAIL"))
1561 vcard_parse_email(item, line);
1563 vcard_parse_address(item, line);
1564 else if(0 == strcmp(key, "TEL"))
1565 vcard_parse_phone(item, line);
1566 else if(0 == strcmp(key, "N"))
1567 vcard_parse_name(item, line);
1569 item[i] = vcard_get_line_element(line, VCARD_VALUE);
1576 vcard_parse_item(FILE *in)
1579 list_item item = item_create();
1582 line = getaline(in);
1584 if(line && !strncmp("END:VCARD", line, 9)) {
1589 vcard_parse_line(item, line);
1594 add_item2database(item);
1599 vcard_parse_file(FILE *in)
1604 line = getaline(in);
1606 if(line && !strncmp("BEGIN:VCARD", line, 11)) {
1608 vcard_parse_item(in);
1619 * end of vCard import filter
1623 * csv addressbook export filters
1626 #define CSV_LAST (-1)
1627 #define CSV_UNDEFINED (-2)
1628 #define CSV_SPECIAL(X) (-3 - (X))
1629 #define CSV_IS_SPECIAL(X) ((X) <= -3)
1632 csv_export_common(FILE *out, struct db_enumerator e,
1633 int fields[], void (*special_func)(FILE *, int, int))
1637 db_enumerate_items(e) {
1638 for(i = 0; fields[i] != CSV_LAST; i++) {
1639 if(fields[i] == CSV_UNDEFINED)
1640 fprintf(out, "\"\"");
1641 else if(CSV_IS_SPECIAL(fields[i])) {
1643 (*special_func)(out, e.item, fields[i]);
1646 strchr(safe_str(database[e.item][field_idx(fields[i])]), ',') ||
1647 strchr(safe_str(database[e.item][field_idx(fields[i])]), '\"')) ?
1649 safe_str(database[e.item][field_idx(fields[i])])
1651 fprintf(out, "\"%s\"",
1652 safe_str(db_fget(e.item,fields[i])));
1654 if(fields[i + 1] != CSV_LAST)
1664 csv_export_database(FILE *out, struct db_enumerator e)
1666 int csv_export_fields[] = {
1675 csv_export_common(out, e, csv_export_fields, NULL);
1681 allcsv_export_database(FILE *out, struct db_enumerator e)
1684 * TODO: Should get these atomatically from abook_fileds
1687 int allcsv_export_fields[] = {
1709 fprintf(out, "\"NAME\",");
1710 fprintf(out, "\"EMAIL\",");
1711 fprintf(out, "\"ADDRESS\",");
1712 fprintf(out, "\"ADDRESS2\",");
1713 fprintf(out, "\"CITY\",");
1714 fprintf(out, "\"STATE\",");
1715 fprintf(out, "\"ZIP\",");
1716 fprintf(out, "\"COUNTRY\",");
1717 fprintf(out, "\"PHONE\",");
1718 fprintf(out, "\"WORKPHONE\",");
1719 fprintf(out, "\"FAX\",");
1720 fprintf(out, "\"MOBILEPHONE\",");
1721 fprintf(out, "\"NICK\",");
1722 fprintf(out, "\"URL\",");
1723 fprintf(out, "\"NOTES\",");
1724 fprintf(out, "\"ANNIVERSARY\",");
1725 fprintf(out, "\"GROUPS\"\n");
1727 csv_export_common(out, e, allcsv_export_fields, NULL);
1736 #define PALM_CSV_NAME CSV_SPECIAL(0)
1737 #define PALM_CSV_END CSV_SPECIAL(1)
1738 #define PALM_CSV_CAT CSV_SPECIAL(2)
1741 palm_split_and_write_name(FILE *out, char *name)
1747 if ( (p = strchr(name, ' ')) ) {
1751 fprintf(out, "\"%s\",\"" , p + 1);
1752 fwrite((void *)name, p - name, sizeof(char), out);
1755 fprintf(out, "\"%s\"", safe_str(name));
1760 palm_csv_handle_specials(FILE *out, int item, int field)
1764 palm_split_and_write_name(out, db_name_get(item));
1767 fprintf(out, "\"abook\"");
1770 fprintf(out, "\"0\"");
1778 palm_export_database(FILE *out, struct db_enumerator e)
1780 int palm_export_fields[] = {
1781 PALM_CSV_NAME, /* LASTNAME, FIRSTNAME */
1782 CSV_UNDEFINED, /* TITLE */
1783 CSV_UNDEFINED, /* COMPANY */
1784 WORKPHONE, /* WORK PHONE */
1785 PHONE, /* HOME PHONE */
1787 MOBILEPHONE, /* OTHER */
1789 ADDRESS, /* ADDRESS */
1793 COUNTRY, /* COUNTRY */
1794 NICK, /* DEFINED 1 */
1795 URL, /* DEFINED 2 */
1796 CSV_UNDEFINED, /* DEFINED 3 */
1797 CSV_UNDEFINED, /* DEFINED 4 */
1799 PALM_CSV_END, /* "0" */
1800 PALM_CSV_CAT, /* CATEGORY */
1804 csv_export_common(out, e, palm_export_fields, palm_csv_handle_specials);
1810 * end of csv export filters
1814 * vCard 2 addressbook export filter
1818 vcard_export_database(FILE *out, struct db_enumerator e)
1822 abook_list *emails, *em;
1824 db_enumerate_items(e) {
1825 fprintf(out, "BEGIN:VCARD\r\nFN:%s\r\n",
1826 safe_str(db_name_get(e.item)));
1828 name = get_surname(db_name_get(e.item));
1829 for( j = strlen(db_name_get(e.item)) - 1; j >= 0; j-- ) {
1830 if((db_name_get(e.item))[j] == ' ')
1833 fprintf(out, "N:%s;%.*s\r\n",
1836 safe_str(db_name_get(e.item))
1841 if(db_fget(e.item, ADDRESS))
1842 fprintf(out, "ADR:;;%s;%s;%s;%s;%s;%s\r\n",
1843 safe_str(db_fget(e.item, ADDRESS)),
1844 safe_str(db_fget(e.item, ADDRESS2)),
1845 safe_str(db_fget(e.item, CITY)),
1846 safe_str(db_fget(e.item, STATE)),
1847 safe_str(db_fget(e.item, ZIP)),
1848 safe_str(db_fget(e.item, COUNTRY))
1851 if(db_fget(e.item, PHONE))
1852 fprintf(out, "TEL;HOME:%s\r\n",
1853 db_fget(e.item, PHONE));
1854 if(db_fget(e.item, WORKPHONE))
1855 fprintf(out, "TEL;WORK:%s\r\n",
1856 db_fget(e.item, WORKPHONE));
1857 if(db_fget(e.item, FAX))
1858 fprintf(out, "TEL;FAX:%s\r\n",
1859 db_fget(e.item, FAX));
1860 if(db_fget(e.item, MOBILEPHONE))
1861 fprintf(out, "TEL;CELL:%s\r\n",
1862 db_fget(e.item, MOBILEPHONE));
1864 tmp = db_email_get(e.item);
1866 emails = csv_to_abook_list(tmp);
1868 for(em = emails; em; em = em->next)
1869 fprintf(out, "EMAIL;INTERNET:%s\r\n", em->data);
1871 abook_list_free(&emails);
1875 if(db_fget(e.item, NOTES))
1876 fprintf(out, "NOTE:%s\r\n",
1877 db_fget(e.item, NOTES));
1878 if(db_fget(e.item, URL))
1879 fprintf(out, "URL:%s\r\n",
1880 db_fget(e.item, URL));
1882 fprintf(out, "END:VCARD\r\n\r\n");
1890 * end of vCard export filter
1895 * mutt alias export filter
1899 mutt_alias_genalias(int i)
1903 if(db_fget(i, NICK))
1904 return xstrdup(db_fget(i, NICK));
1906 tmp = xstrdup(db_name_get(i));
1908 if( ( pos = strchr(tmp, ' ') ) )
1917 * This function is a variant of abook_list_to_csv
1920 mutt_alias_gengroups(int i)
1922 char *groups, *res = NULL;
1923 char groupstr[7] = "-group ";
1924 abook_list *list, *tmp;
1926 groups = db_fget(i, GROUPS);
1931 list = csv_to_abook_list(groups);
1932 for(tmp = list; tmp; tmp = tmp->next) {
1934 res = xmalloc(strlen(groupstr)+strlen(tmp->data)+1);
1935 res = strcpy(res, groupstr);
1937 res = xrealloc(res, strlen(res)+1+strlen(groupstr)+strlen(tmp->data)+1);
1939 strcat(res, groupstr);
1941 strcat(res, tmp->data);
1943 abook_list_free(&list);
1950 mutt_alias_export(FILE *out, struct db_enumerator e)
1952 char email[MAX_EMAIL_LEN];
1954 char *groups = NULL;
1955 int email_addresses;
1958 db_enumerate_items(e) {
1959 alias = (field_id(NICK) != -1) ? mutt_alias_genalias(e.item) : NULL;
1960 groups = (field_id(GROUPS) != -1) ? mutt_alias_gengroups(e.item) : NULL;
1961 get_first_email(email, e.item);
1963 /* do not output contacts without email address */
1964 /* cause this does not make sense in mutt aliases */
1967 /* output first email address */
1968 fprintf(out,"alias ");
1970 fprintf(out, "%s ", groups);
1972 fprintf(out, "%s ", alias);
1973 fprintf(out, "%s <%s>\n",
1974 db_name_get(e.item),
1977 /* number of email addresses */
1978 email_addresses = 1;
1979 ptr = db_email_get(e.item);
1980 while (*ptr != '\0') {
1987 /* output other email addresses */
1988 while (email_addresses-- > 1) {
1989 roll_emails(e.item, ROTATE_RIGHT);
1990 get_first_email(email, e.item);
1991 fprintf(out,"alias ");
1993 fprintf(out, "%s ", groups);
1995 fprintf(out, "%s__%s ", alias, email);
1997 fprintf(out, "%s__%s ", db_name_get(e.item), email);
1998 fprintf(out, "%s <%s>\n",
1999 db_name_get(e.item),
2002 roll_emails(e.item, ROTATE_RIGHT);
2012 * end of mutt alias export filter
2017 * printable export filter
2022 text_write_address_us(FILE *out, int i) {
2023 fprintf(out, "\n%s", db_fget(i, ADDRESS));
2025 if(db_fget(i, ADDRESS2))
2026 fprintf(out, "\n%s", db_fget(i, ADDRESS2));
2028 if(db_fget(i, CITY))
2029 fprintf(out, "\n%s", db_fget(i, CITY));
2031 if(db_fget(i, STATE) || db_fget(i, ZIP)) {
2034 if(db_fget(i, STATE)) {
2035 fprintf(out, "%s", db_fget(i, STATE));
2041 fprintf(out, "%s", db_fget(i, ZIP));
2044 if(db_fget(i, COUNTRY))
2045 fprintf(out, "\n%s", db_fget(i, COUNTRY));
2050 text_write_address_uk(FILE *out, int i) {
2053 for(j = ADDRESS; j <= COUNTRY; j++)
2055 fprintf(out, "\n%s", db_fget(i, j));
2059 text_write_address_eu(FILE *out, int i) {
2060 fprintf(out, "\n%s", db_fget(i, ADDRESS));
2062 if(db_fget(i, ADDRESS2))
2063 fprintf(out, "\n%s", db_fget(i, ADDRESS2));
2065 if(db_fget(i, ZIP) || db_fget(i, CITY)) {
2068 if(db_fget(i, ZIP)) {
2069 fprintf(out, "%s", db_fget(i, ZIP));
2070 if(db_fget(i, CITY))
2074 fprintf(out, "%s", safe_str(db_fget(i, CITY)));
2077 if(db_fget(i, STATE))
2078 fprintf(out, "\n%s", db_fget(i, STATE));
2080 if(db_fget(i, COUNTRY))
2081 fprintf(out, "\n%s", db_fget(i, COUNTRY));
2085 text_export_database(FILE * out, struct db_enumerator e)
2087 abook_list *emails, *em;
2089 char *realname = get_real_name(), *str = NULL, *tmp;
2090 char *style = opt_get_str(STR_ADDRESS_STYLE);
2093 "-----------------------------------------\n%s's address book\n"
2094 "-----------------------------------------\n\n\n",
2098 db_enumerate_items(e) {
2100 "-----------------------------------------\n\n");
2101 fprintf(out, "%s", db_name_get(e.item));
2102 if(db_fget(e.item, NICK) && *db_fget(e.item, NICK))
2103 fprintf(out, "\n(%s)", db_fget(e.item, NICK));
2106 tmp = db_email_get(e.item);
2108 emails = csv_to_abook_list(tmp);
2111 for(em = emails; em; em = em->next)
2112 fprintf(out, "%s\n", em->data);
2114 abook_list_free(&emails);
2118 if(db_fget(e.item, ADDRESS)) {
2119 if(!safe_strcmp(style, "us")) /* US like */
2120 text_write_address_us(out, e.item);
2121 else if(!safe_strcmp(style, "uk")) /* UK like */
2122 text_write_address_uk(out, e.item);
2124 text_write_address_eu(out, e.item);
2129 if((db_fget(e.item, PHONE)) ||
2130 (db_fget(e.item, WORKPHONE)) ||
2131 (db_fget(e.item, FAX)) ||
2132 (db_fget(e.item, MOBILEPHONE))) {
2134 for(j = PHONE; j <= MOBILEPHONE; j++)
2135 if(db_fget(e.item, j)) {
2136 get_field_info(field_id(j),
2138 fprintf(out, "%s: %s\n", str,
2139 db_fget(e.item, j));
2143 if(db_fget(e.item, URL))
2144 fprintf(out, "\n%s\n", db_fget(e.item, URL));
2145 if(db_fget(e.item, NOTES))
2146 fprintf(out, "\n%s\n", db_fget(e.item, NOTES));
2151 fprintf(out, "-----------------------------------------\n");
2157 * end of printable export filter
2161 * elm alias export filter
2165 elm_alias_export(FILE *out, struct db_enumerator e)
2167 char email[MAX_EMAIL_LEN];
2170 db_enumerate_items(e) {
2171 alias = mutt_alias_genalias(e.item);
2172 get_first_email(email, e.item);
2173 fprintf(out, "%s = %s = %s\n",alias,db_name_get(e.item),email);
2181 * end of elm alias export filter
2186 * Spruce export filter
2190 spruce_export_database (FILE *out, struct db_enumerator e)
2192 char email[MAX_EMAIL_LEN];
2194 fprintf(out, "# This is a generated file made by abook for the Spruce e-mail client.\n\n");
2196 db_enumerate_items(e) {
2197 get_first_email(email, e.item);
2198 if(strcmp(email, "")) {
2199 fprintf(out, "# Address %d\nName: %s\nEmail: %s\nMemo: %s\n\n",
2201 db_name_get(e.item),
2203 safe_str(db_fget(e.item, NOTES))
2208 fprintf (out, "# End of address book file.\n");
2214 * end of Spruce export filter
2218 * wanderlust addressbook export filter
2222 wl_export_database(FILE *out, struct db_enumerator e)
2224 char email[MAX_EMAIL_LEN];
2226 fprintf(out, "# Wanderlust address book written by %s\n\n", PACKAGE);
2227 db_enumerate_items(e) {
2228 get_first_email(email, e.item);
2231 "%s\t\"%s\"\t\"%s\"\n",
2233 safe_str(db_fget(e.item, NICK)),
2234 safe_str(db_name_get(e.item))
2239 fprintf (out, "\n# End of address book file.\n");
2245 * end of wanderlust addressbook export filter
2249 * BSD calendar export filter
2253 bsdcal_export_database(FILE *out, struct db_enumerator e)
2255 db_enumerate_items(e) {
2256 int year, month = 0, day = 0;
2257 char *anniversary = db_fget(e.item, ANNIVERSARY);
2260 if(!parse_date_string(anniversary, &day, &month, &year))
2264 _("%02d/%02d\tAnniversary of %s\n"),
2267 safe_str(db_name_get(e.item))
2276 * end of BSD calendar export filter