Example #1
0
static void cache_cb(EBook *book, EBookStatus estatus, GList *contacts,
							void *user_data)
{
	struct query_context *data = user_data;
	GList *l;

	if (estatus == E_BOOK_ERROR_CANCELLED) {
		error("E-Book operation was cancelled: status %d", estatus);
		goto fail;
	}

	data->completed = TRUE;

	if (estatus != E_BOOK_ERROR_OK) {
		error("E-Book query failed: status %d", estatus);
		goto done;
	}

	for (l = contacts; l; l = g_list_next(l)) {
		EContact *contact = E_CONTACT(l->data);
		EVCard *evcard = E_VCARD(contact);
		EVCardAttribute *attrib;
		char *uid, *tel, *name;

		name = evcard_name_attribute_to_string(evcard);
		if (!name)
			continue;

		attrib = e_vcard_get_attribute(evcard, EVC_UID);
		if (!attrib)
			continue;

		uid =  e_vcard_attribute_get_value(attrib);
		if (!uid)
			continue;

		attrib = e_vcard_get_attribute(evcard, EVC_TEL);
		if (!attrib)
			continue;

		tel =  e_vcard_attribute_get_value(attrib);

		data->entry_cb(uid, PHONEBOOK_INVALID_HANDLE, name, NULL,
							tel, data->user_data);
		g_free(name);
		g_free(uid);
		g_free(tel);
	}
done:
	data->ready_cb(data->user_data);

fail:
	if (data->completed)
		g_free(data);
}
Example #2
0
GdkPixbuf *
hito_vcard_get_photo_pixbuf (EVCard *card)
{
  GdkPixbuf *ret;
  GList *list = NULL;

  list = hito_vcard_get_named_attributes (card, EVC_PHOTO);
  if (list)
  {
    GdkPixbufLoader *ploader;
    guchar *buf;
    gsize size;
    const gchar *value;
    gchar *type, *type_up;
    int cmp = 0;

    value = e_vcard_attribute_get_value ((EVCardAttribute *)list->data);
    if (!value)
    {
      g_list_free (list);
      return NULL;
    }

    type = hito_vcard_attribute_get_type (list->data);
    if (type)
    {
      type_up = g_ascii_strup (type, -1);
      cmp = strcmp (type_up, "URL");
      g_free (type);
      g_free (type_up);

      /* TODO: we can't deal with images from URLs yet */
      if (!cmp)
      {
        g_list_free (list);
        return NULL;
      }
    }

    buf = g_base64_decode (value, &size);
    ploader = gdk_pixbuf_loader_new ();
    g_signal_connect (G_OBJECT (ploader), "size-prepared", G_CALLBACK (contact_photo_size),  NULL);

    gdk_pixbuf_loader_write (ploader, buf, size, NULL);
    gdk_pixbuf_loader_close (ploader, NULL);
    ret = g_object_ref (gdk_pixbuf_loader_get_pixbuf (ploader));
    g_object_unref (ploader);
    g_list_free (list);
    return ret;
  }
  else
  {
    return NULL;
  }
}
static void
verify_commit (EContact *contact)
{
	EVCardAttribute *attr;
	gchar *email_value;

	g_assert ((attr = e_vcard_get_attribute (E_VCARD (contact), EVC_EMAIL)));
	g_assert (e_vcard_attribute_is_single_valued (attr));
	email_value = e_vcard_attribute_get_value (attr);
	g_assert (!g_strcmp0 (email_value, EMAIL_ADD));
}
Example #4
0
static gboolean
compare_single_value (EVCard *vcard,
                      const gchar *attrname,
                      const gchar *expected_value)
{
	EVCardAttribute *attr;
	gchar *str;

	g_return_val_if_fail (vcard != NULL, FALSE);
	g_return_val_if_fail (attrname != NULL, FALSE);
	g_return_val_if_fail (expected_value != NULL, FALSE);

	attr = e_vcard_get_attribute (vcard, attrname);
	g_return_val_if_fail (attr != NULL, FALSE);

	str = e_vcard_attribute_get_value (attr);
	g_return_val_if_fail (str != NULL, FALSE);
	g_return_val_if_fail (g_strcmp0 (str, expected_value) == 0, FALSE);

	g_free (str);

	return TRUE;
}
Example #5
0
static void
accum_sip (GString *buffer,
	   EContact *contact,
	   EABContactFormatterSIPType use_sip_type,
	   const gchar *icon,
	   guint html_flags)
{
	const gchar *html_label = _("SIP");
	GList *sip_attr_list, *l;
	GString *val = g_string_new ("");
	gchar *tmp;

	sip_attr_list = e_contact_get_attributes (contact, E_CONTACT_SIP);
	for (l = sip_attr_list; l; l = g_list_next (l)) {
		EVCardAttribute *attr = l->data;
		gchar *sip;
		const gchar *str;
		EABContactFormatterSIPType sip_type;

		if (e_vcard_attribute_has_type (attr, "HOME"))
			sip_type = EAB_CONTACT_FORMATTER_SIP_TYPE_HOME;
		else if (e_vcard_attribute_has_type (attr, "WORK"))
			sip_type = EAB_CONTACT_FORMATTER_SIP_TYPE_WORK;
		else
			sip_type = EAB_CONTACT_FORMATTER_SIP_TYPE_OTHER;

		if (sip_type != use_sip_type)
			continue;

		sip = e_vcard_attribute_get_value (attr);
		if (!sip || !*sip) {
			g_free (sip);
			continue;
		}

		tmp = maybe_create_url (sip, html_flags);
		if (tmp)
			str = tmp;
		else
			str = sip;

		if ((html_flags & E_TEXT_TO_HTML_CONVERT_URLS) != 0) {
			gchar *value = e_text_to_html (str, html_flags);

			if (value && *value) {
				if (val->len)
					g_string_append (val, "<br>");
				g_string_append (val, value);
			}

			g_free (value);
		} else {
			if (val->len)
				g_string_append (val, "<br>");
			g_string_append (val, str);
		}

		g_free (tmp);
		g_free (sip);
	}

	if (val->str && *val->str) {
		if ((html_flags & E_TEXT_TO_HTML_CONVERT_URLS) != 0)
			html_flags = 0;

		render_table_row (buffer, html_label, val->str, icon, html_flags);
	}

	g_string_free (val, TRUE);
	g_list_free_full (sip_attr_list, (GDestroyNotify) e_vcard_attribute_free);
}
Example #6
0
void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
		phonebook_cache_ready_cb ready_cb, void *user_data, int *err)
{
	struct query_context *data;
	EBookQuery *query;
	GSList *l;
	EContact *me;
	EVCard *evcard;
	GError *gerr = NULL;
	EBook *eb;
	EVCardAttribute *attrib;
	char *uid, *tel, *cname;

	if (g_strcmp0(PB_CONTACTS_FOLDER, name) != 0) {
		if (err)
			*err = -ENOENT;

		return NULL;
	}

	DBG("");

	query = e_book_query_any_field_contains("");

	data = g_new0(struct query_context, 1);
	data->entry_cb = entry_cb;
	data->ready_cb = ready_cb;
	data->user_data = user_data;
	data->query = query;
	data->ebooks = open_ebooks();

	/* Add 0.vcf */
	if (e_book_get_self(&me, &eb, &gerr) == FALSE) {
		g_error_free(gerr);
		goto next;
	}

	evcard = E_VCARD(me);

	cname = evcard_name_attribute_to_string(evcard);
	if (!cname)
		cname = g_strdup("");

	attrib = e_vcard_get_attribute(evcard, EVC_UID);
	uid = e_vcard_attribute_get_value(attrib);
	if (!uid)
		uid = g_strdup("");

	attrib = e_vcard_get_attribute(evcard, EVC_TEL);
	if (attrib)
		tel =  e_vcard_attribute_get_value(attrib);
	else
		tel = g_strdup("");

	data->entry_cb(uid, 0, cname, NULL, tel, data->user_data);

	data->count++;

	g_free(cname);
	g_free(uid);
	g_free(tel);
	g_object_unref(eb);

next:
	for (l = data->ebooks; l != NULL; l = g_slist_next(l)) {
		EBook *ebook = l->data;

		if (e_book_is_opened(ebook) == FALSE)
			continue;

		if (e_book_get_contacts_async(ebook, query,
						cache_cb, data) == TRUE)
			data->queued_calls++;
	}

	if (err)
		*err = (data->queued_calls == 0 ? -ENOENT : 0);

	return data;
}
Example #7
0
static void cache_cb(EBook *book, const GError *gerr, GList *contacts,
							void *user_data)
{
	struct query_context *data = user_data;
	GList *l;

	data->queued_calls--;

	if (data->canceled)
		goto canceled;

	if (gerr != NULL) {
		error("E-Book operation failed: %s", gerr->message);
		goto done;
	}

	DBG("");

	for (l = contacts; l; l = g_list_next(l)) {
		EContact *contact = E_CONTACT(l->data);
		EVCard *evcard = E_VCARD(contact);
		EVCardAttribute *attrib;
		char *uid, *tel, *name;

		name = evcard_name_attribute_to_string(evcard);
		if (!name)
			continue;

		attrib = e_vcard_get_attribute(evcard, EVC_UID);
		if (!attrib)
			continue;

		uid = e_vcard_attribute_get_value(attrib);
		if (!uid)
			continue;

		attrib = e_vcard_get_attribute(evcard, EVC_TEL);
		if (attrib)
			tel = e_vcard_attribute_get_value(attrib);
		else
			tel = g_strdup("");

		data->entry_cb(uid, PHONEBOOK_INVALID_HANDLE, name, NULL,
							tel, data->user_data);

		g_free(name);
		g_free(uid);
		g_free(tel);
	}

	g_list_free_full(contacts, g_object_unref);

done:
	if (data->queued_calls == 0)
		data->ready_cb(data->user_data);

	return;

canceled:
	if (data->queued_calls == 0)
		free_query_context(data);
}
Example #8
0
/* This function returns a GtkEntry derived from field_id for a particular
 * contact.
 * Returns GtkWidget * on success, NULL on failure
 * TODO: Lots of duplicated code here, perhaps add a few bits to utils?
 */
