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
34 * import filter prototypes
37 static int ldif_parse_file(FILE *handle);
38 static int mutt_parse_file(FILE *in);
39 static int pine_parse_file(FILE *in);
42 * export filter prototypes
45 static int ldif_export_database(FILE *out, struct db_enumerator e);
46 static int html_export_database(FILE *out, struct db_enumerator e);
47 static int pine_export_database(FILE *out, struct db_enumerator e);
48 static int csv_export_database(FILE *out, struct db_enumerator e);
49 static int gcrd_export_database(FILE *out, struct db_enumerator e);
50 static int mutt_alias_export(FILE *out, struct db_enumerator e);
51 static int elm_alias_export(FILE *out, struct db_enumerator e);
52 static int text_export_database(FILE *out, struct db_enumerator e);
53 static int spruce_export_database(FILE *out, struct db_enumerator e);
56 * end of function declarations
59 struct abook_input_filter i_filters[] = {
60 { "abook", "abook native format", parse_database },
61 { "ldif", "ldif / Netscape addressbook", ldif_parse_file },
62 { "mutt", "mutt alias (beta)", mutt_parse_file },
63 { "pine", "pine addressbook", pine_parse_file },
67 struct abook_output_filter e_filters[] = {
68 { "abook", "abook native format", write_database },
69 { "ldif", "ldif / Netscape addressbook (.4ld)", ldif_export_database },
70 { "mutt", "mutt alias", mutt_alias_export },
71 { "html", "html document", html_export_database },
72 { "pine", "pine addressbook", pine_export_database },
73 { "gcrd", "GnomeCard (VCard) addressbook", gcrd_export_database },
74 { "csv", "comma separated values", csv_export_database },
75 { "elm", "elm alias", elm_alias_export },
76 { "text", "plain text", text_export_database },
77 { "spruce", "Spruce address book", spruce_export_database },
91 for(i=0; *i_filters[i].filtname ; i++)
92 printf("\t%s\t%s\n", i_filters[i].filtname,
98 for(i=0; *e_filters[i].filtname ; i++)
99 printf("\t%s\t%s\n", e_filters[i].filtname,
106 number_of_output_filters()
110 for(i=0; *e_filters[i].filtname ; i++)
117 number_of_input_filters()
121 for(i=0; *i_filters[i].filtname ; i++)
130 char *username = getenv("USER");
131 struct passwd *pwent;
135 pwent = getpwnam(username);
137 if( (tmp = malloc(strlen(pwent->pw_gecos) +1)) == NULL)
138 return strdup(username);
140 rtn = sscanf(pwent->pw_gecos, "%[^,]", tmp);
141 if (rtn == EOF || rtn == 0) {
143 return strdup(username);
152 static int i_read_file(char *filename, int (*func) (FILE *in));
161 refresh_statusline();
162 headerline("import database");
164 mvaddstr(3, 1, "please select a filter");
167 for(i=0; *i_filters[i].filtname ; i++)
168 mvprintw(5 + i, 6, "%c -\t%s\t%s\n", 'a' + i,
169 i_filters[i].filtname,
172 mvprintw(6 + i, 6, "x -\tcancel");
184 filter = getch() - 'a';
185 if(filter == 'x' - 'a' ||
186 filter >= number_of_input_filters() || filter < 0) {
191 mvaddstr(5+filter, 2, "->");
193 filename = ask_filename("Filename: ", 1);
199 if( i_read_file(filename, i_filters[filter].func ) )
200 statusline_msg("Error occured while opening the file");
203 statusline_msg("Hmm.., file seems not to be a valid file");
214 i_read_file(char *filename, int (*func) (FILE *in))
219 if( ( in = fopen( filename, "r" ) ) == NULL )
230 import(char filtname[FILTNAME_LEN], char *filename)
237 if( ! strncmp(i_filters[i].filtname, filtname, FILTNAME_LEN) )
239 if( ! *i_filters[i].filtname ) {
248 if( !strcmp(filename, "-") )
249 ret = (*i_filters[i].func) (stdin);
251 ret = i_read_file(filename, i_filters[i].func);
263 static int e_write_file(char *filename,
264 int (*func) (FILE *in, struct db_enumerator e), int mode);
274 refresh_statusline();
275 headerline("export database");
277 mvaddstr(3, 1, "please select a filter");
280 for(i=0; *e_filters[i].filtname ; i++)
281 mvprintw(5 + i, 6, "%c -\t%s\t%s\n", 'a' + i,
282 e_filters[i].filtname,
285 mvprintw(6 + i, 6, "x -\tcancel");
292 int enum_mode = ENUM_ALL;
297 filter = getch() - 'a';
298 if(filter == 'x' - 'a' ||
299 filter >= number_of_output_filters(e_filters) || filter < 0) {
304 mvaddstr(5+filter, 2, "->");
306 if( selected_items() ) {
307 statusline_addstr("Export All/Selected/Cancel (A/s/c)");
308 switch( tolower(getch()) ) {
310 enum_mode = ENUM_SELECTED;
319 filename = ask_filename("Filename: ", 0);
325 if( e_write_file(filename, e_filters[filter].func, enum_mode ) )
326 statusline_msg("Error occured while exporting");
335 e_write_file(char *filename, int (*func) (FILE *in, struct db_enumerator e),
340 struct db_enumerator enumerator = init_db_enumerator(mode);
342 if( (out = fopen(filename, "a")) == NULL )
348 ret = (*func) (out, enumerator);
356 fexport(char filtname[FILTNAME_LEN], FILE *handle, int enum_mode)
359 struct db_enumerator e = init_db_enumerator(enum_mode);
362 if( ! strncmp(e_filters[i].filtname, filtname, FILTNAME_LEN) )
364 if( ! *e_filters[i].filtname ) {
370 return (e_filters[i].func) (handle, e);
376 export(char filtname[FILTNAME_LEN], char *filename)
378 const int mode = ENUM_ALL;
381 struct db_enumerator e = init_db_enumerator(mode);
384 if( ! strncmp(e_filters[i].filtname, filtname, FILTNAME_LEN) )
386 if( ! *e_filters[i].filtname ) {
395 if( !strcmp(filename, "-") )
396 ret = (e_filters[i].func) (stdout, e);
398 ret = e_write_file(filename, e_filters[i].func, mode);
404 * end of common functions
413 static void ldif_fix_string(char *str);
416 # define LINESIZE 1024
419 #define LDIF_ITEM_FIELDS 15
421 typedef char* ldif_item[LDIF_ITEM_FIELDS];
423 static ldif_item ldif_field_names = {
434 "facsimiletelephonenumber",
438 "objectclass", /* this must be the last entry */
441 static int ldif_conv_table[LDIF_ITEM_FIELDS] = {
444 ADDRESS, /* "streetaddress" */
445 CITY, /* "locality" */
447 ZIP, /* "postalcode" */
448 COUNTRY, /* "countryname" */
449 PHONE, /* "homephone" */
450 NOTES, /* "description" */
452 FAX, /* "facsimiletelephonenumber" */
453 MOBILEPHONE, /* "cellphone" */
454 WORKPHONE, /* "xmozillaanyphone" */
455 NICK, /* "xmozillanickname" */
456 -1, /* "objectclass" */ /* this must be the last entry */
461 ldif_read_line(FILE *in)
471 fgets(line, LINESIZE, in);
482 fseek(in, pos, SEEK_SET);
491 buf = strconcat(buf, ptr, NULL);
502 for(i=0,j=0; j < strlen(buf); i++, j++)
503 buf[i] = buf[j] == '\n' ? buf[++j] : buf[j];
510 ldif_add_item(ldif_item ldif_item)
512 list_item abook_item;
515 memset(abook_item, 0, sizeof(abook_item));
517 if( !ldif_item[LDIF_ITEM_FIELDS -1] )
521 for(i=0; i < LDIF_ITEM_FIELDS; i++) {
522 if(ldif_conv_table[i] >= 0 && ldif_item[i] && *ldif_item[i] )
523 abook_item[ldif_conv_table[i]] = strdup(ldif_item[i]);
526 add_item2database(abook_item);
529 for(i=0; i < LDIF_ITEM_FIELDS; i++)
530 my_free(ldif_item[i]);
535 ldif_convert(ldif_item item, char *type, char *value)
539 if( !strcmp(type, "dn") ) {
544 for(i=0; i < LDIF_ITEM_FIELDS; i++) {
545 if( !safe_strcmp(ldif_field_names[i], type) && *value ) {
546 if( i == LDIF_ITEM_FIELDS -1) /* this is a dirty hack */
547 if( safe_strcmp("person", value))
551 item[i] = strdup(value);
557 ldif_parse_file(FILE *handle)
564 memset(item, 0, sizeof(item));
567 if( ! (line = ldif_read_line(handle)) )
570 if( -1 == ( str_parse_line(line, &type, &value, &vlen)) ) {
572 continue; /* just skip the errors */
575 ldif_fix_string(value);
577 ldif_convert(item, type, value);
580 } while ( !feof(handle) );
582 ldif_convert(item, "dn", "");
588 ldif_fix_string(char *str)
592 for( i = 0, j = 0; j < strlen(str); i++, j++)
593 str[i] = ( str[j] == (char)0xc3 ?
594 (char) str[++j] + (char) 0x40 :
605 * mutt alias import filter
615 remove_newlines(char *buf)
619 for(i=0,j=0; j < strlen(buf); i++, j++)
620 buf[i] = buf[j] == '\n' ? buf[++j] : buf[j];
624 mutt_read_line(FILE *in, char **alias, char **rest)
627 char *ptr=(char *)&line;
630 fgets(line, LINESIZE, in);
631 remove_newlines(line);
633 while( ISSPACE(*ptr) )
636 if( strncmp("alias", ptr, 5) ) {
642 while( ISSPACE(*ptr) )
647 while( ! ISSPACE(*ptr) )
650 if( (*alias = malloc(ptr-tmp+1)) == NULL)
653 strncpy(*alias, tmp, ptr-tmp);
654 *(*alias+(ptr-tmp)) = 0;
656 while( ISSPACE(*ptr) )
665 mutt_parse_email(char *mutt_item[3])
670 if( (tmp = strchr(mutt_item[MUTT_NAME], '<')) )
675 mutt_item[MUTT_EMAIL] = strdup(tmp+1);
677 if( (tmp = strchr(mutt_item[MUTT_EMAIL], '>')) )
680 tmp = mutt_item[MUTT_NAME];
682 for(i=strlen(tmp)-1; i>0; i--)
688 mutt_item[MUTT_NAME] = strdup(tmp);
694 mutt_add_mutt_item(char *mutt_item[3])
696 list_item abook_item;
698 memset(abook_item, 0, sizeof(abook_item));
700 abook_item[NAME] = safe_strdup(mutt_item[MUTT_NAME]);
701 abook_item[EMAIL] = safe_strdup(mutt_item[MUTT_EMAIL]);
702 abook_item[NICK] = safe_strdup(mutt_item[MUTT_ALIAS]);
704 add_item2database(abook_item);
708 mutt_parse_file(FILE *in)
714 memset(mutt_item, 0, sizeof(mutt_item) );
716 if( mutt_read_line(in, &mutt_item[MUTT_ALIAS],
717 &mutt_item[MUTT_NAME]) )
720 mutt_parse_email(mutt_item);
723 free(mutt_item[MUTT_ALIAS]);
724 free(mutt_item[MUTT_NAME]);
725 free(mutt_item[MUTT_EMAIL]);
729 mutt_add_mutt_item(mutt_item);
731 free(mutt_item[MUTT_ALIAS]);
732 free(mutt_item[MUTT_NAME]);
733 free(mutt_item[MUTT_EMAIL]);
741 * end of mutt alias import filter
750 ldif_fput_type_and_value(FILE *out,char *type, char *value )
754 tmp = ldif_type_and_value(type, value, strlen(value));
762 ldif_export_database(FILE *out, struct db_enumerator e)
764 char email[MAX_EMAILSTR_LEN];
766 fprintf(out, "version: 1\n");
768 db_enumerate_items(e) {
771 get_first_email(email, e.item);
773 tmp = mkstr("cn=%s,mail=%s", database[e.item][NAME], email);
774 ldif_fput_type_and_value(out, "dn", tmp);
777 for(j=0; j < LDIF_ITEM_FIELDS; j++) {
778 if(ldif_conv_table[j] >= 0) {
779 if(ldif_conv_table[j] == EMAIL)
780 ldif_fput_type_and_value(out,
781 ldif_field_names[j], email);
782 else if(database[e.item][ldif_conv_table[j]])
783 ldif_fput_type_and_value(out,
785 database[e.item][ldif_conv_table[j]]);
789 fprintf(out, "objectclass: top\n"
790 "objectclass: person\n\n");
797 * end of ldif export filter
804 static void html_export_write_head(FILE *out, int extra_column);
805 static void html_export_write_tail(FILE *out);
808 html_export_database(FILE *out, struct db_enumerator e)
810 char tmp[MAX_EMAILSTR_LEN];
811 int extra_column = options_get_int("extra_column");
816 extra_column = (extra_column > 2 && extra_column < ITEM_FIELDS) ?
817 extra_column : PHONE;
819 html_export_write_head(out, extra_column);
821 db_enumerate_items(e) {
822 get_first_email(tmp, e.item);
823 fprintf(out, "<tr>\n<td><a href=\"mailto:%s\">%s</a>\n",
825 database[e.item][NAME] );
827 fprintf(out, "<td>%s\n<td>%s\n",
828 database[e.item][EMAIL],
829 safe_str(database[e.item][extra_column]) );
830 fprintf(out, "</tr>\n\n");
833 html_export_write_tail(out);
840 html_export_write_head(FILE *out, int extra_column)
842 char *realname = get_real_name();
844 fprintf(out, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n");
845 fprintf(out, "<html>\n<head>\n <title>%s's addressbook</title>",
847 fprintf(out, "\n</head>\n<body>\n");
848 fprintf(out, "\n<h2>%s's addressbook</h2>\n", realname );
849 fprintf(out, "<br><br>\n\n");
851 fprintf(out, "<center><table border>\n");
852 fprintf(out, "\n<tr><th>Name<th>E-mail address(es)<th>%s</tr>\n\n",
853 abook_fields[extra_column].name);
859 html_export_write_tail(FILE *out)
861 fprintf(out, "\n</table></center>\n");
862 fprintf(out, "\n</body>\n</html>\n");
866 * end of html export filter
871 * pine addressbook import filter
875 pine_fixbuf(char *buf)
879 for(i=0,j=0; j < strlen(buf); i++, j++)
880 buf[i] = buf[j] == '\n' ? buf[++j] : buf[j];
884 pine_convert_emails(char *s)
889 if( s == NULL || *s != '(' )
895 if( ( tmp = strchr(s,')')) )
898 for(i=1; ( tmp = strchr(s, ',') ) != NULL ; i++, s=tmp+1 )
907 pine_parse_buf(char *buf)
914 int pine_conv_table[]= {NICK, NAME, EMAIL, -1, NOTES};
916 memset(&item, 0, sizeof(item) );
918 for(i=0, last=0; !last ; i++) {
919 if( ! (end = strchr(start, '\t')) )
922 len = last ? strlen(start) : (int) (end-start);
923 len = min(len, 400-1);
925 if(i < sizeof(pine_conv_table) / sizeof(*pine_conv_table)
926 && pine_conv_table[i] >= 0) {
927 strncpy(tmp, start, len);
929 item[pine_conv_table[i]] = strdup(tmp);
934 pine_convert_emails(item[EMAIL]);
935 add_item2database(item);
939 #define LINESIZE 1024
942 pine_parse_file(FILE *in)
949 fgets(line, LINESIZE, in);
953 buf = realloc(buf, i*LINESIZE);
956 fgets(line, LINESIZE, in);
958 if(*ptr != ' ' || feof(in) )
961 while( *ptr == ' ') ptr++;
978 * end of pine addressbook import filter
983 * pine addressbook export filter
985 * filter doesn't wrap the lines as it should but Pine seems to handle
986 * created files without problems - JH
990 pine_export_database(FILE *out, struct db_enumerator e)
992 db_enumerate_items(e) {
993 fprintf(out, have_multiple_emails(e.item) ?
994 "%s\t%s\t(%s)\t\t%s\n" : "%s\t%s\t%s\t\t%s\n",
995 safe_str(database[e.item][NICK]),
996 safe_str(database[e.item][NAME]),
997 safe_str(database[e.item][EMAIL]),
998 safe_str(database[e.item][NOTES])
1006 * end of pine addressbook export filter
1011 * csv addressbook export filter
1015 csv_export_database(FILE *out, struct db_enumerator e)
1018 int csv_export_fields[] = {
1026 db_enumerate_items(e) {
1027 for(j = 0; csv_export_fields[j] >= 0; j++) {
1028 fprintf(out, strchr(safe_str(database[e.item][csv_export_fields[j]]), ',') ?
1030 safe_str(database[e.item][csv_export_fields[j]])
1032 if(csv_export_fields[j+1] >= 0)
1044 * end of csv export filter
1049 * GnomeCard (VCard) addressbook export filter
1053 gcrd_export_database(FILE *out, struct db_enumerator e)
1055 char emails[MAX_EMAILS][MAX_EMAIL_LEN];
1059 db_enumerate_items(e) {
1060 fprintf(out, "BEGIN:VCARD\nFN:%s\n",
1061 safe_str(database[e.item][NAME]));
1063 name = get_surname(database[e.item][NAME]);
1064 for( j = strlen(database[e.item][NAME]) - 1; j >= 0; j-- ) {
1065 if(database[e.item][NAME][j] == ' ')
1068 fprintf(out, "N:%s;%.*s\n",
1071 safe_str(database[e.item][NAME])
1076 if ( database[e.item][ADDRESS] )
1077 fprintf(out, "ADR:;;%s;%s;%s;%s;%s\n",
1078 safe_str(database[e.item][ADDRESS]),
1079 safe_str(database[e.item][CITY]),
1080 safe_str(database[e.item][STATE]),
1081 safe_str(database[e.item][ZIP]),
1082 safe_str(database[e.item][COUNTRY])
1085 if (database[e.item][PHONE])
1086 fprintf(out, "TEL;HOME:%s\n", database[e.item][PHONE]);
1087 if (database[e.item][WORKPHONE])
1088 fprintf(out, "TEL;WORK:%s\n", database[e.item][WORKPHONE]);
1089 if (database[e.item][FAX])
1090 fprintf(out, "TEL;FAX:%s\n", database[e.item][FAX]);
1091 if (database[e.item][MOBILEPHONE])
1092 fprintf(out, "TEL;CELL:%s\n", database[e.item][MOBILEPHONE]);
1094 if ( database[e.item][EMAIL] ) {
1095 split_emailstr(e.item, emails);
1096 for(j=0; j < MAX_EMAILS ; j++) {
1098 fprintf(out, "EMAIL;INTERNET:%s\n",
1103 if ( database[e.item][NOTES] )
1104 fprintf(out, "NOTE:%s\n", database[e.item][NOTES]);
1105 if (database[e.item][URL])
1106 fprintf(out, "URL:%s\n", database[e.item][URL]);
1108 fprintf(out, "END:VCARD\n\n");
1116 * end of GnomeCard export filter
1121 * mutt alias export filter
1125 mutt_alias_genalias(int i)
1129 if(database[i][NICK])
1130 return strdup(database[i][NICK]);
1132 tmp = strdup(database[i][NAME]);
1134 if( ( pos = strchr(tmp, ' ') ) )
1143 mutt_alias_export(FILE *out, struct db_enumerator e)
1145 char email[MAX_EMAIL_LEN];
1148 db_enumerate_items(e) {
1149 alias = mutt_alias_genalias(e.item);
1151 get_first_email(email, e.item);
1152 fprintf(out, *email ? "alias %s %s <%s>\n": "alias %s %s%s\n",
1154 database[e.item][NAME],
1163 * end of mutt alias export filter
1168 * printable export filter
1173 text_write_address_us(FILE *out, int i) {
1174 fprintf(out, "\n%s", database[i][ADDRESS]);
1176 if (database[i][CITY])
1177 fprintf(out, "\n%s", database[i][CITY]);
1179 if (database[i][STATE] || database[i][ZIP]) {
1182 if(database[i][STATE]) {
1183 fprintf(out, "%s", database[i][STATE]);
1184 if(database[i][ZIP])
1188 if(database[i][ZIP])
1189 fprintf(out, "%s", database[i][ZIP]);
1192 if (database[i][COUNTRY])
1193 fprintf(out, "\n%s", database[i][COUNTRY]);
1198 text_write_address_uk(FILE *out, int i) {
1201 for (j = ADDRESS; j <= COUNTRY; j++)
1203 fprintf(out, "\n%s", database[i][j]);
1207 text_write_address_eu(FILE *out, int i) {
1208 fprintf(out, "\n%s", database[i][ADDRESS]);
1210 if (database[i][ZIP] || database[i][CITY]) {
1213 if(database[i][ZIP]) {
1214 fprintf(out, "%s", database[i][ZIP]);
1215 if(database[i][CITY])
1219 if(database[i][CITY])
1220 fprintf(out, "%s", database[i][CITY]);
1222 fprintf(out, "\n%s %s",
1223 safe_str(database[i][ZIP]),
1224 safe_str(database[i] [CITY]));
1229 if (database[i][STATE])
1230 fprintf(out, "\n%s", database[i][STATE]);
1232 if (database[i][COUNTRY])
1233 fprintf(out, "\n%s", database[i][COUNTRY]);
1237 text_export_database(FILE * out, struct db_enumerator e)
1239 char emails[MAX_EMAILS][MAX_EMAIL_LEN];
1241 char *realname = get_real_name();
1242 char *style = options_get_str("address_style");
1245 "-----------------------------------------\n%s's address book\n"
1246 "-----------------------------------------\n\n\n",
1250 db_enumerate_items(e) {
1252 "-----------------------------------------\n\n");
1253 fprintf(out, "%s", database[e.item][NAME]);
1254 if (database[e.item][NICK])
1255 fprintf(out, "\n(%s)", database[e.item][NICK]);
1258 if (*database[e.item][EMAIL]) {
1260 split_emailstr(e.item, emails);
1261 for (j = 0; j < MAX_EMAILS; j++)
1263 fprintf(out, "%s\n", emails[j]);
1266 if (database[e.item][ADDRESS]) {
1267 if (!safe_strcmp(style, "us")) /* US like */
1268 text_write_address_us(out, e.item);
1269 else if (!safe_strcmp(style, "uk")) /* UK like */
1270 text_write_address_uk(out, e.item);
1272 text_write_address_eu(out, e.item);
1277 if ((database[e.item][PHONE]) ||
1278 (database[e.item][WORKPHONE]) ||
1279 (database[e.item][FAX]) ||
1280 (database[e.item][MOBILEPHONE])) {
1282 for (j = PHONE; j <= MOBILEPHONE; j++)
1283 if (database[e.item][j])
1284 fprintf(out, "%s: %s\n",
1285 abook_fields[j].name,
1286 database[e.item][j]);
1289 if (database[e.item][URL])
1290 fprintf(out, "\n%s\n", database[e.item][URL]);
1291 if (database[e.item][NOTES])
1292 fprintf(out, "\n%s\n", database[e.item][NOTES]);
1297 fprintf(out, "-----------------------------------------\n");
1303 * end of printable export filter
1307 * elm alias export filter
1311 elm_alias_export(FILE *out, struct db_enumerator e)
1313 char email[MAX_EMAIL_LEN];
1316 db_enumerate_items(e) {
1317 alias = mutt_alias_genalias(e.item);
1318 get_first_email(email, e.item);
1319 fprintf(out, "%s = %s = %s\n",
1321 database[e.item][NAME],
1330 * end of elm alias export filter
1335 * Spruce export filter
1339 spruce_export_database (FILE *out, struct db_enumerator e)
1341 char email[MAX_EMAIL_LEN];
1343 fprintf (out, "# This is a generated file made by abook for the Spruce e-mail client.\n\n");
1345 db_enumerate_items(e) {
1346 if(strcmp (safe_str(database[e.item][EMAIL]), "")) {
1347 get_first_email(email, e.item);
1348 fprintf(out, "# Address %d\nName: %s\nEmail: %s\nMemo: %s\n\n",
1350 database[e.item][NAME],
1352 safe_str(database[e.item][NOTES])
1357 fprintf (out, "# End of address book file.\n");
1363 * end of Spruce export filter