[evolution] Bug #685323 - Provide SIP field for contacts



commit 3c497e278d5af861d09db0d57758f0612ea4baf1
Author: Milan Crha <mcrha redhat com>
Date:   Tue Apr 29 14:48:30 2014 +0200

    Bug #685323 - Provide SIP field for contacts

 addressbook/gui/contact-editor/contact-editor.ui   |   78 +++++-
 .../gui/contact-editor/e-contact-editor-dyntable.c |    4 +-
 addressbook/gui/contact-editor/e-contact-editor.c  |  314 ++++++++++++++++++--
 addressbook/gui/widgets/eab-contact-formatter.c    |  206 +++++++++++++-
 e-util/e-html-utils.c                              |   40 +++-
 e-util/e-html-utils.h                              |    3 +
 6 files changed, 611 insertions(+), 34 deletions(-)
---
diff --git a/addressbook/gui/contact-editor/contact-editor.ui 
b/addressbook/gui/contact-editor/contact-editor.ui
index af2d41a..0c6edc8 100644
--- a/addressbook/gui/contact-editor/contact-editor.ui
+++ b/addressbook/gui/contact-editor/contact-editor.ui
@@ -598,6 +598,82 @@
                               </packing>
                             </child>
                             <child>
+                              <object class="GtkFrame" id="sip-frame">
+                                <property name="visible">True</property>
+                                <property name="label_xalign">0</property>
+                                <property name="shadow_type">none</property>
+
+                                    <child>
+                                      <object class="GtkVBox" id="vbox-sip">
+                                        <property name="visible">True</property>
+                                        <property name="border_width">12</property>
+                                        <property name="orientation">vertical</property>
+                                        <property name="spacing">6</property>
+
+                                           <child>
+                                             <object class="EContactEditorDynTable" 
type-func="e_contact_editor_dyntable_get_type" id="sip-dyntable">
+                                               <property name="visible">True</property>
+                                             </object>
+                                               <packing>
+                                                  <property name="position">0</property>
+                                               </packing>
+                                           </child>
+
+                                          </object>
+                                    </child>
+
+                                    <child type="label">
+                                      <object class="GtkHBox" id="hbox-sip">
+                                        <property name="visible">True</property>
+                                        <property name="spacing">4</property>
+                                        <child>
+                                          <object class="GtkLabel" id="label-sip">
+                                            <property name="visible">True</property>
+                                            <property name="label" translatable="yes">SIP Address</property>
+                                            <attributes>
+                                              <attribute name="weight" value="bold"/>
+                                            </attributes>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">0</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkButton" id="button-sip-expand">
+                                            <property name="width_request">20</property>
+                                            <property name="height_request">20</property>
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="receives_default">False</property>
+                                            <property name="relief">none</property>
+                                            <child internal-child="accessible">
+                                              <object class="AtkObject" id="button-sip-expand-atkobject">
+                                                <property name="AtkObject::accessible-name" 
translatable="yes">SIP Address</property>
+                                              </object>
+                                            </child>
+                                            <child>
+                                              <object class="GtkArrow" id="arrow-sip-expand">
+                                                <property name="visible">True</property>
+                                                <property name="shadow_type">none</property>
+                                              </object>
+                                            </child>
+                                          </object>
+                                          <packing>
+                                            <property name="position">1</property>
+                                          </packing>
+                                        </child>
+                                      </object>
+                                    </child>
+
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="position">2</property>
+                              </packing>
+                            </child>
+                            <child>
                               <object class="GtkFrame" id="frame66">
                                 <property name="visible">True</property>
                                 <property name="label_xalign">0</property>
@@ -670,7 +746,7 @@
                               </object>
                               <packing>
                                 <property name="expand">False</property>
-                                <property name="position">2</property>
+                                <property name="position">3</property>
                               </packing>
                             </child>
                           </object>
diff --git a/addressbook/gui/contact-editor/e-contact-editor-dyntable.c 
b/addressbook/gui/contact-editor/e-contact-editor-dyntable.c
index 4706d5b..eb70272 100644
--- a/addressbook/gui/contact-editor/e-contact-editor-dyntable.c
+++ b/addressbook/gui/contact-editor/e-contact-editor-dyntable.c
@@ -492,7 +492,9 @@ e_contact_editor_dyntable_fill_in_data (EContactEditorDynTable *dyntable)
                w = gtk_grid_get_child_at (grid, col + 1, row);
                class->widget_fill (dyntable, w, str_data);
 
