X-Git-Url: https://git.deb.at/w?p=pkg%2Fabook.git;a=blobdiff_plain;f=filter.c;h=2ea5a2dd77bfa3acafa196f5f324a7b47cee2ed6;hp=31b6f2d259fab66e7a4c58fe4705b87541409310;hb=69a912c0db0ac135fff332db4f0b05ad9ed2eec6;hpb=2f827e0ef00d2c90e00adf976147faaa448b1651 diff --git a/filter.c b/filter.c index 31b6f2d..2ea5a2d 100644 --- a/filter.c +++ b/filter.c @@ -35,6 +35,8 @@ extern abook_field_list *fields_list; extern int fields_count; +// see also enum field_types @database.h +extern abook_field standard_fields[]; /* * function declarations @@ -503,8 +505,6 @@ export_file(char filtname[FILTNAME_LEN], char *filename) #include "ldif.h" -static void ldif_fix_string(char *str); - /* During LDIF import we need more fields than the ITEM_FIELDS of a *list_item. Eg: "objectclass" to test valid records, ... @@ -789,8 +789,6 @@ ldif_parse_file(FILE *handle) continue; /* just skip the errors */ } - ldif_fix_string(value); - ldif_convert(item, type, value); xfree(line); @@ -802,19 +800,6 @@ ldif_parse_file(FILE *handle) return 0; } -static void -ldif_fix_string(char *str) -{ - int 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] ); - - str[i] = 0; -} - /* * end of ldif import */ @@ -998,6 +983,7 @@ static int ldif_export_database(FILE *out, struct db_enumerator e) { char email[MAX_EMAILSTR_LEN]; + abook_list *emails, *em; fprintf(out, "version: 1\n"); @@ -1018,10 +1004,15 @@ ldif_export_database(FILE *out, struct db_enumerator e) for(j = 0; j < ITEM_FIELDS; j++) { if(j == EMAIL) { - if(*email) // don't dump an empty email field - ldif_fput_type_and_value(out, - ldif_field_names[j], - email); + if(*email) { + tmp = db_email_get(e.item); + emails = csv_to_abook_list(tmp); + free(tmp); + for(em = emails; em; em = em->next) + ldif_fput_type_and_value(out, + ldif_field_names[EMAIL], + em->data); + } } else if(db_fget(e.item,j)) { ldif_fput_type_and_value(out, @@ -1078,23 +1069,26 @@ html_export_database(FILE *out, struct db_enumerator e) html_export_write_head(out); db_enumerate_items(e) { - fprintf(out, ""); + fprintf(out, " \n"); for(cur = index_elements; cur; cur = cur->next) { if(cur->type != INDEX_FIELD) continue; - + get_list_field(e.item, cur, &f); + fprintf(out, " "); + if(f.type == FIELD_EMAILS) { - fprintf(out, ""); html_print_emails(out, &f); - fprintf(out, ""); - continue; } else { - fprintf(out, "%s", safe_str(f.data)); + if (strcmp(safe_str(f.data), "") == 0) + fprintf(out, " "); + else + fprintf(out, "%s", safe_str(f.data)); } + fprintf(out, "\n"); } - fprintf(out, "\n"); + fprintf(out, " \n"); } html_export_write_tail(out); @@ -1108,22 +1102,45 @@ html_export_write_head(FILE *out) char *realname = get_real_name(), *str; struct index_elem *cur; - 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"); + fprintf(out, "\n"); + fprintf(out, " \n"); + fprintf(out, " "); + fprintf(out, _("%s's addressbook"), realname ); + fprintf(out, "\n"); + fprintf(out, " \n"); + fprintf(out, "\n"); + fprintf(out, "\n"); + fprintf(out, "

"); + fprintf(out, _("%s's addressbook"), realname); + fprintf(out, "

