[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-pim
Subject:    Re: [Kde-pim] [Kde-extra-gear] [PATCH] Add support for multiple
From:       Stefano Avallone <stavallo () unina ! it>
Date:       2010-01-05 0:04:20
Message-ID: 201001050105.00362.stavallo () unina ! it
[Download RAW message or body]

On Monday 04 January 2010 09:05:04 Kevin Krammer wrote:
> I've looked through the patch for the resource and it looks quite ok
> (obviously Adenilson has the last say on both patches).
> 
> I think the two helper functions should start with lower case characters
> because this is the most common style for methods and functions anywhere in
> KDE.
> 
> The transfer of pointer ownership when setting values is a bit strange, the
> values themselves are transferred, the container array is not.
> Since the API docs of the libgcal function does not require any parameter
>  to be dynamically allocated on the heap, I think it would be safer not to
>  assign string pointers inside but to strdup() them and consequently let
>  the caller keep ownership of the array and the strings.

Kevin, many thanks for your quick review. Find attached a second version of 
the patches, hopefully addressing your comments.
I have also done a review request at reviewboard.kde.org as you suggested.

Cheers,
Stefano

 
> Cheers,
> Kevin
> 
> P.S.: for patches against KDE's repository I'd recommend doing a review
> request at reviewboard.kde.org
> This simplifies the review process a lot as one can see the code
>  surrounding the changes
> 

["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,73 @@
 	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 freeArray(char **ptr_str, int n)
+{
+	int i;
+
+	if (ptr_str) {
+		for (i = 0; i < n; i++)
+			if (ptr_str[i])
+				free(ptr_str[i]);
+		free(ptr_str);
+	}
+}
+
+
 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;
+	char **values;
+	char **types;
 
 	if (!authenticated)
 		configure(0);
@@ -453,9 +584,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 = (char**) malloc(listEmail.size() * sizeof(char*));
+		types = (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);
+		
+		freeArray(values, listEmail.size());
+		freeArray(types, listEmail.size());
+	}
 
 	/* Bellow are optional */
 	listAddress = addressee.addresses();
@@ -466,17 +622,27 @@
 			t_byte = temp.toUtf8();
 			gcal_contact_set_address(contact, t_byte.data());
 		}
-
 	}
 
 	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 = (char**) malloc(listNumber.size() * sizeof(char*));
+		types = (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);
+		
+		freeArray(values, listNumber.size());
+		freeArray(types, listNumber.size());
 	}
 
 	temp = addressee.title();
@@ -491,6 +657,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 = (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);
+		freeArray(values, num_elem);
+	}
+
 	temp = addressee.note();
 	if (temp.length()) {
 		t_byte = temp.toUtf8();
@@ -540,15 +721,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;
+	char **values;
+	char **types;
 
 	if (!authenticated)
 		configure(0);
@@ -580,9 +769,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 = (char**) malloc(listEmail.size() * sizeof(char*));
+		types = (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);
+		
+		freeArray(values, listEmail.size());
+		freeArray(types, listEmail.size());
+	}
 
 	/* Bellow are optional */
 	listAddress = addressee.addresses();
@@ -597,13 +811,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 = (char**) malloc(listNumber.size() * sizeof(char*));
+		types = (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);
 
+		freeArray(values, listNumber.size());
+		freeArray(types, listNumber.size());
 	}
 
 	temp = addressee.title();
@@ -618,6 +842,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 = (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);
+		freeArray(values, num_elem);
+	}
+
 	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..da105f6 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, char **fields, 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, char **fields, 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, 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..dd7754a 100644
--- a/src/gcont.c
+++ b/src/gcont.c
@@ -156,6 +156,18 @@ static void clean_string(char *ptr_str)
 		free(ptr_str);
 }
 
+static void clean_multi_string(char **ptr_str, int n)
+{
+	int i;
+
+	if (ptr_str) {
+		for (i = 0; i < n; i++)
+			if (ptr_str[i])
+				free(ptr_str[i]);
+		free(ptr_str);
+	}
+}
+
 void gcal_init_contact(struct gcal_contact *contact)
 {
 	if (!contact)
@@ -165,9 +177,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 +198,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 +208,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..4ca91ff 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, char **fields, 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] = strdup(fields[temp]);
+		contact->emails_type[temp] = strdup(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, char **fields, 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] = strdup(fields[temp]);
+		contact->phone_numbers_type[temp] = strdup(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, 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] = strdup(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 PIM mailing list kde-pim@kde.org
https://mail.kde.org/mailman/listinfo/kde-pim
KDE PIM home page at http://pim.kde.org/

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic