From 2be6b60d8311b0fd537a2889f8997d3f084755b0 Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Mon, 21 Jan 2008 10:21:29 +0000 Subject: ** Fix for bug #324604 inspired by patch of makuchaku (Mayank) 2008-01-21 Milan Crha ** Fix for bug #324604 inspired by patch of makuchaku (Mayank) * gui/widgets/eab-gui-util.h: * gui/widgets/eab-gui-util.c: (eab_parse_qp_email), (eab_parse_qp_email_to_html): New helper functions for decoding email addresses from RFC822 or RFC2047 form to UTF-8. * gui/widgets/e-minicard.c: (add_email_field): * gui/widgets/eab-contact-display.c: (render_contact_list), (render_contact), (eab_contact_display_render_compact): * gui/widgets/e-addressbook-table-adapter.c: (struct _EAddressbookTableAdapterPrivate), (addressbook_dispose), (addressbook_value_at), (addressbook_set_value_at), (remove_contacts), (modify_contact), (model_changed), (eab_table_adapter_construct): * gui/widgets/eab-gui-util.c: (get_email), (eab_send_contact_list_as_attachment): Ensure the print of the email is transformed from RFC822 or RFC2047. svn path=/trunk/; revision=34863 --- addressbook/ChangeLog | 19 +++++ .../gui/widgets/e-addressbook-table-adapter.c | 47 ++++++++++- addressbook/gui/widgets/e-minicard.c | 23 +++-- addressbook/gui/widgets/eab-contact-display.c | 86 ++++++++++++------- addressbook/gui/widgets/eab-gui-util.c | 97 ++++++++++++++++++++-- addressbook/gui/widgets/eab-gui-util.h | 4 + 6 files changed, 236 insertions(+), 40 deletions(-) (limited to 'addressbook') diff --git a/addressbook/ChangeLog b/addressbook/ChangeLog index 2b5060cbc0..947bfcc9af 100644 --- a/addressbook/ChangeLog +++ b/addressbook/ChangeLog @@ -1,3 +1,22 @@ +2008-01-21 Milan Crha + + ** Fix for bug #324604 inspired by patch of makuchaku (Mayank) + + * gui/widgets/eab-gui-util.h: + * gui/widgets/eab-gui-util.c: (eab_parse_qp_email), + (eab_parse_qp_email_to_html): New helper functions for decoding + email addresses from RFC822 or RFC2047 form to UTF-8. + * gui/widgets/e-minicard.c: (add_email_field): + * gui/widgets/eab-contact-display.c: (render_contact_list), + (render_contact), (eab_contact_display_render_compact): + * gui/widgets/e-addressbook-table-adapter.c: + (struct _EAddressbookTableAdapterPrivate), (addressbook_dispose), + (addressbook_value_at), (addressbook_set_value_at), (remove_contacts), + (modify_contact), (model_changed), (eab_table_adapter_construct): + * gui/widgets/eab-gui-util.c: (get_email), + (eab_send_contact_list_as_attachment): + Ensure the print of the email is transformed from RFC822 or RFC2047. + 2008-01-20 Srinivasa Ragavan * gui/widgets/e-addressbook-view.etspec: Revert my last patch. diff --git a/addressbook/gui/widgets/e-addressbook-table-adapter.c b/addressbook/gui/widgets/e-addressbook-table-adapter.c index b208952245..95e3b214a9 100644 --- a/addressbook/gui/widgets/e-addressbook-table-adapter.c +++ b/addressbook/gui/widgets/e-addressbook-table-adapter.c @@ -15,6 +15,8 @@ struct _EAddressbookTableAdapterPrivate { EABModel *model; int create_contact_id, remove_contact_id, modify_contact_id, model_changed_id; + + GHashTable *emails; }; #define PARENT_TYPE e_table_model_get_type() @@ -54,6 +56,9 @@ addressbook_dispose(GObject *object) if (adapter->priv) { unlink_model(adapter); + g_hash_table_remove_all (adapter->priv->emails); + g_hash_table_destroy (adapter->priv->emails); + g_free (adapter->priv); adapter->priv = NULL; } @@ -92,6 +97,28 @@ addressbook_value_at (ETableModel *etc, int col, int row) value = e_contact_get_const((EContact*)eab_model_contact_at (priv->model, row), col); + if (value && *value && (col == E_CONTACT_EMAIL_1 || col == E_CONTACT_EMAIL_2 || col == E_CONTACT_EMAIL_3)) { + char *val = g_hash_table_lookup (priv->emails, value); + + if (val) { + /* we have this already cached, so use value from the cache */ + value = val; + } else { + char *name = NULL, *mail = NULL; + + if (eab_parse_qp_email (value, &name, &mail)) + val = g_strdup_printf ("%s <%s>", name, mail); + else + val = g_strdup (value); + + g_free (name); + g_free (mail); + + g_hash_table_insert (priv->emails, g_strdup (value), val); + value = val; + } + } + return (void *)(value ? value : ""); } @@ -122,9 +149,17 @@ addressbook_set_value_at (ETableModel *etc, int col, int row, const void *val) e_table_model_pre_change(etc); + if (col == E_CONTACT_EMAIL_1 || col == E_CONTACT_EMAIL_2 || col == E_CONTACT_EMAIL_3) { + const char *old_value = e_contact_get_const (contact, col); + + /* remove old value from cache and use new one */ + if (old_value && *old_value) + g_hash_table_remove (priv->emails, old_value); + } + e_contact_set(contact, col, (void *) val); eab_merging_book_commit_contact (eab_model_get_ebook (priv->model), - contact, contact_modified_cb, NULL); + contact, contact_modified_cb, etc); g_object_unref (contact); @@ -266,6 +301,8 @@ remove_contacts (EABModel *model, GArray *indices = (GArray *) data; int count = indices->len; + /* clear whole cache */ + g_hash_table_remove_all (adapter->priv->emails); e_table_model_pre_change (E_TABLE_MODEL (adapter)); if (count == 1) @@ -279,6 +316,9 @@ modify_contact (EABModel *model, gint index, EAddressbookTableAdapter *adapter) { + /* clear whole cache */ + g_hash_table_remove_all (adapter->priv->emails); + e_table_model_pre_change (E_TABLE_MODEL (adapter)); e_table_model_row_changed (E_TABLE_MODEL (adapter), index); } @@ -287,6 +327,9 @@ static void model_changed (EABModel *model, EAddressbookTableAdapter *adapter) { + /* clear whole cache */ + g_hash_table_remove_all (adapter->priv->emails); + e_table_model_pre_change (E_TABLE_MODEL (adapter)); e_table_model_changed (E_TABLE_MODEL (adapter)); } @@ -340,6 +383,8 @@ eab_table_adapter_construct (EAddressbookTableAdapter *adapter, "model_changed", G_CALLBACK(model_changed), adapter); + + priv->emails = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_free); } ETableModel * diff --git a/addressbook/gui/widgets/e-minicard.c b/addressbook/gui/widgets/e-minicard.c index c0fd0b5994..02119d1c7e 100644 --- a/addressbook/gui/widgets/e-minicard.c +++ b/addressbook/gui/widgets/e-minicard.c @@ -839,7 +839,6 @@ add_email_field (EMinicard *e_minicard, GList *email_list, gdouble left_width, i GnomeCanvasGroup *group; EMinicardField *minicard_field; char *name; - char *string; GList *l, *le; int count =0; GList *emails = e_contact_get (e_minicard->contact, E_CONTACT_EMAIL); @@ -847,20 +846,32 @@ add_email_field (EMinicard *e_minicard, GList *email_list, gdouble left_width, i for (l=email_list, le=emails; l!=NULL && count < limit && le!=NULL; l = l->next, le=le->next) { const gchar *tmp; + char *email = NULL; + char *string = NULL; + char *full_string = NULL; + gboolean parser_check; tmp = get_email_location ((EVCardAttribute *) l->data); if (tmp) name = g_strdup_printf ("%s:", tmp); else name = g_strdup (""); - string = e_text_to_html (le->data, 0); + + parser_check = eab_parse_qp_email ((const gchar *) le->data, &string, &email); + if (parser_check) { + /* if true, we had a quoted printable mail address */ + full_string = g_strdup_printf ("%s <%s>", string, email); + } else { + /* we got a NON-quoted printable string */ + string = g_strdup (le->data); + } new_item = e_minicard_label_new(group); gnome_canvas_item_set( new_item, "width", e_minicard->width - 4.0, "fieldname", name, - "field", string, + "field", parser_check ? full_string : string, "max_field_name_length", left_width, "editable", FALSE /* e_minicard->editable */, NULL ); @@ -882,8 +893,10 @@ add_email_field (EMinicard *e_minicard, GList *email_list, gdouble left_width, i e_minicard->fields = g_list_append( e_minicard->fields, minicard_field); e_canvas_item_move_absolute(new_item, 2, e_minicard->height); count++; - g_free(name); - g_free(string); + g_free (name); + g_free (string); + g_free (full_string); + g_free (email); } g_list_foreach (emails, (GFunc) g_free, NULL); g_list_free (emails); diff --git a/addressbook/gui/widgets/eab-contact-display.c b/addressbook/gui/widgets/eab-contact-display.c index 7510d72189..a93f86e2ea 100644 --- a/addressbook/gui/widgets/eab-contact-display.c +++ b/addressbook/gui/widgets/eab-contact-display.c @@ -488,10 +488,18 @@ render_contact_list (GtkHTMLStream *html_stream, EContact *contact) email_list = e_contact_get (contact, E_CONTACT_EMAIL); for (l = email_list; l; l = l->next) { - char *html = e_text_to_html (l->data, E_TEXT_TO_HTML_CONVERT_ADDRESSES); - gtk_html_stream_printf (html_stream, "%s
", html); - g_free (html); + gchar *value; + + value = eab_parse_qp_email_to_html (l->data); + + if (!value) + value = e_text_to_html (l->data, E_TEXT_TO_HTML_CONVERT_ADDRESSES); + + gtk_html_stream_printf (html_stream, "%s
", value); + + g_free (value); } + gtk_html_stream_printf (html_stream, ""); } @@ -542,18 +550,35 @@ render_contact (GtkHTMLStream *html_stream, EContact *contact) 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) { -#ifdef HANDLE_MAILTO_INTERNALLY - char *html = e_text_to_html (l->data, 0); + char *html = NULL, *name = NULL, *mail = NULL; char *attr_str = (char *)get_email_location ((EVCardAttribute *) al->data); - g_string_append_printf (accum, "%s%s (%s)", nl, email_num, html, attr_str?attr_str:""); - email_num ++; - g_free (html); - nl = "
"; +#ifdef HANDLE_MAILTO_INTERNALLY + if (!eab_parse_qp_email (l->data, &name, &mail)) + mail = e_text_to_html (l->data, 0); + + g_string_append_printf (accum, "%s%s%s%s%s (%s)", + nl, + name ? name : "", + name ? " <" : "", + email_num, + mail, + name ? ">" : "", + attr_str ? attr_str : ""); + email_num ++; #else - g_string_append_printf (accum, "%s%s (%s)", nl, (char*)l->data, get_email_location ((EVCardAttribute *) al->data)); - nl = "\n"; + html = eab_parse_qp_email_to_html (l->data); + + if (!html) + html = e_text_to_html (l->data, E_TEXT_TO_HTML_CONVERT_ADDRESSES); + + g_string_append_printf (accum, "%s%s (%s)", nl, html, attr_str ? attr_str : ""); #endif + nl = "
"; + + g_free (html); + g_free (name); + g_free (mail); } g_list_foreach (email_list, (GFunc)g_free, NULL); g_list_free (email_list); @@ -821,29 +846,34 @@ eab_contact_display_render_compact (EABContactDisplay *display, EContact *contac g_free (html); } + #define print_email() { \ + html = eab_parse_qp_email_to_html (str); \ + \ + if (!html) \ + html = e_text_to_html (str, 0); \ + \ + gtk_html_stream_printf (html_stream, "%s%s", comma ? ", " : "", html); \ + g_free (html); \ + comma = TRUE; \ + } + gtk_html_stream_printf (html_stream, "%s: ", _("Email")); str = e_contact_get_const (contact, E_CONTACT_EMAIL_1); - if (str) { - html = e_text_to_html (str, 0); - gtk_html_stream_printf (html_stream, "%s", str); - g_free (html); - comma = TRUE; - } + if (str) + print_email (); + str = e_contact_get_const (contact, E_CONTACT_EMAIL_2); - if (str) { - html = e_text_to_html (str, 0); - gtk_html_stream_printf (html_stream, "%s%s", comma ? ", " : "", str); - g_free (html); - comma = TRUE; - } + if (str) + print_email (); + str = e_contact_get_const (contact, E_CONTACT_EMAIL_3); - if (str) { - html = e_text_to_html (str, 0); - gtk_html_stream_printf (html_stream, "%s%s", comma ? ", " : "", str); - g_free (html); - } + if (str) + print_email (); + gtk_html_stream_write (html_stream, "
", 4); + #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); diff --git a/addressbook/gui/widgets/eab-gui-util.c b/addressbook/gui/widgets/eab-gui-util.c index 9124583b82..842e954f20 100644 --- a/addressbook/gui/widgets/eab-gui-util.c +++ b/addressbook/gui/widgets/eab-gui-util.c @@ -34,11 +34,15 @@ #include "util/eab-book-util.h" #include #include "e-util/e-error.h" +#include "e-util/e-html-utils.h" #include "misc/e-image-chooser.h" #include #include "eab-contact-merging.h" #include +/* we link to camel for decoding quoted printable email addresses */ +#include + #include "addressbook/gui/contact-editor/eab-editor.h" #include "addressbook/gui/contact-editor/e-contact-editor.h" #include "addressbook/gui/contact-list-editor/e-contact-list-editor.h" @@ -932,6 +936,25 @@ eab_send_to_contact_and_email_num_list (GList *c) CORBA_exception_free (&ev); } +static const char * +get_email (EContact *contact, EContactField field_id, gchar **to_free) +{ + char *name = NULL, *mail = NULL; + const char *value = e_contact_get_const (contact, field_id); + + *to_free = NULL; + + if (eab_parse_qp_email (value, &name, &mail)) { + *to_free = g_strdup_printf ("%s <%s>", name, mail); + value = *to_free; + } + + g_free (name); + g_free (mail); + + return value; +} + static void eab_send_contact_list_as_attachment (GList *contacts) { @@ -1005,18 +1028,25 @@ eab_send_contact_list_as_attachment (GList *contacts) } else { EContact *contact = contacts->data; const gchar *tempstr2; + gchar *tempfree = NULL; tempstr2 = e_contact_get_const (contact, E_CONTACT_FILE_AS); if (!tempstr2 || !*tempstr2) tempstr2 = e_contact_get_const (contact, E_CONTACT_FULL_NAME); if (!tempstr2 || !*tempstr2) tempstr2 = e_contact_get_const (contact, E_CONTACT_ORG); - if (!tempstr2 || !*tempstr2) - tempstr2 = e_contact_get_const (contact, E_CONTACT_EMAIL_1); - if (!tempstr2 || !*tempstr2) - tempstr2 = e_contact_get_const (contact, E_CONTACT_EMAIL_2); - if (!tempstr2 || !*tempstr2) - tempstr2 = e_contact_get_const (contact, E_CONTACT_EMAIL_3); + if (!tempstr2 || !*tempstr2) { + g_free (tempfree); + tempstr2 = get_email (contact, E_CONTACT_EMAIL_1, &tempfree); + } + if (!tempstr2 || !*tempstr2) { + g_free (tempfree); + tempstr2 = get_email (contact, E_CONTACT_EMAIL_2, &tempfree); + } + if (!tempstr2 || !*tempstr2) { + g_free (tempfree); + tempstr2 = get_email (contact, E_CONTACT_EMAIL_3, &tempfree); + } if (!tempstr2 || !*tempstr2) tempstr = g_strdup_printf (_("Contact information")); @@ -1024,6 +1054,7 @@ eab_send_contact_list_as_attachment (GList *contacts) tempstr = g_strdup_printf (_("Contact information for %s"), tempstr2); subject = CORBA_string_dup (tempstr); g_free (tempstr); + g_free (tempfree); } GNOME_Evolution_Composer_setHeaders (composer_server, "", to_list, cc_list, bcc_list, subject, &ev); @@ -1118,3 +1149,57 @@ eab_create_image_chooser_widget(gchar *name, return w; } + +/* To parse something like... +=?UTF-8?Q?=E0=A4=95=E0=A4=95=E0=A4=AC=E0=A5=82=E0=A5=8B=E0=A5=87?=\t\n=?UTF-8?Q?=E0=A4=B0?=\t\n +and return the decoded representation of name & email parts. +*/ +gboolean +eab_parse_qp_email (const gchar *string, gchar **name, gchar **email) +{ + struct _camel_header_address *address; + gboolean res = FALSE; + + address = camel_header_address_decode (string, "UTF-8"); + + if (!address) + return FALSE; + + /* report success only when we have filled both name and email address */ + if (address->type == CAMEL_HEADER_ADDRESS_NAME && address->name && *address->name && address->v.addr && *address->v.addr) { + *name = g_strdup (address->name); + *email = g_strdup (address->v.addr); + res = TRUE; + } + + camel_header_address_unref (address); + + return res; +} + +/* This is only wrapper to parse_qp_mail, it decodes string and if returned TRUE, + then makes one string and returns it, otherwise returns NULL. + Returned string is usable to place directly into GtkHtml stream. + Returned value should be freed with g_free. */ +char * +eab_parse_qp_email_to_html (const gchar *string) +{ + char *name = NULL, *mail = NULL; + char *html_name, *html_mail; + char *value; + + if (!eab_parse_qp_email (string, &name, &mail)) + return NULL; + + html_name = e_text_to_html (name, 0); + html_mail = e_text_to_html (mail, E_TEXT_TO_HTML_CONVERT_ADDRESSES); + + value = g_strdup_printf ("%s <%s>", html_name, html_mail); + + g_free (html_name); + g_free (html_mail); + g_free (name); + g_free (mail); + + return value; +} diff --git a/addressbook/gui/widgets/eab-gui-util.h b/addressbook/gui/widgets/eab-gui-util.h index 96459e42f1..9dc8f67818 100644 --- a/addressbook/gui/widgets/eab-gui-util.h +++ b/addressbook/gui/widgets/eab-gui-util.h @@ -77,6 +77,10 @@ GtkWidget *eab_create_image_chooser_widget (gchar *name, gchar *string1, gchar * ESource *eab_select_source (const gchar *title, const gchar *message, const gchar *select_uid, GtkWindow *parent); +/* To parse quoted printable address & return email & name fields */ +gboolean eab_parse_qp_email (const gchar *string, gchar **name, gchar **email); +char *eab_parse_qp_email_to_html (const gchar *string); + G_END_DECLS #endif /* __E_ADDRESSBOOK_UTIL_H__ */ -- cgit