From 43270b7ca9e0b54b976a40162c6ad7c062cb206a Mon Sep 17 00:00:00 2001 From: Rafal Michalski <michalski.raf@xxxxxxxxx> Date: Wed, 1 Sep 2010 13:07:12 +0200 Subject: [PATCH] Add handling for more than one address in vCard After pulling contacts only fields (pobox, extended, street, locality, region, postal, country) of one address were present in downloaded vCard structure (under ADR tag) in spite of that there can be more adresses stored on phonebook. To solve this problem extending number of columns and queries of database was needed especially. Distinguish between two types of address (HOME and WORK) is supported. --- plugins/phonebook-tracker.c | 93 ++++++++++++++++++++++++++++++++++++------ plugins/vcard.c | 89 ++++++++++++++++++++++++++++++++++------- plugins/vcard.h | 15 ++++++- 3 files changed, 167 insertions(+), 30 deletions(-) diff --git a/plugins/phonebook-tracker.c b/plugins/phonebook-tracker.c index bff85b8..193226f 100644 --- a/plugins/phonebook-tracker.c +++ b/plugins/phonebook-tracker.c @@ -43,16 +43,17 @@ #define TRACKER_RESOURCES_INTERFACE "org.freedesktop.Tracker1.Resources" #define TRACKER_DEFAULT_CONTACT_ME "http://www.semanticdesktop.org/ontologies/2007/03/22/nco#default-contact-me" -#define CONTACTS_ID_COL 28 -#define PULL_QUERY_COL_AMOUNT 29 +#define CONTACTS_ID_COL 35 +#define PULL_QUERY_COL_AMOUNT 36 #define COL_HOME_NUMBER 0 #define COL_HOME_EMAIL 7 #define COL_WORK_NUMBER 8 #define COL_FAX_NUMBER 16 #define COL_WORK_EMAIL 17 -#define COL_DATE 25 -#define COL_SENT 26 -#define COL_ANSWERED 27 +#define COL_DATE 32 +#define COL_SENT 33 +#define COL_ANSWERED 34 +#define ADDR_FIELD_AMOUNT 7 #define CONTACTS_QUERY_ALL \ "SELECT ?v nco:fullname(?c) " \ @@ -64,7 +65,9 @@ "nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew) " \ "nco:birthDate(?c) nco:nickname(?c) nco:websiteUrl(?c) " \ "nco:photo(?c) nco:fullname(?o) nco:department(?a) " \ - "nco:role(?a) " \ + "nco:role(?a) nco:pobox(?pw) nco:extendedAddress(?pw) " \ + "nco:streetAddress(?pw) nco:locality(?pw) nco:region(?pw) " \ + "nco:postalcode(?pw) nco:country(?pw) " \ "\"NOTACALL\" \"false\" \"false\" ?c " \ "WHERE { " \ "?c a nco:PersonContact . " \ @@ -84,6 +87,7 @@ "?c nco:hasAffiliation ?a . " \ "OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \ "OPTIONAL { ?a nco:hasEmailAddress ?ew . } " \ + "OPTIONAL { ?a nco:hasPostalAddress ?pw . } " \ "OPTIONAL { ?a nco:org ?o . } " \ "} " \ "}" @@ -112,7 +116,9 @@ "nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew) " \ "nco:birthDate(?c) nco:nickname(?c) nco:websiteUrl(?c) " \ "nco:photo(?c) nco:fullname(?o) nco:department(?a) " \ - "nco:role(?a) " \ + "nco:role(?a) nco:pobox(?pw) nco:extendedAddress(?pw) " \ + "nco:streetAddress(?pw) nco:locality(?pw) nco:region(?pw) " \ + "nco:postalcode(?pw) nco:country(?pw) " \ "nmo:receivedDate(?call) " \ "nmo:isSent(?call) nmo:isAnswered(?call) ?c " \ "WHERE { " \ @@ -133,6 +139,7 @@ "?c nco:hasAffiliation ?a . " \ "OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \ "OPTIONAL { ?a nco:hasEmailAddress ?ew . } " \ + "OPTIONAL { ?a nco:hasPostalAddress ?pw . } " \ "OPTIONAL { ?a nco:org ?o . } " \ "} " \ "} ORDER BY DESC(nmo:receivedDate(?call))" @@ -161,7 +168,9 @@ "nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew) " \ "nco:birthDate(?c) nco:nickname(?c) nco:websiteUrl(?c) " \ "nco:photo(?c) nco:fullname(?o) nco:department(?a) " \ - "nco:role(?a) " \ + "nco:role(?a) nco:pobox(?pw) nco:extendedAddress(?pw) " \ + "nco:streetAddress(?pw) nco:locality(?pw) nco:region(?pw) " \ + "nco:postalcode(?pw) nco:country(?pw) " \ "nmo:receivedDate(?call) " \ "nmo:isSent(?call) nmo:isAnswered(?call) ?c " \ "WHERE { " \ @@ -182,6 +191,7 @@ "?c nco:hasAffiliation ?a . " \ "OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \ "OPTIONAL { ?a nco:hasEmailAddress ?ew . } " \ + "OPTIONAL { ?a nco:hasPostalAddress ?pw . } " \ "OPTIONAL { ?a nco:org ?o . } " \ "} " \ "} ORDER BY DESC(nmo:receivedDate(?call))" @@ -210,7 +220,9 @@ "nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew)" \ "nco:birthDate(?c) nco:nickname(?c) nco:websiteUrl(?c) " \ "nco:photo(?c) nco:fullname(?o) nco:department(?a) " \ - "nco:role(?a) " \ + "nco:role(?a) nco:pobox(?pw) nco:extendedAddress(?pw) " \ + "nco:streetAddress(?pw) nco:locality(?pw) nco:region(?pw) " \ + "nco:postalcode(?pw) nco:country(?pw) " \ "nmo:receivedDate(?call) " \ "nmo:isSent(?call) nmo:isAnswered(?call) ?c " \ "WHERE { " \ @@ -230,6 +242,7 @@ "?c nco:hasAffiliation ?a . " \ "OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \ "OPTIONAL { ?a nco:hasEmailAddress ?ew . } " \ + "OPTIONAL { ?a nco:hasPostalAddress ?pw . } " \ "OPTIONAL { ?a nco:org ?o . } " \ "} " \ "} ORDER BY DESC(nmo:sentDate(?call))" @@ -257,7 +270,9 @@ "nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew) " \ "nco:birthDate(?c) nco:nickname(?c) nco:websiteUrl(?c) " \ "nco:photo(?c) nco:fullname(?o) nco:department(?a) " \ - "nco:role(?a) " \ + "nco:role(?a) nco:pobox(?pw) nco:extendedAddress(?pw) " \ + "nco:streetAddress(?pw) nco:locality(?pw) nco:region(?pw) " \ + "nco:postalcode(?pw) nco:country(?pw) " \ "nmo:receivedDate(?call) " \ "nmo:isSent(?call) nmo:isAnswered(?call) ?c " \ "WHERE { " \ @@ -277,6 +292,7 @@ "OPTIONAL { ?c nco:hasAffiliation ?a . " \ "OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \ "OPTIONAL { ?a nco:hasEmailAddress ?ew . } " \ + "OPTIONAL { ?a nco:hasPostalAddress ?pw . } " \ "OPTIONAL { ?a nco:org ?o . } " \ "} " \ "} UNION { " \ @@ -295,6 +311,7 @@ "OPTIONAL { ?c nco:hasAffiliation ?a . " \ "OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \ "OPTIONAL { ?a nco:hasEmailAddress ?ew . } " \ + "OPTIONAL { ?a nco:hasPostalAddress ?pw . } " \ "OPTIONAL { ?a nco:org ?o . } " \ "} " \ "} } ORDER BY DESC(nmo:receivedDate(?call))" @@ -329,7 +346,9 @@ "nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew)" \ "nco:birthDate(<%s>) nco:nickname(<%s>) nco:websiteUrl(<%s>) " \ "nco:photo(<%s>) nco:fullname(?o) nco:department(?a) " \ - "nco:role(?a) " \ + "nco:role(?a) nco:pobox(?pw) nco:extendedAddress(?pw) " \ + "nco:streetAddress(?pw) nco:locality(?pw) nco:region(?pw) " \ + "nco:postalcode(?pw) nco:country(?pw) " \ "\"NOTACALL\" \"false\" \"false\" <%s> " \ "WHERE { " \ "<%s> a nco:Contact . " \ @@ -349,6 +368,7 @@ "<%s> nco:hasAffiliation ?a . " \ "OPTIONAL { ?a nco:hasPhoneNumber ?w . }" \ "OPTIONAL { ?a nco:hasEmailAddress ?ew . }" \ + "OPTIONAL { ?a nco:hasPostalAddress ?pw . } " \ "OPTIONAL { ?a nco:org ?o . } " \ "} " \ "}" @@ -721,6 +741,41 @@ static void add_email(struct phonebook_contact *contact, const char *address, contact->emails = g_slist_append(contact->emails, email); } +static struct phonebook_address *find_address(GSList *addresses, + const char *address, int type) +{ + GSList *l; + + for (l = addresses; l; l = l->next) { + struct phonebook_address *addr = l->data; + if (g_strcmp0(addr->addr, address) == 0 && + addr->type == type) + return addr; + } + + return NULL; +} + +static void add_address(struct phonebook_contact *contact, + const char *address, int type) +{ + struct phonebook_address *addr; + + if (address == NULL || address_fields_present(address) == FALSE) + return; + + /* Not adding address if there is already added with the same value */ + if (find_address(contact->addresses, address, type)) + return; + + addr = g_new0(struct phonebook_address, 1); + + addr->addr = g_strdup(address); + addr->type = type; + + contact->addresses = g_slist_append(contact->addresses, addr); +} + static GString *gen_vcards(GSList *contacts, const struct apparam_field *params) { @@ -753,6 +808,7 @@ static void pull_contacts(char **reply, int num_fields, void *user_data) GString *vcards; int last_index, i; gboolean cdata_present = FALSE; + char *home_addr, *work_addr; DBG("reply %p", reply); @@ -803,9 +859,6 @@ add_entry: contact->additional = g_strdup(reply[4]); contact->prefix = g_strdup(reply[5]); contact->suffix = g_strdup(reply[6]); - contact->address = g_strdup_printf("%s;%s;%s;%s;%s;%s;%s", - reply[9], reply[10], reply[11], reply[12], - reply[13], reply[14], reply[15]); contact->birthday = g_strdup(reply[18]); contact->nickname = g_strdup(reply[19]); contact->website = g_strdup(reply[20]); @@ -827,6 +880,18 @@ add_numbers: add_email(contact, reply[COL_HOME_EMAIL], EMAIL_TYPE_HOME); add_email(contact, reply[COL_WORK_EMAIL], EMAIL_TYPE_WORK); + /* Adding addresses */ + home_addr = g_strdup_printf("%s;%s;%s;%s;%s;%s;%s", + reply[9], reply[10], reply[11], reply[12], + reply[13], reply[14], reply[15]); + + work_addr = g_strdup_printf("%s;%s;%s;%s;%s;%s;%s", + reply[25], reply[26], reply[27], reply[28], + reply[29], reply[30], reply[31]); + + add_address(contact, home_addr, ADDR_TYPE_HOME); + add_address(contact, work_addr, ADDR_TYPE_WORK); + DBG("contact %p", contact); /* Adding contacts data to wrapper struct - this data will be used to diff --git a/plugins/vcard.c b/plugins/vcard.c index 33a1ede..6d74e06 100644 --- a/plugins/vcard.c +++ b/plugins/vcard.c @@ -156,21 +156,20 @@ static gboolean contact_fields_present(struct phonebook_contact * contact) return FALSE; } -static gboolean address_fields_present(struct phonebook_contact *contact) +gboolean address_fields_present(const char *address) { - gchar **address_fields = g_strsplit(contact->address, ";", - ADDR_FIELD_AMOUNT); - int i = 0; + gchar **fields = g_strsplit(address, ";", ADDR_FIELD_AMOUNT); + int i; - for (; i < ADDR_FIELD_AMOUNT; ++i) { + for (i = 0; i < ADDR_FIELD_AMOUNT; ++i) { - if (strlen(address_fields[i]) != 0) { - g_strfreev(address_fields); + if (strlen(fields[i]) != 0) { + g_strfreev(fields); return TRUE; } } - g_strfreev(address_fields); + g_strfreev(fields); return FALSE; } @@ -376,15 +375,54 @@ static void vcard_printf_org(GString *vcards, contact->department, contact->title); } -static void vcard_printf_adr(GString *vcards, - struct phonebook_contact *contact) +static void vcard_printf_address(GString *vcards, uint8_t format, + const char *address, + enum phonebook_address_type category) { - if (address_fields_present(contact) == FALSE) { + char buf[LEN_MAX]; + char field[ADDR_FIELD_AMOUNT][LEN_MAX]; + const char *category_string = ""; + int len, i; + gchar **address_fields; + + if (!address || address_fields_present(address) == FALSE) { vcard_printf(vcards, "ADR:"); return; } - vcard_printf(vcards, "ADR:%s", contact->address); + switch (category) { + case ADDR_TYPE_HOME: + if (format == FORMAT_VCARD21) + category_string = "HOME"; + else if (format == FORMAT_VCARD30) + category_string = "TYPE=HOME"; + break; + case ADDR_TYPE_WORK: + if (format == FORMAT_VCARD21) + category_string = "WORK"; + else if (format == FORMAT_VCARD30) + category_string = "TYPE=WORK"; + break; + default: + if (format == FORMAT_VCARD21) + category_string = "OTHER"; + else if (format == FORMAT_VCARD30) + category_string = "TYPE=OTHER"; + break; + } + + address_fields = g_strsplit(address, ";", ADDR_FIELD_AMOUNT); + + for (i = 0; i < ADDR_FIELD_AMOUNT; ++i) { + len = strlen(address_fields[i]); + add_slash(field[i], address_fields[i], LEN_MAX, len); + } + + snprintf(buf, LEN_MAX, "%s;%s;%s;%s;%s;%s;%s", + field[0], field[1], field[2], field[3], field[4], field[5], field[6]); + g_strfreev(address_fields); + + vcard_printf(vcards,"ADR;%s:%s", category_string, buf); } static void vcard_printf_datetime(GString *vcards, @@ -465,8 +503,19 @@ void phonebook_add_contact(GString *vcards, struct phonebook_contact *contact, } } - if (filter & FILTER_ADR) - vcard_printf_adr(vcards, contact); + if (filter & FILTER_ADR) { + GSList *l = contact->addresses; + + if (g_slist_length(l) == 0) + vcard_printf_address(vcards, format, NULL, + ADDR_TYPE_OTHER); + + for (; l; l = l->next) { + struct phonebook_address *addr = l->data; + vcard_printf_address(vcards, format, addr->addr, + addr->type); + } + } if (filter & FILTER_BDAY) vcard_printf_tag(vcards, format, "BDAY", NULL, @@ -509,6 +558,14 @@ static void email_free(gpointer data, gpointer user_data) g_free(email); } +static void address_free(gpointer data, gpointer user_data) +{ + struct phonebook_address *addr = data; + + g_free(addr->addr); + g_free(addr); +} + void phonebook_contact_free(struct phonebook_contact *contact) { if (contact == NULL) @@ -520,13 +577,15 @@ void phonebook_contact_free(struct phonebook_contact *contact) g_slist_foreach(contact->emails, email_free, NULL); g_slist_free(contact->emails); + g_slist_foreach(contact->addresses, address_free, NULL); + g_slist_free(contact->addresses); + g_free(contact->fullname); g_free(contact->given); g_free(contact->family); g_free(contact->additional); g_free(contact->prefix); g_free(contact->suffix); - g_free(contact->address); g_free(contact->birthday); g_free(contact->nickname); g_free(contact->website); diff --git a/plugins/vcard.h b/plugins/vcard.h index b1e971e..d012106 100644 --- a/plugins/vcard.h +++ b/plugins/vcard.h @@ -40,6 +40,12 @@ enum phonebook_call_type { CALL_TYPE_OUTGOING, }; +enum phonebook_address_type { + ADDR_TYPE_HOME, + ADDR_TYPE_WORK, + ADDR_TYPE_OTHER, +}; + struct phonebook_number { char *tel; int type; @@ -50,6 +56,11 @@ struct phonebook_email { int type; }; +struct phonebook_address { + char *addr; + int type; +}; + struct phonebook_contact { char *fullname; char *given; @@ -59,7 +70,7 @@ struct phonebook_contact { GSList *emails; char *prefix; char *suffix; - char *address; + GSList *addresses; char *birthday; char *nickname; char *website; @@ -75,3 +86,5 @@ void phonebook_add_contact(GString *vcards, struct phonebook_contact *contact, uint64_t filter, uint8_t format); void phonebook_contact_free(struct phonebook_contact *contact); + +gboolean address_fields_present(const char *address); -- 1.6.3.3