5 * by JH <jheinonen@bigfoot.com>
7 * Copyright (C) Jaakko Heinonen
15 #include <sys/types.h>
16 #include "abook_curses.h"
26 extern list_item *database;
27 extern struct abook_field abook_fields[];
30 * function declarations
33 static int ldif_parse_file(FILE *handle);
34 static int mutt_parse_file(FILE *in);
35 static int pine_parse_file(FILE *in);
37 static int ldif_export_database(FILE *out);
38 static int html_export_database(FILE *out);
39 static int pine_export_database(FILE *out);
40 static int csv_export_database(FILE *out);
41 static int gcrd_export_database(FILE *out);
42 static int mutt_alias_export(FILE *out);
43 static int elm_alias_export(FILE *out);
44 static int text_export_database(FILE *out);
45 static int spruce_export_database(FILE *out);
48 struct abook_filter i_filters[] = {
49 { "abook", "abook native format", parse_database },
50 { "ldif", "ldif / Netscape addressbook", ldif_parse_file },
51 { "mutt", "mutt alias (beta)", mutt_parse_file },
52 { "pine", "pine addressbook", pine_parse_file },
56 struct abook_filter e_filters[] = {
57 { "abook", "abook native format", write_database },
58 { "ldif", "ldif / Netscape addressbook (.4ld)", ldif_export_database },
59 { "mutt", "mutt alias", mutt_alias_export },
60 { "html", "html document", html_export_database },
61 { "pine", "pine addressbook", pine_export_database },
62 { "gcrd", "GnomeCard (VCard) addressbook", gcrd_export_database },
63 { "csv", "comma separated values", csv_export_database },
64 { "elm", "elm alias", elm_alias_export },
65 { "text", "plain text", text_export_database },
66 { "spruce", "Spruce address book", spruce_export_database },
80 for(i=0; *i_filters[i].filtname ; i++)
81 printf("\t%s\t%s\n", i_filters[i].filtname,
87 for(i=0; *e_filters[i].filtname ; i++)
88 printf("\t%s\t%s\n", e_filters[i].filtname,
95 number_of_filters(struct abook_filter * filters)
99 for(i=0; *filters[i].filtname ; i++)
108 char *username = getenv("USER");
109 struct passwd *pwent;
113 pwent = getpwnam(username);
115 if( (tmp = malloc(strlen(pwent->pw_gecos) +1)) == NULL)
116 return strdup(username);
118 rtn = sscanf(pwent->pw_gecos, "%[^,]", tmp);
119 if (rtn == EOF || rtn == 0) {
121 return strdup(username);
130 static int i_read_file(char *filename, int (*func) (FILE *in));
139 refresh_statusline();
140 headerline("import database");
142 mvaddstr(3, 1, "please select a filter");
145 for(i=0; *i_filters[i].filtname ; i++)
146 mvprintw(5 + i, 6, "%c -\t%s\t%s\n", 'a' + i,
147 i_filters[i].filtname,
150 mvprintw(6 + i, 6, "x -\tcancel");
162 filter = getch() - 'a';
163 if(filter == 'x' - 'a' || filter >= number_of_filters(e_filters) ||
169 mvaddstr(5+filter, 2, "->");
171 filename = ask_filename("Filename: ", 1);
177 if( i_read_file(filename, i_filters[filter].func ) )
178 statusline_msg("Error occured while opening the file");
181 statusline_msg("Hmm.., file seems not to be a valid file");
192 i_read_file(char *filename, int (*func) (FILE *in))
197 if( ( in = fopen( filename, "r" ) ) == NULL )
208 import(char filtname[FILTNAME_LEN], char *filename)
215 if( ! strncmp(i_filters[i].filtname, filtname, FILTNAME_LEN) )
217 if( ! *i_filters[i].filtname ) {
226 if( !strcmp(filename, "-") )
227 ret = (*i_filters[i].func) (stdin);
229 ret = i_read_file(filename, i_filters[i].func);
241 static int e_write_file(char *filename, int (*func) (FILE *in));
251 refresh_statusline();
252 headerline("export database");
254 mvaddstr(3, 1, "please select a filter");
257 for(i=0; *e_filters[i].filtname ; i++)
258 mvprintw(5 + i, 6, "%c -\t%s\t%s\n", 'a' + i,
259 e_filters[i].filtname,
262 mvprintw(6 + i, 6, "x -\tcancel");
273 filter = getch() - 'a';
274 if(filter == 'x' - 'a' || filter >= number_of_filters(e_filters) ||
280 mvaddstr(5+filter, 2, "->");
282 filename = ask_filename("Filename: ", 0);
288 if( e_write_file(filename, e_filters[filter].func ) )
289 statusline_msg("Error occured while exporting");
298 e_write_file(char *filename, int (*func) (FILE *in))
303 if( (out = fopen(filename, "a")) == NULL )
317 fexport(char filtname[FILTNAME_LEN], FILE *handle)
322 if( ! strncmp(e_filters[i].filtname, filtname, FILTNAME_LEN) )
324 if( ! *e_filters[i].filtname ) {
330 return (e_filters[i].func) (handle);
336 export(char filtname[FILTNAME_LEN], char *filename)
342 if( ! strncmp(e_filters[i].filtname, filtname, FILTNAME_LEN) )
344 if( ! *e_filters[i].filtname ) {
353 if( !strcmp(filename, "-") )
354 ret = (e_filters[i].func) (stdout);
356 ret = e_write_file(filename, e_filters[i].func);
362 * end of common functions
371 static void ldif_fix_string(char *str);
374 # define LINESIZE 1024
377 #define LDIF_ITEM_FIELDS 15
379 typedef char* ldif_item[LDIF_ITEM_FIELDS];
381 static ldif_item ldif_field_names = {
392 "facsimiletelephonenumber",
396 "objectclass", /* this must be the last entry */
399 static int ldif_conv_table[LDIF_ITEM_FIELDS] = {
402 ADDRESS, /* "streetaddress" */
403 CITY, /* "locality" */
405 ZIP, /* "postalcode" */
406 COUNTRY, /* "countryname" */
407 PHONE, /* "homephone" */
408 NOTES, /* "description" */
410 FAX, /* "facsimiletelephonenumber" */
411 MOBILEPHONE, /* "cellphone" */
412 WORKPHONE, /* "xmozillaanyphone" */
413 NICK, /* "xmozillanickname" */
414 -1, /* "objectclass" */ /* this must be the last entry */
419 ldif_read_line(FILE *in)
429 fgets(line, LINESIZE, in);
440 fseek(in, pos, SEEK_SET);
449 buf = strconcat(buf, ptr, NULL);
460 for(i=0,j=0; j < strlen(buf); i++, j++)
461 buf[i] = buf[j] == '\n' ? buf[++j] : buf[j];
468 ldif_add_item(ldif_item ldif_item)
470 list_item abook_item;
473 memset(abook_item, 0, sizeof(abook_item));
475 if( !ldif_item[LDIF_ITEM_FIELDS -1] )
479 for(i=0; i < LDIF_ITEM_FIELDS; i++) {
480 if(ldif_conv_table[i] >= 0 && ldif_item[i] && *ldif_item[i] )
481 abook_item[ldif_conv_table[i]] = strdup(ldif_item[i]);
484 add_item2database(abook_item);
487 for(i=0; i < LDIF_ITEM_FIELDS; i++)
488 my_free(ldif_item[i]);
493 ldif_convert(ldif_item item, char *type, char *value)
497 if( !strcmp(type, "dn") ) {
502 for(i=0; i < LDIF_ITEM_FIELDS; i++) {
503 if( !safe_strcmp(ldif_field_names[i], type) && *value ) {
504 if( i == LDIF_ITEM_FIELDS -1) /* this is a dirty hack */
505 if( safe_strcmp("person", value))
509 item[i] = strdup(value);
515 ldif_parse_file(FILE *handle)
522 memset(item, 0, sizeof(item));
525 if( ! (line = ldif_read_line(handle)) )
528 if( -1 == ( str_parse_line(line, &type, &value, &vlen)) ) {
530 continue; /* just skip the errors */
533 ldif_fix_string(value);
535 ldif_convert(item, type, value);
538 } while ( !feof(handle) );
540 ldif_convert(item, "dn", "");
546 ldif_fix_string(char *str)
550 for( i = 0, j = 0; j < strlen(str); i++, j++)
551 str[i] = ( str[j] == (char)0xc3 ?
552 (char) str[++j] + (char) 0x40 :
563 * mutt alias import filter
573 remove_newlines(char *buf)
577 for(i=0,j=0; j < strlen(buf); i++, j++)
578 buf[i] = buf[j] == '\n' ? buf[++j] : buf[j];
582 mutt_read_line(FILE *in, char **alias, char **rest)
585 char *ptr=(char *)&line;
588 fgets(line, LINESIZE, in);
589 remove_newlines(line);
591 while( ISSPACE(*ptr) )
594 if( strncmp("alias", ptr, 5) ) {
600 while( ISSPACE(*ptr) )
605 while( ! ISSPACE(*ptr) )
608 if( (*alias = malloc(ptr-tmp+1)) == NULL)
611 strncpy(*alias, tmp, ptr-tmp);
612 *(*alias+(ptr-tmp)) = 0;
614 while( ISSPACE(*ptr) )
623 mutt_parse_email(char *mutt_item[3])
628 if( (tmp = strchr(mutt_item[MUTT_NAME], '<')) )
633 mutt_item[MUTT_EMAIL] = strdup(tmp+1);
635 if( (tmp = strchr(mutt_item[MUTT_EMAIL], '>')) )
638 tmp = mutt_item[MUTT_NAME];
640 for(i=strlen(tmp)-1; i>0; i--)
646 mutt_item[MUTT_NAME] = strdup(tmp);
652 mutt_add_mutt_item(char *mutt_item[3])
654 list_item abook_item;
656 memset(abook_item, 0, sizeof(abook_item));
658 abook_item[NAME] = safe_strdup(mutt_item[MUTT_NAME]);
659 abook_item[EMAIL] = safe_strdup(mutt_item[MUTT_EMAIL]);
660 abook_item[NICK] = safe_strdup(mutt_item[MUTT_ALIAS]);
662 add_item2database(abook_item);
666 mutt_parse_file(FILE *in)
672 memset(mutt_item, 0, sizeof(mutt_item) );
674 if( mutt_read_line(in, &mutt_item[MUTT_ALIAS],
675 &mutt_item[MUTT_NAME]) )
678 mutt_parse_email(mutt_item);
681 free(mutt_item[MUTT_ALIAS]);
682 free(mutt_item[MUTT_NAME]);
683 free(mutt_item[MUTT_EMAIL]);
687 mutt_add_mutt_item(mutt_item);
689 free(mutt_item[MUTT_ALIAS]);
690 free(mutt_item[MUTT_NAME]);
691 free(mutt_item[MUTT_EMAIL]);
699 * end of mutt alias import filter
707 ldif_fput_type_and_value(FILE *out,char *type, char *value )
711 tmp = ldif_type_and_value(type, value, strlen(value));
719 ldif_export_database(FILE *out)
722 char email[MAX_EMAILSTR_LEN];
724 fprintf(out, "version: 1\n");
725 for(i=0; i<items; i++) {
728 get_first_email(email, i);
730 tmp = mkstr("cn=%s,mail=%s", database[i][NAME], email);
731 ldif_fput_type_and_value(out, "dn", tmp);
734 for(j=0; j < LDIF_ITEM_FIELDS; j++) {
735 if(ldif_conv_table[j] >= 0) {
736 if(ldif_conv_table[j] == EMAIL)
737 ldif_fput_type_and_value(out,
738 ldif_field_names[j], email);
739 else if(database[i][ldif_conv_table[j]])
740 ldif_fput_type_and_value(out,
742 database[i][ldif_conv_table[j]]);
746 fprintf(out, "objectclass: top\n"
747 "objectclass: person\n\n");
754 * end of ldif export filter
761 static void html_export_write_head(FILE *out, int extra_column);
762 static void html_export_write_tail(FILE *out);
765 html_export_database(FILE *out)
767 char tmp[MAX_EMAILSTR_LEN];
769 int extra_column = options_get_int("extra_column");
774 extra_column = (extra_column > 2 && extra_column < ITEM_FIELDS) ?
775 extra_column : PHONE;
777 html_export_write_head(out, extra_column);
778 for( i = 0; i < items; i++ ) {
779 get_first_email(tmp, i);
780 fprintf(out, "<tr>\n<td><a href=\"mailto:%s\">%s</a>\n",
784 fprintf(out, "<td>%s\n<td>%s\n",
786 safe_str(database[i][extra_column]) );
787 fprintf(out, "</tr>\n\n");
789 html_export_write_tail(out);
796 html_export_write_head(FILE *out, int extra_column)
798 char *realname = get_real_name();
800 fprintf(out, "<html>\n<head>\n <title>%s's addressbook</title>",
802 fprintf(out, "\n</head>\n<body>\n");
803 fprintf(out, "\n<h2>%s's addressbook</h2>\n", realname );
804 fprintf(out, "<br><br>\n\n");
806 fprintf(out, "<center><table border>\n");
807 fprintf(out, "\n<tr><th>Name<th>E-mail address(es)<th>%s</tr>\n\n",
808 abook_fields[extra_column].name);
814 html_export_write_tail(FILE *out)
816 fprintf(out, "\n</table></center>\n");
817 fprintf(out, "\n</body>\n</html>\n");
821 * end of html export filter
825 * pine addressbook import filter
829 pine_fixbuf(char *buf)
833 for(i=0,j=0; j < strlen(buf); i++, j++)
834 buf[i] = buf[j] == '\n' ? buf[++j] : buf[j];
838 pine_convert_emails(char *s)
843 if( s == NULL || *s != '(' )
849 if( ( tmp = strchr(s,')')) )
852 for(i=1; ( tmp = strchr(s, ',') ) != NULL ; i++, s=tmp+1 )
861 pine_parse_buf(char *buf)
868 int pine_conv_table[]= {NICK, NAME, EMAIL, -1, NOTES};
870 memset(&item, 0, sizeof(item) );
872 for(i=0, last=0; !last ; i++) {
873 if( ! (end = strchr(start, '\t')) )
876 len = last ? strlen(start) : (int) (end-start);
877 len = min(len, 400-1);
879 if(i < sizeof(pine_conv_table) / sizeof(*pine_conv_table)
880 && pine_conv_table[i] >= 0) {
881 strncpy(tmp, start, len);
883 item[pine_conv_table[i]] = strdup(tmp);
888 pine_convert_emails(item[EMAIL]);
889 add_item2database(item);
893 #define LINESIZE 1024
896 pine_parse_file(FILE *in)
903 fgets(line, LINESIZE, in);
907 buf = realloc(buf, i*LINESIZE);
910 fgets(line, LINESIZE, in);
912 if(*ptr != ' ' || feof(in) )
915 while( *ptr == ' ') ptr++;
932 * end of pine addressbook import filter
936 * pine addressbook export filter
938 * filter doesn't wrap the lines as it should but Pine seems to handle
939 * created files without problems - JH
943 pine_export_database(FILE *out)
947 for(i=0; i < items; i++ ) {
948 fprintf(out, have_multiple_emails(i) ?
949 "%s\t%s\t(%s)\t\t%s\n" : "%s\t%s\t%s\t\t%s\n",
950 safe_str(database[i][NICK]),
951 safe_str(database[i][NAME]),
952 safe_str(database[i][EMAIL]),
953 safe_str(database[i][NOTES])
961 * end of pine addressbook export filter
966 * csv addressbook export filter
970 csv_export_database(FILE *out)
973 int csv_export_fields[] = {
981 for(i=0; i < items; i++ ) {
982 for(j = 0; csv_export_fields[j] >= 0; j++) {
983 fprintf(out, strchr(safe_str(database[i][csv_export_fields[j]]), ',') ?
985 safe_str(database[i][csv_export_fields[j]])
987 if(csv_export_fields[j+1] >= 0)
999 * end of csv export filter
1004 * GnomeCard (VCard) addressbook export filter
1008 gcrd_export_database(FILE *out)
1010 char emails[MAX_EMAILS][MAX_EMAIL_LEN];
1014 for(i=0; i < items; i++ ) {
1015 fprintf(out, "BEGIN:VCARD\nFN:%s\n",
1016 safe_str(database[i][NAME]));
1018 name = get_surname(database[i][NAME]);
1019 for( j = strlen(database[i][NAME]) - 1; j >= 0; j-- ) {
1020 if(database[i][NAME][j] == ' ')
1023 fprintf(out, "N:%s;%.*s\n",
1026 safe_str(database[i][NAME])
1031 if ( database[i][ADDRESS] )
1032 fprintf(out, "ADR:;;%s;%s;%s;%s;%s\n",
1033 safe_str(database[i][ADDRESS]),
1034 safe_str(database[i][CITY]),
1035 safe_str(database[i][STATE]),
1036 safe_str(database[i][ZIP]),
1037 safe_str(database[i][COUNTRY])
1040 if (database[i][PHONE])
1041 fprintf(out, "TEL;HOME:%s\n", database[i][PHONE]);
1042 if (database[i][WORKPHONE])
1043 fprintf(out, "TEL;WORK:%s\n", database[i][WORKPHONE]);
1044 if (database[i][FAX])
1045 fprintf(out, "TEL;FAX:%s\n", database[i][FAX]);
1046 if (database[i][MOBILEPHONE])
1047 fprintf(out, "TEL;CELL:%s\n", database[i][MOBILEPHONE]);
1049 if ( database[i][EMAIL] ) {
1050 split_emailstr(i, emails);
1051 for(j=0; j < MAX_EMAILS ; j++) {
1053 fprintf(out, "EMAIL;INTERNET:%s\n",
1058 if ( database[i][NOTES] )
1059 fprintf(out, "NOTE:%s\n", database[i][NOTES]);
1060 if (database[i][URL])
1061 fprintf(out, "URL:%s\n", database[i][URL]);
1063 fprintf(out, "END:VCARD\n\n");
1071 * end of GnomeCard export filter
1076 * mutt alias export filter
1080 mutt_alias_genalias(int i)
1084 if(database[i][NICK])
1085 return strdup(database[i][NICK]);
1087 tmp = strdup(database[i][NAME]);
1089 if( ( pos = strchr(tmp, ' ') ) )
1098 mutt_alias_export(FILE *out)
1101 char email[MAX_EMAIL_LEN];
1104 for(i=0; i<items; i++) {
1105 alias = mutt_alias_genalias(i);
1107 get_first_email(email, i);
1108 fprintf(out, *email ? "alias %s %s <%s>\n": "alias %s %s%s\n",
1119 * end of mutt alias export filter
1124 * printable export filter
1128 text_export_database(FILE * out)
1130 char emails[MAX_EMAILS][MAX_EMAIL_LEN];
1132 char *realname = get_real_name();
1133 char *style = options_get_str("address_style");
1136 "-----------------------------------------\n%s's address book\n"
1137 "-----------------------------------------\n\n\n",
1141 for (i = 0; i < items; i++) {
1143 "-----------------------------------------\n\n");
1144 fprintf(out, "%s", database[i][NAME]);
1145 if (database[i][NICK])
1146 fprintf(out, "\n(%s)", database[i][NICK]);
1149 if (*database[i][EMAIL]) {
1151 split_emailstr(i, emails);
1152 for (j = 0; j < MAX_EMAILS; j++)
1154 fprintf(out, "%s\n", emails[j]);
1157 if (database[i][ADDRESS]) {
1158 if (!safe_strcmp(style, "us")) { /* US like */
1159 fprintf(out, "\n%s", database[i][ADDRESS]);
1160 if (database[i][CITY])
1161 fprintf(out, "\n%s",
1163 if (database[i][STATE] || database[i][ZIP])
1164 fprintf(out, "\n%s %s",
1165 safe_str(database[i]
1167 safe_str(database[i]
1169 if (database[i][COUNTRY])
1170 fprintf(out, "\n%s",
1171 database[i][COUNTRY]);
1174 else if (!safe_strcmp(style, "uk")) { /* UK like */
1175 for (j = ADDRESS; j <= COUNTRY; j++)
1177 fprintf(out, "\n%s",
1179 } else { /* EU like */
1180 fprintf(out, "\n%s", database[i][ADDRESS]);
1181 if (database[i][ZIP] || database[i][CITY])
1182 fprintf(out, "\n%s %s",
1183 safe_str(database[i][ZIP]),
1184 safe_str(database[i]
1186 if (database[i][STATE])
1187 fprintf(out, "\n%s",
1188 database[i][STATE]);
1189 if (database[i][COUNTRY])
1190 fprintf(out, "\n%s",
1191 database[i][COUNTRY]);
1197 if ((database[i][PHONE]) || (database[i][WORKPHONE]) ||
1198 (database[i][FAX]) || (database[i][MOBILEPHONE])) {
1200 for (j = PHONE; j <= MOBILEPHONE; j++)
1202 fprintf(out, "%s: %s\n",
1203 abook_fields[j].name,
1207 if (database[i][URL])
1208 fprintf(out, "\n%s\n", database[i][URL]);
1209 if (database[i][NOTES])
1210 fprintf(out, "\n%s\n", database[i][NOTES]);
1215 fprintf(out, "-----------------------------------------\n");
1221 * end of printable export filter
1225 * elm alias export filter
1229 elm_alias_export(FILE *out)
1232 char email[MAX_EMAIL_LEN];
1235 for(i=0; i<items; i++) {
1236 alias = mutt_alias_genalias(i);
1237 get_first_email(email, i);
1238 fprintf(out, "%s = %s = %s\n",
1249 * end of elm alias export filter
1254 * Spruce export filter
1258 spruce_export_database (FILE *out)
1261 char email[MAX_EMAIL_LEN];
1263 fprintf (out, "# This is a generated file made by abook for the Spruce e-mail client.\n\n");
1265 for (i= 0; i< items; i++) {
1266 if(strcmp (safe_str(database[i][EMAIL]), "")) {
1267 get_first_email(email, i);
1268 fprintf(out, "# Address %d\nName: %s\nEmail: %s\nMemo: %s\n\n",
1272 safe_str(database[i][NOTES])
1277 fprintf (out, "# End of address book file.\n");
1283 * end of Spruce export filter