-               g_return_if_fail(pos < dyntable->priv->max_entries);
+               if (pos >= dyntable->priv->max_entries)
+                       break;
+
                valid = gtk_tree_model_iter_next (store, &iter);
        }
 
diff --git a/addressbook/gui/contact-editor/e-contact-editor.c 
b/addressbook/gui/contact-editor/e-contact-editor.c
index 07cfa01..6751a00 100644
--- a/addressbook/gui/contact-editor/e-contact-editor.c
+++ b/addressbook/gui/contact-editor/e-contact-editor.c
@@ -50,6 +50,7 @@
 #define SLOTS_IN_COLLAPSED_STATE SLOTS_PER_LINE
 #define EMAIL_SLOTS   4
 #define PHONE_SLOTS   50
+#define SIP_SLOTS     4
 #define IM_SLOTS      50
 #define ADDRESS_SLOTS 3
 
@@ -123,8 +124,7 @@ static struct {
        EContactField field_id;
        const gchar *type_1;
        const gchar *type_2;
-}
-phones[] = {
+} phones[] = {
        { E_CONTACT_PHONE_ASSISTANT,    EVC_X_ASSISTANT,       NULL    },
        { E_CONTACT_PHONE_BUSINESS,     "WORK",                "VOICE" },
        { E_CONTACT_PHONE_BUSINESS_FAX, "WORK",                "FAX"   },
@@ -212,6 +212,7 @@ common_location[] =
 
 /* Default from the table above */
 static const gint email_default[] = { 0, 1, 2, 2 };
+static const gint sips_default[] = { 0, 1, 2, 2 };
 
 #define STRING_IS_EMPTY(x)      (!(x) || !(*(x)))
 #define STRING_MAKE_NON_NULL(x) ((x) ? (x) : "")
@@ -1017,6 +1018,13 @@ phone_index_to_type (gint index,
        *type_2 = phones [index].type_2;
 }
 
+static void
+sip_index_to_type (gint index,
+                  const gchar **type_1)
+{
+       *type_1 = common_location[index].name;
+}
+
 static gint
 get_email_location (EVCardAttribute *attr)
 {
@@ -1037,14 +1045,26 @@ get_phone_type (EVCardAttribute *attr)
 
        for (i = 0; i < G_N_ELEMENTS (phones); i++) {
                if (e_vcard_attribute_has_type (attr, phones[i].type_1) &&
-                       (phones[i].type_2 == NULL ||
-                        e_vcard_attribute_has_type (attr, phones[i].type_2)))
+                   (phones[i].type_2 == NULL || e_vcard_attribute_has_type (attr, phones[i].type_2)))
                        return i;
        }
 
        return -1;
 }
 
