X-Git-Url: https://git.deb.at/?a=blobdiff_plain;f=filter.c;h=e1111e3724b9fb4874b011cf5a6376405586242a;hb=781c0d657fffe80e45d0fda6ed5ddbf5f796fefb;hp=4489839470e5b2eb6a9957c3a5d6a06ce083014c;hpb=12a57d9405d7910566d5ff888d743d29b0716554;p=pkg%2Fabook.git diff --git a/filter.c b/filter.c index 4489839..e1111e3 100644 --- a/filter.c +++ b/filter.c @@ -2,7 +2,7 @@ /* * $Id$ * - * by JH + * by JH * * Copyright (C) Jaakko Heinonen */ @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "abook_curses.h" #include "filter.h" @@ -21,6 +22,8 @@ #include "list.h" #include "misc.h" #include "options.h" +#include "xmalloc.h" +#include extern int items; extern list_item *database; @@ -30,30 +33,47 @@ extern struct abook_field abook_fields[]; * function declarations */ +/* + * import filter prototypes + */ + static int ldif_parse_file(FILE *handle); static int mutt_parse_file(FILE *in); static int pine_parse_file(FILE *in); +static int csv_parse_file(FILE *in); +static int allcsv_parse_file(FILE *in); + +/* + * export filter prototypes + */ -static int ldif_export_database(FILE *out); -static int html_export_database(FILE *out); -static int pine_export_database(FILE *out); -static int csv_export_database(FILE *out); -static int gcrd_export_database(FILE *out); -static int mutt_alias_export(FILE *out); -static int elm_alias_export(FILE *out); -static int text_export_database(FILE *out); -static int spruce_export_database(FILE *out); +static int ldif_export_database(FILE *out, struct db_enumerator e); +static int html_export_database(FILE *out, struct db_enumerator e); +static int pine_export_database(FILE *out, struct db_enumerator e); +static int csv_export_database(FILE *out, struct db_enumerator e); +static int allcsv_export_database(FILE *out, struct db_enumerator e); +static int palm_export_database(FILE *out, struct db_enumerator e); +static int gcrd_export_database(FILE *out, struct db_enumerator e); +static int mutt_alias_export(FILE *out, struct db_enumerator e); +static int elm_alias_export(FILE *out, struct db_enumerator e); +static int text_export_database(FILE *out, struct db_enumerator e); +static int spruce_export_database(FILE *out, struct db_enumerator e); +/* + * end of function declarations + */ -struct abook_filter i_filters[] = { +struct abook_input_filter i_filters[] = { { "abook", "abook native format", parse_database }, { "ldif", "ldif / Netscape addressbook", ldif_parse_file }, - { "mutt", "mutt alias (beta)", mutt_parse_file }, + { "mutt", "mutt alias", mutt_parse_file }, { "pine", "pine addressbook", pine_parse_file }, + { "csv", "comma separated values", csv_parse_file }, + { "allcsv", "comma separated all values", allcsv_parse_file }, { "\0", NULL, NULL } }; -struct abook_filter e_filters[] = { +struct abook_output_filter e_filters[] = { { "abook", "abook native format", write_database }, { "ldif", "ldif / Netscape addressbook (.4ld)", ldif_export_database }, { "mutt", "mutt alias", mutt_alias_export }, @@ -61,6 +81,8 @@ struct abook_filter e_filters[] = { { "pine", "pine addressbook", pine_export_database }, { "gcrd", "GnomeCard (VCard) addressbook", gcrd_export_database }, { "csv", "comma separated values", csv_export_database }, + { "allcsv", "comma separated all values", allcsv_export_database }, + { "palmcsv", "Palm comma separated values", palm_export_database}, { "elm", "elm alias", elm_alias_export }, { "text", "plain text", text_export_database }, { "spruce", "Spruce address book", spruce_export_database }, @@ -75,14 +97,14 @@ void print_filters() { int i; - + puts("input:"); for(i=0; *i_filters[i].filtname ; i++) printf("\t%s\t%s\n", i_filters[i].filtname, i_filters[i].desc); putchar('\n'); - + puts("output:"); for(i=0; *e_filters[i].filtname ; i++) printf("\t%s\t%s\n", e_filters[i].filtname, @@ -92,11 +114,22 @@ print_filters() } static int -number_of_filters(struct abook_filter * filters) +number_of_output_filters() { int i; - for(i=0; *filters[i].filtname ; i++) + for(i=0; *e_filters[i].filtname ; i++) + ; + + return i; +} + +static int +number_of_input_filters() +{ + int i; + + for(i=0; *i_filters[i].filtname ; i++) ; return i; @@ -112,13 +145,13 @@ get_real_name() pwent = getpwnam(username); - if( (tmp = malloc(strlen(pwent->pw_gecos) +1)) == NULL) - return strdup(username); + if((tmp = xstrdup(pwent->pw_gecos)) == NULL) + return xstrdup(username); rtn = sscanf(pwent->pw_gecos, "%[^,]", tmp); if (rtn == EOF || rtn == 0) { free(tmp); - return strdup(username); + return xstrdup(username); } else return tmp; } @@ -126,21 +159,21 @@ get_real_name() /* * import */ - + static int i_read_file(char *filename, int (*func) (FILE *in)); static void import_screen() { int i; - + clear(); refresh_statusline(); headerline("import database"); mvaddstr(3, 1, "please select a filter"); - + for(i=0; *i_filters[i].filtname ; i++) mvprintw(5 + i, 6, "%c -\t%s\t%s\n", 'a' + i, @@ -158,28 +191,27 @@ import_database() int tmp = items; import_screen(); - + filter = getch() - 'a'; - if(filter == 'x' - 'a' || filter >= number_of_filters(e_filters) || - filter < 0) { + if(filter == 'x' - 'a' || + filter >= number_of_input_filters() || filter < 0) { refresh_screen(); return 1; } - + mvaddstr(5+filter, 2, "->"); - - filename = ask_filename("Filename: ", 1); + + filename = ask_filename("Filename: "); if( !filename ) { refresh_screen(); return 2; } - + if( i_read_file(filename, i_filters[filter].func ) ) statusline_msg("Error occured while opening the file"); - else - if( tmp == items ) + else if( tmp == items ) statusline_msg("Hmm.., file seems not to be a valid file"); - + refresh_screen(); free(filename); @@ -194,25 +226,26 @@ i_read_file(char *filename, int (*func) (FILE *in)) FILE *in; int ret = 0; - if( ( in = fopen( filename, "r" ) ) == NULL ) + if( ( in = abook_fopen( filename, "r" ) ) == NULL ) return 1; ret = (*func) (in); fclose(in); - return ret; + return ret; } int -import(char filtname[FILTNAME_LEN], char *filename) +import_file(char filtname[FILTNAME_LEN], char *filename) { int i; int tmp = items; int ret = 0; for(i=0;; i++) { - if( ! strncmp(i_filters[i].filtname, filtname, FILTNAME_LEN) ) + if( ! strncasecmp(i_filters[i].filtname, filtname, + FILTNAME_LEN) ) break; if( ! *i_filters[i].filtname ) { i = -1; @@ -223,14 +256,18 @@ import(char filtname[FILTNAME_LEN], char *filename) if( i<0 ) return -1; - if( !strcmp(filename, "-") ) - ret = (*i_filters[i].func) (stdin); - else + if( !strcmp(filename, "-") ) { + struct stat s; + if( (fstat(fileno(stdin), &s)) == -1 || S_ISDIR(s.st_mode)) + ret = 1; + else + ret = (*i_filters[i].func) (stdin); + } else ret = i_read_file(filename, i_filters[i].func); - + if( tmp == items ) ret = 1; - + return ret; } @@ -238,13 +275,14 @@ import(char filtname[FILTNAME_LEN], char *filename) * export */ -static int e_write_file(char *filename, int (*func) (FILE *in)); +static int e_write_file(char *filename, + int (*func) (FILE *in, struct db_enumerator e), int mode); static void export_screen() { int i; - + clear(); @@ -252,7 +290,7 @@ export_screen() headerline("export database"); mvaddstr(3, 1, "please select a filter"); - + for(i=0; *e_filters[i].filtname ; i++) mvprintw(5 + i, 6, "%c -\t%s\t%s\n", 'a' + i, @@ -266,28 +304,42 @@ int export_database() { int filter; + int enum_mode = ENUM_ALL; char *filename; export_screen(); - + filter = getch() - 'a'; - if(filter == 'x' - 'a' || filter >= number_of_filters(e_filters) || - filter < 0) { + if(filter == 'x' - 'a' || + filter >= number_of_output_filters() || filter < 0) { refresh_screen(); return 1; } - + mvaddstr(5+filter, 2, "->"); - - filename = ask_filename("Filename: ", 0); + + if( selected_items() ) { + statusline_addstr("Export All/Selected/Cancel (A/s/c)"); + switch( tolower(getch()) ) { + case 's': + enum_mode = ENUM_SELECTED; + break; + case 'c': + clear_statusline(); + return 1; + } + clear_statusline(); + } + + filename = ask_filename("Filename: "); if( !filename ) { refresh_screen(); return 2; } - - if( e_write_file(filename, e_filters[filter].func ) ) + + if( e_write_file(filename, e_filters[filter].func, enum_mode ) ) statusline_msg("Error occured while exporting"); - + refresh_screen(); free(filename); @@ -295,10 +347,12 @@ export_database() } static int -e_write_file(char *filename, int (*func) (FILE *in)) +e_write_file(char *filename, int (*func) (FILE *in, struct db_enumerator e), + int mode) { FILE *out; int ret = 0; + struct db_enumerator enumerator = init_db_enumerator(mode); if( (out = fopen(filename, "a")) == NULL ) return 1; @@ -306,20 +360,22 @@ e_write_file(char *filename, int (*func) (FILE *in)) if( ftell(out) ) return 1; - ret = (*func) (out); - + ret = (*func) (out, enumerator); + fclose(out); - + return ret; } int -fexport(char filtname[FILTNAME_LEN], FILE *handle) +fexport(char filtname[FILTNAME_LEN], FILE *handle, int enum_mode) { int i; + struct db_enumerator e = init_db_enumerator(enum_mode); for(i=0;; i++) { - if( ! strncmp(e_filters[i].filtname, filtname, FILTNAME_LEN) ) + if( ! strncasecmp(e_filters[i].filtname, filtname, + FILTNAME_LEN) ) break; if( ! *e_filters[i].filtname ) { i = -1; @@ -327,19 +383,22 @@ fexport(char filtname[FILTNAME_LEN], FILE *handle) } } - return (e_filters[i].func) (handle); + return (e_filters[i].func) (handle, e); } - + int -export(char filtname[FILTNAME_LEN], char *filename) +export_file(char filtname[FILTNAME_LEN], char *filename) { + const int mode = ENUM_ALL; int i; int ret = 0; - + struct db_enumerator e = init_db_enumerator(mode); + for(i=0;; i++) { - if( ! strncmp(e_filters[i].filtname, filtname, FILTNAME_LEN) ) + if( ! strncasecmp(e_filters[i].filtname, filtname, + FILTNAME_LEN) ) break; if( ! *e_filters[i].filtname ) { i = -1; @@ -351,9 +410,9 @@ export(char filtname[FILTNAME_LEN], char *filename) return -1; if( !strcmp(filename, "-") ) - ret = (e_filters[i].func) (stdout); + ret = (e_filters[i].func) (stdout, e); else - ret = e_write_file(filename, e_filters[i].func); + ret = e_write_file(filename, e_filters[i].func, mode); return ret; } @@ -370,18 +429,15 @@ export(char filtname[FILTNAME_LEN], char *filename) static void ldif_fix_string(char *str); -#ifndef LINESIZE -# define LINESIZE 1024 -#endif - -#define LDIF_ITEM_FIELDS 15 +#define LDIF_ITEM_FIELDS 16 -typedef char* ldif_item[LDIF_ITEM_FIELDS]; +typedef char *ldif_item[LDIF_ITEM_FIELDS]; static ldif_item ldif_field_names = { - "cn", + "cn", "mail", "streetaddress", + "streetaddress2", "locality", "st", "postalcode", @@ -400,6 +456,7 @@ static int ldif_conv_table[LDIF_ITEM_FIELDS] = { NAME, /* "cn" */ EMAIL, /* "mail" */ ADDRESS, /* "streetaddress" */ + ADDRESS2, /* "streetaddress2" */ CITY, /* "locality" */ STATE, /* "st" */ ZIP, /* "postalcode" */ @@ -415,77 +472,74 @@ static int ldif_conv_table[LDIF_ITEM_FIELDS] = { }; -static char * +static char * ldif_read_line(FILE *in) { - char line[LINESIZE]; - char *buf=NULL; + char *buf = NULL; char *ptr, *tmp; long pos; int i; - for(i=1;;i++) { + for(i = 1;;i++) { + char *line; + pos = ftell(in); - fgets(line, LINESIZE, in); - - if( feof(in) ) + line = getaline(in); + + if( feof(in) || !line ) break; - + if(i == 1) { - buf = strdup(line); + buf = line; continue; } - + if(*line != ' ') { - fseek(in, pos, SEEK_SET); + fseek(in, pos, SEEK_SET); /* fixme ! */ + free(line); break; } - ptr = (char *)&line; + ptr = line; while( *ptr == ' ') ptr++; tmp = buf; buf = strconcat(buf, ptr, NULL); free(tmp); + free(line); } - if( *buf == '#' ) { + if(buf && *buf == '#' ) { free(buf); return NULL; } - - if(buf) { - int i,j; - for(i=0,j=0; j < strlen(buf); i++, j++) - buf[i] = buf[j] == '\n' ? buf[++j] : buf[j]; - } return buf; } static void -ldif_add_item(ldif_item ldif_item) +ldif_add_item(ldif_item li) { list_item abook_item; int i; memset(abook_item, 0, sizeof(abook_item)); - - if( !ldif_item[LDIF_ITEM_FIELDS -1] ) + + if(!li[LDIF_ITEM_FIELDS -1] ) goto bail_out; - + for(i=0; i < LDIF_ITEM_FIELDS; i++) { - if(ldif_conv_table[i] >= 0 && ldif_item[i] && *ldif_item[i] ) - abook_item[ldif_conv_table[i]] = strdup(ldif_item[i]); + if(ldif_conv_table[i] >= 0 && li[i] && *li[i] ) + abook_item[ldif_conv_table[i]] = xstrdup(li[i]); } add_item2database(abook_item); bail_out: for(i=0; i < LDIF_ITEM_FIELDS; i++) - my_free(ldif_item[i]); + xfree(li[i]); } @@ -505,8 +559,8 @@ ldif_convert(ldif_item item, char *type, char *value) if( safe_strcmp("person", value)) break; if(item[i]) - my_free(item[i]); - item[i] = strdup(value); + xfree(item[i]); + item[i] = xstrdup(value); } } } @@ -526,15 +580,15 @@ ldif_parse_file(FILE *handle) continue; if( -1 == ( str_parse_line(line, &type, &value, &vlen)) ) { - my_free(line); + xfree(line); continue; /* just skip the errors */ } - + ldif_fix_string(value); ldif_convert(item, type, value); - my_free(line); + xfree(line); } while ( !feof(handle) ); ldif_convert(item, "dn", ""); @@ -547,7 +601,7 @@ ldif_fix_string(char *str) { int i, j; - for( i = 0, j = 0; j < strlen(str); i++, j++) + for( i = 0, j = 0; j < (int)strlen(str); i++, j++) str[i] = ( str[j] == (char)0xc3 ? (char) str[++j] + (char) 0x40 : str[j] ); @@ -563,38 +617,25 @@ ldif_fix_string(char *str) * mutt alias import filter */ -enum { - MUTT_ALIAS, - MUTT_NAME, - MUTT_EMAIL -}; - -static void -remove_newlines(char *buf) -{ - int i,j; - - for(i=0,j=0; j < strlen(buf); i++, j++) - buf[i] = buf[j] == '\n' ? buf[++j] : buf[j]; -} +#include "getname.h" static int mutt_read_line(FILE *in, char **alias, char **rest) { - char line[LINESIZE]; - char *ptr=(char *)&line; - char *tmp; + char *line, *ptr, *tmp; + size_t alias_len; - fgets(line, LINESIZE, in); - remove_newlines(line); + if( !(line = ptr = getaline(in)) ) + return 1; /* error / EOF */ while( ISSPACE(*ptr) ) ptr++; if( strncmp("alias", ptr, 5) ) { + free(line); return 1; } - + ptr += 5; while( ISSPACE(*ptr) ) @@ -605,93 +646,109 @@ mutt_read_line(FILE *in, char **alias, char **rest) while( ! ISSPACE(*ptr) ) ptr++; - if( (*alias = malloc(ptr-tmp+1)) == NULL) - return 1; + alias_len = (size_t)(ptr - tmp); - strncpy(*alias, tmp, ptr-tmp); - *(*alias+(ptr-tmp)) = 0; + *alias = xmalloc_inc(alias_len, 1); - while( ISSPACE(*ptr) ) + strncpy(*alias, tmp, alias_len); + *(*alias + alias_len) = 0; + + while(ISSPACE(*ptr)) ptr++; - *rest = strdup(ptr); - + *rest = xstrdup(ptr); + + free(line); return 0; } static void -mutt_parse_email(char *mutt_item[3]) +mutt_fix_quoting(char *p) { - char *tmp; - int i; - - if( (tmp = strchr(mutt_item[MUTT_NAME], '<')) ) - *tmp = 0; - else - return; - - mutt_item[MUTT_EMAIL] = strdup(tmp+1); - - if( (tmp = strchr(mutt_item[MUTT_EMAIL], '>')) ) - *tmp = 0; - - tmp = mutt_item[MUTT_NAME]; - - for(i=strlen(tmp)-1; i>0; i--) - if(ISSPACE(tmp[i])) - tmp[i] = 0; - else - break; + char *escape = 0; - mutt_item[MUTT_NAME] = strdup(tmp); - - free(tmp); + for(; *p; p++) { + switch(*p) { + case '\"': + if(escape) + *escape = ' '; + break; + case '\\': + escape = p; + break; + default: + escape = 0; + } + } } static void -mutt_add_mutt_item(char *mutt_item[3]) +mutt_parse_email(list_item item) { - list_item abook_item; + char *line = item[NAME]; + char *tmp; + char *name, *email; +#if 0 + char *start = line; + int i = 0; +#endif - memset(abook_item, 0, sizeof(abook_item)); + mutt_fix_quoting(line); + tmp = strconcat("From: ", line, NULL); + getname(tmp, &name, &email); + free(tmp); - abook_item[NAME] = safe_strdup(mutt_item[MUTT_NAME]); - abook_item[EMAIL] = safe_strdup(mutt_item[MUTT_EMAIL]); - abook_item[NICK] = safe_strdup(mutt_item[MUTT_ALIAS]); + if(name) + item[NAME] = name; + else + return; + if(email) + item[EMAIL] = email; + else + return; - add_item2database(abook_item); + /* + * this is completely broken + */ +#if 0 + while( (start = strchr(start, ',')) && i++ < MAX_EMAILS - 1) { + tmp = strconcat("From: ", ++start, NULL); + getname(tmp, &name, &email); + free(tmp); + free(name); + if(email) { + if(*email) { + tmp = strconcat(item[EMAIL], ",", email, NULL); + free(item[EMAIL]); + item[EMAIL] = tmp; + } else { + xfree(email); + } + } + } +#endif } static int mutt_parse_file(FILE *in) { - char *mutt_item[3]; + list_item item; for(;;) { + memset(item, 0, sizeof(item)); - memset(mutt_item, 0, sizeof(mutt_item) ); - - if( mutt_read_line(in, &mutt_item[MUTT_ALIAS], - &mutt_item[MUTT_NAME]) ) - continue; - - mutt_parse_email(mutt_item); + if( !mutt_read_line(in, &item[NICK], + &item[NAME]) ) + mutt_parse_email(item); if( feof(in) ) { - free(mutt_item[MUTT_ALIAS]); - free(mutt_item[MUTT_NAME]); - free(mutt_item[MUTT_EMAIL]); + free_list_item(item); break; } - mutt_add_mutt_item(mutt_item); - - free(mutt_item[MUTT_ALIAS]); - free(mutt_item[MUTT_NAME]); - free(mutt_item[MUTT_EMAIL]); + add_item2database(item); } - return 0; } @@ -699,6 +756,7 @@ mutt_parse_file(FILE *in) * end of mutt alias import filter */ + /* * ldif export filter */ @@ -716,18 +774,18 @@ ldif_fput_type_and_value(FILE *out,char *type, char *value ) } static int -ldif_export_database(FILE *out) +ldif_export_database(FILE *out, struct db_enumerator e) { - int i; char email[MAX_EMAILSTR_LEN]; fprintf(out, "version: 1\n"); - for(i=0; i\n%s\n", - tmp, - database[i][NAME] ); - + + db_enumerate_items(e) { + get_first_email(tmp, e.item); + if (*tmp) + fprintf(out, "\n%s\n", + tmp, + database[e.item][NAME] ); + else + fprintf(out, "\n%s\n", + database[e.item][NAME] ); + fprintf(out, "%s\n%s\n", - database[i][EMAIL], - safe_str(database[i][extra_column]) ); + database[e.item][EMAIL], + safe_str(database[e.item][extra_column]) ); fprintf(out, "\n\n"); } + html_export_write_tail(out); return 0; @@ -797,13 +861,13 @@ html_export_write_head(FILE *out, int extra_column) { char *realname = get_real_name(); - fprintf(out, "\n\n %s's addressbook", - realname ); + fprintf(out, "\n"); + fprintf(out, "\n\n %s's addressbook", realname ); fprintf(out, "\n\n\n"); fprintf(out, "\n