\n"); + + fprintf(out, "
\n"); + fprintf(out, "\n"); + fprintf(out, " \n"); for(cur = index_elements; cur; cur = cur->next) { if(cur->type != INDEX_FIELD) continue; get_field_info(cur->d.field.id, NULL, &str, NULL); - fprintf(out, "", str); + + fprintf(out, " \n"); } - fprintf(out, "\n\n"); + fprintf(out, " \n"); + fprintf(out, "\n"); + fprintf(out, "\n"); free(realname); } @@ -1131,8 +1148,9 @@ html_export_write_head(FILE *out) static void html_export_write_tail(FILE *out) { - fprintf(out, "\n
%s"); + + if (strcmp(str, "") == 0) + fprintf(out, " "); + else + fprintf(out, "%s", str); + + fprintf(out, "
\n"); - fprintf(out, "\n\n\n"); + fprintf(out, "\n"); + fprintf(out, "\n"); + fprintf(out, ""); } /* @@ -1296,6 +1314,11 @@ pine_export_database(FILE *out, struct db_enumerator e) * csv import filter */ +/* This is used by both allcsv_export_database() and csv_export_common() + to distinguish between standard and defined fields. + To avoid confusions this should stay > ITEM_FIELDS */ +#define CUSTOM_FIELD_START_INDEX (ITEM_FIELDS + 10) + /* FIXME * these files should be parsed according to a certain * lay out, or the default if layout is not given, at @@ -1549,7 +1572,7 @@ static char *vcard_fields[] = { "FN", /* FORMATTED NAME */ "EMAIL", /* EMAIL */ "ADR", /* ADDRESS */ - "ADR", /* ADDRESS2 - not used */ + "ADR", /* ADDRESS2 */ "ADR", /* CITY */ "ADR", /* STATE */ "ADR", /* ZIP */ @@ -1561,22 +1584,9 @@ static char *vcard_fields[] = { "NICKNAME", /* NICK */ "URL", /* URL */ "NOTE", /* NOTES */ + "BDAY", /* ANNIVERSARY */ "N", /* NAME: special case/mapping in vcard_parse_line() */ - NULL /* not implemented: ANNIVERSARY, ITEM_FIELDS */ -}; - -/* - * mappings between vCard ADR field and abook's ADDRESS - * see rfc2426 section 3.2.1 - */ -static int vcard_address_fields[] = { - -1, /* vCard(post office box) - not used */ - -1, /* vCard(the extended address) - not used */ - 2, /* vCard(the street address) - ADDRESS */ - 4, /* vCard(the locality) - CITY */ - 5, /* vCard(the region) - STATE */ - 6, /* vCard(the postal code) - ZIP */ - 7 /* vCard(the country name) - COUNTRY */ + NULL /* ITEM_FIELDS */ }; enum { @@ -1662,33 +1672,49 @@ vcard_parse_email(list_item item, char *line) } } + +/* + * mappings between vCard ADR field and abook's ADDRESS + * see rfc2426 section 3.2.1 + */ static void vcard_parse_address(list_item item, char *line) { - int i; - int k; char *value; - char *address_field; value = vcard_get_line_element(line, VCARD_VALUE); if(!value) return; - address_field = value; - for(i=k=0; value[i]; i++) { - if(value[i] == ';') { - value[i] = '\0'; - if(vcard_address_fields[k] >= 0) { - item[vcard_address_fields[k]] = xstrdup(address_field); - } - address_field = &value[i+1]; - k++; - if((k+1)==(sizeof(vcard_address_fields)/sizeof(*vcard_address_fields))) - break; - } - } - item[vcard_address_fields[k]] = xstrdup(address_field); - xfree(value); + // vCard(post office box) - not used + strsep(&value, ";"); + if(!value) return; + + // vCard(the extended address) + item_fput(item, ADDRESS2, xstrdup(strsep(&value, ";"))); + if(!value) return; + + // vCard(the street address) + item_fput(item, ADDRESS, xstrdup(strsep(&value, ";"))); + if(!value) return; + + // vCard(the locality) + item_fput(item, CITY, xstrdup(strsep(&value, ";"))); + if(!value) return; + + // vCard(the region) + item_fput(item, STATE, xstrdup(strsep(&value, ";"))); + if(!value) return; + + // vCard(the postal code) + item_fput(item, ZIP, xstrdup(strsep(&value, ";"))); + if(!value) return; + + // vCard(the country name) + item_fput(item, COUNTRY, xstrdup(strsep(&value, ";"))); + + // support of optional trailing ";" to the ADR field + if(value && *value) xfree(value); } static void @@ -1835,7 +1861,12 @@ csv_export_common(FILE *out, struct db_enumerator e, else if(CSV_IS_SPECIAL(fields[i])) { if(special_func) (*special_func)(out, e.item, fields[i]); - } else + } + else if(fields[i] >= CUSTOM_FIELD_START_INDEX) { + fprintf(out, "\"%s\"", + safe_str(db_fget_byid(e.item, fields[i] - CUSTOM_FIELD_START_INDEX))); + } + else /*fprintf(out,( strchr(safe_str(database[e.item][field_idx(fields[i])]), ',') || strchr(safe_str(database[e.item][field_idx(fields[i])]), '\"')) ? @@ -1878,7 +1909,7 @@ allcsv_export_database(FILE *out, struct db_enumerator e) * TODO: Should get these atomatically from abook_fileds * - JH */ - int allcsv_export_fields[] = { + int allcsv_export_fields[ITEM_FIELDS + 6] = { // only the 5 custom fields are allowed so far NAME, EMAIL, ADDRESS, @@ -1890,7 +1921,7 @@ allcsv_export_database(FILE *out, struct db_enumerator e) PHONE, WORKPHONE, FAX, - MOBILEPHONE, + MOBILEPHONE, // spelt "mobile" in standard_fields NICK, URL, NOTES, @@ -1900,23 +1931,47 @@ allcsv_export_database(FILE *out, struct db_enumerator e) }; 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, "\"ANNIVERSARY\","); - fprintf(out, "\"GROUPS\"\n"); + int i = 0; + while(allcsv_export_fields[i+1] != CSV_LAST) { + fprintf(out, "\"%s\",", standard_fields[i++].key); + } + fprintf(out, "\"%s\"", standard_fields[i].key); + + /* + Custom fields handling: + This loop appends custom fields' id at the end of allcsv_export_fields and shift + the CSV_LAST sentinel value each time one is found. + CUSTOM_FIELD_START_INDEX is added to these index values so csv_export_common() + can later recognize them and call db_fget_byid() instead of the traditional db_fget() + + It only search for defined the [legacy?] "custom" fields. + */ + + // pointer to the end of the field list + int append_field = ITEM_FIELDS; + // custom field's trailing number (between 1 and 5) + int j; + // full custom field name, eg "custom4" + char custom_field_key[8]; + // index used by custom_field_key + int field_no; + // name of the defined field as chosen by the user + char *custom_field_name; + + for (j = 1; j <= 5; j++) { + snprintf(custom_field_key, 8, "custom%d", j++); + if(find_declared_field(custom_field_key)) { + find_field_number(custom_field_key, &field_no); + get_field_info(field_no, NULL, &custom_field_name, NULL); + // append the field to the list + allcsv_export_fields[append_field] = field_no + CUSTOM_FIELD_START_INDEX; + allcsv_export_fields[++append_field] = CSV_LAST; + // print column name + fprintf(out, ",\"%s\"", custom_field_name); + } + } + free(custom_field_name); + fprintf(out, "\n"); csv_export_common(out, e, allcsv_export_fields, NULL); @@ -2019,7 +2074,7 @@ vcard_export_database(FILE *out, struct db_enumerator e) void vcard_export_item(FILE *out, int item) { - int j; + int j, email_no; char *name, *tmp; abook_list *emails, *em; fprintf(out, "BEGIN:VCARD\r\nFN:%s\r\n", @@ -2038,15 +2093,25 @@ vcard_export_item(FILE *out, int 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, NICK)) + fprintf(out, "NICKNAME:%s\r\n", + safe_str(db_fget(item, NICK))); + if(db_fget(item, ANNIVERSARY)) + fprintf(out, "BDAY:%s\r\n", + safe_str(db_fget(item, ANNIVERSARY))); + + // see rfc6350 section 6.3.1 + if(db_fget(item, ADDRESS)) { + fprintf(out, "ADR:;%s;%s;%s;%s;%s;%s\r\n", + // pobox (unsupported) + safe_str(db_fget(item, ADDRESS2)), // ext (n°, ...) + safe_str(db_fget(item, ADDRESS)), // street + safe_str(db_fget(item, CITY)), // locality + safe_str(db_fget(item, STATE)), // region + safe_str(db_fget(item, ZIP)), // code (postal) + safe_str(db_fget(item, COUNTRY)) // country + ); + } if(db_fget(item, PHONE)) fprintf(out, "TEL;HOME:%s\r\n", @@ -2064,9 +2129,10 @@ vcard_export_item(FILE *out, int item) 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); + fprintf(out, "EMAIL;PREF;INTERNET:%s\r\n", emails->data); + email_no = 1; + for(em = emails->next; em; em = em->next, email_no++ ) + fprintf(out, "EMAIL;%d;INTERNET:%s\r\n", email_no, em->data); abook_list_free(&emails); } @@ -2496,37 +2562,13 @@ 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; + int i = -1; + while(standard_fields[++i].key) + if(!strcmp(standard_fields[i].key, s)) + return i; + return -1; } /* Convert a string with named placeholders to @@ -2540,17 +2582,17 @@ parse_custom_format(char *s, char *fmt_string, enum field_types *ft) exit(EXIT_FAILURE); } + char tmp[1] = { 0 }; char *p, *start, *field_name = NULL; p = start = s; while(*p) { if(*p == '{') { start = ++p; + + if(! *start) goto cannotparse; p = strchr(start, '}'); - if(! *p) { - fprintf(stderr, _("parse_custom_format: invalid format\n")); - exit(EXIT_FAILURE); - } + if(! p) goto cannotparse; strcat(fmt_string, "%s"); field_name = strndup(start, (size_t)(p-start)); *ft = find_field_enum(field_name); @@ -2560,23 +2602,53 @@ parse_custom_format(char *s, char *fmt_string, enum field_types *ft) } ft++; - p++; - start = p; - } else { + start = ++p; + } + + else if(*p == '\\') { + ++p; + if(! *p) tmp[0] = '\\'; // last char is a '\' ? + else if(*p == 'n') *tmp = '\n'; + else if(*p == 't') *tmp = '\t'; + else if(*p == 'r') *tmp = '\r'; + else if(*p == 'v') *tmp = '\v'; + else if(*p == 'b') *tmp = '\b'; + else if(*p == 'a') *tmp = '\a'; + else *tmp = *p; + strncat(fmt_string, tmp, 1); + start = ++p; + } + + // if no '\' following: quick mode using strchr/strncat + else if(! strchr(start, '\\')) { p = strchr(start, '{'); - if(p && *p) { + if(p) { // copy until the next placeholder strncat(fmt_string, start, (size_t)(p-start)); start = p; } - else { + else { // copy till the end strncat( fmt_string, start, FORMAT_STRING_LEN - strlen(fmt_string) - 1 ); break; } } + + // otherwise character by character + else { + strncat(fmt_string, p, 1); + start = ++p; + } } - *ft = 66; + + *ft = ITEM_FIELDS; + return; + + cannotparse: + fprintf(stderr, _("%s: invalid format, index %ld\n"), __FUNCTION__, (start - s)); + free(fmt_string); + free(ft); + exit(EXIT_FAILURE); } static int @@ -2609,7 +2681,7 @@ custom_export_item(FILE *out, int item, char *fmt, enum field_types *ft) // we first check that all fields exist before continuing if(*fmt == '!') { enum field_types *ftp = ft; - while(*ft != 66) { + while(*ft != ITEM_FIELDS) { if(! db_fget(item, *ft) ) return 1; ft++; @@ -2623,7 +2695,7 @@ custom_export_item(FILE *out, int item, char *fmt, enum field_types *ft) fprintf(out, "%s", safe_str(db_fget(item, *ft))); ft++; fmt+=2; - } else if (*ft == 66) { + } else if (*ft == ITEM_FIELDS) { fprintf(out, "%s", fmt); return 0; } else { @@ -2651,11 +2723,10 @@ 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*)); + char *format_string = (char *)malloc(FORMAT_STRING_LEN); enum field_types *ft = - (enum field_types *)malloc(FORMAT_STRING_MAX_FIELDS * sizeof(enum field_types *)); + (enum field_types *)malloc(FORMAT_STRING_MAX_FIELDS * sizeof(enum field_types)); parse_custom_format(custom_format, format_string, ft);