+static gint
+get_sip_type (EVCardAttribute *attr)
+{
+       gint ii;
+
+       for (ii = 0; ii < G_N_ELEMENTS (common_location); ii++) {
+               if (e_vcard_attribute_has_type (attr, common_location[ii].name))
+                       return ii;
+       }
+
+       return -1;
+}
+
 static EVCardAttributeParam *
 get_ui_slot_param (EVCardAttribute *attr)
 {
@@ -1368,6 +1388,24 @@ expand_phone (EContactEditor *editor,
 }
 
 static void
+expand_sip (EContactEditor *editor,
+           gboolean expanded)
+{
+       GtkWidget *w;
+       EContactEditorDynTable *dyntable;
+
+       set_arrow_image (editor, "arrow-sip-expand", expanded);
+
+       w = e_builder_get_widget (editor->priv->builder, "sip-dyntable");
+       dyntable = E_CONTACT_EDITOR_DYNTABLE (w);
+
+       if (expanded)
+               e_contact_editor_dyntable_set_show_max (dyntable, SIP_SLOTS);
+       else
+               e_contact_editor_dyntable_set_show_max (dyntable, SLOTS_IN_COLLAPSED_STATE);
+}
+
+static void
 expand_im (EContactEditor *editor,
            gboolean expanded)
 {
@@ -1431,7 +1469,7 @@ init_email (EContactEditor *editor)
 static void
 fill_in_phone (EContactEditor *editor)
 {
-       GList *phone_attr_list;
+       GList *tel_attr_list;
        GList *l;
        GtkWidget *w;
        EContactEditorDynTable *dyntable;
@@ -1447,14 +1485,15 @@ fill_in_phone (EContactEditor *editor)
 
        /* Fill in */
 
-       phone_attr_list = e_contact_get_attributes (editor->priv->contact, E_CONTACT_TEL);
+       tel_attr_list = e_contact_get_attributes (editor->priv->contact, E_CONTACT_TEL);
+
        data_store = e_contact_editor_dyntable_extract_data (dyntable);
 
-       for (l = phone_attr_list;l ; l = g_list_next (l)) {
+       for (l = tel_attr_list; l; l = g_list_next (l)) {
                EVCardAttribute *attr = l->data;
-               gchar           *phone;
-               gint             slot;
-               gint            phone_type;
+               gchar *phone;
+               gint slot;
+               gint phone_type;
 
                slot = get_ui_slot (attr);
                phone_type = get_phone_type (attr);
@@ -1471,7 +1510,7 @@ fill_in_phone (EContactEditor *editor)
        }
 
        e_contact_editor_dyntable_fill_in_data (dyntable);
-       g_list_free_full (phone_attr_list, (GDestroyNotify) e_vcard_attribute_free);
+       g_list_free_full (tel_attr_list, (GDestroyNotify) e_vcard_attribute_free);
 
        expand_phone (editor, TRUE);
 }
@@ -1479,10 +1518,10 @@ fill_in_phone (EContactEditor *editor)
 static void
 extract_phone (EContactEditor *editor)
 {
-       GList *attr_list = NULL;
+       GList *tel_attr_list = NULL;
        GList *old_attr_list;
        GList *ll;
-       gint   i;
+       gint i;
        GtkWidget *w;
        EContactEditorDynTable *dyntable;
        GtkListStore *data_store;
@@ -1496,17 +1535,17 @@ extract_phone (EContactEditor *editor)
        tree_model = GTK_TREE_MODEL (data_store);
 
        valid = gtk_tree_model_get_iter_first (tree_model, &iter);
-       while (valid){
+       while (valid) {
                gint phone_type;
                gchar *phone;
                EVCardAttribute *attr;
 
-               attr = e_vcard_attribute_new ("", "TEL");
                gtk_tree_model_get (tree_model,&iter,
                                   DYNTABLE_STORE_COLUMN_SELECTED_ITEM, &phone_type,
                                   DYNTABLE_STORE_COLUMN_ENTRY_STRING, &phone,
                                   -1);
 
+               attr = e_vcard_attribute_new ("", EVC_TEL);
                if (phone_type >= 0) {
                        const gchar *type_1;
                        const gchar *type_2;
@@ -1523,14 +1562,14 @@ extract_phone (EContactEditor *editor)
 
                e_vcard_attribute_add_value (attr, phone);
 
-               attr_list = g_list_prepend (attr_list, attr);
+               tel_attr_list = g_list_prepend (tel_attr_list, attr);
 
                valid = gtk_tree_model_iter_next (tree_model, &iter);
        }
-       attr_list = g_list_reverse (attr_list);
 
        /* Splice in the old attributes, minus the PHONE_SLOTS first */
 
+       tel_attr_list = g_list_reverse (tel_attr_list);
        old_attr_list = e_contact_get_attributes (editor->priv->contact, E_CONTACT_TEL);
        for (ll = old_attr_list, i = 1; ll && i <= PHONE_SLOTS; i++) {
                e_vcard_attribute_free (ll->data);
@@ -1538,11 +1577,11 @@ extract_phone (EContactEditor *editor)
        }
 
        old_attr_list = ll;
-       attr_list = g_list_concat (attr_list, old_attr_list);
+       tel_attr_list = g_list_concat (tel_attr_list, old_attr_list);
 
-       e_contact_set_attributes (editor->priv->contact, E_CONTACT_TEL, attr_list);
+       e_contact_set_attributes (editor->priv->contact, E_CONTACT_TEL, tel_attr_list);
 
-       g_list_free_full (attr_list, (GDestroyNotify) e_vcard_attribute_free);
+       g_list_free_full (tel_attr_list, (GDestroyNotify) e_vcard_attribute_free);
 }
 
 static void
@@ -1650,6 +1689,226 @@ sensitize_phone (EContactEditor *editor)
 }
 
 static void
+fill_in_sip (EContactEditor *editor)
+{
+       GList *sip_attr_list;
+       GList *l;
+       GtkWidget *w;
+       EContactEditorDynTable *dyntable;
+       GtkListStore *data_store;
+       GtkTreeIter iter;
+
+       w = e_builder_get_widget (editor->priv->builder, "sip-dyntable");
+       dyntable = E_CONTACT_EDITOR_DYNTABLE (w);
+
+       /* Clear */
+
+       e_contact_editor_dyntable_clear_data (dyntable);
+
+       /* Fill in */
+
+       sip_attr_list = e_contact_get_attributes (editor->priv->contact, E_CONTACT_SIP);
+
+       data_store = e_contact_editor_dyntable_extract_data (dyntable);
+
+       for (l = sip_attr_list; l; l = g_list_next (l)) {
+               EVCardAttribute *attr = l->data;
+               gchar *sip;
+               gint sip_type;
+
+               sip_type = get_sip_type (attr);
+               sip = e_vcard_attribute_get_value (attr);
+
+               if (sip_type < 0)
+                       sip_type = 2;
+
+               gtk_list_store_append (data_store, &iter);
+               gtk_list_store_set (data_store,&iter,
+                                  DYNTABLE_STORE_COLUMN_SORTORDER, -1,
+                                  DYNTABLE_STORE_COLUMN_SELECTED_ITEM, sip_type,
+                                  DYNTABLE_STORE_COLUMN_ENTRY_STRING, sip,
+                                  -1);
+
+               g_free (sip);
+       }
+
+       e_contact_editor_dyntable_fill_in_data (dyntable);
+       g_list_free_full (sip_attr_list, (GDestroyNotify) e_vcard_attribute_free);
+
+       expand_sip (editor, TRUE);
+}
+
+static void
+extract_sip (EContactEditor *editor)
+{
+       GList *sip_attr_list = NULL;
+       GList *old_attr_list;
+       GList *ll;
+       gint i;
+       GtkWidget *w;
+       EContactEditorDynTable *dyntable;
+       GtkListStore *data_store;
+       GtkTreeModel *tree_model;
+       GtkTreeIter iter;
+       gboolean valid;
+
+       w = e_builder_get_widget (editor->priv->builder, "sip-dyntable");
+       dyntable = E_CONTACT_EDITOR_DYNTABLE (w);
+       data_store = e_contact_editor_dyntable_extract_data (dyntable);
+       tree_model = GTK_TREE_MODEL (data_store);
+
+       valid = gtk_tree_model_get_iter_first (tree_model, &iter);
+       while (valid) {
+               gint sip_type;
+               gchar *sip;
+               EVCardAttribute *attr;
+
+               gtk_tree_model_get (tree_model,&iter,
+                                  DYNTABLE_STORE_COLUMN_SELECTED_ITEM, &sip_type,
+                                  DYNTABLE_STORE_COLUMN_ENTRY_STRING, &sip,
+                                  -1);
+
+               attr = e_vcard_attribute_new ("", EVC_X_SIP);
+               if (sip_type >= 0) {
+                       const gchar *type_1;
+
+                       sip_index_to_type (sip_type, &type_1);
+
+                       e_vcard_attribute_add_param_with_value (
+                               attr, e_vcard_attribute_param_new (EVC_TYPE), type_1);
+               }
+
+               e_vcard_attribute_add_value (attr, sip);
+
+               sip_attr_list = g_list_prepend (sip_attr_list, attr);
+
+               valid = gtk_tree_model_iter_next (tree_model, &iter);
+       }
+
+       /* Splice in the old attributes, minus the SIP_SLOTS first */
+
+       sip_attr_list = g_list_reverse (sip_attr_list);
+       old_attr_list = e_contact_get_attributes (editor->priv->contact, E_CONTACT_SIP);
+       for (ll = old_attr_list, i = 1; ll && i <= SIP_SLOTS; i++) {
+               e_vcard_attribute_free (ll->data);
+               ll = g_list_delete_link (ll, ll);
+       }
+
+       old_attr_list = ll;
+       sip_attr_list = g_list_concat (sip_attr_list, old_attr_list);
+
+       e_contact_set_attributes (editor->priv->contact, E_CONTACT_SIP, sip_attr_list);
+
+       g_list_free_full (sip_attr_list, (GDestroyNotify) e_vcard_attribute_free);
+}
+
+static void
+init_sip_record_type (EContactEditor *editor)
+{
+       GtkWidget *w;
+       GtkListStore *store;
+       gint i;
+       EContactEditorDynTable *dyntable;
+
+       w = e_builder_get_widget (editor->priv->builder, "sip-dyntable");
+       dyntable = E_CONTACT_EDITOR_DYNTABLE (w);
+       store = e_contact_editor_dyntable_get_combo_store (dyntable);
+
+       for (i = 0; i < G_N_ELEMENTS (common_location); i++) {
+               GtkTreeIter iter;
+
+               gtk_list_store_append (store, &iter);
+               gtk_list_store_set (store, &iter,
+                                   DYNTABLE_COMBO_COLUMN_TEXT, _(common_location[i].pretty_name),
+                                   DYNTABLE_COMBO_COLUMN_SENSITIVE, TRUE,
+                                   -1);
+       }
+
+       e_contact_editor_dyntable_set_combo_defaults (dyntable, sips_default, G_N_ELEMENTS (sips_default));
+}
+
+static void
+row_added_sip (EContactEditorDynTable *dyntable,
+              EContactEditor *editor)
+{
+       expand_sip (editor, TRUE);
+}
+
+static void
+init_sip (EContactEditor *editor)
+{
+       GtkWidget *w;
+       EContactEditorDynTable *dyntable;
+
+       w = e_builder_get_widget (editor->priv->builder, "sip-dyntable");
+       dyntable = E_CONTACT_EDITOR_DYNTABLE (w);
+
+       e_contact_editor_dyntable_set_max_entries (dyntable, SIP_SLOTS);
+       e_contact_editor_dyntable_set_num_columns (dyntable, SLOTS_PER_LINE, TRUE);
+       e_contact_editor_dyntable_set_show_min (dyntable, SLOTS_PER_LINE);
+
+       g_signal_connect (
+               w, "changed",
+               G_CALLBACK (object_changed), editor);
+       g_signal_connect_swapped (
+               w, "activate",
+               G_CALLBACK (entry_activated), editor);
+       g_signal_connect (
+               w, "row-added",
+               G_CALLBACK (row_added_sip), editor);
+
+       init_sip_record_type (editor);
+}
+
+static void
+sensitize_sip_types (EContactEditor *editor)
+{
+       GtkWidget *w;
+       GtkListStore *listStore;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       gint i;
+       gboolean valid;
+
+       w = e_builder_get_widget (editor->priv->builder, "sip-dyntable");
+       listStore = e_contact_editor_dyntable_get_combo_store (E_CONTACT_EDITOR_DYNTABLE (w));
+       model = GTK_TREE_MODEL (listStore);
+
+       valid = gtk_tree_model_get_iter_first (model, &iter);
+
+       for (i = 0; i < G_N_ELEMENTS (common_location); i++) {
+               if (!valid) {
+                       g_warning (G_STRLOC ": Unexpected end of sip items in combo box");
+                       return;
+               }
+
+               gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+                                   DYNTABLE_COMBO_COLUMN_SENSITIVE,
+                                   is_field_supported (editor, E_CONTACT_SIP),
+                                   -1);
+
+               valid = gtk_tree_model_iter_next (model, &iter);
+       }
+}
+
+static void
+sensitize_sip (EContactEditor *editor)
+{
+       GtkWidget *w;
+       gboolean enabled = TRUE;
+
+       w = e_builder_get_widget (editor->priv->builder, "sip-dyntable");
+
+       if (!editor->priv->target_editable ||
+           !is_field_supported (editor, E_CONTACT_SIP))
+               enabled = FALSE;
+
+       gtk_widget_set_sensitive (w, enabled);
+
+       sensitize_sip_types (editor);
+}
+
+static void
 row_added_im (EContactEditorDynTable *dyntable, EContactEditor *editor)
 {
        expand_im (editor, TRUE);
@@ -2906,6 +3165,7 @@ fill_in_all (EContactEditor *editor)
        fill_in_simple       (editor);
        fill_in_email        (editor);
        fill_in_phone        (editor);
+       fill_in_sip          (editor);
        fill_in_im           (editor);
        fill_in_address      (editor);
 }
@@ -2916,6 +3176,7 @@ extract_all (EContactEditor *editor)
        extract_simple  (editor);
        extract_email   (editor);
        extract_phone   (editor);
+       extract_sip     (editor);
        extract_im      (editor);
        extract_address (editor);
 }
@@ -2927,6 +3188,7 @@ sensitize_all (EContactEditor *editor)
        sensitize_simple  (editor);
        sensitize_email   (editor);
        sensitize_phone   (editor);
+       sensitize_sip     (editor);
        sensitize_im      (editor);
        sensitize_address (editor);
 }
@@ -2942,6 +3204,7 @@ init_all (EContactEditor *editor)
        init_simple   (editor);
        init_email    (editor);
        init_phone    (editor);
+       init_sip      (editor);
        init_im       (editor);
        init_personal (editor);
        init_address  (editor);
@@ -3969,6 +4232,12 @@ expand_phone_toggle (EContactEditor *ce)
 }
 
 static void