%s's addressbook

\n", realname ); fprintf(out, "

\n\n"); - fprintf(out, "
\n"); + fprintf(out, "
\n"); fprintf(out, "\n\n\n", abook_fields[extra_column].name); @@ -813,24 +877,27 @@ html_export_write_head(FILE *out, int extra_column) static void html_export_write_tail(FILE *out) { - fprintf(out, "\n
NameE-mail address(es)%s
\n"); + fprintf(out, "\n\n"); fprintf(out, "\n\n\n"); } - + /* * end of html export filter */ + /* * pine addressbook import filter */ +#define PINE_BUF_SIZE 2048 + static void pine_fixbuf(char *buf) { int i,j; - for(i=0,j=0; j < strlen(buf); i++, j++) + for(i=0,j=0; j < (int)strlen(buf); i++, j++) buf[i] = buf[j] == '\n' ? buf[++j] : buf[j]; } @@ -848,11 +915,11 @@ pine_convert_emails(char *s) if( ( tmp = strchr(s,')')) ) *tmp=0; - + for(i=1; ( tmp = strchr(s, ',') ) != NULL ; i++, s=tmp+1 ) - if( i > 3 ) { + if( i > MAX_EMAILS - 1 ) { *tmp = 0; - break; + break; } } @@ -863,32 +930,33 @@ pine_parse_buf(char *buf) list_item item; char *start = buf; char *end; - char tmp[400]; + char tmp[PINE_BUF_SIZE]; int i, len, last; int pine_conv_table[]= {NICK, NAME, EMAIL, -1, NOTES}; - memset(&item, 0, sizeof(item) ); - + memset(&item, 0, sizeof(item)); + for(i=0, last=0; !last ; i++) { if( ! (end = strchr(start, '\t')) ) last=1; - + len = last ? strlen(start) : (int) (end-start); - len = min(len, 400-1); - - if(i < sizeof(pine_conv_table) / sizeof(*pine_conv_table) + len = min(len, PINE_BUF_SIZE - 1); + + if(i < (int)(sizeof(pine_conv_table) / sizeof(*pine_conv_table)) && pine_conv_table[i] >= 0) { strncpy(tmp, start, len); tmp[len] = 0; - item[pine_conv_table[i]] = strdup(tmp); + if(*tmp) + item[pine_conv_table[i]] = xstrdup(tmp); } start = end + 1; } - + pine_convert_emails(item[EMAIL]); add_item2database(item); } - + #define LINESIZE 1024 @@ -896,33 +964,36 @@ static int pine_parse_file(FILE *in) { char line[LINESIZE]; - char *buf=NULL; + char *buf = NULL; char *ptr; int i; - fgets(line, LINESIZE, in); - + fgets(line, LINESIZE, in); + while(!feof(in)) { - for(i=2;;i++) { - buf = realloc(buf, i*LINESIZE); - if(i==2) + for(i = 2;;i++) { + buf = xrealloc(buf, i*LINESIZE); + if(i == 2) strcpy(buf, line); fgets(line, LINESIZE, in); ptr=(char *)&line; if(*ptr != ' ' || feof(in) ) break; else - while( *ptr == ' ') ptr++; - + while( *ptr == ' ') + ptr++; + strcat(buf, ptr); } - if( *buf == '#' ) + if( *buf == '#' ) { + xfree(buf); continue; + } pine_fixbuf(buf); pine_parse_buf(buf); - my_free(buf); + xfree(buf); } return 0; @@ -932,6 +1003,7 @@ pine_parse_file(FILE *in) * end of pine addressbook import filter */ + /* * pine addressbook export filter * @@ -940,17 +1012,15 @@ pine_parse_file(FILE *in) */ static int -pine_export_database(FILE *out) +pine_export_database(FILE *out, struct db_enumerator e) { - int i; - - for(i=0; i < items; i++ ) { - fprintf(out, have_multiple_emails(i) ? + db_enumerate_items(e) { + fprintf(out, have_multiple_emails(e.item) ? "%s\t%s\t(%s)\t\t%s\n" : "%s\t%s\t%s\t\t%s\n", - safe_str(database[i][NICK]), - safe_str(database[i][NAME]), - safe_str(database[i][EMAIL]), - safe_str(database[i][NOTES]) + safe_str(database[e.item][NICK]), + safe_str(database[e.item][NAME]), + safe_str(database[e.item][EMAIL]), + safe_str(database[e.item][NOTES]) ); } @@ -963,105 +1033,529 @@ pine_export_database(FILE *out) /* - * csv addressbook export filter + * csv import filter + */ + +/* FIXME + * these files should be parsed according to a certain + * lay out, or the default if layout is not given, at + * the moment only default is done... */ +#define CSV_COMMENT_CHAR '#' + +static int csv_conv_table[] = { + NAME, + EMAIL, + PHONE, + NOTES, + NICK +}; + +static int allcsv_conv_table[] = { + NAME, + EMAIL, + ADDRESS, + ADDRESS2, + CITY, + STATE, + ZIP, + COUNTRY, + PHONE, + WORKPHONE, + FAX, + MOBILEPHONE, + NICK, + URL, + NOTES, + CUSTOM1, + CUSTOM2, + CUSTOM3, + CUSTOM4, + CUSTOM5, +}; + +static void +csv_convert_emails(char *s) +{ + int i; + char *tmp; + + if( s == NULL ) + return; + + for(i=1; ( tmp = strchr(s, ',') ) != NULL ; i++, s = tmp + 1 ) + if( i > MAX_EMAILS - 1 ) { + *tmp = 0; + break; + } + +} + +static char * +csv_remove_quotes(char *s) +{ + char *copy, *trimmed; + int len; + + copy = trimmed = xstrdup(s); + strtrim(trimmed); + + len = strlen(trimmed); + if(trimmed[len - 1] == '\"' && *trimmed == '\"') { + if(len < 3) { + xfree(copy); + return NULL; + } + trimmed[len - 1] = 0; + trimmed++; + trimmed = xstrdup(trimmed); + free(copy); + return trimmed; + } + + xfree(copy); + return xstrdup(s); +} + +static void +csv_store_field(list_item item, char *s, int field) +{ + char *newstr = NULL; + + if(!s || !*s) + return; + + if( !(newstr = csv_remove_quotes(s)) ) + return; + + if(field < (int)(sizeof(csv_conv_table) / sizeof(*csv_conv_table)) + && csv_conv_table[field] >= 0) { + item[csv_conv_table[field]] = newstr; + } else { + xfree(newstr); + } +} + +static void +allcsv_store_field(list_item item, char *s, int field) +{ + char *newstr = NULL; + + if(!s || !*s) + return; + + if( !(newstr = csv_remove_quotes(s)) ) + return; + + if(field < (int)(sizeof(allcsv_conv_table) / sizeof(*allcsv_conv_table)) + && allcsv_conv_table[field] >= 0) { + item[allcsv_conv_table[field]] = newstr; + } else { + xfree(newstr); + } +} + static int -csv_export_database(FILE *out) +csv_is_valid_quote_end(char *p) +{ + if(*p != '\"') + return FALSE; + + for(p++; *p; p++) { + if(*p == ',') + return TRUE; + else if(!ISSPACE(*p)) + return FALSE; + } + + return TRUE; +} + +static int +csv_is_valid_quote_start(char *p) +{ + for(; *p; p++) { + if(*p == '\"') + return TRUE; + else if(!ISSPACE(*p)) + return FALSE; + } + + return FALSE; +} + +static void +csv_parse_line(char *line) +{ + char *p, *start; + int field; + bool in_quote = FALSE; + list_item item; + + memset(item, 0, sizeof(item)); + + for(p = start = line, field = 0; *p; p++) { + if(in_quote) { + if(csv_is_valid_quote_end(p)) + in_quote = FALSE; + } else { + if ( (((p - start) / sizeof (char)) < 2 ) && + csv_is_valid_quote_start(p) ) + in_quote = TRUE; + } + + if( *p == ',' && !in_quote) { + *p = 0; + csv_store_field(item, start, field); + field++; + start = p + 1; + } + } + /* + * store last field + */ + csv_store_field(item, start, field); + + csv_convert_emails(item[EMAIL]); + add_item2database(item); +} + +static void +allcsv_parse_line(char *line) +{ + char *p, *start; + int field; + bool in_quote = FALSE; + list_item item; + + memset(item, 0, sizeof(item)); + + for(p = start = line, field = 0; *p; p++) { + if(in_quote) { + if(csv_is_valid_quote_end(p)) + in_quote = FALSE; + } else { + if ( (((p - start) / sizeof (char)) < 2 ) && + csv_is_valid_quote_start(p) ) + in_quote = TRUE; + } + + if( *p == ',' && !in_quote) { + *p = 0; + allcsv_store_field(item, start, field); + field++; + start = p + 1; + } + } + /* + * store last field + */ + allcsv_store_field(item, start, field); + + csv_convert_emails(item[EMAIL]); + add_item2database(item); +} + + +static int +csv_parse_file(FILE *in) +{ + char *line = NULL; + + while(!feof(in)) { + line = getaline(in); + + if(line && *line && *line != CSV_COMMENT_CHAR) + csv_parse_line(line); + + xfree(line); + } + + return 0; +} + +static int +allcsv_parse_file(FILE *in) +{ + char *line = NULL; + + while(!feof(in)) { + line = getaline(in); + + if(line && *line && *line != CSV_COMMENT_CHAR) + allcsv_parse_line(line); + + xfree(line); + } + + return 0; +} + +/* + * end of csv import filter + */ + +/* + * csv addressbook export filters + */ + +#define CSV_LAST (-1) +#define CSV_UNDEFINED (-2) +#define CSV_SPECIAL(X) (-3 - (X)) +#define CSV_IS_SPECIAL(X) ((X) <= -3) + +static int +csv_export_common(FILE *out, struct db_enumerator e, + int fields[], void (*special_func)(FILE *, int, int)) +{ + int i; + + db_enumerate_items(e) { + for(i = 0; fields[i] != CSV_LAST; i++) { + if(fields[i] == CSV_UNDEFINED) + fprintf(out, "\"\""); + else if(CSV_IS_SPECIAL(fields[i])) { + if(special_func) + (*special_func)(out, e.item, fields[i]); + } else + /*fprintf(out,( + strchr(safe_str(database[e.item][fields[i]]), ',') || + strchr(safe_str(database[e.item][fields[i]]), '\"')) ? + "\"%s\"" : "%s", + safe_str(database[e.item][fields[i]]) + );*/ + fprintf(out, "\"%s\"", + safe_str(database[e.item][fields[i]])); + + if(fields[i + 1] != CSV_LAST) + fputc(',', out); + } + fputc('\n', out); + } + + return 0; +} + +static int +csv_export_database(FILE *out, struct db_enumerator e) { - int i, j; int csv_export_fields[] = { NAME, EMAIL, PHONE, NOTES, - -1 + NICK, + CSV_LAST }; - for(i=0; i < items; i++ ) { - for(j = 0; csv_export_fields[j] >= 0; j++) { - fprintf(out, strchr(safe_str(database[i][csv_export_fields[j]]), ',') ? - "\"%s\"" : "%s", - safe_str(database[i][csv_export_fields[j]]) - ); - if(csv_export_fields[j+1] >= 0) - fputc(',', out); - } - fputc('\n', out); - } - + csv_export_common(out, e, csv_export_fields, NULL); + + return 0; +} +static int +allcsv_export_database(FILE *out, struct db_enumerator e) +{ + /* + * TODO: Should get these atomatically from abook_fileds + * - JH + */ + int allcsv_export_fields[] = { + NAME, + EMAIL, + ADDRESS, + ADDRESS2, + CITY, + STATE, + ZIP, + COUNTRY, + PHONE, + WORKPHONE, + FAX, + MOBILEPHONE, + NICK, + URL, + NOTES, + CUSTOM1, + CUSTOM2, + CUSTOM3, + CUSTOM4, + CUSTOM5, + CSV_LAST + }; + + fprintf(out, "#"); + fprintf(out, "\"NAME\","); + fprintf(out, "\"EMAIL\","); + fprintf(out, "\"ADDRESS\","); + fprintf(out, "\"ADDRESS2\","); + fprintf(out, "\"CITY\","); + fprintf(out, "\"STATE\","); + fprintf(out, "\"ZIP\","); + fprintf(out, "\"COUNTRY\","); + fprintf(out, "\"PHONE\","); + fprintf(out, "\"WORKPHONE\","); + fprintf(out, "\"FAX\","); + fprintf(out, "\"MOBILEPHONE\","); + fprintf(out, "\"NICK\","); + fprintf(out, "\"URL\","); + fprintf(out, "\"NOTES\","); + fprintf(out, "\"CUSTOM1\","); + fprintf(out, "\"CUSTOM2\","); + fprintf(out, "\"CUSTOM3\","); + fprintf(out, "\"CUSTOM4\","); + fprintf(out, "\"CUSTOM5\"\n"); + + csv_export_common(out, e, allcsv_export_fields, NULL); return 0; } /* - * end of csv export filter + * palm csv */ +#define PALM_CSV_NAME CSV_SPECIAL(0) +#define PALM_CSV_END CSV_SPECIAL(1) +#define PALM_CSV_CAT CSV_SPECIAL(2) + +static void +palm_split_and_write_name(FILE *out, char *name) +{ + char *p; + + assert(name); + + if ( (p = strchr(name, ' ')) ) { + /* + * last name first + */ + fprintf(out, "\"%s\",\"" , p + 1); + fwrite((void *)name, p - name, sizeof(char), out); + fputc('\"', out); + } else { + fprintf(out, "\"%s\"", safe_str(name)); + } +} + +static void +palm_csv_handle_specials(FILE *out, int item, int field) +{ + switch(field) { + case PALM_CSV_NAME: + palm_split_and_write_name(out, database[item][NAME]); + break; + case PALM_CSV_CAT: + fprintf(out, "\"abook\""); + break; + case PALM_CSV_END: + fprintf(out, "\"0\""); + break; + default: + assert(0); + } +} + +static int +palm_export_database(FILE *out, struct db_enumerator e) +{ + int palm_export_fields[] = { + PALM_CSV_NAME, /* LASTNAME, FIRSTNAME */ + CSV_UNDEFINED, /* TITLE */ + CSV_UNDEFINED, /* COMPANY */ + WORKPHONE, /* WORK PHONE */ + PHONE, /* HOME PHONE */ + FAX, /* FAX */ + MOBILEPHONE, /* OTHER */ + EMAIL, /* EMAIL */ + ADDRESS, /* ADDRESS */ + CITY, /* CITY */ + STATE, /* STATE */ + ZIP, /* ZIP */ + COUNTRY, /* COUNTRY */ + NICK, /* DEFINED 1 */ + URL, /* DEFINED 2 */ + CSV_UNDEFINED, /* DEFINED 3 */ + CSV_UNDEFINED, /* DEFINED 4 */ + NOTES, /* NOTE */ + PALM_CSV_END, /* "0" */ + PALM_CSV_CAT, /* CATEGORY */ + CSV_LAST + }; + + csv_export_common(out, e, palm_export_fields, palm_csv_handle_specials); + + return 0; +} + +/* + * end of csv export filters + */ /* * GnomeCard (VCard) addressbook export filter */ static int -gcrd_export_database(FILE *out) +gcrd_export_database(FILE *out, struct db_enumerator e) { char emails[MAX_EMAILS][MAX_EMAIL_LEN]; - int i, j; + int j; char *name; - for(i=0; i < items; i++ ) { + db_enumerate_items(e) { fprintf(out, "BEGIN:VCARD\nFN:%s\n", - safe_str(database[i][NAME])); + safe_str(database[e.item][NAME])); - name = get_surname(database[i][NAME]); - for( j = strlen(database[i][NAME]) - 1; j >= 0; j-- ) { - if(database[i][NAME][j] == ' ') + name = get_surname(database[e.item][NAME]); + for( j = strlen(database[e.item][NAME]) - 1; j >= 0; j-- ) { + if(database[e.item][NAME][j] == ' ') break; - } + } fprintf(out, "N:%s;%.*s\n", safe_str(name), j, - safe_str(database[i][NAME]) - ); + safe_str(database[e.item][NAME]) + ); free(name); - if ( database[i][ADDRESS] ) - fprintf(out, "ADR:;;%s;%s;%s;%s;%s\n", - safe_str(database[i][ADDRESS]), - safe_str(database[i][CITY]), - safe_str(database[i][STATE]), - safe_str(database[i][ZIP]), - safe_str(database[i][COUNTRY]) + if ( database[e.item][ADDRESS] ) + fprintf(out, "ADR:;;%s;%s;%s;%s;%s;%s\n", + safe_str(database[e.item][ADDRESS]), + safe_str(database[e.item][ADDRESS2]), + safe_str(database[e.item][CITY]), + safe_str(database[e.item][STATE]), + safe_str(database[e.item][ZIP]), + safe_str(database[e.item][COUNTRY]) ); - - if (database[i][PHONE]) - fprintf(out, "TEL;HOME:%s\n", database[i][PHONE]); - if (database[i][WORKPHONE]) - fprintf(out, "TEL;WORK:%s\n", database[i][WORKPHONE]); - if (database[i][FAX]) - fprintf(out, "TEL;FAX:%s\n", database[i][FAX]); - if (database[i][MOBILEPHONE]) - fprintf(out, "TEL;CELL:%s\n", database[i][MOBILEPHONE]); - - if ( database[i][EMAIL] ) { - split_emailstr(i, emails); + + if (database[e.item][PHONE]) + fprintf(out, "TEL;HOME:%s\n", database[e.item][PHONE]); + if (database[e.item][WORKPHONE]) + fprintf(out, "TEL;WORK:%s\n", database[e.item][WORKPHONE]); + if (database[e.item][FAX]) + fprintf(out, "TEL;FAX:%s\n", database[e.item][FAX]); + if (database[e.item][MOBILEPHONE]) + fprintf(out, "TEL;CELL:%s\n", database[e.item][MOBILEPHONE]); + + if ( database[e.item][EMAIL] ) { + split_emailstr(e.item, emails); for(j=0; j < MAX_EMAILS ; j++) { - if ( *emails[j] ) + if ( *emails[j] ) fprintf(out, "EMAIL;INTERNET:%s\n", emails[j]); } } - - if ( database[i][NOTES] ) - fprintf(out, "NOTE:%s\n", database[i][NOTES]); - if (database[i][URL]) - fprintf(out, "URL:%s\n", database[i][URL]); + + if ( database[e.item][NOTES] ) + fprintf(out, "NOTE:%s\n", database[e.item][NOTES]); + if (database[e.item][URL]) + fprintf(out, "URL:%s\n", database[e.item][URL]); fprintf(out, "END:VCARD\n\n"); - + } return 0; @@ -1080,36 +1574,35 @@ static char * mutt_alias_genalias(int i) { char *tmp, *pos; - + if(database[i][NICK]) - return strdup(database[i][NICK]); + return xstrdup(database[i][NICK]); - tmp = strdup(database[i][NAME]); + tmp = xstrdup(database[i][NAME]); if( ( pos = strchr(tmp, ' ') ) ) *pos = 0; strlower(tmp); - return tmp; + return tmp; } static int -mutt_alias_export(FILE *out) +mutt_alias_export(FILE *out, struct db_enumerator e) { - int i; char email[MAX_EMAIL_LEN]; char *alias = NULL; - for(i=0; i\n": "alias %s %s%s\n", alias, - database[i][NAME], + database[e.item][NAME], email); - my_free(alias); + xfree(alias); } return 0; @@ -1124,13 +1617,78 @@ mutt_alias_export(FILE *out) * printable export filter */ + +static void +text_write_address_us(FILE *out, int i) { + fprintf(out, "\n%s", database[i][ADDRESS]); + + if (database[i][ADDRESS2]) + fprintf(out, "\n%s", database[i][ADDRESS2]); + + if (database[i][CITY]) + fprintf(out, "\n%s", database[i][CITY]); + + if (database[i][STATE] || database[i][ZIP]) { + fputc('\n', out); + + if(database[i][STATE]) { + fprintf(out, "%s", database[i][STATE]); + if(database[i][ZIP]) + fputc(' ', out); + } + + if(database[i][ZIP]) + fprintf(out, "%s", database[i][ZIP]); + } + + if (database[i][COUNTRY]) + fprintf(out, "\n%s", database[i][COUNTRY]); +} + + +static void +text_write_address_uk(FILE *out, int i) { + int j; + + for (j = ADDRESS; j <= COUNTRY; j++) + if (database[i][j]) + fprintf(out, "\n%s", database[i][j]); +} + +static void +text_write_address_eu(FILE *out, int i) { + fprintf(out, "\n%s", database[i][ADDRESS]); + + if (database[i][ADDRESS2]) + fprintf(out, "\n%s", database[i][ADDRESS2]); + + if (database[i][ZIP] || database[i][CITY]) { + fputc('\n', out); + + if(database[i][ZIP]) { + fprintf(out, "%s", database[i][ZIP]); + if(database[i][CITY]) + fputc(' ', out); + } + + if(database[i][CITY]) + fprintf(out, "%s", database[i][CITY]); + } + + if (database[i][STATE]) + fprintf(out, "\n%s", database[i][STATE]); + + if (database[i][COUNTRY]) + fprintf(out, "\n%s", database[i][COUNTRY]); +} + static int -text_export_database(FILE * out) +text_export_database(FILE * out, struct db_enumerator e) { char emails[MAX_EMAILS][MAX_EMAIL_LEN]; - int i, j; + int j; char *realname = get_real_name(); - char *style = options_get_str("address_style"); + char *style = opt_get_str(STR_ADDRESS_STYLE); fprintf(out, "-----------------------------------------\n%s's address book\n" @@ -1138,76 +1696,49 @@ text_export_database(FILE * out) realname); free(realname); - for (i = 0; i < items; i++) { + db_enumerate_items(e) { fprintf(out, "-----------------------------------------\n\n"); - fprintf(out, "%s", database[i][NAME]); - if (database[i][NICK]) - fprintf(out, "\n(%s)", database[i][NICK]); + fprintf(out, "%s", database[e.item][NAME]); + if (database[e.item][NICK] && *database[e.item][NICK]) + fprintf(out, "\n(%s)", database[e.item][NICK]); fprintf(out, "\n"); - if (*database[i][EMAIL]) { + if (*database[e.item][EMAIL]) { fprintf(out, "\n"); - split_emailstr(i, emails); + split_emailstr(e.item, emails); for (j = 0; j < MAX_EMAILS; j++) if (*emails[j]) fprintf(out, "%s\n", emails[j]); } /* Print address */ - if (database[i][ADDRESS]) { - if (!safe_strcmp(style, "us")) { /* US like */ - fprintf(out, "\n%s", database[i][ADDRESS]); - if (database[i][CITY]) - fprintf(out, "\n%s", - database[i][CITY]); - if (database[i][STATE] || database[i][ZIP]) - fprintf(out, "\n%s %s", - safe_str(database[i] - [STATE]), - safe_str(database[i] - [ZIP])); - if (database[i][COUNTRY]) - fprintf(out, "\n%s", - database[i][COUNTRY]); - } - - else if (!safe_strcmp(style, "uk")) { /* UK like */ - for (j = ADDRESS; j <= COUNTRY; j++) - if (database[i][j]) - fprintf(out, "\n%s", - database[i][j]); - } else { /* EU like */ - fprintf(out, "\n%s", database[i][ADDRESS]); - if (database[i][ZIP] || database[i][CITY]) - fprintf(out, "\n%s %s", - safe_str(database[i][ZIP]), - safe_str(database[i] - [CITY])); - if (database[i][STATE]) - fprintf(out, "\n%s", - database[i][STATE]); - if (database[i][COUNTRY]) - fprintf(out, "\n%s", - database[i][COUNTRY]); - } + if (database[e.item][ADDRESS]) { + if (!safe_strcmp(style, "us")) /* US like */ + text_write_address_us(out, e.item); + else if (!safe_strcmp(style, "uk")) /* UK like */ + text_write_address_uk(out, e.item); + else /* EU like */ + text_write_address_eu(out, e.item); fprintf(out, "\n"); } - if ((database[i][PHONE]) || (database[i][WORKPHONE]) || - (database[i][FAX]) || (database[i][MOBILEPHONE])) { + if ((database[e.item][PHONE]) || + (database[e.item][WORKPHONE]) || + (database[e.item][FAX]) || + (database[e.item][MOBILEPHONE])) { fprintf(out, "\n"); for (j = PHONE; j <= MOBILEPHONE; j++) - if (database[i][j]) + if (database[e.item][j]) fprintf(out, "%s: %s\n", abook_fields[j].name, - database[i][j]); + database[e.item][j]); } - if (database[i][URL]) - fprintf(out, "\n%s\n", database[i][URL]); - if (database[i][NOTES]) - fprintf(out, "\n%s\n", database[i][NOTES]); + if (database[e.item][URL]) + fprintf(out, "\n%s\n", database[e.item][URL]); + if (database[e.item][NOTES]) + fprintf(out, "\n%s\n", database[e.item][NOTES]); fprintf(out, "\n"); } @@ -1226,20 +1757,19 @@ text_export_database(FILE * out) */ static int -elm_alias_export(FILE *out) +elm_alias_export(FILE *out, struct db_enumerator e) { - int i; char email[MAX_EMAIL_LEN]; char *alias = NULL; - for(i=0; i