static GtkWidget *
contacts_edit_widget_new (EContact *contact, EVCardAttribute *attr,
			  gboolean multi_line, gboolean *changed)
{
	GtkWidget *type_edit;
	EContactChangeData *data;
	const gchar *attr_name = e_vcard_attribute_get_name (attr);

	/* Create data structure for changes */
	data = g_new0 (EContactChangeData, 1);
	data->contact = contact;
	data->attr = attr;
	data->changed = changed;

	/* Create widget */
	if (!e_vcard_attribute_is_single_valued (attr)) {
		/* Handle structured fields */
		GtkWidget *adr_table;
		guint field;
		GList *values = e_vcard_attribute_get_values (attr);
		
		adr_table = gtk_table_new (1, 2, FALSE);
		gtk_table_set_col_spacings (GTK_TABLE (adr_table), 6);
		gtk_table_set_row_spacings (GTK_TABLE (adr_table), 6);
		gtk_container_set_border_width (GTK_CONTAINER (adr_table), 6);
		
		/* Set widget that contains attribute data */		
		data->widget = adr_table;
		
		/* Add type editor */
		type_edit = contacts_type_edit_widget_new (attr, multi_line,
			changed);
		if (type_edit) {
			GtkWidget *label = gtk_label_new (NULL);
			gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
			gtk_label_set_markup (GTK_LABEL (label),
                                /* TODO: make nicer for i18n */
				_("<b>Type:</b>"));
			gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);
			gtk_table_attach (GTK_TABLE (adr_table), label, 0, 1,
					  0, 1, GTK_FILL, GTK_FILL, 0, 0);
			gtk_table_attach (GTK_TABLE (adr_table), type_edit,
					  1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
			gtk_widget_show (label);
			gtk_widget_show (type_edit);
		}

		/* Create sub-fields */
		for (field = 0; values; values = values->next, field++) {
			/* If no information exists, assume field is
			 * single-lined.
			 * TODO: It may be more intelligent in the future
			 * to look at the value and search for new-line
			 * characters.
			 */
			gboolean multiline = FALSE;
			GtkWidget *label = NULL, *entry;
			const ContactsStructuredField *sfield =
			    contacts_get_structured_field (attr_name, field);
			const gchar *string = (const gchar *)values->data;
			/* If we have the information, label the field */
			if (sfield) {
				gchar *label_markup;

				if (sfield->priority == 0)
					continue;

				label = gtk_label_new (NULL);
				multiline = sfield->multiline;				
				gtk_label_set_use_markup (GTK_LABEL (label),
							  TRUE);

				label_markup = g_strdup_printf (
                                        /** Translators, the first
                                         * argument is the field's
                                         * name, ex. <b>Country:</b>
                                         */				
                                        _("<b>%s:</b>"),
					gettext(sfield->subfield_name));
				gtk_label_set_markup (GTK_LABEL (label),
						      label_markup);
				g_free (label_markup);
				gtk_label_set_justify (GTK_LABEL (label),
						       GTK_JUSTIFY_RIGHT);
				if (!multiline)
					gtk_misc_set_alignment (
						GTK_MISC (label), 1, 0.5);
				else
					gtk_misc_set_alignment (
						GTK_MISC (label), 1, 0);
				gtk_table_attach (GTK_TABLE (adr_table), label,
						  0, 1, field + 1, field + 2,
						  GTK_FILL, GTK_FILL, 0, 0);
				gtk_widget_show (label);
			}
			/* This code is pretty much a verbatim copy of the
			 * code below to handle single-valued fields
			 */
			if (multiline) {
				GtkTextBuffer *buffer;
				GtkTextView *view;
				
				view = GTK_TEXT_VIEW (gtk_text_view_new ());
				gtk_widget_set_name (GTK_WIDGET (view),
						     attr_name);
				buffer = gtk_text_view_get_buffer (view);
				
				gtk_text_buffer_set_text (buffer, string ?
							   string : "", -1);
				gtk_text_view_set_editable (view, TRUE);
				gtk_text_view_set_accepts_tab (view, FALSE);
				
				entry = gtk_frame_new (NULL);
				gtk_frame_set_shadow_type (GTK_FRAME (entry),
							   GTK_SHADOW_IN);
				gtk_container_add (GTK_CONTAINER (entry),
						   GTK_WIDGET (view));
				gtk_widget_show (GTK_WIDGET (view));
				
				/* Connect signal for changes */
				g_signal_connect (G_OBJECT (buffer), "changed",
						  G_CALLBACK
						  (contacts_entry_changed),
						  data);
			} else {
				entry = gtk_entry_new ();
				gtk_widget_set_name (entry, attr_name);
				gtk_entry_set_text (GTK_ENTRY (entry),
						    string ? string : "");

				/* Connect signal for changes */
				g_signal_connect (G_OBJECT (entry), "changed",
						  G_CALLBACK
						  (contacts_entry_changed),
						  data);
			}
			gtk_widget_show (entry);
	     		/* Hide the label when the entry is hidden */
			g_signal_connect_swapped (G_OBJECT (entry), "hide", 
					  G_CALLBACK (gtk_widget_hide),
					  label);
			gtk_table_attach (GTK_TABLE (adr_table), entry,
					  1, 2, field + 1, field + 2,
					  GTK_FILL | GTK_EXPAND, GTK_FILL,
					  0, 0);
		}
	} else if (multi_line) {
		/* Handle single-valued fields that span multiple lines */
		gchar *string = e_vcard_attribute_get_value (attr);
		
		GtkWidget *container = NULL;
		GtkTextView *view = GTK_TEXT_VIEW (gtk_text_view_new ());
		GtkTextBuffer *buffer = gtk_text_view_get_buffer (view);
		
		gtk_widget_set_name (GTK_WIDGET (view), attr_name);
		gtk_text_buffer_set_text (buffer, string ? string : "", -1);
		gtk_text_view_set_editable (view, TRUE);
		gtk_text_view_set_accepts_tab (view, FALSE);
		g_free (string);

		container = gtk_frame_new (NULL);
		gtk_frame_set_shadow_type (
			GTK_FRAME (container), GTK_SHADOW_IN);
		gtk_container_add (GTK_CONTAINER (container),
				   GTK_WIDGET (view));
		gtk_widget_show (GTK_WIDGET (view));

/*		if (type_edit) {
			gtk_widget_show (type_edit);
			gtk_widget_show (window);
			container = gtk_hbox_new (FALSE, 6);
			gtk_box_pack_start (GTK_BOX (container), type_edit,
					    FALSE, TRUE, 0);
			gtk_box_pack_end (GTK_BOX (container), window,
					    TRUE, TRUE, 0);
		}*/

		/* Set widget that contains attribute data */		
		data->widget = container;
		
		/* Connect signal for changes */
		g_signal_connect (G_OBJECT (buffer), "changed", G_CALLBACK
				  (contacts_entry_changed), data);
	} else {
		/* Handle simple single-valued single-line fields */
		gchar *string = e_vcard_attribute_get_value (attr);
		GtkWidget *entry, *container = NULL;

		entry = gtk_entry_new ();
		gtk_entry_set_text (GTK_ENTRY (entry),
				    string ? string : "");
		gtk_widget_set_name (entry, attr_name);
		g_free (string);

/*		if (type_edit) {
			gtk_widget_show (type_edit);
			gtk_widget_show (entry);
			container = gtk_hbox_new (FALSE, 6);
			gtk_box_pack_start (GTK_BOX (container), type_edit,
					    FALSE, TRUE, 0);
			gtk_box_pack_end (GTK_BOX (container), entry,
					    TRUE, TRUE, 0);
		}*/

		/* Set widget that contains attribute data */		
		data->widget = container ? container : entry;
		
		/* Connect signal for changes */
		g_signal_connect (G_OBJECT (entry), "changed", G_CALLBACK
				  (contacts_entry_changed), data);
	}

	/* Free change data structure on destruction */
	g_signal_connect_swapped (G_OBJECT (data->widget), "destroy", 
				  G_CALLBACK (g_free), data);
	
	gtk_widget_set_name (data->widget, attr_name);
	return data->widget;
}
Example #9
0
static gboolean
check_if_same (EContact *contact,
               EContact *match)
{
	EContactField field;
	gchar *string = NULL, *string1 = NULL;
	gboolean res = TRUE;


	for (field = E_CONTACT_FULL_NAME; res && field != (E_CONTACT_LAST_SIMPLE_STRING -1); field++) {

		if (field == E_CONTACT_EMAIL_1) {
			GList *email_attr_list1, *email_attr_list2, *iter1, *iter2;
			gint num_of_email1, num_of_email2;

			email_attr_list1 = e_contact_get_attributes (contact, E_CONTACT_EMAIL);
			num_of_email1 = g_list_length (email_attr_list1);

			email_attr_list2 = e_contact_get_attributes (match, E_CONTACT_EMAIL);
			num_of_email2 = g_list_length (email_attr_list2);

			if (num_of_email1 != num_of_email2) {
				res = FALSE;
				break;
			} else { /* Do pairwise-comparisons on all of the e-mail addresses. */
				iter1 = email_attr_list1;
				while (iter1) {
					gboolean         match = FALSE;
					EVCardAttribute *attr;
					gchar           *email_address1;

					attr = iter1->data;
					email_address1 = e_vcard_attribute_get_value (attr);

					iter2 = email_attr_list2;
					while ( iter2 && match == FALSE) {
						gchar *email_address2;

						attr = iter2->data;
						email_address2 = e_vcard_attribute_get_value (attr);

						if (g_ascii_strcasecmp (email_address1, email_address2) == 0) {
							match = TRUE;
						}

						g_free (email_address2);
						iter2 = g_list_next (iter2);
					}

					g_free (email_address1);
					iter1 = g_list_next (iter1);

					if (match == FALSE) {
						res = FALSE;
						break;
					}
				}
			}

			g_list_free_full (email_attr_list1, (GDestroyNotify) e_vcard_attribute_free);
			g_list_free_full (email_attr_list2, (GDestroyNotify) e_vcard_attribute_free);
		} else if (field > E_CONTACT_FIRST_EMAIL_ID && field <= E_CONTACT_LAST_EMAIL_ID) {
			/* nothing to do, all emails are checked above */
		}
		else {
			string = (gchar *) e_contact_get_const (contact, field);
			string1 = (gchar *) e_contact_get_const (match, field);
			if ((string && *string) && (string1 && *string1) && (g_ascii_strcasecmp (string1, string))) {
				res = FALSE;
				break;
			/*if the field entry exist in either of the contacts,we'll have to give the choice and thus merge button should be sensitive*/
			} else if ((string && *string) && !(string1 && *string1)) {
				res = FALSE;
				break;
			}
		}
	}

	return res;
}
Example #10
0
static void
create_dropdowns_for_multival_attr(GList *match_attr_list,
                                   GList *contact_attr_list,
                                   GList **use_attr_list,
                                   gint *row,
                                   GtkTable *table,
                                   gchar *label_str)
{
	GtkWidget *label, *hbox, *dropdown;
	GList *miter, *citer;
	GHashTable *match_attrs; /* attr in the 'match' contact from address book */

	match_attrs = g_hash_table_new_full (camel_strcase_hash, camel_strcase_equal, g_free, NULL);

	for (miter = match_attr_list; miter; miter = g_list_next (miter)) {
		EVCardAttribute *attr = miter->data;
		gchar *value;

		value = e_vcard_attribute_get_value (attr);
		if (value && *value) {
			g_hash_table_insert (match_attrs, value, attr);
			*use_attr_list = g_list_prepend (*use_attr_list, attr);
		} else {
			g_free (value);
		}
	}

	*use_attr_list = g_list_reverse (*use_attr_list);

	for (citer = contact_attr_list; citer; citer = g_list_next (citer)) {
		EVCardAttribute *attr = citer->data;
		gchar *value;

		value = e_vcard_attribute_get_value (attr);
		if (value && *value) {
			if (!g_hash_table_lookup (match_attrs, value)) {
				dropdown_data *data;

				/* the attr is not set in both contacts */
				*use_attr_list = g_list_append (*use_attr_list, attr);

				/* remove to avoid collisions with match UI_SLOTs */
				e_vcard_attribute_remove_param (attr, EVOLUTION_UI_SLOT_PARAM);

				(*row)++;
				label = gtk_label_new (label_str);
				hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
				gtk_box_pack_start (GTK_BOX (hbox), (GtkWidget *) label, FALSE, FALSE, 0);
				gtk_table_attach_defaults (table, (GtkWidget *) hbox, 0, 1, *row, *row + 1);

				dropdown = gtk_combo_box_text_new ();
				gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (dropdown), value);

				data = g_new0 (dropdown_data, 1);

				gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (dropdown), "");

				gtk_combo_box_set_active (GTK_COMBO_BOX (dropdown), 0);
				data->email_attr_list_item = g_list_last (*use_attr_list);
				data->email_attr = attr;

				g_signal_connect (
					dropdown, "changed",
					G_CALLBACK (attr_dropdown_changed), data);
				g_object_set_data_full (G_OBJECT (dropdown), "eab-contact-merging::dropdown-data", data, g_free);

				hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
				gtk_box_pack_start (GTK_BOX (hbox), (GtkWidget *) dropdown, FALSE, FALSE, 0);
				gtk_table_attach_defaults (table, (GtkWidget *) hbox, 1, 2, *row, *row + 1);
				gtk_widget_show ((GtkWidget *) dropdown);
			}
		}
		g_free (value);
	}
	g_hash_table_destroy (match_attrs);
}
Example #11
0
static void
render_contact_column (EABContactFormatter *formatter,
                       EContact *contact,
                       GString *buffer)
{
	GString *accum, *email;
	GList *email_list, *l, *email_attr_list, *al, *phone_attr_list;
	gint email_num = 0;
	const gchar *nl;
	guint32 phone_flags = 0, sip_flags = 0;

	if (formatter->priv->supports_tel)
		phone_flags = E_TEXT_TO_HTML_CONVERT_URLS |
			      E_TEXT_TO_HTML_HIDE_URL_SCHEME |
			      E_TEXT_TO_HTML_URL_IS_WHOLE_TEXT |
			      E_CREATE_TEL_URL;

	if (formatter->priv->supports_sip)
		sip_flags = E_TEXT_TO_HTML_CONVERT_URLS |
			    E_TEXT_TO_HTML_HIDE_URL_SCHEME |
			    E_TEXT_TO_HTML_URL_IS_WHOLE_TEXT |
			    E_CREATE_SIP_URL;

	email = g_string_new ("");
	nl = "";

	email_list = e_contact_get (contact, E_CONTACT_EMAIL);
	email_attr_list = e_contact_get_attributes (contact, E_CONTACT_EMAIL);

	for (l = email_list, al = email_attr_list; l && al; l = l->next, al = al->next) {
		gchar *name = NULL, *mail = NULL;
		gchar *attr_str = (gchar *) get_email_location ((EVCardAttribute *) al->data);

		if (!eab_parse_qp_email (l->data, &name, &mail))
			mail = e_text_to_html (l->data, 0);

		g_string_append_printf (
			email,
			"%s%s%s<a href=\"internal-mailto:%d\">%s</a>%s "
			"<span class=\"header\">(%s)</span>",
			nl,
			name ? name : "",
			name ? " &lt;" : "",
			email_num,
			mail,
			name ? "&gt;" : "",
			attr_str ? attr_str : "");
		email_num++;
		nl = "<br>";

		g_free (name);
		g_free (mail);
	}
	g_list_foreach (email_list, (GFunc) g_free, NULL);
	g_list_foreach (email_attr_list, (GFunc) e_vcard_attribute_free, NULL);
	g_list_free (email_list);
	g_list_free (email_attr_list);

	accum = g_string_new ("");

	if (email->len)
		render_table_row (accum, _("Email"), email->str, NULL, 0);

	phone_attr_list = e_contact_get_attributes (contact, E_CONTACT_TEL);

	for (l = phone_attr_list; l; l = g_list_next (l)) {
		EVCardAttribute *attr = l->data;

		if (!e_vcard_attribute_has_type (attr, "WORK") &&
		    !e_vcard_attribute_has_type (attr, "HOME")) {
			guint32 html_flags = phone_flags;
			const gchar *attr_str, *str;
			gchar *phone, *tmp_value, *label;

			phone = e_vcard_attribute_get_value (attr);
			if (!phone || !*phone) {
				g_free (phone);
				continue;
			}

			attr_str = get_phone_location (attr);
			label = e_text_to_html (attr_str, E_TEXT_TO_HTML_CONVERT_ALL_SPACES);

			tmp_value = maybe_create_url (phone, html_flags);
			if (tmp_value)
				str = tmp_value;
			else
				str = phone;

			render_table_row (accum, label, str, NULL, html_flags);

			g_free (tmp_value);
			g_free (phone);
			g_free (label);
		}
	}

	g_list_free_full (phone_attr_list, (GDestroyNotify) e_vcard_attribute_free);

	accum_sip (accum, contact, EAB_CONTACT_FORMATTER_SIP_TYPE_OTHER, NULL, sip_flags);

	accum_attribute (accum, contact, _("Nickname"), E_CONTACT_NICKNAME, NULL, 0);
	accum_attribute_multival (accum, contact, _("AIM"), E_CONTACT_IM_AIM, AIM_ICON, 0);
	accum_attribute_multival (accum, contact, _("GroupWise"), E_CONTACT_IM_GROUPWISE, GROUPWISE_ICON, 0);
	accum_attribute_multival (accum, contact, _("ICQ"), E_CONTACT_IM_ICQ, ICQ_ICON, 0);
	accum_attribute_multival (accum, contact, _("Jabber"), E_CONTACT_IM_JABBER, JABBER_ICON, 0);
	accum_attribute_multival (accum, contact, _("MSN"), E_CONTACT_IM_MSN, MSN_ICON, 0);
	accum_attribute_multival (accum, contact, _("Yahoo"), E_CONTACT_IM_YAHOO, YAHOO_ICON, 0);
	accum_attribute_multival (accum, contact, _("Gadu-Gadu"), E_CONTACT_IM_GADUGADU, GADUGADU_ICON, 0);
	accum_attribute_multival (accum, contact, _("Skype"), E_CONTACT_IM_SKYPE, SKYPE_ICON, 0);
	accum_attribute_multival (accum, contact, _("Twitter"), E_CONTACT_IM_TWITTER, TWITTER_ICON, 0);

	if (accum->len)
		g_string_append_printf (
			buffer,
			"<div class=\"column\" id=\"contact-internet\">"
			"<table border=\"0\" cellspacing=\"5\">%s</table>"
			"</div>", accum->str);

	g_string_free (accum, TRUE);
	g_string_free (email, TRUE);
}