+expand_sip_toggle (EContactEditor *ce)
+{
+       expand_sip (ce, !is_arrow_image_arrow_down (ce, "arrow-sip-expand"));
+}
+
+static void
 expand_im_toggle (EContactEditor *ce)
 {
        expand_im (ce, !is_arrow_image_arrow_down (ce, "arrow-im-expand"));
@@ -4100,6 +4369,11 @@ e_contact_editor_init (EContactEditor *e_contact_editor)
                widget, "clicked",
                G_CALLBACK (expand_phone_toggle), e_contact_editor);
        widget = e_builder_get_widget (
+               e_contact_editor->priv->builder, "button-sip-expand");
+       g_signal_connect_swapped (
+               widget, "clicked",
+               G_CALLBACK (expand_sip_toggle), e_contact_editor);
+       widget = e_builder_get_widget (
                e_contact_editor->priv->builder, "button-im-expand");
        g_signal_connect_swapped (
                widget, "clicked",
diff --git a/addressbook/gui/widgets/eab-contact-formatter.c b/addressbook/gui/widgets/eab-contact-formatter.c
index f4b24a2..5935145 100644
--- a/addressbook/gui/widgets/eab-contact-formatter.c
+++ b/addressbook/gui/widgets/eab-contact-formatter.c
@@ -64,6 +64,8 @@
 struct _EABContactFormatterPrivate {
        EABContactDisplayMode mode;
        gboolean render_maps;
+       gboolean supports_callto;
+       gboolean supports_sip;
 };
 
 enum {
@@ -86,6 +88,9 @@ G_DEFINE_TYPE (
        eab_contact_formatter,
        G_TYPE_OBJECT);
 
+#define E_CREATE_CALLTO_URL    (E_TEXT_TO_HTML_LAST_FLAG << 0)
+#define E_CREATE_SIP_URL       (E_TEXT_TO_HTML_LAST_FLAG << 1)
+
 static gboolean
 icon_available (const gchar *icon)
 {
@@ -285,6 +290,31 @@ render_table_row (GString *buffer,
                g_free (value);
 }
 
+/* Returns NULL if no replace had been done (and
+   original 'str' should be used instead). Otherwise
+   free the returned pointer with g_free().
+*/
+static gchar *
+maybe_create_url (const gchar *str,
+                 guint html_flags)
+{
+       gchar *tmp = NULL;
+       const gchar *url = NULL;
+
+       g_return_val_if_fail (str != NULL, NULL);
+
+       if ((html_flags & E_CREATE_CALLTO_URL) != 0) {
+               url = "callto:";
+       } else if ((html_flags & E_CREATE_SIP_URL) != 0) {
+               url = "sip:";
+       }
+
+       if (url && g_ascii_strncasecmp (str, url, strlen (url)) != 0)
+               tmp = g_strconcat (url, str, NULL);
+
+       return tmp;
+}
+
 static void
 accum_attribute (GString *buffer,
                  EContact *contact,
@@ -297,8 +327,17 @@ accum_attribute (GString *buffer,
 
        str = e_contact_get_const (contact, field);
 
-       if (str != NULL && *str != '\0')
+       if (str != NULL && *str != '\0') {
+               gchar *tmp = NULL;
+
+               tmp = maybe_create_url (str, html_flags);
+               if (tmp)
+                       str = tmp;
+
                render_table_row (buffer, html_label, str, icon, html_flags);
+
+               g_free (tmp);
+       }
 }
 
 static void
@@ -336,24 +375,125 @@ accum_attribute_multival (GString *buffer,
 {
        GList *val_list, *l;
        GString *val = g_string_new ("");
+       const gchar *str;
+       gchar *tmp;
 
        val_list = e_contact_get (contact, field);
 
        for (l = val_list; l; l = l->next) {
+               str = l->data;
+
                if (l != val_list)
                        g_string_append (val, "<br>");
 
-               g_string_append (val, l->data);
+               tmp = maybe_create_url (str, html_flags);
+               if (tmp)
+                       str = tmp;
+
+               if ((html_flags & E_TEXT_TO_HTML_CONVERT_URLS) != 0) {
+                       gchar *value = e_text_to_html (str, html_flags);
+
+                       if (value && *value)
+                               g_string_append (val, value);
+
+                       g_free (value);
+               } else {
+                       g_string_append (val, str);
+               }
+
+               g_free (tmp);
        }
 
-       if (val->str && *val->str)
+       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_foreach (val_list, (GFunc) g_free, NULL);
        g_list_free (val_list);
 }
 
+typedef enum {
+       EAB_CONTACT_FORMATTER_SIP_TYPE_HOME,
+       EAB_CONTACT_FORMATTER_SIP_TYPE_WORK,
+       EAB_CONTACT_FORMATTER_SIP_TYPE_OTHER
+} EABContactFormatterSIPType;
+
+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);
+}
+
 static const gchar *
 get_email_location (EVCardAttribute *attr)
 {
@@ -554,6 +694,13 @@ render_contact_column (EABContactFormatter *formatter,
        GList *email_list, *l, *email_attr_list, *al;
        gint email_num = 0;
        const gchar *nl;
+       guint32 sip_flags = 0;
+
+       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 = "";
@@ -595,6 +742,8 @@ render_contact_column (EABContactFormatter *formatter,
        if (email->len)
                render_table_row (accum, _("Email"), email->str, NULL, 0);
 
+       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);
@@ -647,6 +796,19 @@ render_work_column (EABContactFormatter *formatter,
                     GString *buffer)
 {
        GString *accum = g_string_new ("");
+       guint32 phone_flags = 0, sip_flags = 0;
+
+       if (formatter->priv->supports_callto)
+               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_CALLTO_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;
 
        accum_attribute (accum, contact, _("Company"), E_CONTACT_ORG, NULL, 0);
        accum_attribute (accum, contact, _("Department"), E_CONTACT_ORG_UNIT, NULL, 0);
@@ -658,8 +820,9 @@ render_work_column (EABContactFormatter *formatter,
        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, _("Phone"), E_CONTACT_PHONE_BUSINESS, NULL, phone_flags);
        accum_attribute (accum, contact, _("Fax"), E_CONTACT_PHONE_BUSINESS_FAX, NULL, 0);
+       accum_sip       (accum, contact, EAB_CONTACT_FORMATTER_SIP_TYPE_WORK, NULL, sip_flags);
        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);
@@ -682,11 +845,25 @@ render_personal_column (EABContactFormatter *formatter,
                         GString *buffer)
 {
        GString *accum = g_string_new ("");
+       guint32 phone_flags = 0, sip_flags = 0;
+
+       if (formatter->priv->supports_callto)
+               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_CALLTO_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;
 
        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_attribute (accum, contact, _("Phone"), E_CONTACT_PHONE_HOME, NULL, phone_flags);
+       accum_attribute (accum, contact, _("Mobile Phone"), E_CONTACT_PHONE_MOBILE, NULL, phone_flags);
+       accum_sip       (accum, contact, EAB_CONTACT_FORMATTER_SIP_TYPE_HOME, NULL, sip_flags);
        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);
@@ -1022,6 +1199,21 @@ render_compact (EABContactFormatter *formatter,
        g_string_append (buffer, "</body></html>\n");
 }
 
+static gboolean
+eab_contact_formatter_scheme_supported (const gchar *scheme)
+{
+       GAppInfo *app_info;
+       gboolean supported;
+
+       app_info = g_app_info_get_default_for_uri_scheme (scheme);
+       supported = app_info != NULL;
+
+       if (app_info && g_app_info_can_delete (app_info))
+               g_app_info_delete (app_info);
+
+       return supported;
+}
+
 static void
 eab_contact_formatter_set_property (GObject *object,
                                     guint property_id,
@@ -1115,6 +1307,8 @@ eab_contact_formatter_init (EABContactFormatter *formatter)
 
        formatter->priv->mode = EAB_CONTACT_DISPLAY_RENDER_NORMAL;
        formatter->priv->render_maps = FALSE;
+       formatter->priv->supports_callto = eab_contact_formatter_scheme_supported ("callto");
+       formatter->priv->supports_sip = eab_contact_formatter_scheme_supported ("sip");
 }
 
 EABContactFormatter *
diff --git a/e-util/e-html-utils.c b/e-util/e-html-utils.c
index 4c49315..260e26b 100644
--- a/e-util/e-html-utils.c
+++ b/e-util/e-html-utils.c
@@ -75,13 +75,18 @@ static gint special_chars[] = {
 
 static gchar *
 url_extract (const guchar **text,
-             gboolean full_url)
+             gboolean full_url,
+            gboolean use_whole_text)
 {
        const guchar *end = *text, *p;
        gchar *out;
 
-       while (*end && is_url_char (*end))
-               end++;
+       if (use_whole_text) {
+               end = (*text) + strlen ((const gchar *) (*text));
+       } else {
+               while (*end && is_url_char (*end))
+                       end++;
+       }
 
        /* Back up if we probably went too far. */
        while (end > *text && is_trailing_garbage (*(end - 1)))
@@ -221,6 +226,13 @@ is_citation (const guchar *c,
  *   - E_TEXT_TO_HTML_CITE: quote the text with "> " at the start of each
  *     line.
  *
+ *   - E_TEXT_TO_HTML_HIDE_URL_SCHEME: hides scheme part of the URL in
+ *     the display part of the generated text (thus, instead of "http://www.example.com";,
+ *     user will only see "www.example.com")
+ *
+ *   - E_TEXT_TO_HTML_URL_IS_WHOLE_TEXT: set when the whole @input text
+ *     represents a URL
+ *
  * Returns: a newly-allocated string containing HTML
  **/
 gchar *
@@ -291,14 +303,30 @@ e_text_to_html_full (const gchar *input,
                            !g_ascii_strncasecmp ((gchar *) cur, "h323:", 5) ||
                            !g_ascii_strncasecmp ((gchar *) cur, "sip:", 4) ||
                            !g_ascii_strncasecmp ((gchar *) cur, "webcal:", 7)) {
-                               tmpurl = url_extract (&cur, TRUE);
+                               tmpurl = url_extract (&cur, TRUE, (flags & E_TEXT_TO_HTML_URL_IS_WHOLE_TEXT) 
!= 0);
                                if (tmpurl) {
                                        refurl = e_text_to_html (tmpurl, 0);
-                                       dispurl = g_strdup (refurl);
+                                       if ((flags & E_TEXT_TO_HTML_HIDE_URL_SCHEME) != 0) {
+                                               const gchar *str;
+
+                                               str = strchr (refurl, ':');
+                                               if (str) {
+                                                       str++;
+                                                       if (g_ascii_strncasecmp (str, "//", 2) == 0) {
+                                                               str += 2;
+                                                       }
+
+                                                       dispurl = g_strdup (str);
+                                               } else {
+                                                       dispurl = g_strdup (refurl);
+                                               }
+                                       } else {
+                                               dispurl = g_strdup (refurl);
+                                       }
                                }
                        } else if (!g_ascii_strncasecmp ((gchar *) cur, "www.", 4) &&
                                   is_url_char (*(cur + 4))) {
-                               tmpurl = url_extract (&cur, FALSE);
+                               tmpurl = url_extract (&cur, FALSE, (flags & E_TEXT_TO_HTML_URL_IS_WHOLE_TEXT) 
!= 0);
                                if (tmpurl) {
                                        dispurl = e_text_to_html (tmpurl, 0);
                                        refurl = g_strdup_printf (
diff --git a/e-util/e-html-utils.h b/e-util/e-html-utils.h
index 6ff93d7..ea48fbd 100644
--- a/e-util/e-html-utils.h
+++ b/e-util/e-html-utils.h
@@ -36,6 +36,9 @@
 #define E_TEXT_TO_HTML_CONVERT_ADDRESSES (1 << 5)
 #define E_TEXT_TO_HTML_ESCAPE_8BIT       (1 << 6)
 #define E_TEXT_TO_HTML_CITE              (1 << 7)
+#define E_TEXT_TO_HTML_HIDE_URL_SCHEME   (1 << 8)
+#define E_TEXT_TO_HTML_URL_IS_WHOLE_TEXT (1 << 9)
+#define E_TEXT_TO_HTML_LAST_FLAG         (1 << 10)
 
 gchar *e_text_to_html_full (const gchar *input, guint flags, guint32 color);
 gchar *e_text_to_html      (const gchar *input, guint flags);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]