/*
* 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 TWITTER_ICON "im-twitter"
#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 gboolean
icon_available (const gchar *icon)
{
GtkIconTheme *icon_theme;
GtkIconInfo *icon_info;
if (!icon)
return FALSE;
icon_theme = gtk_icon_theme_get_default ();
icon_info = gtk_icon_theme_lookup_icon (icon_theme, icon, 16, 0);
if (icon_info != NULL)
gtk_icon_info_free (icon_info);
return icon_info != NULL;
}
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 && icon_available (icon)) {
icon_html = g_strdup_printf ("<img src=\"gtk-stock://%s\" width=\"16\" height=\"16\" />", icon);
} 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)) {
g_string_append_printf (buffer, "<img src=\"gtk-stock://%s\">", CONTACT_LIST_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 <"
"<a href=\"mailto:%s\">%s</a>>"
"</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 ? " <" : "",
email_num,
mail,
name ? ">" : "",
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);
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);
}
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> <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);
}