[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-extra-gear
Subject: [Kde-extra-gear] [PATCH] Add support for multiple phone numbers in
From: Stefano Avallone <stavallo () unina ! it>
Date: 2010-01-03 12:30:58
Message-ID: 201001031331.08745.stavallo () unina ! it
[Download RAW message or body]
Hi list,
I implemented the support for multiple phone numbers and multiple email
addresses in the akonadi googledata agent and libgcal. The type of a phone
number and an email is also stored. Thanks to Kevin's suggestion, the google
group membership info for each contact is stored as a custom property, and
thus the membership is not lost upon a contact update made within
kaddressbook.
Please find attached the patches against:
svn://anonsvn.kde.org/home/kde/trunk/extragear/pim/googledata
and
git://repo.or.cz/libgcal.git
I have done some tests and it seems to work. Please review the patches and
test it. It would be great if those patches could be applied, as they provide
a much needed functionality, in my opinion.
Thanks,
Stefano
["googledata.diff" (text/x-patch)]
Index: contacts/googledataresource.cpp
===================================================================
--- contacts/googledataresource.cpp (revision 1066667)
+++ contacts/googledataresource.cpp (working copy)
@@ -124,6 +124,26 @@
return result;
}
+KABC::PhoneNumber::Type GoogleLabelToAkonadiType(char *label) {
+ if (!strcmp(label,"home"))
+ return KABC::PhoneNumber::Home;
+ if (!strcmp(label,"work"))
+ return KABC::PhoneNumber::Work;
+ if (!strcmp(label,"mobile"))
+ return KABC::PhoneNumber::Cell;
+ if (!strcmp(label,"car"))
+ return KABC::PhoneNumber::Car;
+ if (!strcmp(label,"isdn"))
+ return KABC::PhoneNumber::Isdn;
+ if (!strcmp(label,"pager"))
+ return KABC::PhoneNumber::Pager;
+ if (!strcmp(label,"home_fax"))
+ return KABC::PhoneNumber::Home | KABC::PhoneNumber::Fax;
+ if (!strcmp(label,"work_fax"))
+ return KABC::PhoneNumber::Work | KABC::PhoneNumber::Fax;
+ return KABC::PhoneNumber::Home | KABC::PhoneNumber::Work; // other
+}
+
void GoogleContactsResource::retrieveItems( const Akonadi::Collection &collection )
{
Q_UNUSED( collection );
@@ -175,32 +195,62 @@
contact = gcal_contact_element(&all_contacts, i);
KABC::Addressee addressee;
- KABC::PhoneNumber number;
KABC::Address address;
KABC::Picture photo;
QImage image;
QString temp;
+ int num_elem;
+ int pref;
+ int j;
+ char **values;
+ char **types;
/* name */
temp = QString::fromUtf8(gcal_contact_get_title(contact));
addressee.setNameFromString(temp);
/* email */
- temp = QString::fromUtf8(gcal_contact_get_email(contact));
- addressee.insertEmail(temp, true);
+ num_elem = gcal_contact_get_emails_nr(contact);
+ pref = gcal_contact_get_pref_email(contact);
+ values = gcal_contact_get_emails_field(contact);
+ types = gcal_contact_get_emails_type(contact);
+ for (j = 0; j < num_elem; j++) {
+ temp = QString::fromUtf8(values[j]);
+ addressee.insertEmail(temp, (j == pref));
+ temp = QString::fromUtf8(types[j]);
+ addressee.insertCustom(QString::fromUtf8("Google"), \
QString::fromUtf8("typeof_email_").append(QString::number(j)), temp); + }
/* address */
temp = QString::fromUtf8(gcal_contact_get_address(contact));
address.setExtended(temp);
addressee.insertAddress(address);
/* telephone */
- temp = QString::fromUtf8(gcal_contact_get_phone(contact));
- number.setNumber(temp);
- addressee.insertPhoneNumber(number);
+ num_elem = gcal_contact_get_phone_numbers_nr(contact);
+ values = gcal_contact_get_phone_numbers_field(contact);
+ types = gcal_contact_get_phone_numbers_type(contact);
+
+ for (j = 0; j < num_elem; j++) {
+ KABC::PhoneNumber number;
+ temp = QString::fromUtf8(values[j]);
+ number.setNumber(temp);
+ number.setType(GoogleLabelToAkonadiType(types[j]));
+ addressee.insertPhoneNumber(number);
+ }
+
/* profission */
temp = QString::fromUtf8(gcal_contact_get_profission(contact));
addressee.setTitle(temp);
/* company */
temp = QString::fromUtf8(gcal_contact_get_organization(contact));
addressee.setOrganization(temp);
+ /* Google group membership */
+ num_elem = gcal_contact_get_groupMembership_nr(contact);
+ values = gcal_contact_get_groupMembership(contact);
+ addressee.insertCustom(QString::fromUtf8("Google"), \
QString::fromUtf8("groupMembership_nr"), QString::number(num_elem)); +
+ for (j = 0; j < num_elem; j++) {
+ temp = QString::fromUtf8(values[j]);
+ addressee.insertCustom(QString::fromUtf8("Google"), \
QString::fromUtf8("groupMembership_").append(QString::number(j)), temp); + }
/* description */
temp = QString::fromUtf8(gcal_contact_get_content(contact));
addressee.setNote(temp);
@@ -274,6 +324,11 @@
QString temp;
KABC::Picture photo;
QImage image;
+ int num_elem;
+ int pref;
+ int j;
+ char **values;
+ char **types;
/* Just in case, I'm not sure when this member function is called */
pending.clear();
@@ -290,7 +345,8 @@
/* Query is inclusive regarding timestamp */
- if (all_contacts.length == 1) {
+ /* RFC: don't think so... */
+ if (all_contacts.length == 0) {
kError() << "no updates, done!";
itemsRetrievedIncremental(pending, deleted);
return result;
@@ -303,35 +359,58 @@
contact = gcal_contact_element(&all_contacts, i);
Item item(QLatin1String("text/directory"));
if (!strcmp(timestamp, gcal_contact_get_updated(contact))) {
- kError() << "This is an old contact... continue.";
+ kError() << "This is an old contact... continue.";
continue;
}
if (!gcal_contact_is_deleted(contact)) {
KABC::Addressee addressee;
- KABC::PhoneNumber number;
KABC::Address address;
/* name */
temp = QString::fromUtf8(gcal_contact_get_title(contact));
addressee.setNameFromString(temp);
kError() << "index: " << i <<"updated: " << temp;
/* email */
- temp = QString::fromUtf8(gcal_contact_get_email(contact));
- addressee.insertEmail(temp, true);
+ num_elem = gcal_contact_get_emails_nr(contact);
+ pref = gcal_contact_get_pref_email(contact);
+ values = gcal_contact_get_emails_field(contact);
+ types = gcal_contact_get_emails_type(contact);
+ for (j = 0; j < num_elem; j++) {
+ temp = QString::fromUtf8(values[j]);
+ addressee.insertEmail(temp, (j == pref));
+ temp = QString::fromUtf8(types[j]);
+ addressee.insertCustom(QString::fromUtf8("Google"), \
QString::fromUtf8("typeof_email_").append(QString::number(j)), temp); + }
/* address */
temp = QString::fromUtf8(gcal_contact_get_address(contact));
address.setExtended(temp);
addressee.insertAddress(address);
/* telephone */
- temp = QString::fromUtf8(gcal_contact_get_phone(contact));
- number.setNumber(temp);
- addressee.insertPhoneNumber(number);
+ num_elem = gcal_contact_get_phone_numbers_nr(contact);
+ values = gcal_contact_get_phone_numbers_field(contact);
+ types = gcal_contact_get_phone_numbers_type(contact);
+ for (j = 0; j < num_elem; j++) {
+ KABC::PhoneNumber number;
+ temp = QString::fromUtf8(values[j]);
+ number.setNumber(temp);
+ number.setType(GoogleLabelToAkonadiType(types[j]));
+ addressee.insertPhoneNumber(number);
+ }
/* profission */
temp = QString::fromUtf8(gcal_contact_get_profission(contact));
addressee.setTitle(temp);
/* company */
temp = QString::fromUtf8(gcal_contact_get_organization(contact));
addressee.setOrganization(temp);
+ /* Google group membership */
+ num_elem = gcal_contact_get_groupMembership_nr(contact);
+ values = gcal_contact_get_groupMembership(contact);
+ addressee.insertCustom(QString::fromUtf8("Google"), \
QString::fromUtf8("groupMembership_nr"), QString::number(num_elem)); +
+ for (j = 0; j < num_elem; j++) {
+ temp = QString::fromUtf8(values[j]);
+ addressee.insertCustom(QString::fromUtf8("Google"), \
QString::fromUtf8("groupMembership_").append(QString::number(j)), temp); + }
/* description */
temp = QString::fromUtf8(gcal_contact_get_content(contact));
addressee.setNote(temp);
@@ -414,21 +493,60 @@
synchronize();
}
+char *AkonadiTypeToGoogleLabel(KABC::PhoneNumber::Type type) {
+ switch ( type ) {
+ case KABC::PhoneNumber::Home:
+ return strdup("home");
+ break;
+ case KABC::PhoneNumber::Work:
+ return strdup("work");
+ break;
+ case KABC::PhoneNumber::Cell:
+ return strdup("mobile");
+ break;
+ case KABC::PhoneNumber::Car:
+ return strdup("car");
+ break;
+ case KABC::PhoneNumber::Isdn:
+ return strdup("isdn");
+ break;
+ case KABC::PhoneNumber::Pager:
+ return strdup("pager");
+ break;
+ case KABC::PhoneNumber::Home + KABC::PhoneNumber::Fax:
+ return strdup("home_fax");
+ break;
+ case KABC::PhoneNumber::Work + KABC::PhoneNumber::Fax:
+ return strdup("work_fax");
+ break;
+ default:
+ return strdup("other");
+ }
+}
+
void GoogleContactsResource::itemAdded( const Akonadi::Item &item, const \
Akonadi::Collection &collection ) {
Q_UNUSED(collection);
KABC::Addressee addressee;
- KABC::PhoneNumber number;
KABC::Address address;
gcal_contact_t contact;
QString temp;
+ QStringList listEmail;
+ QStringList::iterator email;
QByteArray t_byte;
QList<KABC::Address> listAddress;
QList<KABC::PhoneNumber> listNumber;
+ QList<KABC::PhoneNumber>::iterator number;
KABC::Picture photo;
int result;
+ int num_elem;
+ int pref = 0;
+ int j;
+ bool ok;
+ const char **values;
+ const char **types;
if (!authenticated)
configure(0);
@@ -453,9 +571,34 @@
t_byte = temp.toUtf8();
gcal_contact_set_title(contact, t_byte.data());
- temp = addressee.preferredEmail();
- t_byte = temp.toUtf8();
- gcal_contact_set_email(contact, t_byte.data());
+ listEmail = addressee.emails();
+ if (!listEmail.empty()) {
+ values = (const char**) malloc(listEmail.size() * sizeof(char*));
+ types = (const char**) malloc(listEmail.size() * sizeof(char*));
+ num_elem = 0;
+ for (email = listEmail.begin(); email != listEmail.end(); email++) {
+ temp = *email;
+ if (temp.length()) {
+ t_byte = temp.toUtf8();
+ values[num_elem] = strdup(t_byte.data());
+ if (temp == addressee.preferredEmail())
+ pref = num_elem;
+ temp = addressee.custom(QString::fromUtf8("Google"), \
QString::fromUtf8("typeof_email_").append(QString::number(num_elem))); + if \
(temp.length()) { + t_byte = temp.toUtf8();
+ types[num_elem] = strdup(t_byte.data());
+ }
+ else
+ types[num_elem] = strdup("other");
+ num_elem++;
+ }
+ }
+ if (num_elem)
+ gcal_contact_set_email(contact, num_elem, values, types, pref);
+
+ free(values);
+ free(types);
+ }
/* Bellow are optional */
listAddress = addressee.addresses();
@@ -471,12 +614,23 @@
listNumber = addressee.phoneNumbers();
if (!listNumber.empty()) {
- number = listNumber.first();
- temp = number.number();
- if (temp.length()) {
- t_byte = temp.toUtf8();
- gcal_contact_set_phone(contact, t_byte.data());
+ values = (const char**) malloc(listNumber.size() * sizeof(char*));
+ types = (const char**) malloc(listNumber.size() * sizeof(char*));
+ num_elem = 0;
+ for (number = listNumber.begin(); number != listNumber.end(); number++) {
+ temp = number->number();
+ if (temp.length()) {
+ t_byte = temp.toUtf8();
+ values[num_elem] = strdup(t_byte.data());
+ types[num_elem] = AkonadiTypeToGoogleLabel(number->type());
+ num_elem++;
+ }
}
+ if (num_elem)
+ gcal_contact_set_phone(contact, num_elem, values, types);
+
+ free(values);
+ free(types);
}
temp = addressee.title();
@@ -491,6 +645,21 @@
gcal_contact_set_organization(contact, t_byte.data());
}
+ temp = addressee.custom(QString::fromUtf8("Google"), \
QString::fromUtf8("groupMembership_nr")); + num_elem = temp.toInt(&ok);
+ if (ok) {
+ values = (const char**) malloc(num_elem * sizeof(char*));
+ for (j = 0; j < num_elem; j++) {
+ temp = addressee.custom(QString::fromUtf8("Google"), \
QString::fromUtf8("groupMembership_").append(QString::number(j))); + if \
(temp.length()) { + t_byte = temp.toUtf8();
+ values[j] = strdup(t_byte.data());
+ }
+ }
+ gcal_contact_set_groupMembership(contact, num_elem, values);
+ free(values);
+ }
+
temp = addressee.note();
if (temp.length()) {
t_byte = temp.toUtf8();
@@ -540,15 +709,23 @@
Q_UNUSED(parts);
KABC::Addressee addressee;
- KABC::PhoneNumber number;
KABC::Address address;
QList<KABC::Address> listAddress;
+ QStringList listEmail;
+ QStringList::iterator email;
QList<KABC::PhoneNumber> listNumber;
+ QList<KABC::PhoneNumber>::iterator number;
gcal_contact_t contact;
QByteArray t_byte;
QString temp;
KABC::Picture photo;
int result;
+ int num_elem;
+ int j;
+ bool ok;
+ int pref = 0;
+ const char **values;
+ const char **types;
if (!authenticated)
configure(0);
@@ -580,9 +757,34 @@
t_byte = temp.toUtf8();
gcal_contact_set_title(contact, t_byte.data());
- temp = addressee.preferredEmail();
- t_byte = temp.toUtf8();
- gcal_contact_set_email(contact, t_byte.data());
+ listEmail = addressee.emails();
+ if (!listEmail.empty()) {
+ values = (const char**) malloc(listEmail.size() * sizeof(char*));
+ types = (const char**) malloc(listEmail.size() * sizeof(char*));
+ num_elem = 0;
+ for (email = listEmail.begin(); email != listEmail.end(); email++) {
+ temp = *email;
+ if (temp.length()) {
+ t_byte = temp.toUtf8();
+ values[num_elem] = strdup(t_byte.data());
+ if (temp == addressee.preferredEmail())
+ pref = num_elem;
+ temp = addressee.custom(QString::fromUtf8("Google"), \
QString::fromUtf8("typeof_email_").append(QString::number(num_elem))); + if \
(temp.length()) { + t_byte = temp.toUtf8();
+ types[num_elem] = strdup(t_byte.data());
+ }
+ else
+ types[num_elem] = strdup("other");
+ num_elem++;
+ }
+ }
+ if (num_elem)
+ gcal_contact_set_email(contact, num_elem, values, types, pref);
+
+ free(values);
+ free(types);
+ }
/* Bellow are optional */
listAddress = addressee.addresses();
@@ -597,13 +799,23 @@
listNumber = addressee.phoneNumbers();
if (!listNumber.empty()) {
- number = listNumber.first();
- temp = number.number();
- if (temp.length()) {
- t_byte = temp.toUtf8();
- gcal_contact_set_phone(contact, t_byte.data());
+ values = (const char**) malloc(listNumber.size() * sizeof(char*));
+ types = (const char**) malloc(listNumber.size() * sizeof(char*));
+ num_elem = 0;
+ for (number = listNumber.begin(); number != listNumber.end(); number++) {
+ temp = number->number();
+ if (temp.length()) {
+ t_byte = temp.toUtf8();
+ values[num_elem] = strdup(t_byte.data());
+ types[num_elem] = AkonadiTypeToGoogleLabel(number->type());
+ num_elem++;
+ }
}
+ if (num_elem)
+ gcal_contact_set_phone(contact, num_elem, values, types);
+ free(values);
+ free(types);
}
temp = addressee.title();
@@ -618,6 +830,21 @@
gcal_contact_set_organization(contact, t_byte.data());
}
+ temp = addressee.custom(QString::fromUtf8("Google"), \
QString::fromUtf8("groupMembership_nr")); + num_elem = temp.toInt(&ok);
+ if (ok) {
+ values = (const char**) malloc(num_elem * sizeof(char*));
+ for (j = 0; j < num_elem; j++) {
+ temp = addressee.custom(QString::fromUtf8("Google"), \
QString::fromUtf8("groupMembership_").append(QString::number(j))); + if \
(temp.length()) { + t_byte = temp.toUtf8();
+ values[j] = strdup(t_byte.data());
+ }
+ }
+ gcal_contact_set_groupMembership(contact, num_elem, values);
+ free(values);
+ }
+
temp = addressee.note();
if (temp.length()) {
t_byte = temp.toUtf8();
["libgcal.diff" (text/x-patch)]
diff --git a/inc/gcontact.h b/inc/gcontact.h
index dabf528..67d3437 100644
--- a/inc/gcontact.h
+++ b/inc/gcontact.h
@@ -303,7 +303,10 @@ char gcal_contact_is_deleted(gcal_contact_t contact);
* atom stream, it will be set to an empty string (i.e. "").
*/
-char *gcal_contact_get_email(gcal_contact_t contact);
+int gcal_contact_get_emails_nr(gcal_contact_t contact);
+int gcal_contact_get_pref_email(gcal_contact_t contact);
+char **gcal_contact_get_emails_field(gcal_contact_t contact);
+char **gcal_contact_get_emails_type(gcal_contact_t contact);
/** Access contact description.
*
@@ -362,7 +365,9 @@ char *gcal_contact_get_im(gcal_contact_t contact);
* atom stream, it will be set to an empty string (i.e. "").
*/
-char *gcal_contact_get_phone(gcal_contact_t contact);
+int gcal_contact_get_phone_numbers_nr(gcal_contact_t contact);
+char **gcal_contact_get_phone_numbers_field(gcal_contact_t contact);
+char **gcal_contact_get_phone_numbers_type(gcal_contact_t contact);
/** Access contact telephone.
*
@@ -377,6 +382,18 @@ char *gcal_contact_get_phone(gcal_contact_t contact);
*/
char *gcal_contact_get_address(gcal_contact_t contact);
+/** Access Google group membership info.
+ *
+ * @param contact A contact object, see \ref gcal_contact.
+ *
+ * @return Pointer to internal object field (dont free it!) or NULL (in error
+ * case or if the field is not set). If the entry hasn't this field in the
+ * atom stream, it will be set to an empty string (i.e. "").
+
+ */
+int gcal_contact_get_groupMembership_nr(gcal_contact_t contact);
+char **gcal_contact_get_groupMembership(gcal_contact_t contact);
+
/** Access contact photo data.
*
* @param contact A contact object, see \ref gcal_contact.
@@ -425,11 +442,15 @@ int gcal_contact_set_title(gcal_contact_t contact, const char \
*field);
*
* @param contact A contact object, see \ref gcal_contact.
*
- * @param field String with contact email (e.g. "joe.doe@nobody.com").
+ * @param num_elem Number of email addresses.
*
- * @return 0 for sucess, -1 otherwise.
+ * @param fields Email addresses.
+ *
+ * @param types Email addresses types.
+ *
+ * @return 0 for success, -1 otherwise
*/
-int gcal_contact_set_email(gcal_contact_t contact, const char *field);
+int gcal_contact_set_email(gcal_contact_t contact, int num_elem, const char \
**fields, const char **types, int pref);
/** Sets contact edit url.
*
@@ -480,11 +501,15 @@ int gcal_contact_set_etag(gcal_contact_t contact, const char \
*field);
*
* @param contact A contact object, see \ref gcal_contact.
*
- * @param field Phone number.
+ * @param num_elem Number of phone numbers.
+ *
+ * @param fields Phone numbers.
+ *
+ * @param types Phone number types.
*
* @return 0 for success, -1 otherwise
*/
-int gcal_contact_set_phone(gcal_contact_t contact, const char *field);
+int gcal_contact_set_phone(gcal_contact_t contact, int num_elem, const char \
**fields, const char **types);
/** Sets the contact address (for while only a single address is supported).
*
@@ -498,6 +523,18 @@ int gcal_contact_set_phone(gcal_contact_t contact, const char \
*field);
*/
int gcal_contact_set_address(gcal_contact_t contact, const char *field);
+/** Sets the contact group membership info.
+ *
+ * @param contact A contact object, see \ref gcal_contact.
+ *
+ * @param num_elem Number of groups.
+ *
+ * @param field Group names.
+ *
+ * @return 0 for success, -1 otherwise
+ */
+int gcal_contact_set_groupMembership(gcal_contact_t contact, int num_elem, const \
char **fields); +
/** Sets the organization title.
*
*
diff --git a/inc/internal_gcal.h b/inc/internal_gcal.h
index 849d3e9..abf42ef 100644
--- a/inc/internal_gcal.h
+++ b/inc/internal_gcal.h
@@ -188,8 +188,14 @@ struct gcal_contact {
/** Has the common entry data fields (id, updated, title, edit_uri) */
struct gcal_entry common;
/* Here starts google contact unique fields */
- /** Contact email */
- char *email;
+ /** Contact emails */
+ char **emails_field;
+ /** Contact email types */
+ char **emails_type;
+ /** Number of contact emails */
+ int emails_nr;
+ /** Index of the preferred email */
+ int pref_email;
/* Here starts the extra fields */
/** Notes about contact */
@@ -200,10 +206,18 @@ struct gcal_contact {
char *org_title;
/** IM contact */
char *im;
- /** Phone number */
- char *phone_number;
+ /** Phone numbers */
+ char **phone_numbers_field;
+ /** Phone number types */
+ char **phone_numbers_type;
+ /** Number of phone numbers */
+ int phone_numbers_nr;
/** Address */
char *post_address;
+ /** Google group membership info */
+ char **groupMembership;
+ /** Google group membership info */
+ int groupMembership_nr;
/** Photo edit url */
char *photo;
/** Photo byte array */
diff --git a/inc/xml_aux.h b/inc/xml_aux.h
index 0138644..97c8e3c 100644
--- a/inc/xml_aux.h
+++ b/inc/xml_aux.h
@@ -57,6 +57,10 @@ static const char atom_ns[] = "atom";
static const char gd_href[] = "http://schemas.google.com/g/2005";
static const char gd_ns[] = "gd";
+/** Google group membership URL/URI */
+static const char gContact_href[] = "http://schemas.google.com/contact/2008";
+static const char gContact_ns[] = "gContact";
+
/** Opensearch URL/URI */
static const char open_search_href[] = "http://a9.com/-/spec/opensearch/1.1/";
static const char open_search_ns[] = "openSearch";
diff --git a/src/atom_parser.c b/src/atom_parser.c
index 95e5ac2..86b34c7 100644
--- a/src/atom_parser.c
+++ b/src/atom_parser.c
@@ -226,6 +226,74 @@ exit:
return result;
}
+static int extract_and_check_multi(xmlDoc *doc, char *xpath_expression, int \
getContent, char *attr1, char *attr2, char* attr3, char ***values, char ***types, int \
*pref) +{
+ xmlXPathObject *xpath_obj;
+ xmlNodeSet *node;
+ xmlChar *tmp;
+ int result = -1;
+ int i;
+
+ xpath_obj = execute_xpath_expression(doc,
+ xpath_expression,
+ NULL);
+
+ if ( (!values) || (attr2 && !types) || (attr3 && !pref) ) {
+ fprintf(stderr, "extract_and_check: null pointers received");
+ goto exit;
+ }
+
+ if (!xpath_obj) {
+ fprintf(stderr, "extract_and_check: failed to extract data");
+ goto exit;
+ }
+
+ node = xpath_obj->nodesetval;
+
+ if (!node) {
+ result = 0;
+ goto cleanup;
+ }
+ result = node->nodeNr;
+
+ *values = (char **)malloc( node->nodeNr * sizeof(char*) );
+ if (attr2)
+ *types = (char **)malloc( node->nodeNr * sizeof(char*) );
+
+ for (i = 0; i < node->nodeNr; i++) {
+ if (getContent)
+ (*values)[i] = xmlNodeGetContent(node->nodeTab[i]);
+ else if (xmlHasProp(node->nodeTab[i],attr1))
+ (*values)[i] = xmlGetProp(node->nodeTab[i],attr1);
+ else
+ (*values)[i] = strdup(" ");
+
+ if (attr2) {
+ if (xmlHasProp(node->nodeTab[i],attr2)) {
+ tmp = xmlGetProp(node->nodeTab[i], attr2);
+ (*types)[i] = strdup(strchr(tmp,'#')+1);
+ xmlFree(tmp);
+ }
+ else
+ (*types)[i] = strdup("");
+ }
+
+ if (attr3) {
+ if (xmlHasProp(node->nodeTab[i],attr3)) {
+ tmp = xmlGetProp(node->nodeTab[i], attr3);
+ if (!strcmp(tmp,"true"))
+ *pref = i;
+ xmlFree(tmp);
+ }
+ }
+ }
+
+cleanup:
+ xmlXPathFreeObject(xpath_obj);
+exit:
+ return result;
+}
+
char *get_etag_attribute(xmlNode * a_node)
{
xmlChar *uri = NULL;
@@ -478,12 +546,21 @@ int atom_extract_contact(xmlNode *entry, struct gcal_contact \
*ptr_entry) if (!ptr_entry->common.edit_uri)
goto cleanup;
- /* Gets the email contact field */
- ptr_entry->email = extract_and_check(doc, "//atom:entry/"
- "gd:email",
- "address");
+ /* Gets email addressess */
+ ptr_entry->emails_nr = extract_and_check_multi(doc,
+ "//atom:entry/"
+ "gd:email",
+ 0,
+ "address",
+ "rel",
+ "primary",
+ &ptr_entry->emails_field,
+ &ptr_entry->emails_type,
+ &ptr_entry->pref_email);
+
+ /* TODO Commented to allow contacts without an email address
if (!ptr_entry->email)
- goto cleanup;
+ goto cleanup; */
/* Here begins extra fields */
@@ -508,10 +585,16 @@ int atom_extract_contact(xmlNode *entry, struct gcal_contact \
*ptr_entry) NULL);
- /* Gets contact first phone number */
- ptr_entry->phone_number = extract_and_check(doc,
+ /* Gets contact phone numbers */
+ ptr_entry->phone_numbers_nr = extract_and_check_multi(doc,
"//atom:entry/"
- "gd:phoneNumber/text()",
+ "gd:phoneNumber",
+ 1,
+ NULL,
+ "rel",
+ NULL,
+ &ptr_entry->phone_numbers_field,
+ &ptr_entry->phone_numbers_type,
NULL);
/* Gets contact first address */
@@ -520,6 +603,17 @@ int atom_extract_contact(xmlNode *entry, struct gcal_contact \
*ptr_entry) "gd:postalAddress/text()",
NULL);
+ /* Gets contact group membership info */
+ ptr_entry->groupMembership_nr = extract_and_check_multi(doc,
+ "//atom:entry/"
+ "gContact:groupMembershipInfo[@deleted='false']",
+ 0,
+ "href",
+ NULL,
+ NULL,
+ &ptr_entry->groupMembership,
+ NULL,
+ NULL);
/* Gets contact photo edit url and test for etag */
ptr_entry->photo = extract_and_check(doc, "//atom:entry/"
diff --git a/src/gcal_parser.c b/src/gcal_parser.c
index 5ca0467..c36493e 100644
--- a/src/gcal_parser.c
+++ b/src/gcal_parser.c
@@ -457,12 +457,16 @@ int xmlcontact_create(struct gcal_contact *contact, char \
**xml_contact,
* contact X calendar.
*/
int result = -1;
+ int i;
xmlDoc *doc = NULL;
xmlNode *root = NULL;
xmlNode *node = NULL;
xmlNode *child = NULL;
xmlNs *ns;
+ xmlNs *ns2;
xmlChar *xml_str = NULL;
+ char *temp;
+ const char * rel_prefix = "http://schemas.google.com/g/2005#";
doc = xmlNewDoc(BAD_CAST "1.0");
root = xmlNewNode(NULL, BAD_CAST "entry");
@@ -478,6 +482,9 @@ int xmlcontact_create(struct gcal_contact *contact, char \
**xml_contact,
ns = xmlNewNs(root, BAD_CAST gd_href, BAD_CAST "gd");
+ /* Google contact group */
+ ns2 = xmlNewNs(root, BAD_CAST gContact_href, BAD_CAST "gContact");
+
xmlDocSetRootElement(doc, root);
/* category element */
@@ -522,18 +529,25 @@ int xmlcontact_create(struct gcal_contact *contact, char \
**xml_contact, xmlAddChild(root, node);
}
-
- /* There are 3 types of e-mail: other, work, home */
- node = xmlNewNode(ns, "email");
- if (!node)
- goto cleanup;
-
- xmlSetProp(node, BAD_CAST "rel",
- BAD_CAST "http://schemas.google.com/g/2005#other");
- xmlSetProp(node, BAD_CAST "address",
- BAD_CAST contact->email);
- xmlAddChild(root, node);
-
+ /* email addresses */
+ if (contact->emails_nr > 0) {
+ for (i = 0; i < contact->emails_nr; i++) {
+ if (!(node = xmlNewNode(ns, "email")))
+ goto cleanup;
+ temp = (char *)malloc((strlen(contact->emails_type[i])+strlen(rel_prefix)+1) * \
sizeof(char)); + strcpy(temp, rel_prefix);
+ strcat(temp, contact->emails_type[i]);
+ xmlSetProp(node, BAD_CAST "rel",
+ BAD_CAST temp);
+ xmlSetProp(node, BAD_CAST "address",
+ BAD_CAST contact->emails_field[i]);
+ if (i == contact->pref_email)
+ xmlSetProp(node, BAD_CAST "primary",
+ BAD_CAST "true");
+ xmlAddChild(root, node);
+ free(temp);
+ }
+ }
/* Here begin extra fields */
/* content element */
@@ -569,18 +583,23 @@ int xmlcontact_create(struct gcal_contact *contact, char \
**xml_contact, xmlAddChild(root, node);
}
- /* For while I will get only the first phone number
- * TODO: use an array in gcal_contact to support multiple
- */
- if (contact->phone_number) {
- if (!(node = xmlNewNode(ns, "phoneNumber")))
- goto cleanup;
- /* TODO: support user settting phone type */
- xmlSetProp(node, BAD_CAST "rel",
- BAD_CAST "http://schemas.google.com/g/2005#other");
- xmlNodeAddContent(node, contact->phone_number);
- xmlAddChild(root, node);
+ /* Get phone numbers */
+ if (contact->phone_numbers_nr > 0) {
+ for (i = 0; i < contact->phone_numbers_nr; i++) {
+ if (!(node = xmlNewNode(ns, "phoneNumber")))
+ goto cleanup;
+ /* TODO: support user settting phone type */
+ temp = (char *)malloc((strlen(contact->phone_numbers_type[i])+strlen(rel_prefix)+1) \
* sizeof(char)); + strcpy(temp, rel_prefix);
+ strcat(temp, contact->phone_numbers_type[i]);
+ xmlSetProp(node, BAD_CAST "rel",
+ BAD_CAST temp);
+
+ xmlNodeAddContent(node, contact->phone_numbers_field[i]);
+ xmlAddChild(root, node);
+ free(temp);
+ }
}
/* For while I will get only the first postal address
@@ -596,6 +615,18 @@ int xmlcontact_create(struct gcal_contact *contact, char \
**xml_contact, xmlAddChild(root, node);
}
+ /* Google group membership info */
+ if (contact->groupMembership_nr > 0) {
+ for (i = 0; i < contact->groupMembership_nr; i++) {
+ if (!(node = xmlNewNode(ns2, "groupMembershipInfo")))
+ goto cleanup;
+ xmlSetProp(node, BAD_CAST "deleted",
+ BAD_CAST "false");
+ xmlSetProp(node, BAD_CAST "href",
+ BAD_CAST contact->groupMembership[i]);
+ xmlAddChild(root, node);
+ }
+ }
/* TODO: implement missing fields (im)
*/
diff --git a/src/gcont.c b/src/gcont.c
index 9a1b125..d2e7ffd 100644
--- a/src/gcont.c
+++ b/src/gcont.c
@@ -156,6 +156,17 @@ static void clean_string(char *ptr_str)
free(ptr_str);
}
+static void clean_multi_string(char **ptr_str, int n)
+{
+ int i;
+
+ for (i = 0; i < n; i++)
+ if (ptr_str[i])
+ free(ptr_str[i]);
+ if (ptr_str)
+ free(ptr_str);
+}
+
void gcal_init_contact(struct gcal_contact *contact)
{
if (!contact)
@@ -165,9 +176,13 @@ void gcal_init_contact(struct gcal_contact *contact)
contact->common.id = contact->common.updated = NULL;
contact->common.title = contact->common.xml = NULL;
contact->common.edit_uri = contact->common.etag = NULL;
- contact->email = contact->content = NULL;
+ contact->emails_field = contact->emails_type = NULL;
+ contact->emails_nr = contact->pref_email = 0;
+ contact->content = NULL;
contact->org_name = contact->org_title = contact->im = NULL;
- contact->phone_number = contact->post_address = NULL;
+ contact->phone_numbers_field = contact->phone_numbers_type = NULL;
+ contact->phone_numbers_nr = contact->groupMembership_nr = 0;
+ contact->post_address = contact->groupMembership = NULL;
contact->photo = contact->photo_data = NULL;
contact->photo_length = 0;
}
@@ -182,7 +197,9 @@ void gcal_destroy_contact(struct gcal_contact *contact)
clean_string(contact->common.title);
clean_string(contact->common.edit_uri);
clean_string(contact->common.etag);
- clean_string(contact->email);
+ clean_multi_string(contact->emails_field, contact->emails_nr);
+ clean_multi_string(contact->emails_type, contact->emails_nr);
+ contact->emails_nr = contact->pref_email = 0;
clean_string(contact->common.xml);
/* Extra fields */
@@ -190,7 +207,10 @@ void gcal_destroy_contact(struct gcal_contact *contact)
clean_string(contact->org_name);
clean_string(contact->org_title);
clean_string(contact->im);
- clean_string(contact->phone_number);
+ clean_multi_string(contact->phone_numbers_field, contact->phone_numbers_nr);
+ clean_multi_string(contact->phone_numbers_type, contact->phone_numbers_nr);
+ clean_multi_string(contact->groupMembership, contact->groupMembership_nr);
+ contact->phone_numbers_nr = contact->groupMembership_nr = 0;
clean_string(contact->post_address);
clean_string(contact->photo);
clean_string(contact->photo_data);
diff --git a/src/gcontact.c b/src/gcontact.c
index d3d8218..93ec44e 100644
--- a/src/gcontact.c
+++ b/src/gcontact.c
@@ -317,11 +317,32 @@ char gcal_contact_is_deleted(gcal_contact_t contact)
/* This are the fields unique to calendar contacts */
-char *gcal_contact_get_email(gcal_contact_t contact)
+int gcal_contact_get_emails_nr(gcal_contact_t contact)
+{
+ if ((!contact))
+ return 0;
+ return contact->emails_nr;
+}
+
+int gcal_contact_get_pref_email(gcal_contact_t contact)
+{
+ if ((!contact))
+ return 0;
+ return contact->pref_email;
+}
+
+char **gcal_contact_get_emails_field(gcal_contact_t contact)
+{
+ if ((!contact))
+ return NULL;
+ return contact->emails_field;
+}
+
+char **gcal_contact_get_emails_type(gcal_contact_t contact)
{
if ((!contact))
return NULL;
- return contact->email;
+ return contact->emails_type;
}
char *gcal_contact_get_content(gcal_contact_t contact)
@@ -352,11 +373,25 @@ char *gcal_contact_get_im(gcal_contact_t contact)
return contact->im;
}
-char *gcal_contact_get_phone(gcal_contact_t contact)
+int gcal_contact_get_phone_numbers_nr(gcal_contact_t contact)
+{
+ if ((!contact))
+ return 0;
+ return contact->phone_numbers_nr;
+}
+
+char **gcal_contact_get_phone_numbers_field(gcal_contact_t contact)
+{
+ if ((!contact))
+ return NULL;
+ return contact->phone_numbers_field;
+}
+
+char **gcal_contact_get_phone_numbers_type(gcal_contact_t contact)
{
if ((!contact))
return NULL;
- return contact->phone_number;
+ return contact->phone_numbers_type;
}
char *gcal_contact_get_address(gcal_contact_t contact)
@@ -366,6 +401,20 @@ char *gcal_contact_get_address(gcal_contact_t contact)
return contact->post_address;
}
+int gcal_contact_get_groupMembership_nr(gcal_contact_t contact)
+{
+ if ((!contact))
+ return 0;
+ return contact->groupMembership_nr;
+}
+
+char **gcal_contact_get_groupMembership(gcal_contact_t contact)
+{
+ if ((!contact))
+ return NULL;
+ return contact->groupMembership;
+}
+
char *gcal_contact_get_photo(gcal_contact_t contact)
{
if ((!contact))
@@ -400,18 +449,34 @@ int gcal_contact_set_title(gcal_contact_t contact, const char \
*field) return result;
}
-int gcal_contact_set_email(gcal_contact_t contact, const char *field)
+int gcal_contact_set_email(gcal_contact_t contact, int num_elem, const char \
**fields, const char **types, int pref) {
int result = -1;
+ int temp;
- if ((!contact) || (!field))
+ if ((!contact) || (!num_elem) || (!fields) || (!types))
return result;
- if (contact->email)
- free(contact->email);
+ if (contact->emails_nr > 0) {
+ for (temp = 0; temp < contact->emails_nr; temp++) {
+ if (contact->emails_field[temp])
+ free(contact->emails_field[temp]);
+ if (contact->emails_type[temp])
+ free(contact->emails_type[temp]);
+ }
+ free(contact->emails_field);
+ free(contact->emails_type);
+ }
- contact->email = strdup(field);
- if (contact->email)
+ contact->emails_nr = num_elem;
+ contact->pref_email = pref;
+ contact->emails_field = (char**) malloc(num_elem * sizeof(char*));
+ contact->emails_type = (char**) malloc(num_elem * sizeof(char*));
+ for (temp = 0; temp < contact->emails_nr; temp++) {
+ contact->emails_field[temp] = fields[temp];
+ contact->emails_type[temp] = types[temp];
+ }
+ if (contact->emails_nr)
result = 0;
return result;
@@ -470,18 +535,33 @@ int gcal_contact_set_etag(gcal_contact_t contact, const char \
*field) return result;
}
-int gcal_contact_set_phone(gcal_contact_t contact, const char *field)
+int gcal_contact_set_phone(gcal_contact_t contact, int num_elem, const char \
**fields, const char **types) {
int result = -1;
+ int temp;
- if ((!contact) || (!field))
+ if ((!contact) || (!num_elem) || (!fields) || (!types))
return result;
- if (contact->phone_number)
- free(contact->phone_number);
+ if (contact->phone_numbers_nr > 0) {
+ for (temp = 0; temp < contact->phone_numbers_nr; temp++) {
+ if (contact->phone_numbers_field[temp])
+ free(contact->phone_numbers_field[temp]);
+ if (contact->phone_numbers_type[temp])
+ free(contact->phone_numbers_type[temp]);
+ }
+ free(contact->phone_numbers_field);
+ free(contact->phone_numbers_type);
+ }
- contact->phone_number = strdup(field);
- if (contact->phone_number)
+ contact->phone_numbers_nr = num_elem;
+ contact->phone_numbers_field = (char**) malloc(num_elem * sizeof(char*));
+ contact->phone_numbers_type = (char**) malloc(num_elem * sizeof(char*));
+ for (temp = 0; temp < contact->phone_numbers_nr; temp++) {
+ contact->phone_numbers_field[temp] = fields[temp];
+ contact->phone_numbers_type[temp] = types[temp];
+ }
+ if (contact->phone_numbers_nr)
result = 0;
return result;
@@ -504,6 +584,33 @@ int gcal_contact_set_address(gcal_contact_t contact, const char \
*field) return result;
}
+int gcal_contact_set_groupMembership(gcal_contact_t contact, int num_elem, const \
char **fields) +{
+ int result = -1;
+ int temp;
+
+ if ((!contact) || (!num_elem) || (!fields))
+ return result;
+
+ if (contact->groupMembership_nr > 0) {
+ for (temp = 0; temp < contact->groupMembership_nr; temp++) {
+ if (contact->groupMembership[temp])
+ free(contact->groupMembership[temp]);
+ }
+ free(contact->groupMembership);
+ }
+
+ contact->groupMembership_nr = num_elem;
+ contact->groupMembership = (char**) malloc(num_elem * sizeof(char*));
+ for (temp = 0; temp < contact->groupMembership_nr; temp++) {
+ contact->groupMembership[temp] = fields[temp];
+ }
+ if (contact->groupMembership_nr)
+ result = 0;
+
+ return result;
+}
+
int gcal_contact_set_profission(gcal_contact_t contact, const char *field)
{
int result = -1;
diff --git a/src/xml_aux.c b/src/xml_aux.c
index 26a1ef1..bc69d6c 100644
--- a/src/xml_aux.c
+++ b/src/xml_aux.c
@@ -61,6 +61,7 @@ int register_namespaces(xmlXPathContext *xpathCtx, const xmlChar \
*name_space, else {
if (register_namespaces(xpathCtx, atom_ns, atom_href) ||
register_namespaces(xpathCtx, gd_ns, gd_href) ||
+ register_namespaces(xpathCtx, gContact_ns, gContact_href) ||
register_namespaces(xpathCtx, open_search_ns,
open_search_href))
goto exit;
_______________________________________________
Kde-extra-gear mailing list
Kde-extra-gear@kde.org
https://mail.kde.org/mailman/listinfo/kde-extra-gear
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic