Hi, sorry for the waiting time but i'm offline in these days.
I wrote two patches that both fixes this bug without changing contact_ids.h. The first is more simple but needs to do a search of the right position of the fields at any call of add_date/add_string #define number_ids(c,id) for (c=0; value_ids[c] != id && c < MAX_ID; c ++); The changes into the second patch are more numerous but avoid to do the search. There is another bug fixed from these patchs, if rra_contact_from_vcard tries to parse a vcard with two or more fields of the same type (for example four mobile phones) it creates an object with four entries and the contact on my ipaq contain the last value and some dirty fields. With these patches it considers only the first value of any type: if (propval->propid & CEVT_FLAG_EMPTY) { ... } I'm waiting to know if there is something to change into these patch. Regards Sergio Il giorno ven, 28/10/2005 alle 18.57 +0200, David Eriksson ha scritto: > On Fri, 2005-10-28 at 18:19 +0200, Sergio CERLESI wrote: > > Hi, > > > > attached patch. > > Hi again! > > It makes me really glad that you try to fix this bug, but I really want > to keep the IDs in contact_ids.h as constants! > > I'm sure you can find a way to solve this without changing > contact_ids.h!
--- ./lib/contact_ids.h.orig 2005-10-27 17:55:18.000000000 +0200 +++ ./lib/contact_ids.h 2005-11-01 14:50:18.000000000 +0100 @@ -59,6 +59,8 @@ #define ID_EMAIL2 0x4093 #define ID_EMAIL3 0x40a3 +#define MAX_ID 47 + #define MAX_TEL_WORK 2 #define MAX_TEL_HOME 2 #define MAX_EMAIL 3 --- ./lib/contact.c.orig 2005-10-30 15:57:59.000000000 +0100 +++ ./lib/contact.c 2005-11-01 15:27:21.000000000 +0100 @@ -746,6 +746,59 @@ {ID_HOME_COUNTRY, ID_WORK_COUNTRY, ID_OTHER_COUNTRY} /* country */ }; +static const uint32_t value_ids[MAX_ID] = +{ + ID_NOTE, + ID_SUFFIX, + ID_FIRST_NAME, + ID_WORK_TEL, + ID_HOME_TEL, + ID_LAST_NAME, + ID_COMPANY, + ID_JOB_TITLE, + ID_DEPARTMENT, + ID_OFFICE_LOC, + ID_MOBILE_TEL, + ID_RADIO_TEL, + ID_CAR_TEL, + ID_WORK_FAX, + ID_HOME_FAX, + ID_HOME2_TEL, + ID_BIRTHDAY, + ID_ANNIVERSARY, + ID_CATEGORY, + ID_ASSISTANT, + ID_ASSISTANT_TEL, + ID_CHILDREN, + ID_WORK2_TEL, + ID_WEB_PAGE, + ID_PAGER, + ID_SPOUSE, + ID_FULL_NAME, + ID_TITLE, + ID_MIDDLE_NAME, + ID_HOME_STREET, + ID_HOME_LOCALITY, + ID_HOME_REGION, + ID_HOME_POSTAL_CODE, + ID_HOME_COUNTRY, + ID_WORK_STREET, + ID_WORK_LOCALITY, + ID_WORK_REGION, + ID_WORK_POSTAL_CODE, + ID_WORK_COUNTRY, + ID_OTHER_STREET, + ID_OTHER_LOCALITY, + ID_OTHER_REGION, + ID_OTHER_POSTAL_CODE, + ID_OTHER_COUNTRY, + ID_EMAIL, + ID_EMAIL2, + ID_EMAIL3 +}; + +#define number_ids(c,id) for (c=0; value_ids[c] != id && c < MAX_ID; c++); + static char* strdup_quoted_printable(const unsigned char* source)/*{{{*/ { char* result = malloc(strlen(source) + 1); @@ -841,39 +894,54 @@ if (date_to_struct(value, &time_fields)) { - CEPROPVAL* propval = &parser->fields[parser->field_index++]; - propval->propid = (id << 16) | CEVT_FILETIME; - time_fields_to_filetime(&time_fields, &propval->val.filetime); + int count; + + number_ids(count, id); + + CEPROPVAL* propval = &parser->fields[count]; + + if (propval->propid & CEVT_FLAG_EMPTY) + { + propval->propid = (id << 16) | CEVT_FILETIME; + time_fields_to_filetime(&time_fields, &propval->val.filetime); + } } } static void add_string(Parser* parser, uint32_t id, const char* type, char* value)/*{{{*/ { char* converted = NULL; - CEPROPVAL* field = &parser->fields[parser->field_index++]; + int count; + + number_ids(count, id); + + CEPROPVAL* field = &parser->fields[count]; assert(value); - - field->propid = (id << 16) | CEVT_LPWSTR; - if (STR_IN_STR(type, "QUOTED-PRINTABLE")) + if (field->propid & CEVT_FLAG_EMPTY) { - value = converted = strdup_quoted_printable(value); - assert(value); - } + field->propid = (id << 16) | CEVT_LPWSTR; - unescape_string(value); - assert(value); + if (STR_IN_STR(type, "QUOTED-PRINTABLE")) + { + value = converted = strdup_quoted_printable(value); + assert(value); + } - if (parser->utf8 || STR_IN_STR(type, "UTF-8")) - field->val.lpwstr = wstr_from_utf8(value); - else - field->val.lpwstr = wstr_from_ascii(value); + unescape_string(value); + assert(value); + + if (parser->utf8 || STR_IN_STR(type, "UTF-8")) + field->val.lpwstr = wstr_from_utf8(value); + else + field->val.lpwstr = wstr_from_ascii(value); - assert(field->val.lpwstr); + assert(field->val.lpwstr); - if (converted) - free(converted); + if (converted) + free(converted); + } }/*}}}*/ static bool parser_handle_field(/*{{{*/ @@ -1242,6 +1310,7 @@ size_t max_field_count = *field_count; const char* p = vcard; int state = VCARD_STATE_NEWLINE; + int count; const char* name = NULL; const char* name_end = NULL; const char* type = NULL; @@ -1263,6 +1332,19 @@ parser.field_index = 0; parser.utf8 = flags & RRA_CONTACT_UTF8; + for (count=0; count < MAX_ID; count++) + { + CEPROPVAL* field = &parser.fields[parser.field_index++]; + + if ( value_ids[count] == ID_BIRTHDAY || + value_ids[count] == ID_ANNIVERSARY) + field->propid = (value_ids[count] << 16) | + CEVT_FLAG_EMPTY | CEVT_FILETIME; + else + field->propid = (value_ids[count] << 16) | + CEVT_FLAG_EMPTY | CEVT_LPWSTR; + } + while (*p && parser.field_index < max_field_count) { switch (state)
--- ./lib/contact_ids.h.orig 2005-10-27 17:55:18.000000000 +0200 +++ ./lib/contact_ids.h 2005-11-01 14:50:18.000000000 +0100 @@ -59,6 +59,8 @@ #define ID_EMAIL2 0x4093 #define ID_EMAIL3 0x40a3 +#define MAX_ID 47 + #define MAX_TEL_WORK 2 #define MAX_TEL_HOME 2 #define MAX_EMAIL 3 --- ./lib/contact.c.orig 2005-10-30 15:57:59.000000000 +0100 +++ ./lib/contact.c 2005-11-01 15:50:26.000000000 +0100 @@ -718,15 +718,66 @@ bool utf8; /* default charset is utf8 */ } Parser; +typedef enum _field_ids +{ + ENUM_NOTE, + ENUM_SUFFIX, + ENUM_FIRST_NAME, + ENUM_WORK_TEL, + ENUM_HOME_TEL, + ENUM_LAST_NAME, + ENUM_COMPANY, + ENUM_JOB_TITLE, + ENUM_DEPARTMENT, + ENUM_OFFICE_LOC, + ENUM_MOBILE_TEL, + ENUM_RADIO_TEL, + ENUM_CAR_TEL, + ENUM_WORK_FAX, + ENUM_HOME_FAX, + ENUM_HOME2_TEL, + ENUM_BIRTHDAY, + ENUM_ANNIVERSARY, + ENUM_CATEGORY, + ENUM_ASSISTANT, + ENUM_ASSISTANT_TEL, + ENUM_CHILDREN, + ENUM_WORK2_TEL, + ENUM_WEB_PAGE, + ENUM_PAGER, + ENUM_SPOUSE, + ENUM_FULL_NAME, + ENUM_TITLE, + ENUM_MIDDLE_NAME, + ENUM_HOME_STREET, + ENUM_HOME_LOCALITY, + ENUM_HOME_REGION, + ENUM_HOME_POSTAL_CODE, + ENUM_HOME_COUNTRY, + ENUM_WORK_STREET, + ENUM_WORK_LOCALITY, + ENUM_WORK_REGION, + ENUM_WORK_POSTAL_CODE, + ENUM_WORK_COUNTRY, + ENUM_OTHER_STREET, + ENUM_OTHER_LOCALITY, + ENUM_OTHER_REGION, + ENUM_OTHER_POSTAL_CODE, + ENUM_OTHER_COUNTRY, + ENUM_EMAIL, + ENUM_EMAIL2, + ENUM_EMAIL3 +} field_ids; + #define NAME_FIELD_COUNT 5 static uint32_t name_ids[NAME_FIELD_COUNT] = { - ID_LAST_NAME, - ID_FIRST_NAME, - ID_MIDDLE_NAME, - ID_TITLE, - ID_SUFFIX + ENUM_LAST_NAME, + ENUM_FIRST_NAME, + ENUM_MIDDLE_NAME, + ENUM_TITLE, + ENUM_SUFFIX }; #define HOME 0 @@ -739,11 +790,62 @@ { {0, 0}, /* post office box */ {0, 0}, /* extended address */ - {ID_HOME_STREET, ID_WORK_STREET, ID_OTHER_STREET}, /* street */ - {ID_HOME_LOCALITY, ID_WORK_LOCALITY, ID_OTHER_LOCALITY}, /* locality */ - {ID_HOME_REGION, ID_WORK_REGION, ID_OTHER_REGION}, /* region */ - {ID_HOME_POSTAL_CODE, ID_WORK_POSTAL_CODE, ID_OTHER_POSTAL_CODE}, /* postal code */ - {ID_HOME_COUNTRY, ID_WORK_COUNTRY, ID_OTHER_COUNTRY} /* country */ + {ENUM_HOME_STREET, ENUM_WORK_STREET, ENUM_OTHER_STREET}, /* street */ + {ENUM_HOME_LOCALITY, ENUM_WORK_LOCALITY, ENUM_OTHER_LOCALITY}, /* locality */ + {ENUM_HOME_REGION, ENUM_WORK_REGION, ENUM_OTHER_REGION}, /* region */ + {ENUM_HOME_POSTAL_CODE, ENUM_WORK_POSTAL_CODE, ENUM_OTHER_POSTAL_CODE}, /* postal code */ + {ENUM_HOME_COUNTRY, ENUM_WORK_COUNTRY, ENUM_OTHER_COUNTRY} /* country */ +}; + +static const uint32_t value_ids[MAX_ID] = +{ + ID_NOTE, + ID_SUFFIX, + ID_FIRST_NAME, + ID_WORK_TEL, + ID_HOME_TEL, + ID_LAST_NAME, + ID_COMPANY, + ID_JOB_TITLE, + ID_DEPARTMENT, + ID_OFFICE_LOC, + ID_MOBILE_TEL, + ID_RADIO_TEL, + ID_CAR_TEL, + ID_WORK_FAX, + ID_HOME_FAX, + ID_HOME2_TEL, + ID_BIRTHDAY, + ID_ANNIVERSARY, + ID_CATEGORY, + ID_ASSISTANT, + ID_ASSISTANT_TEL, + ID_CHILDREN, + ID_WORK2_TEL, + ID_WEB_PAGE, + ID_PAGER, + ID_SPOUSE, + ID_FULL_NAME, + ID_TITLE, + ID_MIDDLE_NAME, + ID_HOME_STREET, + ID_HOME_LOCALITY, + ID_HOME_REGION, + ID_HOME_POSTAL_CODE, + ID_HOME_COUNTRY, + ID_WORK_STREET, + ID_WORK_LOCALITY, + ID_WORK_REGION, + ID_WORK_POSTAL_CODE, + ID_WORK_COUNTRY, + ID_OTHER_STREET, + ID_OTHER_LOCALITY, + ID_OTHER_REGION, + ID_OTHER_POSTAL_CODE, + ID_OTHER_COUNTRY, + ID_EMAIL, + ID_EMAIL2, + ID_EMAIL3 }; static char* strdup_quoted_printable(const unsigned char* source)/*{{{*/ @@ -841,39 +943,47 @@ if (date_to_struct(value, &time_fields)) { - CEPROPVAL* propval = &parser->fields[parser->field_index++]; - propval->propid = (id << 16) | CEVT_FILETIME; - time_fields_to_filetime(&time_fields, &propval->val.filetime); + CEPROPVAL* propval = &parser->fields[id]; + + if (propval->propid & CEVT_FLAG_EMPTY) + { + propval->propid = (value_ids[id] << 16) | CEVT_FILETIME; + time_fields_to_filetime(&time_fields, &propval->val.filetime); + } } } static void add_string(Parser* parser, uint32_t id, const char* type, char* value)/*{{{*/ { char* converted = NULL; - CEPROPVAL* field = &parser->fields[parser->field_index++]; + + CEPROPVAL* field = &parser->fields[id]; assert(value); - - field->propid = (id << 16) | CEVT_LPWSTR; - if (STR_IN_STR(type, "QUOTED-PRINTABLE")) + if (field->propid & CEVT_FLAG_EMPTY) { - value = converted = strdup_quoted_printable(value); - assert(value); - } + field->propid = (value_ids[id] << 16) | CEVT_LPWSTR; - unescape_string(value); - assert(value); + if (STR_IN_STR(type, "QUOTED-PRINTABLE")) + { + value = converted = strdup_quoted_printable(value); + assert(value); + } - if (parser->utf8 || STR_IN_STR(type, "UTF-8")) - field->val.lpwstr = wstr_from_utf8(value); - else - field->val.lpwstr = wstr_from_ascii(value); + unescape_string(value); + assert(value); - assert(field->val.lpwstr); + if (parser->utf8 || STR_IN_STR(type, "UTF-8")) + field->val.lpwstr = wstr_from_utf8(value); + else + field->val.lpwstr = wstr_from_ascii(value); + + assert(field->val.lpwstr); - if (converted) - free(converted); + if (converted) + free(converted); + } }/*}}}*/ static bool parser_handle_field(/*{{{*/ @@ -941,7 +1051,7 @@ }/*}}}*/ else if (STR_EQUAL(name, "FN"))/*{{{*/ { - add_string(parser, ID_FULL_NAME, type, value); + add_string(parser, ENUM_FULL_NAME, type, value); }/*}}}*/ else if (STR_EQUAL(name, "N"))/*{{{*/ { @@ -996,28 +1106,28 @@ if (STR_IN_STR(type, "HOME")) { if (nth==1) - add_string(parser, fax ? ID_HOME_FAX : ID_HOME_TEL, type, value); + add_string(parser, fax ? ENUM_HOME_FAX : ENUM_HOME_TEL, type, value); else - add_string(parser, ID_HOME2_TEL, type, value); + add_string(parser, ENUM_HOME2_TEL, type, value); } else if (STR_IN_STR(type, "WORK")) { if (nth==1) - add_string(parser, fax ? ID_WORK_FAX : ID_WORK_TEL, type, value); + add_string(parser, fax ? ENUM_WORK_FAX : ENUM_WORK_TEL, type, value); else - add_string(parser, ID_WORK2_TEL, type, value); + add_string(parser, ENUM_WORK2_TEL, type, value); } else if (STR_IN_STR(type, "CELL")) { - add_string(parser, ID_MOBILE_TEL, type, value); + add_string(parser, ENUM_MOBILE_TEL, type, value); } else if (STR_IN_STR(type, "X-EVOLUTION-ASSISTANT")) { - add_string(parser, ID_ASSISTANT_TEL, type, value); + add_string(parser, ENUM_ASSISTANT_TEL, type, value); } else if (STR_IN_STR(type, "X-EVOLUTION-RADIO")) { - add_string(parser, ID_RADIO_TEL, type, value); + add_string(parser, ENUM_RADIO_TEL, type, value); } else { @@ -1038,19 +1148,19 @@ switch (nth) { case 1: - add_string(parser, ID_EMAIL, type, value); + add_string(parser, ENUM_EMAIL, type, value); break; case 2: - add_string(parser, ID_EMAIL2, type, value); + add_string(parser, ENUM_EMAIL2, type, value); break; case 3: - add_string(parser, ID_EMAIL3, type, value); + add_string(parser, ENUM_EMAIL3, type, value); break; } }/*}}}*/ else if (STR_EQUAL(name, "URL"))/*{{{*/ { - add_string(parser, ID_WEB_PAGE, type, value); + add_string(parser, ENUM_WEB_PAGE, type, value); }/*}}}*/ else if (STR_EQUAL(name, "ORG"))/*{{{*/ { @@ -1058,19 +1168,19 @@ if (separator) { if (separator[1]) { - add_string(parser, ID_DEPARTMENT, type, separator + 1); + add_string(parser, ENUM_DEPARTMENT, type, separator + 1); } *separator = '\0'; } if (value[0]) { - add_string(parser, ID_COMPANY, type, value); + add_string(parser, ENUM_COMPANY, type, value); } }/*}}}*/ else if (STR_EQUAL(name, "TITLE"))/*{{{*/ { - add_string(parser, ID_JOB_TITLE, type, value); + add_string(parser, ENUM_JOB_TITLE, type, value); }/*}}}*/ else if (STR_EQUAL(name, "X-EVOLUTION-FILE-AS"))/*{{{*/ { @@ -1088,27 +1198,27 @@ }/*}}}*/ else if (STR_EQUAL(name, "CATEGORIES")) { - add_string(parser, ID_CATEGORY, type, value); + add_string(parser, ENUM_CATEGORY, type, value); } else if (STR_EQUAL(name, "BDAY")) { - add_date(parser, ID_BIRTHDAY, type, value); + add_date(parser, ENUM_BIRTHDAY, type, value); } else if (STR_EQUAL(name, "X-EVOLUTION-ANNIVERSARY")) { - add_date(parser, ID_ANNIVERSARY, type, value); + add_date(parser, ENUM_ANNIVERSARY, type, value); } else if (STR_EQUAL(name, "X-EVOLUTION-SPOUSE")) { - add_string(parser, ID_SPOUSE, type, value); + add_string(parser, ENUM_SPOUSE, type, value); } else if (STR_EQUAL(name, "X-EVOLUTION-ASSISTANT")) { - add_string(parser, ID_ASSISTANT, type, value); + add_string(parser, ENUM_ASSISTANT, type, value); } else if (STR_EQUAL(name, "X-EVOLUTION-OFFICE")) { - add_string(parser, ID_OFFICE_LOC, type, value); + add_string(parser, ENUM_OFFICE_LOC, type, value); } #if 0 @@ -1242,6 +1352,7 @@ size_t max_field_count = *field_count; const char* p = vcard; int state = VCARD_STATE_NEWLINE; + int count; const char* name = NULL; const char* name_end = NULL; const char* type = NULL; @@ -1263,6 +1374,19 @@ parser.field_index = 0; parser.utf8 = flags & RRA_CONTACT_UTF8; + for (count=0; count < MAX_ID; count++) + { + CEPROPVAL* field = &parser.fields[parser.field_index++]; + + if ( value_ids[count] == ID_BIRTHDAY || + value_ids[count] == ID_ANNIVERSARY) + field->propid = (value_ids[count] << 16) | + CEVT_FLAG_EMPTY | CEVT_FILETIME; + else + field->propid = (value_ids[count] << 16) | + CEVT_FLAG_EMPTY | CEVT_LPWSTR; + } + while (*p && parser.field_index < max_field_count) { switch (state)