aboutsummaryrefslogtreecommitdiffstats
path: root/addressbook/gui/widgets/eab-contact-formatter.c
diff options
context:
space:
mode:
Diffstat (limited to 'addressbook/gui/widgets/eab-contact-formatter.c')
-rw-r--r--addressbook/gui/widgets/eab-contact-formatter.c1267
1 files changed, 1267 insertions, 0 deletions
diff --git a/addressbook/gui/widgets/eab-contact-formatter.c b/addressbook/gui/widgets/eab-contact-formatter.c
new file mode 100644
index 0000000000..c0ca4ed524
--- /dev/null
+++ b/addressbook/gui/widgets/eab-contact-formatter.c
@@ -0,0 +1,1267 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "eab-contact-formatter.h"
+
+#include "eab-gui-util.h"
+#include "e-util/e-util.h"
+#include "e-util/e-util-private.h"
+#include "e-util/e-html-utils.h"
+#include "e-util/e-icon-factory.h"
+#include "e-util/e-plugin-ui.h"
+
+#ifdef WITH_CONTACT_MAPS
+#include "widgets/misc/e-contact-map.h"
+#endif
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+G_DEFINE_TYPE (
+ EABContactFormatter,
+ eab_contact_formatter,
+ G_TYPE_OBJECT);
+
+#define EAB_CONTACT_FORMATTER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), EAB_TYPE_CONTACT_FORMATTER, EABContactFormatterPrivate))
+
+#define TEXT_IS_RIGHT_TO_LEFT \
+ (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL)
+
+static gpointer parent_class = NULL;
+
+enum {
+ PROP_0,
+ PROP_DISPLAY_MODE,
+ PROP_RENDER_MAPS
+};
+
+struct _EABContactFormatterPrivate {
+
+ EContact *contact;
+
+ EABContactDisplayMode mode;
+ gboolean render_maps;
+};
+
+static struct {
+ const gchar *name;
+ const gchar *pretty_name;
+}
+common_location[] =
+{
+ { "WORK", N_ ("Work") },
+ { "HOME", N_ ("Home") },
+ { "OTHER", N_ ("Other") }
+};
+
+#define IMAGE_COL_WIDTH "20"
+#define CONTACT_LIST_ICON "stock_contact-list"
+#define AIM_ICON "im-aim"
+#define GROUPWISE_ICON "im-nov"
+#define ICQ_ICON "im-icq"
+#define JABBER_ICON "im-jabber"
+#define MSN_ICON "im-msn"
+#define YAHOO_ICON "im-yahoo"
+#define GADUGADU_ICON "im-gadugadu"
+#define SKYPE_ICON "stock_people"
+#define VIDEOCONF_ICON "stock_video-conferencing"
+
+#define MAX_COMPACT_IMAGE_DIMENSION 48
+
+#define HTML_HEADER "<!doctype html public \"-//W3C//DTD HTML 4.0 TRANSITIONAL//EN\">\n<html>\n" \
+"<head>\n<meta name=\"generator\" content=\"Evolution Addressbook Component\">\n" \
+"<link type=\"text/css\" rel=\"stylesheet\" href=\"evo-file://" EVOLUTION_PRIVDATADIR "/theme/webview.css\">" \
+"<style type=\"text/css\">\n" \
+" div#header { width:100%; clear: both; }\n" \
+" div#columns { width: 100%; clear: both; }\n" \
+" div#footer { width: 100%; clear: both; }\n" \
+" div.column { width: auto; float: left; margin-right: 15px; }\n" \
+" img#contact-photo { float: left; }\n" \
+" div#contact-name { float: left; margin-left: 20px; }\n" \
+"</style>\n" \
+"<script type=\"text/javascript\">\n" \
+"function collapse_list (obj, listId) {\n" \
+" var l = document.getElementById (listId);\n" \
+" if (l.style.display == \"none\") {\n" \
+" l.style.display = \"block\"; obj.src = obj.src.substr (0, obj.src.lastIndexOf (\"/\")) + \"/minus.png\";\n" \
+" } else {\n" \
+" l.style.display = \"none\"; obj.src = obj.src.substr (0, obj.src.lastIndexOf (\"/\")) + \"/plus.png\";\n" \
+" }\n" \
+"}\n" \
+"</script>\n" \
+"</head>\n"
+
+static gchar *
+get_icon_uri (const gchar *icon_name)
+{
+ GtkIconTheme *icon_theme;
+ GtkIconInfo *icon_info;
+ const gchar *filename;
+ gchar *icon_uri;
+ GError *error = NULL;
+
+ icon_theme = gtk_icon_theme_get_default ();
+ icon_info = gtk_icon_theme_lookup_icon (
+ icon_theme, icon_name, GTK_ICON_SIZE_MENU, 0);
+ g_return_val_if_fail (icon_info != NULL, NULL);
+
+ filename = gtk_icon_info_get_filename (icon_info);
+ icon_uri = g_filename_to_uri (filename, NULL, &error);
+
+ if (error != NULL) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+
+ gtk_icon_info_free (icon_info);
+
+ return icon_uri;
+}
+
+static void
+render_address_link (GString *buffer,
+ EContact *contact,
+ gint map_type)
+{
+ EContactAddress *adr;
+ GString *link = g_string_new ("");
+
+ adr = e_contact_get (contact, map_type);
+ if (adr &&
+ (adr->street || adr->locality || adr->region || adr->country)) {
+ gchar *escaped;
+
+ if (adr->street && *adr->street)
+ g_string_append_printf (link, "%s, ", adr->street);
+
+ if (adr->locality && *adr->locality)
+ g_string_append_printf (link, "%s, ", adr->locality);
+
+ if (adr->region && *adr->region)
+ g_string_append_printf (link, "%s, ", adr->region);
+
+ if (adr->country && *adr->country)
+ g_string_append_printf (link, "%s", adr->country);
+
+ escaped = g_uri_escape_string (link->str, NULL, TRUE);
+ g_string_assign (link, escaped);
+ g_free (escaped);
+
+ g_string_prepend (link, "<a href=\"http://maps.google.com?q=");
+ g_string_append_printf (link, "\">%s</a>", _("Open map"));
+ }
+
+ if (adr)
+ e_contact_address_free (adr);
+
+ g_string_append (buffer, link->str);
+ g_string_free (link, TRUE);
+}
+
+static void
+accum_address (GString *buffer,
+ EContact *contact,
+ const gchar *html_label,
+ EContactField adr_field,
+ EContactField label_field)
+{
+ EContactAddress *adr;
+ const gchar *label;
+ GString *map_link = g_string_new ("<br>");
+
+ render_address_link (map_link, contact, adr_field);
+
+ label = e_contact_get_const (contact, label_field);
+ if (label) {
+ gchar *html = e_text_to_html (label, E_TEXT_TO_HTML_CONVERT_NL);
+
+ if (TEXT_IS_RIGHT_TO_LEFT) {
+ g_string_append_printf (
+ buffer,
+ "<tr>"
+ "<td align=\"right\" valign=\"top\" nowrap>%s</td>"
+ "<th>%s:<br>%s</th>"
+ "<td valign=\"top\" width=\"" IMAGE_COL_WIDTH "\"></td>"
+ "</tr>",
+ html, html_label, map_link->str);
+ } else {
+ g_string_append_printf (
+ buffer,
+ "<tr>"
+ "<td width=\"" IMAGE_COL_WIDTH "\"></td>"
+ "<th>%s:<br>%s</th>"
+ "<td valign=\"top\" nowrap>%s</td>"
+ "</tr>",
+ html_label, map_link->str, html);
+ }
+
+ g_free (html);
+ g_string_free (map_link, TRUE);
+ return;
+ }
+
+ adr = e_contact_get (contact, adr_field);
+ if (adr &&
+ (adr->po || adr->ext || adr->street || adr->locality ||
+ adr->region || adr->code || adr->country)) {
+
+ if (TEXT_IS_RIGHT_TO_LEFT) {
+ g_string_append_printf (
+ buffer, "<tr><td align=\"right\" valign=\"top\" nowrap>");
+ } else {
+ g_string_append_printf (
+ buffer,
+ "<tr>"
+ "<td valign=\"top\" width=\"" IMAGE_COL_WIDTH "\"></td>"
+ "<th>%s:<br>%s</th>"
+ "<td valign=\"top\" nowrap>",
+ html_label, map_link->str);
+ }
+
+ if (adr->po && *adr->po)
+ g_string_append_printf (buffer, "%s<br>", adr->po);
+
+ if (adr->ext && *adr->ext)
+ g_string_append_printf (buffer, "%s<br>", adr->ext);
+
+ if (adr->street && *adr->street)
+ g_string_append_printf (buffer, "%s<br>", adr->street);
+
+ if (adr->locality && *adr->locality)
+ g_string_append_printf (buffer, "%s<br>", adr->locality);
+
+ if (adr->region && *adr->region)
+ g_string_append_printf (buffer, "%s<br>", adr->region);
+
+ if (adr->code && *adr->code)
+ g_string_append_printf (buffer, "%s<br>", adr->code);
+
+ if (adr->country && *adr->country)
+ g_string_append_printf (buffer, "%s<br>", adr->country);
+
+ if (TEXT_IS_RIGHT_TO_LEFT) {
+ g_string_append_printf (
+ buffer,
+ "</td><th%s:<br>%s</th>"
+ "<td width=\"" IMAGE_COL_WIDTH "\"></td>"
+ "</tr>", html_label, map_link->str);
+ } else {
+ g_string_append_printf (buffer, "</td></tr>");
+ }
+
+ }
+
+ if (adr)
+ e_contact_address_free (adr);
+
+ g_string_free (map_link, TRUE);
+}
+
+static void
+render_table_row (GString *buffer,
+ const gchar *label,
+ const gchar *str,
+ const gchar *icon,
+ guint html_flags)
+{
+ const gchar *icon_html;
+ gchar *value;
+
+ if (html_flags)
+ value = e_text_to_html (str, html_flags);
+ else
+ value = (gchar *) str;
+
+ if (icon) {
+ gchar *icon_uri = get_icon_uri (icon);
+ icon_html = g_strdup_printf ("<img src=\"%s\" width=\"16\" height=\"16\" />", icon_uri);
+ g_free (icon_uri);
+ } else {
+ icon_html = "";
+ }
+
+ if (TEXT_IS_RIGHT_TO_LEFT) {
+ g_string_append_printf (
+ buffer, "<tr>"
+ "<td valign=\"top\" align=\"right\">%s</td>"
+ "<th align=\"right\" valign=\"top\" width=\"100\" nowrap>:%s</th>"
+ "<td valign=\"top\" width=\"" IMAGE_COL_WIDTH "\">%s</td>"
+ "</tr>",
+ value, label, icon_html);
+ } else {
+ g_string_append_printf (
+ buffer, "<tr>"
+ "<td valign=\"top\" width=\"" IMAGE_COL_WIDTH "\">%s</td>"
+ "<th valign=\"top\" width=\"100\" nowrap>%s:</th>"
+ "<td valign=\"top\">%s</td>"
+ "</tr>",
+ icon_html, label, value);
+ }
+
+ if (html_flags)
+ g_free (value);
+}
+
+static void
+accum_attribute (GString *buffer,
+ EContact *contact,
+ const gchar *html_label,
+ EContactField field,
+ const gchar *icon,
+ guint html_flags)
+{
+ const gchar *str;
+
+ str = e_contact_get_const (contact, field);
+
+ if (str != NULL && *str != '\0')
+ render_table_row (buffer, html_label, str, icon, html_flags);
+}
+
+static void
+accum_time_attribute (GString *buffer,
+ EContact *contact,
+ const gchar *html_label,
+ EContactField field,
+ const gchar *icon,
+ guint html_flags)
+{
+ EContactDate *date;
+ GDate *gdate = NULL;
+ gchar sdate[100];
+
+ date = e_contact_get (contact, field);
+ if (date) {
+ gdate = g_date_new_dmy ( date->day,
+ date->month,
+ date->year );
+ g_date_strftime (sdate, 100, "%x", gdate);
+ g_date_free (gdate);
+ render_table_row (buffer, html_label, sdate, icon, html_flags);
+ e_contact_date_free (date);
+ }
+}
+
+static void
+accum_attribute_multival (GString *buffer,
+ EContact *contact,
+ const gchar *html_label,
+ EContactField field,
+ const gchar *icon,
+ guint html_flags)
+{
+ GList *val_list, *l;
+ GString *val = g_string_new ("");
+
+ val_list = e_contact_get (contact, field);
+
+ for (l = val_list; l; l = l->next) {
+ if (l != val_list)
+ g_string_append (val, "<br>");
+
+ g_string_append (val, l->data);
+ }
+
+ if (val->str && *val->str)
+ render_table_row (buffer, html_label, val->str, icon, html_flags);
+
+ g_string_free (val, TRUE);
+ g_list_foreach (val_list, (GFunc) g_free, NULL);
+ g_list_free (val_list);
+}
+
+static const gchar *
+get_email_location (EVCardAttribute *attr)
+{
+ gint i;
+
+ for (i = 0; i < G_N_ELEMENTS (common_location); i++) {
+ if (e_vcard_attribute_has_type (attr, common_location[i].name))
+ return _(common_location[i].pretty_name);
+ }
+
+ return _("Other");
+}
+
+static void
+render_title_block (EABContactFormatter *formatter,
+ GString *buffer)
+{
+ const gchar *str;
+ gchar *html;
+ EContactPhoto *photo;
+ EContact *contact;
+
+ contact = formatter->priv->contact;
+
+ g_string_append_printf (
+ buffer,
+ "<table border=\"0\"><tr>"
+ "<td %s valign=\"middle\">", TEXT_IS_RIGHT_TO_LEFT ?
+ "align=\"right\"" : "");
+
+ photo = e_contact_get (contact, E_CONTACT_PHOTO);
+ if (!photo)
+ photo = e_contact_get (contact, E_CONTACT_LOGO);
+
+ if (photo && photo->type == E_CONTACT_PHOTO_TYPE_INLINED) {
+ gchar *photo_data;
+ photo_data = g_base64_encode (
+ photo->data.inlined.data,
+ photo->data.inlined.length);
+ g_string_append_printf (
+ buffer, "<img border=\"1\" src=\"data:%s;base64,%s\">",
+ photo->data.inlined.mime_type,
+ photo_data);
+ } else if (photo && photo->type == E_CONTACT_PHOTO_TYPE_URI && photo->data.uri && *photo->data.uri) {
+ g_string_append_printf (
+ buffer, "<img border=\"1\" src=\"%s\">", photo->data.uri);
+ }
+
+ if (photo)
+ e_contact_photo_free (photo);
+
+ if (e_contact_get (contact, E_CONTACT_IS_LIST)) {
+ gchar *icon = get_icon_uri (CONTACT_LIST_ICON);
+ g_string_append_printf (buffer, "<img src=\"%s\">", icon);
+ g_free (icon);
+ }
+
+ g_string_append_printf (
+ buffer,
+ "</td><td width=\"20\"></td><td %s valign=\"top\">\n",
+ TEXT_IS_RIGHT_TO_LEFT ? "align=\"right\"" : "");
+
+ str = e_contact_get_const (contact, E_CONTACT_FILE_AS);
+ if (!str)
+ str = e_contact_get_const (contact, E_CONTACT_FULL_NAME);
+
+ if (str) {
+ html = e_text_to_html (str, 0);
+ if (e_contact_get (contact, E_CONTACT_IS_LIST)) {
+ g_string_append_printf (
+ buffer,
+ "<h2><a href=\"internal-mailto:0\">%s</a></h2>",
+ html);
+ } else {
+ g_string_append_printf (buffer, "<h2>%s</h2>", html);
+ }
+ g_free (html);
+ }
+
+ g_string_append (buffer, "</td></tr></table>");
+}
+
+static void
+render_contact_list_row (EABContactFormatter *formatter,
+ EDestination *destination,
+ GString *buffer)
+{
+ gchar *evolution_imagesdir;
+ gboolean list_collapsed = FALSE;
+ const gchar *textrep;
+ gchar *name = NULL, *email_addr = NULL;
+
+ evolution_imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL);
+
+ textrep = e_destination_get_textrep (destination, TRUE);
+ if (!eab_parse_qp_email (textrep, &name, &email_addr))
+ email_addr = g_strdup (textrep);
+
+ g_string_append (buffer, "<tr>");
+ if (e_destination_is_evolution_list (destination)) {
+ g_string_append_printf (
+ buffer,
+ "<td width=" IMAGE_COL_WIDTH " valign=\"top\">"
+ "<img src=\"%s/minus.png\" "
+ "onClick=\"collapse_list(this, %s);\" "
+ "class=\"navigable\">"
+ "</td><td width=\"100%%\">%s",
+ evolution_imagesdir,
+ e_destination_get_contact_uid (destination),
+ name ? name : email_addr);
+
+ if (!list_collapsed) {
+ const GList *dest, *dests;
+ g_string_append_printf (
+ buffer,
+ "<br><table cellspacing=\"1\" id=\"%s\">",
+ e_destination_get_contact_uid (destination));
+
+ dests = e_destination_list_get_root_dests (destination);
+ for (dest = dests; dest; dest = dest->next) {
+ render_contact_list_row (
+ formatter, dest->data, buffer);
+ }
+
+ g_string_append (buffer, "</table>");
+ }
+
+ g_string_append (buffer, "</td>");
+
+ } else {
+ if (name && *name) {
+ g_string_append_printf (
+ buffer,
+ "<td colspan=\"2\">%s &lt"
+ "<a href=\"mailto:%s\">%s</a>&gt;"
+ "</td>",
+ name, email_addr, email_addr);
+ } else {
+ g_string_append_printf (
+ buffer,
+ "<td colspan=\"2\">"
+ "<a href=\"mailto:%s\">%s</a>"
+ "</td>",
+ email_addr, email_addr);
+ }
+ }
+
+ g_string_append (buffer, "</tr>");
+
+ g_free (evolution_imagesdir);
+ g_free (name);
+ g_free (email_addr);
+}
+
+static void
+render_contact_list (EABContactFormatter *formatter,
+ GString *buffer)
+{
+ EContact *contact;
+ EDestination *destination;
+ const GList *dest, *dests;
+
+ contact = formatter->priv->contact;
+
+ destination = e_destination_new ();
+ e_destination_set_contact (destination, contact, 0);
+ dests = e_destination_list_get_root_dests (destination);
+
+ render_title_block (formatter, buffer);
+
+ g_string_append_printf (
+ buffer,
+ "<table border=\"0\"><tr><th colspan=\"2\">%s</th></tr>"
+ "<tr><td with=" IMAGE_COL_WIDTH "></td><td>", _("List Members:"));
+
+ g_string_append (buffer, "<table border=\"0\" cellspacing=\"1\">");
+
+ for (dest = dests; dest; dest = dest->next)
+ render_contact_list_row (formatter, dest->data, buffer);
+
+ g_string_append (buffer, "</table>");
+ g_string_append (buffer, "</td></tr></table>");
+
+ g_object_unref (destination);
+}
+
+static void
+render_contact_column (EABContactFormatter *formatter,
+ GString *buffer)
+{
+ EContact *contact;
+ GString *accum, *email;
+ GList *email_list, *l, *email_attr_list, *al;
+ gint email_num = 0;
+ const gchar *nl;
+
+ contact = formatter->priv->contact;
+ 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);
+
+ 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);
+
+ 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);
+}
+
+static void
+accum_address_map (GString *buffer,
+ EContact *contact,
+ gint map_type)
+{
+ #ifdef WITH_CONTACT_MAPS
+
+ g_string_append (buffer, "<tr><td colspan=\"3\">");
+
+ if (map_type == E_CONTACT_ADDRESS_WORK) {
+ g_string_append (buffer,
+ "<object type=\"application/x-work-map-widget\" "
+ "width=\"250\" height=\"250\"></object>");
+ } else {
+ g_string_append (buffer,
+ "<object type=\"application/x-home-map-widget\" "
+ "width=\"250\" height=\"250\"></object>");
+ }
+
+ g_string_append (buffer, "</td></tr>");
+
+ #endif
+}
+
+static void
+render_work_column (EABContactFormatter *formatter,
+ GString *buffer)
+{
+ EContact *contact = formatter->priv->contact;
+ GString *accum = g_string_new ("");
+
+ accum_attribute (accum, contact, _("Company"), E_CONTACT_ORG, NULL, 0);
+ accum_attribute (accum, contact, _("Department"), E_CONTACT_ORG_UNIT, NULL, 0);
+ accum_attribute (accum, contact, _("Profession"), E_CONTACT_ROLE, NULL, 0);
+ accum_attribute (accum, contact, _("Position"), E_CONTACT_TITLE, NULL, 0);
+ accum_attribute (accum, contact, _("Manager"), E_CONTACT_MANAGER, NULL, 0);
+ accum_attribute (accum, contact, _("Assistant"), E_CONTACT_ASSISTANT, NULL, 0);
+ accum_attribute (accum, contact, _("Video Chat"), E_CONTACT_VIDEO_URL, VIDEOCONF_ICON, E_TEXT_TO_HTML_CONVERT_URLS);
+ accum_attribute (accum, contact, _("Calendar"), E_CONTACT_CALENDAR_URI, NULL, E_TEXT_TO_HTML_CONVERT_URLS);
+ accum_attribute (accum, contact, _("Free/Busy"), E_CONTACT_FREEBUSY_URL, NULL, E_TEXT_TO_HTML_CONVERT_URLS);
+ accum_attribute (accum, contact, _("Phone"), E_CONTACT_PHONE_BUSINESS, NULL, 0);
+ accum_attribute (accum, contact, _("Fax"), E_CONTACT_PHONE_BUSINESS_FAX, NULL, 0);
+ accum_address (accum, contact, _("Address"), E_CONTACT_ADDRESS_WORK, E_CONTACT_ADDRESS_LABEL_WORK);
+ if (formatter->priv->render_maps)
+ accum_address_map (accum, contact, E_CONTACT_ADDRESS_WORK);
+
+ if (accum->len > 0) {
+ g_string_append_printf (
+ buffer,
+ "<div class=\"column\" id=\"contact-work\">"
+ "<h3>%s</h3>"
+ "<table border=\"0\" cellspacing=\"5\">%s</table>"
+ "</div>", _("Work"), accum->str);
+ }
+
+ g_string_free (accum, TRUE);
+}
+
+static void
+render_personal_column (EABContactFormatter *formatter,
+ GString *buffer)
+{
+ EContact *contact = formatter->priv->contact;
+ GString *accum = g_string_new ("");
+
+ accum_attribute (accum, contact, _("Home Page"), E_CONTACT_HOMEPAGE_URL, NULL, E_TEXT_TO_HTML_CONVERT_URLS);
+ accum_attribute (accum, contact, _("Web Log"), E_CONTACT_BLOG_URL, NULL, E_TEXT_TO_HTML_CONVERT_URLS);
+ accum_attribute (accum, contact, _("Phone"), E_CONTACT_PHONE_HOME, NULL, 0);
+ accum_attribute (accum, contact, _("Mobile Phone"), E_CONTACT_PHONE_MOBILE, NULL, 0);
+ accum_address (accum, contact, _("Address"), E_CONTACT_ADDRESS_HOME, E_CONTACT_ADDRESS_LABEL_HOME);
+ accum_time_attribute (accum, contact, _("Birthday"), E_CONTACT_BIRTH_DATE, NULL, 0);
+ accum_time_attribute (accum, contact, _("Anniversary"), E_CONTACT_ANNIVERSARY, NULL, 0);
+ accum_attribute (accum, contact, _("Spouse"), E_CONTACT_SPOUSE, NULL, 0);
+ if (formatter->priv->render_maps)
+ accum_address_map (accum, contact, E_CONTACT_ADDRESS_HOME);
+
+ if (accum->len > 0) {
+ g_string_append_printf (
+ buffer,
+ "<div class=\"column\" id=\"contact-personal\">"
+ "<h3>%s</h3>"
+ "<table border=\"0\" cellspacing=\"5\">%s</table>"
+ "</div>", _("Personal"), accum->str);
+ }
+
+ g_string_free (accum, TRUE);
+}
+
+static void
+render_footer (EABContactFormatter *formatter,
+ GString *buffer)
+{
+ EContact *contact;
+ const gchar *str;
+
+ contact = formatter->priv->contact;
+
+ str = e_contact_get_const (contact, E_CONTACT_NOTE);
+ if (!str || !*str)
+ return;
+
+ g_string_append (
+ buffer,
+ "<div id=\"footer\"><table border=\"0\" cellspacing=\"5\">");
+
+ render_table_row (
+ buffer, _("Note"),
+ e_contact_get_const (contact, E_CONTACT_NOTE),
+ NULL,
+ E_TEXT_TO_HTML_CONVERT_ADDRESSES |
+ E_TEXT_TO_HTML_CONVERT_URLS |
+ E_TEXT_TO_HTML_CONVERT_NL);
+
+ g_string_append (buffer, "</table></div>");
+}
+
+static void
+render_contact (EABContactFormatter *formatter,
+ GString *buffer)
+{
+ render_title_block (formatter, buffer);
+
+ g_string_append (buffer, "<div id=\"columns\">");
+ render_contact_column (formatter, buffer);
+ render_work_column (formatter, buffer);
+ render_personal_column (formatter, buffer);
+ g_string_append (buffer, "</div>");
+
+ render_footer (formatter, buffer);
+}
+
+static void
+render_normal (EABContactFormatter *formatter,
+ GString *buffer)
+{
+ g_string_append (buffer, HTML_HEADER);
+ g_string_append (buffer, "<body>");
+
+ if (formatter->priv->contact) {
+
+ if (e_contact_get (formatter->priv->contact, E_CONTACT_IS_LIST))
+
+ render_contact_list (
+ formatter,
+ buffer);
+ else
+ render_contact (
+ formatter,
+ buffer);
+
+ }
+
+ g_string_append (buffer, "</body></html>\n");
+}
+
+static void
+render_compact (EABContactFormatter *formatter,
+ GString *buffer)
+{
+ EContact *contact = formatter->priv->contact;
+ const gchar *str;
+ gchar *html;
+ EContactPhoto *photo;
+
+ g_string_append (buffer, HTML_HEADER);
+ g_string_append (buffer, "<body>\n");
+
+ if (!contact) {
+ g_string_append (buffer, "</body></html>");
+ return;
+ }
+
+ g_string_append_printf (
+ buffer,
+ "<table><tr><td valign=\"top\">");
+
+ photo = e_contact_get (contact, E_CONTACT_PHOTO);
+
+ if (!photo)
+ photo = e_contact_get (contact, E_CONTACT_LOGO);
+
+ if (photo) {
+ gint calced_width = MAX_COMPACT_IMAGE_DIMENSION, calced_height = MAX_COMPACT_IMAGE_DIMENSION;
+ GdkPixbufLoader *loader = gdk_pixbuf_loader_new ();
+ GdkPixbuf *pixbuf;
+
+ /* figure out if we need to downscale the
+ * image here. we don't scale the pixbuf
+ * itself, just insert width/height tags in
+ * the html */
+ if (photo->type == E_CONTACT_PHOTO_TYPE_INLINED) {
+ gdk_pixbuf_loader_write (
+ loader, photo->data.inlined.data,
+ photo->data.inlined.length, NULL);
+ } else if (photo->type == E_CONTACT_PHOTO_TYPE_URI &&
+ photo->data.uri &&
+ g_ascii_strncasecmp (photo->data.uri, "file://", 7) == 0) {
+ gchar *filename, *contents = NULL;
+ gsize length;
+
+ filename = g_filename_from_uri (photo->data.uri, NULL, NULL);
+
+ if (filename) {
+ if (g_file_get_contents (filename, &contents, &length, NULL)) {
+ gdk_pixbuf_loader_write (loader, (const guchar *) contents, length, NULL);
+ g_free (contents);
+ }
+
+ g_free (filename);
+ }
+ }
+
+ gdk_pixbuf_loader_close (loader, NULL);
+ pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+
+ if (pixbuf)
+ g_object_ref (pixbuf);
+
+ g_object_unref (loader);
+
+ if (pixbuf) {
+ gint max_dimension;
+
+ calced_width = gdk_pixbuf_get_width (pixbuf);
+ calced_height = gdk_pixbuf_get_height (pixbuf);
+
+ max_dimension = calced_width;
+
+ if (max_dimension < calced_height)
+ max_dimension = calced_height;
+
+ if (max_dimension > MAX_COMPACT_IMAGE_DIMENSION) {
+ calced_width *= ( (gfloat) MAX_COMPACT_IMAGE_DIMENSION / max_dimension);
+ calced_height *= ( (gfloat) MAX_COMPACT_IMAGE_DIMENSION / max_dimension);
+ }
+
+ g_object_unref (pixbuf);
+ }
+
+ if (photo->type == E_CONTACT_PHOTO_TYPE_URI &&
+ photo->data.uri && *photo->data.uri)
+ g_string_append_printf (
+ buffer,
+ "<img width=\"%d\" height=\"%d\" src=\"%s\">",
+ calced_width, calced_height, photo->data.uri);
+ else {
+ gchar *photo_data;
+
+ photo_data = g_base64_encode (
+ photo->data.inlined.data,
+ photo->data.inlined.length);
+ g_string_append_printf (buffer,
+ "<img border=\"1\" src=\"data:%s;base64,%s\" "
+ "width=\"%d\" height=\"%d\">",
+ photo->data.inlined.mime_type,
+ photo_data,
+ calced_width, calced_height);
+ g_free (photo_data);
+ }
+
+ e_contact_photo_free (photo);
+ }
+
+ g_string_append (buffer, "</td><td width=\"5\"></td><td valign=\"top\">\n");
+
+ str = e_contact_get_const (contact, E_CONTACT_FILE_AS);
+
+ if (str) {
+ html = e_text_to_html (str, 0);
+ g_string_append_printf (buffer, "<b>%s</b>", html);
+ g_free (html);
+ } else {
+ str = e_contact_get_const (contact, E_CONTACT_FULL_NAME);
+
+ if (str) {
+ html = e_text_to_html (str, 0);
+ g_string_append_printf (buffer, "<b>%s</b>", html);
+ g_free (html);
+ }
+ }
+
+ g_string_append (buffer, "<hr>");
+
+ if (e_contact_get (contact, E_CONTACT_IS_LIST)) {
+ GList *email_list;
+ GList *l;
+
+ g_string_append (
+ buffer,
+ "<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">"
+ "<tr><td valign=\"top\">");
+ g_string_append_printf (
+ buffer,
+ "<b>%s:</b>&nbsp;<td>", _ ("List Members"));
+
+ email_list = e_contact_get (contact, E_CONTACT_EMAIL);
+
+ for (l = email_list; l; l = l->next) {
+ if (l->data) {
+ html = e_text_to_html (l->data, 0);
+ g_string_append_printf (buffer, "%s, ", html);
+ g_free (html);
+ }
+ }
+
+ g_string_append (buffer, "</td></tr></table>");
+
+ } else {
+
+ gboolean comma = FALSE;
+ str = e_contact_get_const (contact, E_CONTACT_TITLE);
+
+ if (str) {
+ html = e_text_to_html (str, 0);
+ g_string_append_printf (buffer, "<b>%s:</b> %s<br>", _ ("Job Title"), str);
+ g_free (html);
+ }
+
+ #define print_email() { \
+ html = eab_parse_qp_email_to_html (str); \
+ \
+ if (!html) \
+ html = e_text_to_html (str, 0); \
+ \
+ g_string_append_printf (buffer, "%s%s", comma ? ", " : "", html); \
+ g_free (html); \
+ comma = TRUE; \
+ }
+
+ g_string_append_printf (buffer, "<b>%s:</b> ", _ ("Email"));
+ str = e_contact_get_const (contact, E_CONTACT_EMAIL_1);
+
+ if (str)
+ print_email ();
+
+ str = e_contact_get_const (contact, E_CONTACT_EMAIL_2);
+
+ if (str)
+ print_email ();
+
+ str = e_contact_get_const (contact, E_CONTACT_EMAIL_3);
+
+ if (str)
+ print_email ();
+
+ g_string_append (buffer, "<br>");
+
+ #undef print_email
+
+ str = e_contact_get_const (contact, E_CONTACT_HOMEPAGE_URL);
+
+ if (str) {
+ html = e_text_to_html (str, E_TEXT_TO_HTML_CONVERT_URLS);
+ g_string_append_printf (
+ buffer, "<b>%s:</b> %s<br>",
+ _ ("Home page"), html);
+ g_free (html);
+ }
+
+ str = e_contact_get_const (contact, E_CONTACT_BLOG_URL);
+
+ if (str) {
+ html = e_text_to_html (str, E_TEXT_TO_HTML_CONVERT_URLS);
+ g_string_append_printf (
+ buffer, "<b>%s:</b> %s<br>",
+ _ ("Blog"), html);
+ }
+ }
+
+ g_string_append (buffer, "</td></tr></table>\n");
+
+ g_string_append (buffer, "</body></html>\n");
+}
+
+static CamelStream *
+format_contact (EABContactFormatter *formatter,
+ GCancellable *cancellable)
+{
+ GString *buffer;
+ CamelStream *stream;
+
+ buffer = g_string_new ("");
+
+ if (formatter->priv->mode == EAB_CONTACT_DISPLAY_RENDER_NORMAL) {
+ render_normal (formatter, buffer);
+ } else {
+ render_compact (formatter, buffer);
+ }
+
+ stream = camel_stream_mem_new ();
+ camel_stream_write_string (stream, buffer->str, cancellable, NULL);
+
+ g_string_free (buffer, TRUE);
+
+ return stream;
+}
+
+static void
+do_start_async_formatter (GSimpleAsyncResult *result,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ EABContactFormatter *formatter;
+ CamelStream *stream;
+
+ formatter = EAB_CONTACT_FORMATTER (object);
+
+ stream = format_contact (formatter, cancellable);
+
+ g_simple_async_result_set_op_res_gpointer (result, stream, NULL);
+}
+
+static void
+eab_contact_formatter_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EABContactFormatter *formatter = EAB_CONTACT_FORMATTER (object);
+
+ switch (property_id) {
+ case PROP_DISPLAY_MODE:
+ eab_contact_formatter_set_display_mode (
+ formatter, g_value_get_int (value));
+ return;
+ case PROP_RENDER_MAPS:
+ eab_contact_formatter_set_render_maps (
+ formatter, g_value_get_boolean (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+eab_contact_formatter_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EABContactFormatter *formatter = EAB_CONTACT_FORMATTER (object);
+
+ switch (property_id) {
+ case PROP_DISPLAY_MODE:
+ g_value_set_int (value,
+ eab_contact_formatter_get_display_mode (
+ formatter));
+ return;
+ case PROP_RENDER_MAPS:
+ g_value_set_boolean (value,
+ eab_contact_formatter_get_render_maps (
+ formatter));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+eab_contact_formatter_finalize (GObject *object)
+{
+ EABContactFormatter *formatter;
+
+ formatter = EAB_CONTACT_FORMATTER (object);
+
+ if (formatter->priv->contact) {
+ g_object_unref (formatter->priv->contact);
+ formatter->priv->contact = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+eab_contact_formatter_class_init (EABContactFormatterClass *klass)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (klass);
+ g_type_class_add_private (klass, sizeof (EABContactFormatterClass));
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = eab_contact_formatter_finalize;
+ object_class->set_property = eab_contact_formatter_set_property;
+ object_class->get_property = eab_contact_formatter_get_property;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_DISPLAY_MODE,
+ g_param_spec_int (
+ "display-mode",
+ "",
+ "",
+ EAB_CONTACT_DISPLAY_RENDER_NORMAL,
+ EAB_CONTACT_DISPLAY_RENDER_COMPACT,
+ EAB_CONTACT_DISPLAY_RENDER_NORMAL,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_RENDER_MAPS,
+ g_param_spec_boolean (
+ "render-maps",
+ "",
+ "",
+ FALSE,
+ G_PARAM_READWRITE));
+}
+
+static void
+eab_contact_formatter_init (EABContactFormatter *formatter)
+{
+ formatter->priv = EAB_CONTACT_FORMATTER_GET_PRIVATE (formatter);
+
+ formatter->priv->contact = NULL;
+ formatter->priv->mode = EAB_CONTACT_DISPLAY_RENDER_NORMAL;
+ formatter->priv->render_maps = FALSE;
+}
+
+void
+eab_contact_formatter_set_display_mode (EABContactFormatter *formatter,
+ EABContactDisplayMode mode)
+{
+ g_return_if_fail (EAB_IS_CONTACT_FORMATTER (formatter));
+
+ if (formatter->priv->mode == mode)
+ return;
+
+ formatter->priv->mode = mode;
+
+ g_object_notify (G_OBJECT (formatter), "display-mode");
+}
+
+EABContactDisplayMode
+eab_contact_formatter_get_display_mode (EABContactFormatter *formatter)
+{
+ g_return_val_if_fail (EAB_IS_CONTACT_FORMATTER (formatter),
+ EAB_CONTACT_DISPLAY_RENDER_NORMAL);
+
+ return formatter->priv->mode;
+}
+
+void
+eab_contact_formatter_set_render_maps (EABContactFormatter *formatter,
+ gboolean render_maps)
+{
+ g_return_if_fail (EAB_IS_CONTACT_FORMATTER (formatter));
+
+ if (formatter->priv->render_maps == render_maps)
+ return;
+
+ formatter->priv->render_maps = render_maps;
+
+ g_object_notify (G_OBJECT (formatter), "render-maps");
+}
+
+gboolean
+eab_contact_formatter_get_render_maps (EABContactFormatter *formatter)
+{
+ g_return_val_if_fail (EAB_IS_CONTACT_FORMATTER (formatter), FALSE);
+
+ return formatter->priv->render_maps;
+}
+
+void
+eab_contact_formatter_format_contact_sync (EABContactFormatter *formatter,
+ EContact *contact,
+ CamelStream *stream,
+ GCancellable *cancellable)
+{
+ CamelStream *out;
+
+ g_return_if_fail (EAB_IS_CONTACT_FORMATTER (formatter));
+ g_return_if_fail (E_IS_CONTACT (contact));
+
+ g_object_ref (contact);
+
+ if (formatter->priv->contact)
+ g_object_unref (formatter->priv->contact);
+
+ formatter->priv->contact = contact;
+
+ out = format_contact (formatter, cancellable);
+
+ g_seekable_seek (G_SEEKABLE (out), 0, G_SEEK_SET, cancellable, NULL);
+ camel_stream_write_to_stream (out, stream, cancellable, NULL);
+
+ g_object_unref (out);
+}
+
+void
+eab_contact_formatter_format_contact_async (EABContactFormatter *formatter,
+ EContact *contact,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+
+ g_return_if_fail (EAB_IS_CONTACT_FORMATTER (formatter));
+ g_return_if_fail (E_IS_CONTACT (contact));
+ g_return_if_fail (callback != NULL);
+
+ g_object_ref (contact);
+ if (formatter->priv->contact)
+ g_object_unref (formatter->priv->contact);
+
+ formatter->priv->contact = contact;
+
+ result = g_simple_async_result_new (
+ G_OBJECT (formatter),
+ callback, user_data,
+ eab_contact_formatter_format_contact_async);
+
+ g_simple_async_result_run_in_thread (
+ result, do_start_async_formatter,
+ G_PRIORITY_DEFAULT, cancellable);
+}