X-Git-Url: https://git.deb.at/?a=blobdiff_plain;f=filter.c;h=3aa3708a78acd5c2c23b1c8d0450a74821a4b4cb;hb=1f1bc68c78000f3269bb4bb1f15db6fefac03901;hp=ff4d116b1ac652afd816e41efe8ee6c93f9bb95d;hpb=5b294375faaa96e4c8e724de274e8badccf3395c;p=pkg%2Fabook.git diff --git a/filter.c b/filter.c index ff4d116..3aa3708 100644 --- a/filter.c +++ b/filter.c @@ -29,6 +29,10 @@ #include "xmalloc.h" #include +#ifdef HAVE_VFORMAT +#include "vcard.h" +#endif + extern abook_field_list *fields_list; extern int fields_count; @@ -60,11 +64,21 @@ static int allcsv_export_database(FILE *out, struct db_enumerator e); static int palm_export_database(FILE *out, struct db_enumerator e); static int vcard_export_database(FILE *out, struct db_enumerator e); static int mutt_alias_export(FILE *out, struct db_enumerator e); +static int mutt_query_export_database(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); static int wl_export_database(FILE *out, struct db_enumerator e); static int bsdcal_export_database(FILE *out, struct db_enumerator e); +static int custom_export_database(FILE *out, struct db_enumerator e); + +/* + * export filter item prototypes + */ + +void vcard_export_item(FILE *out, int item); +void muttq_print_item(FILE *file, int item); +void custom_print_item(FILE *out, int item); /* * end of function declarations @@ -87,6 +101,7 @@ struct abook_output_filter e_filters[] = { { "ldif", N_("ldif / Netscape addressbook (.4ld)"), ldif_export_database }, { "vcard", N_("vCard 2 file"), vcard_export_database }, { "mutt", N_("mutt alias"), mutt_alias_export }, + { "muttq", N_("mutt query format (internal use)"), mutt_query_export_database }, { "html", N_("html document"), html_export_database }, { "pine", N_("pine addressbook"), pine_export_database }, { "csv", N_("comma separated values"), csv_export_database }, @@ -97,10 +112,14 @@ struct abook_output_filter e_filters[] = { { "wl", N_("Wanderlust address book"), wl_export_database }, { "spruce", N_("Spruce address book"), spruce_export_database }, { "bsdcal", N_("BSD calendar"), bsdcal_export_database }, + { "custom", N_("Custom format"), custom_export_database }, { "\0", NULL, NULL } }; struct abook_output_item_filter u_filters[] = { + { "vcard", N_("vCard 2 file"), vcard_export_item }, + { "muttq", N_("mutt alias"), muttq_print_item }, + { "custom", N_("Custom format"), custom_print_item }, { "\0", NULL } }; @@ -113,21 +132,21 @@ print_filters() { int i; - puts(_("input:")); + puts(_("input formats:")); for(i=0; *i_filters[i].filtname ; i++) printf("\t%s\t%s\n", i_filters[i].filtname, gettext(i_filters[i].desc)); putchar('\n'); - puts(_("output:")); + puts(_("output formats:")); for(i=0; *e_filters[i].filtname ; i++) printf("\t%s\t%s\n", e_filters[i].filtname, gettext(e_filters[i].desc)); putchar('\n'); - puts(_("output (with query):")); + puts(_("query-compatible output formats:")); for(i=0; *u_filters[i].filtname ; i++) printf("\t%s\t%s\n", u_filters[i].filtname, gettext(u_filters[i].desc)); @@ -278,6 +297,18 @@ import_file(char filtname[FILTNAME_LEN], char *filename) if(i < 0) return -1; +#ifdef HAVE_VFORMAT + // this is a special case for + // libvformat whose API expects a filename + if(!strcmp(filtname, "vcard")) { + if(!strcmp(filename, "-")) + ret = vcard_parse_file_libvformat("/dev/stdin"); + else + ret = vcard_parse_file_libvformat(filename); + } + else +#endif + if(!strcmp(filename, "-")) { struct stat s; if((fstat(fileno(stdin), &s)) == -1 || S_ISDIR(s.st_mode)) @@ -516,35 +547,42 @@ static int ldif_conv_table[LDIF_ITEM_FIELDS] = { -1, /* "objectclass" */ /* this must be the last entry */ }; - +/* + Handles multi-line strings. + If a string starts with a space, it's the continuation + of the previous line. Thus we need to always read ahead. + But for this to work with stdin, we need to stores the next + line for later use in case it's not a continuation of the + first line. + */ static char * -ldif_read_line(FILE *in) +ldif_read_line(FILE *in, char **next_line) { char *buf = NULL; char *ptr, *tmp; - long pos; - int i; + char *line; - for(i = 1;;i++) { - char *line; + // buf filled with the first line + if(!*next_line) + buf = getaline(in); + else { + buf = xstrdup(*next_line); + xfree(*next_line); + } - pos = ftell(in); + while(!feof(in)) { + // if no line already read-ahead. line = getaline(in); + if(!line) break; - if(feof(in) || !line) - break; - - if(i == 1) { - buf = line; - continue; - } - + // this is not a continuation of what is already in buf + // store it for the next round if(*line != ' ') { - fseek(in, pos, SEEK_SET); /* fixme ! */ - free(line); + *next_line = line; break; } + // starts with ' ': this is the continuation of buf ptr = line; while( *ptr == ' ') ptr++; @@ -599,16 +637,10 @@ ldif_convert(ldif_item item, char *type, char *value) return; } - for(i=0; i < LDIF_ITEM_FIELDS; i++) { - if(!safe_strcmp(ldif_field_names[i], type) && *value) { - if(i == LDIF_ITEM_FIELDS - 1) /* this is a dirty hack */ - if(safe_strcmp("person", value)) - break; - - if(item_fget(item, i)) - free(item_fget(item, i)); - + for(i=0; i < LDIF_ITEM_FIELDS - 1; i++) { + if(!strcasecmp(ldif_field_names[i], type) && *value) { item_fput(item, i, xstrdup(value)); + break; } } } @@ -617,6 +649,7 @@ static int ldif_parse_file(FILE *handle) { char *line = NULL; + char *next_line = NULL; char *type, *value; int vlen; ldif_item item; @@ -624,8 +657,10 @@ ldif_parse_file(FILE *handle) memset(item, 0, sizeof(item)); do { - if( !(line = ldif_read_line(handle)) ) - continue; + line = ldif_read_line(handle, &next_line); + + // EOF or empty lines: continue; + if(!line || *line == '\0') continue; if(-1 == (str_parse_line(line, &type, &value, &vlen))) { xfree(line); @@ -848,16 +883,22 @@ ldif_export_database(FILE *out, struct db_enumerator e) int j; get_first_email(email, e.item); - tmp = strdup_printf("cn=%s,mail=%s",db_name_get(e.item),email); + if(*email) + tmp = strdup_printf("cn=%s,mail=%s",db_name_get(e.item),email); + else + tmp = strdup_printf("cn=%s",db_name_get(e.item)); ldif_fput_type_and_value(out, "dn", tmp); free(tmp); for(j = 0; j < LDIF_ITEM_FIELDS; j++) { if(ldif_conv_table[j] >= 0) { - if(ldif_conv_table[j] == EMAIL) - ldif_fput_type_and_value(out, - ldif_field_names[j], email); + if(ldif_conv_table[j] == EMAIL) { + if(*email) // don't dump en empty email field + ldif_fput_type_and_value(out, + ldif_field_names[j], + email); + } else if(db_fget(e.item,ldif_conv_table[j])) ldif_fput_type_and_value(out, ldif_field_names[j], @@ -1846,74 +1887,77 @@ palm_export_database(FILE *out, struct db_enumerator e) static int vcard_export_database(FILE *out, struct db_enumerator e) +{ + db_enumerate_items(e) + vcard_export_item(out, e.item); + return 0; +} + +void +vcard_export_item(FILE *out, int item) { int j; char *name, *tmp; abook_list *emails, *em; + fprintf(out, "BEGIN:VCARD\r\nFN:%s\r\n", + safe_str(db_name_get(item))); - db_enumerate_items(e) { - fprintf(out, "BEGIN:VCARD\r\nFN:%s\r\n", - safe_str(db_name_get(e.item))); - - name = get_surname(db_name_get(e.item)); - for( j = strlen(db_name_get(e.item)) - 1; j >= 0; j-- ) { - if((db_name_get(e.item))[j] == ' ') - break; - } - fprintf(out, "N:%s;%.*s\r\n", - safe_str(name), - j, - safe_str(db_name_get(e.item)) - ); - - free(name); - - if(db_fget(e.item, ADDRESS)) - fprintf(out, "ADR:;;%s;%s;%s;%s;%s;%s\r\n", - safe_str(db_fget(e.item, ADDRESS)), - safe_str(db_fget(e.item, ADDRESS2)), - safe_str(db_fget(e.item, CITY)), - safe_str(db_fget(e.item, STATE)), - safe_str(db_fget(e.item, ZIP)), - safe_str(db_fget(e.item, COUNTRY)) - ); - - if(db_fget(e.item, PHONE)) - fprintf(out, "TEL;HOME:%s\r\n", - db_fget(e.item, PHONE)); - if(db_fget(e.item, WORKPHONE)) - fprintf(out, "TEL;WORK:%s\r\n", - db_fget(e.item, WORKPHONE)); - if(db_fget(e.item, FAX)) - fprintf(out, "TEL;FAX:%s\r\n", - db_fget(e.item, FAX)); - if(db_fget(e.item, MOBILEPHONE)) - fprintf(out, "TEL;CELL:%s\r\n", - db_fget(e.item, MOBILEPHONE)); - - tmp = db_email_get(e.item); - if(*tmp) { - emails = csv_to_abook_list(tmp); - - for(em = emails; em; em = em->next) - fprintf(out, "EMAIL;INTERNET:%s\r\n", em->data); - - abook_list_free(&emails); - } - free(tmp); + name = get_surname(db_name_get(item)); + for( j = strlen(db_name_get(item)) - 1; j >= 0; j-- ) { + if((db_name_get(item))[j] == ' ') + break; + } + fprintf(out, "N:%s;%.*s\r\n", + safe_str(name), + j, + safe_str(db_name_get(item)) + ); + + free(name); + + if(db_fget(item, ADDRESS)) + fprintf(out, "ADR:;;%s;%s;%s;%s;%s;%s\r\n", + safe_str(db_fget(item, ADDRESS)), + safe_str(db_fget(item, ADDRESS2)), + safe_str(db_fget(item, CITY)), + safe_str(db_fget(item, STATE)), + safe_str(db_fget(item, ZIP)), + safe_str(db_fget(item, COUNTRY)) + ); + + if(db_fget(item, PHONE)) + fprintf(out, "TEL;HOME:%s\r\n", + db_fget(item, PHONE)); + if(db_fget(item, WORKPHONE)) + fprintf(out, "TEL;WORK:%s\r\n", + db_fget(item, WORKPHONE)); + if(db_fget(item, FAX)) + fprintf(out, "TEL;FAX:%s\r\n", + db_fget(item, FAX)); + if(db_fget(item, MOBILEPHONE)) + fprintf(out, "TEL;CELL:%s\r\n", + db_fget(item, MOBILEPHONE)); + + tmp = db_email_get(item); + if(*tmp) { + emails = csv_to_abook_list(tmp); + + for(em = emails; em; em = em->next) + fprintf(out, "EMAIL;INTERNET:%s\r\n", em->data); + + abook_list_free(&emails); + } + free(tmp); - if(db_fget(e.item, NOTES)) - fprintf(out, "NOTE:%s\r\n", - db_fget(e.item, NOTES)); - if(db_fget(e.item, URL)) - fprintf(out, "URL:%s\r\n", - db_fget(e.item, URL)); + if(db_fget(item, NOTES)) + fprintf(out, "NOTE:%s\r\n", + db_fget(item, NOTES)); + if(db_fget(item, URL)) + fprintf(out, "URL:%s\r\n", + db_fget(item, URL)); - fprintf(out, "END:VCARD\r\n\r\n"); + fprintf(out, "END:VCARD\r\n\r\n"); - } - - return 0; } /* @@ -2056,6 +2100,15 @@ void muttq_print_item(FILE *file, int item) abook_list_free(&emails); } +static int +mutt_query_export_database(FILE *out, struct db_enumerator e) +{ + fprintf(out, "All items\n"); + db_enumerate_items(e) + muttq_print_item(out, e.item); + return 0; +} + /* * end of mutt alias export filter */ @@ -2320,6 +2373,176 @@ bsdcal_export_database(FILE *out, struct db_enumerator e) return 0; } +// see enum field_types @database.h +static char *conv_table[] = { + "name", + "email", + "address", + "address2", + "city", + "state", + "zip", + "country", + "phone", + "workphone", + "fax", + "mobile", + "nick", + "url", + "notes", + "anniversary", + 0 /* ITEM_FIELDS */ +}; + +static int +find_field_enum(char *s) { + int i = 0; + while (conv_table[i]) { + if(!safe_strcmp(conv_table[i], s)) + return i; + i++; + } + // failed + return -1; +} + +/* Convert a string with named placeholders to + a *printf() compatible string. + Stores the abook field values into ft. */ +void +parse_custom_format(char *s, char *fmt_string, enum field_types *ft) +{ + if(! fmt_string || ! ft) { + fprintf(stderr, _("parse_custom_format: fmt_string or ft not allocated\n")); + exit(EXIT_FAILURE); + } + + char *p, *start, *field_name = NULL; + p = start = s; + + while(*p) { + if(*p == '{') { + start = ++p; + p = strchr(start, '}'); + if(! *p) { + fprintf(stderr, _("parse_custom_format: invalid format\n")); + exit(EXIT_FAILURE); + } + strcat(fmt_string, "%s"); + field_name = strndup(start, (size_t)(p-start)); + *ft = find_field_enum(field_name); + if(*ft == -1) { + fprintf(stderr, _("parse_custom_format: invalid placeholder: {%s}\n"), field_name); + exit(EXIT_FAILURE); + } + + ft++; + p++; + start = p; + } else { + p = strchr(start, '{'); + if(p && *p) { + strncat(fmt_string, start, (size_t)(p-start)); + start = p; + } + else { + strncat( fmt_string, + start, + FORMAT_STRING_LEN - strlen(fmt_string) - 1 ); + break; + } + } + } + *ft = 66; +} + +static int +custom_export_item(FILE *out, int item, char *s, enum field_types *ft); + + +// used to store the format string from --outformatstr when "custom" format is used +// default value overriden in export_file() +extern char *parsed_custom_format; +extern enum field_types *custom_format_fields; + +/* wrapper for custom_export_item: + 1) avoid messing with extern pointer + 2) adds \n + 3) follow the prototype needed for an abook_output_item_filter entry */ +void +custom_print_item(FILE *out, int item) +{ + + if(custom_export_item(out, item, parsed_custom_format, custom_format_fields) == 0) + fprintf(out, "\n"); +} + +static int +custom_export_item(FILE *out, int item, char *fmt, enum field_types *ft) +{ + char *p, *q = 0; + + // if the first character is '!': + // we first check that all fields exist before continuing + if(*fmt == '!') { + enum field_types *ftp = ft; + while(*ft != 66) { + if(! db_fget(item, *ft) ) + return 1; + ft++; + } + ft = ftp; + fmt++; + } + + while (*fmt) { + if(!strncmp(fmt, "%s", 2)) { + fprintf(out, "%s", safe_str(db_fget(item, *ft))); + ft++; + fmt+=2; + } else if (*ft == 66) { + fprintf(out, "%s", fmt); + return 0; + } else { + p = strchr(fmt, '%'); + if(*p) { + q = strndup(fmt, (size_t)(p-fmt)); + fprintf(out, "%s", q); + free(q); + fmt = p; + } + else { + fprintf(out, "%s", fmt); + return 0; + } + } + } + + return 0; +} + +// used to store the format string from --outformatstr when "custom" format is used +// default value overriden from abook.c +extern char custom_format[FORMAT_STRING_LEN]; + +static int +custom_export_database(FILE *out, struct db_enumerator e) +{ + char *format_string = + (char *)malloc(FORMAT_STRING_LEN * sizeof(char*)); + + enum field_types *ft = + (enum field_types *)malloc(FORMAT_STRING_MAX_FIELDS * sizeof(enum field_types *)); + + parse_custom_format(custom_format, format_string, ft); + + db_enumerate_items(e) { + if(custom_export_item(out, e.item, format_string, ft) == 0) + fprintf(out, "\n"); + } + return 0; +} + /* * end of BSD calendar export filter */