From 3ca3f79dbe4641478582cd0b78a6e377c3430b19 Mon Sep 17 00:00:00 2001 From: Jon Trowbridge Date: Fri, 18 May 2001 07:10:04 +0000 Subject: Return the serialized EDestinations (rather than just a string w/ e-mail 2001-05-18 Jon Trowbridge * gui/component/select-names/e-select-names-bonobo.c (entry_get_property_fn): Return the serialized EDestinations (rather than just a string w/ e-mail addresses) through the bonobo component's property bag. * gui/component/select-names/e-select-names-model.c (e_select_names_model_export_destinationv): Added. A convenience routine for serializing the model's EDestinations into a string. * gui/component/select-names/e-select-names-popup.c (add_html_mail): Added. Puts in a check menu item for whether or not the recipient wants HTML mail. (popup_menu_card): Add menu item for HTML mail. Enable edit contact info item. (popup_menu_nocard): Add menu item for HTML mail. Enable edit contact info item. * backend/ebook/e-book-util.c (e_book_use_local_address_book): Added. Fetches the local addressbook and caches it on the first call. This is meant to be an easy and efficient way to get at the local addressbook with the minimum of code. (e_book_query_address_locally): Added. Convenience code that does an e-mail only e_book_name_and_email_query against the local address book. * backend/ebook/e-destination.c (e_destination_set_html_mail_pref): Added. Allows the intended recipient's HTML mail preference to be manipulated. (e_destination_get_email_verbose): Added. Cleaned up to use e_destination_get_name. (e_destination_get_html_mail_pref): Added. Read the recipient's HTML mail preference. If the destination is linked to a card, the preference is taken from the card (unless it has been explicitly overridden by a called to e_destination_set_html_mail_pref). (e_destination_get_address_textv): Added. Form a unified address string from a NULL-terminated vector of EDestinations. (e_destination_export): Added. Serialize an EDestination to a string. (e_destination_import): Added. Unserialize a string to build an EDestination. (e_destination_exportv): Added. Serialize a NULL-terminated vector of EDestinations to a string. (e_destination_importv): Added. Unserialize a string to build a NULL-terminated vector of EDestinations. * gui/component/select-names/e-select-names-completion.c: Implemented local versions of g_strcasecmp and g_strncasecmp (which should really be in glib, I think...) for utf8, and used them to make this code utf8-safe. 2001-05-18 Jon Trowbridge * Makefile.am (evolution_mail_LDADD): Added libebook.la (which is now required by the composer.) 2001-05-18 Jon Trowbridge * e-msg-composer-hdrs.c (set_recipients): Properly unserialize the string returned by the "text" property of the bonobo control, convert it into EDestinations, and use them to get the e-mail addresses of our recipients. 22001-05-18 Jon Trowbridge * Makefile.am (SUBDIRS): Changed build order. Now addressbook gets built before mail. svn path=/trunk/; revision=9878 --- ChangeLog | 5 + Makefile.am | 2 +- addressbook/ChangeLog | 53 +++++ addressbook/backend/ebook/e-book-util.c | 128 +++++++++++ addressbook/backend/ebook/e-book-util.h | 10 + addressbook/backend/ebook/e-destination.c | 246 ++++++++++++++++++++- addressbook/backend/ebook/e-destination.h | 41 +++- .../component/select-names/e-select-names-bonobo.c | 3 +- .../select-names/e-select-names-completion.c | 70 +++++- .../component/select-names/e-select-names-model.c | 25 ++- .../component/select-names/e-select-names-model.h | 9 +- .../component/select-names/e-select-names-popup.c | 93 +++++++- composer/ChangeLog | 7 + composer/Makefile.am | 1 + composer/e-msg-composer-hdrs.c | 32 ++- doc/devel/calendar/cal-client/tmpl/cal-client.sgml | 46 ---- .../tmpl/evolution-cal-client-unused.sgml | 44 ++++ .../tmpl/evolution-services-unused.sgml | 8 + .../tmpl/executive-summary-html-view.sgml | 8 - .../devel/calendar/cal-client/tmpl/cal-client.sgml | 46 ---- .../tmpl/evolution-cal-client-unused.sgml | 44 ++++ .../tmpl/evolution-services-unused.sgml | 8 + .../tmpl/executive-summary-html-view.sgml | 8 - mail/ChangeLog | 5 + mail/Makefile.am | 2 + 25 files changed, 788 insertions(+), 156 deletions(-) diff --git a/ChangeLog b/ChangeLog index 431e69a97c..214966ea8c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2001-05-18 Jon Trowbridge + + * Makefile.am (SUBDIRS): Changed build order. Now addressbook + gets built before mail. + 2001-05-15 Jeffrey Stedfast * configure.in: Create CAMEL_CFLAGS and CAMEL_LIBS so that we diff --git a/Makefile.am b/Makefile.am index a1fb079cde..5c72dc6a19 100644 --- a/Makefile.am +++ b/Makefile.am @@ -25,10 +25,10 @@ SUBDIRS = \ camel \ filter \ composer \ - mail \ libical \ libversit \ addressbook \ + mail \ calendar \ wombat \ importers \ diff --git a/addressbook/ChangeLog b/addressbook/ChangeLog index 796dc23b0d..37f07c9782 100644 --- a/addressbook/ChangeLog +++ b/addressbook/ChangeLog @@ -1,3 +1,54 @@ +2001-05-18 Jon Trowbridge + + * gui/component/select-names/e-select-names-bonobo.c + (entry_get_property_fn): Return the serialized EDestinations + (rather than just a string w/ e-mail addresses) through the bonobo + component's property bag. + + * gui/component/select-names/e-select-names-model.c + (e_select_names_model_export_destinationv): Added. A convenience routine + for serializing the model's EDestinations into a string. + + * gui/component/select-names/e-select-names-popup.c + (add_html_mail): Added. Puts in a check menu item for whether or + not the recipient wants HTML mail. + (popup_menu_card): Add menu item for HTML mail. Enable edit + contact info item. + (popup_menu_nocard): Add menu item for HTML mail. Enable edit + contact info item. + + * backend/ebook/e-book-util.c (e_book_use_local_address_book): + Added. Fetches the local addressbook and caches it on the first + call. This is meant to be an easy and efficient way to get at the + local addressbook with the minimum of code. + (e_book_query_address_locally): Added. Convenience code that + does an e-mail only e_book_name_and_email_query against the + local address book. + + * backend/ebook/e-destination.c + (e_destination_set_html_mail_pref): Added. Allows the intended + recipient's HTML mail preference to be manipulated. + (e_destination_get_email_verbose): Added. Cleaned up to use + e_destination_get_name. + (e_destination_get_html_mail_pref): Added. Read the recipient's HTML mail + preference. If the destination is linked to a card, the + preference is taken from the card (unless it has been explicitly + overridden by a called to e_destination_set_html_mail_pref). + (e_destination_get_address_textv): Added. Form a unified address string + from a NULL-terminated vector of EDestinations. + (e_destination_export): Added. Serialize an EDestination to a string. + (e_destination_import): Added. Unserialize a string to build an + EDestination. + (e_destination_exportv): Added. Serialize a NULL-terminated vector of + EDestinations to a string. + (e_destination_importv): Added. Unserialize a string to build a + NULL-terminated vector of EDestinations. + + * gui/component/select-names/e-select-names-completion.c: + Implemented local versions of g_strcasecmp and g_strncasecmp + (which should really be in glib, I think...) for utf8, and used + them to make this code utf8-safe. + 2001-05-17 Chris Toshok * gui/component/addressbook.c (update_command_state): no more @@ -63,6 +114,7 @@ (addressbook_factory_new_control): register command_state_change to update the commands. +>>>>>>> 1.504 2001-05-15 Chris Toshok * gui/search/e-addressbook-search-dialog.c @@ -164,6 +216,7 @@ * gui/widgets/e-addressbook-model.h: same. +>>>>>>> 1.502 2001-05-14 Christopher James Lahey * gui/widgets/e-minicard-view-model.c (remove_card): Fix a small diff --git a/addressbook/backend/ebook/e-book-util.c b/addressbook/backend/ebook/e-book-util.c index aa7ead900f..d10c5612f1 100644 --- a/addressbook/backend/ebook/e-book-util.c +++ b/addressbook/backend/ebook/e-book-util.c @@ -48,12 +48,77 @@ e_book_load_local_address_book (EBook *book, EBookCallback open_response, gpoint rv = e_book_load_uri (book, uri, open_response, closure); + if (!rv) { + g_warning ("Couldn't load local addressbook %s", uri); + } + g_free (filename); g_free (uri); return rv; } +static EBook *common_local_book = NULL; + +typedef struct _CommonBookInfo CommonBookInfo; +struct _CommonBookInfo { + EBookCommonCallback cb; + gpointer closure; +}; + +static void +got_local_book_cb (EBook *book, EBookStatus status, gpointer closure) +{ + CommonBookInfo *info = (CommonBookInfo *) closure; + + if (status == E_BOOK_STATUS_SUCCESS) { + + /* We try not to leak in a race condition where the + local book got loaded twice. */ + + if (common_local_book) { + gtk_object_unref (GTK_OBJECT (book)); + book = common_local_book; + } + + info->cb (book, info->closure); + + if (common_local_book == NULL) { + common_local_book = book; + } + + } else { + + info->cb (NULL, info->closure); + + } + g_free (info); +} + +void +e_book_use_local_address_book (EBookCommonCallback cb, gpointer closure) +{ + EBook *book; + CommonBookInfo *info; + + g_return_if_fail (cb != NULL); + + if (common_local_book != NULL) { + cb (common_local_book, closure); + return; + } + + info = g_new0 (CommonBookInfo, 1); + info->cb = cb; + info->closure = closure; + + book = e_book_new (); + if (! e_book_load_local_address_book (book, got_local_book_cb, info)) { + gtk_object_unref (GTK_OBJECT (book)); + g_free (info); + } +} + /* * * Simple Query Stuff @@ -441,3 +506,66 @@ e_book_name_and_email_query (EBook *book, return tag; } + +/* + * Convenience routine to check for addresses in the local address book. + */ + +typedef struct _HaveAddressInfo HaveAddressInfo; +struct _HaveAddressInfo { + gchar *email; + EBookHaveAddressCallback cb; + gpointer closure; +}; + +static void +have_address_query_cb (EBook *book, EBookSimpleQueryStatus status, const GList *cards, gpointer closure) +{ + HaveAddressInfo *info = (HaveAddressInfo *) closure; + + + info->cb (book, + info->email, + cards && (status == E_BOOK_SIMPLE_QUERY_STATUS_SUCCESS) ? E_CARD (cards->data) : NULL, + info->closure); + + g_free (info->email); + g_free (info); +} + +static void +have_address_book_open_cb (EBook *book, gpointer closure) +{ + HaveAddressInfo *info = (HaveAddressInfo *) closure; + + if (book) { + + e_book_name_and_email_query (book, NULL, info->email, have_address_query_cb, info); + + } else { + + info->cb (NULL, info->email, NULL, info->closure); + + g_free (info->email); + g_free (info); + + } +} + +void +e_book_query_address_locally (const gchar *email, + EBookHaveAddressCallback cb, + gpointer closure) +{ + HaveAddressInfo *info; + + g_return_if_fail (email != NULL); + g_return_if_fail (cb != NULL); + + info = g_new0 (HaveAddressInfo, 1); + info->email = g_strdup (email); + info->cb = cb; + info->closure = closure; + + e_book_use_local_address_book (have_address_book_open_cb, info); +} diff --git a/addressbook/backend/ebook/e-book-util.h b/addressbook/backend/ebook/e-book-util.h index cf0103bfea..0988887324 100644 --- a/addressbook/backend/ebook/e-book-util.h +++ b/addressbook/backend/ebook/e-book-util.h @@ -34,12 +34,16 @@ BEGIN_GNOME_DECLS /* Callbacks for asynchronous functions. */ +typedef void (*EBookCommonCallback) (EBook *book, gpointer closure); typedef void (*EBookSimpleQueryCallback) (EBook *book, EBookSimpleQueryStatus status, const GList *cards, gpointer closure); +typedef void (*EBookHaveAddressCallback) (EBook *book, const gchar *addr, ECard *card, gpointer closure); gboolean e_book_load_local_address_book (EBook *book, EBookCallback open_response, gpointer closure); +void e_book_use_local_address_book (EBookCommonCallback cb, gpointer closure); + /* Simple Query Interface. */ guint e_book_simple_query (EBook *book, @@ -57,6 +61,12 @@ guint e_book_name_and_email_query (EBook *book, EBookSimpleQueryCallback cb, gpointer closure); +/* Returns the ECard associated to email in the callback, + or NULL if no match is found in the local address book. */ +void e_book_query_address_locally (const gchar *email, + EBookHaveAddressCallback cb, + gpointer closure); + END_GNOME_DECLS diff --git a/addressbook/backend/ebook/e-destination.c b/addressbook/backend/ebook/e-destination.c index e6fdb3ee43..83bd96a7d1 100644 --- a/addressbook/backend/ebook/e-destination.c +++ b/addressbook/backend/ebook/e-destination.c @@ -40,6 +40,9 @@ struct _EDestinationPrivate { gchar *string; gchar *string_email; gchar *string_email_verbose; + + gboolean html_mail_override; + gboolean wants_html_mail; }; static void e_destination_clear_card (EDestination *); @@ -187,6 +190,15 @@ e_destination_set_string (EDestination *dest, const gchar *string) dest->priv->string = g_strdup (string); } +void +e_destination_set_html_mail_pref (EDestination *dest, gboolean x) +{ + g_return_if_fail (dest && E_IS_DESTINATION (dest)); + + dest->priv->html_mail_override = TRUE; + dest->priv->wants_html_mail = x; +} + ECard * e_destination_get_card (const EDestination *dest) { @@ -319,11 +331,11 @@ e_destination_get_email_verbose (const EDestination *dest) if (priv->string_email_verbose == NULL) { const gchar *email = e_destination_get_email (dest); + const gchar *name = e_destination_get_name (dest); - if (priv->card) { - gchar *n = e_card_name_to_string (priv->card->name); - priv->string_email_verbose = g_strdup_printf ("%s <%s>", n, email); - g_free (n); + if (name) { + + priv->string_email_verbose = g_strdup_printf ("%s <%s>", name, email); } else { @@ -335,4 +347,230 @@ e_destination_get_email_verbose (const EDestination *dest) return priv->string_email_verbose; } +gboolean +e_destination_get_html_mail_pref (const EDestination *dest) +{ + g_return_val_if_fail (dest && E_IS_DESTINATION (dest), FALSE); + + if (dest->priv->html_mail_override || dest->priv->card == NULL) + return dest->priv->wants_html_mail; + + return dest->priv->card->wants_html; +} + +gchar * +e_destination_get_address_textv (EDestination **destv) +{ + gint i, j, len = 0; + gchar **strv; + gchar *str; + g_return_val_if_fail (destv, NULL); + + while (destv[len]) { + g_return_val_if_fail (E_IS_DESTINATION (destv[len]), NULL); + ++len; + } + + strv = g_new0 (gchar *, len+1); + for (i = 0, j = 0; destv[i]; ++i) { + const gchar *addr = e_destination_get_email_verbose (destv[i]); + + strv[j++] = addr ? (gchar *) addr : ""; + } + + str = g_strjoinv (", ", strv); + + g_free (strv); + + return str; +} + +/* + * + * Serialization code + * + */ + +#define DESTINATION_TAG "DEST" +#define DESTINATION_SEPARATOR "|" + +static gchar * +join_strings (gchar **strv) +{ + /* FIXME: Should also quote any |'s that occur in any of the strings. */ + return g_strjoinv (DESTINATION_SEPARATOR, strv); +} + +static gchar ** +unjoin_string (const gchar *str) +{ + /* FIXME: Should properly handle quoteded |'s in the string. */ + return g_strsplit (str, DESTINATION_SEPARATOR, 0); +} + +static gchar * +build_field (const gchar *key, const gchar *value) +{ + return g_strdup_printf ("%s=%s", key, value); +} + +/* Modifies string in place, \0-terminates after the key, returns pointer to "value", + or NULL if the field is malformed. */ +static gchar * +extract_field (gchar *field) +{ + gchar *s = strchr (field, '='); + if (s == NULL) + return NULL; + *s = '\0'; + return s+1; +} + + +gchar * +e_destination_export (const EDestination *dest) +{ + gchar **fields; + gchar *str; + gint i; + + g_return_val_if_fail (dest && E_IS_DESTINATION (dest), NULL); + + fields = g_new (gchar *, 5); + fields[0] = g_strdup (DESTINATION_TAG); + fields[1] = build_field ("addr", e_destination_get_email (dest)); + + i = 2; + + if (e_destination_get_name (dest)) + fields[i++] = build_field ("name", e_destination_get_name (dest)); + + fields[i++] = build_field ("html", + e_destination_get_html_mail_pref (dest) ? "Y" : "N"); + + fields[i] = NULL; + + + str = join_strings (fields); + g_strfreev (fields); + + return str; +} + +EDestination * +e_destination_import (const gchar *str) +{ + EDestination *dest; + gchar **fields; + gint i; + + gchar *addr = NULL, *name = NULL; + gboolean want_html = FALSE; + + g_return_val_if_fail (str, NULL); + + fields = unjoin_string (str); + g_return_val_if_fail (fields && fields[0], NULL); + g_return_val_if_fail (!strcmp (fields[0], DESTINATION_TAG), NULL); + + for (i = 1; fields[i]; ++i) { + gchar *key = fields[i]; + gchar *value = extract_field (fields[i]); + + if (value) { + + if (!strcmp ("addr", key)) { + + if (addr) { + g_warning ("addr redefined: \"%s\" => \"%s\"", addr, value); + } + + addr = g_strdup (value); + + } else if (!strcmp ("name", key)) { + + if (name) { + g_warning ("name redefined: \"%s\" => \"%s\"", name, value); + } + + name = g_strdup (name); + + } else if (!strcmp ("html", key)) { + + want_html = (*value == 'Y'); + + } + + } + + } + dest = e_destination_new (); + + /* We construct this part of the object in a rather abusive way. */ + dest->priv->string_email = addr; + dest->priv->name = name; + + e_destination_set_html_mail_pref (dest, want_html); + + g_strfreev (fields); + + return dest; +} + +#define VEC_SEPARATOR "\1" + +gchar * +e_destination_exportv (EDestination **destv) +{ + gint i, len = 0; + gchar **strv; + gchar *str; + + g_return_val_if_fail (destv, NULL); + + while (destv[len]) { + g_return_val_if_fail (E_IS_DESTINATION (destv[len]), NULL); + ++len; + } + + strv = g_new0 (gchar *, len+1); + for (i = 0; i < len; ++i) + strv[i] = e_destination_export (destv[i]); + + str = g_strjoinv (VEC_SEPARATOR, strv); + + for (i = 0; i < len; ++i) + g_free (strv[i]); + g_free (strv); + + return str; +} + +EDestination ** +e_destination_importv (const gchar *str) +{ + gchar** strv; + EDestination **destv; + gint i = 0, j = 0, len = 0; + + if (!(str && *str)) + return NULL; + + strv = g_strsplit (str, VEC_SEPARATOR, 0); + while (strv[len]) + ++len; + + destv = g_new0 (EDestination *, len+1); + + while (strv[i]) { + EDestination *dest = e_destination_import (strv[i]); + if (dest) { + destv[j++] = dest; + } + ++i; + } + + g_strfreev (strv); + return destv; +} diff --git a/addressbook/backend/ebook/e-destination.h b/addressbook/backend/ebook/e-destination.h index 3c6de6e316..bb3c77d475 100644 --- a/addressbook/backend/ebook/e-destination.h +++ b/addressbook/backend/ebook/e-destination.h @@ -54,23 +54,40 @@ struct _EDestinationClass { GtkType e_destination_get_type (void); -EDestination *e_destination_new (void); -EDestination *e_destination_copy (EDestination *); -gboolean e_destination_is_empty (EDestination *); +EDestination *e_destination_new (void); +EDestination *e_destination_copy (EDestination *); -void e_destination_set_card (EDestination *, ECard *card, gint email_num); -void e_destination_set_string (EDestination *, const gchar *string); +gboolean e_destination_is_empty (EDestination *); -ECard *e_destination_get_card (const EDestination *); -gint e_destination_get_email_num (const EDestination *); -const gchar *e_destination_get_string (const EDestination *); -gint e_destination_get_strlen (const EDestination *); /* a convenience function... */ +void e_destination_set_card (EDestination *, ECard *card, gint email_num); +void e_destination_set_string (EDestination *, const gchar *string); +void e_destination_set_html_mail_pref (EDestination *, gboolean); + +ECard *e_destination_get_card (const EDestination *); +gint e_destination_get_email_num (const EDestination *); +const gchar *e_destination_get_string (const EDestination *); +gint e_destination_get_strlen (const EDestination *); /* a convenience function... */ + +const gchar *e_destination_get_name (const EDestination *); + +const gchar *e_destination_get_email (const EDestination *); +const gchar *e_destination_get_email_verbose (const EDestination *); + +/* If true, they want HTML mail. */ +gboolean e_destination_get_html_mail_pref (const EDestination *); + +gchar *e_destination_get_address_textv (EDestination **); + + +gchar *e_destination_export (const EDestination *); +EDestination *e_destination_import (const gchar *str); + +gchar *e_destination_exportv (EDestination **); +EDestination **e_destination_importv (const gchar *str); + -const gchar *e_destination_get_name (const EDestination *); -const gchar *e_destination_get_email (const EDestination *); -const gchar *e_destination_get_email_verbose (const EDestination *); diff --git a/addressbook/gui/component/select-names/e-select-names-bonobo.c b/addressbook/gui/component/select-names/e-select-names-bonobo.c index 98c235c067..18f88c7f5a 100644 --- a/addressbook/gui/component/select-names/e-select-names-bonobo.c +++ b/addressbook/gui/component/select-names/e-select-names-bonobo.c @@ -82,8 +82,9 @@ entry_get_property_fn (BonoboPropertyBag *bag, gtk_object_get(GTK_OBJECT(text_model), "source", &model, NULL); - text = e_select_names_model_get_address_text (model); + text = e_select_names_model_export_destinationv (model); BONOBO_ARG_SET_STRING (arg, text); + g_free (text); } break; default: diff --git a/addressbook/gui/component/select-names/e-select-names-completion.c b/addressbook/gui/component/select-names/e-select-names-completion.c index cebd57791f..76b8fd0550 100644 --- a/addressbook/gui/component/select-names/e-select-names-completion.c +++ b/addressbook/gui/component/select-names/e-select-names-completion.c @@ -34,6 +34,8 @@ #include #include +#include + #include #include #include @@ -98,6 +100,54 @@ sexp_nickname (ESelectNamesCompletion *comp) } +static gint +e_utf8_strncasecmp (const gchar *p, const gchar *q, gint len) +{ + if (p == NULL || q == NULL) { + if (p) return +1; + if (q) return -1; + return 0; + } + + if (len < 0) + len = G_MAXINT; + + while (*p && *q && len > 0) { + gunichar cp = g_utf8_get_char (p); + gunichar cq = g_utf8_get_char (q); + + if (!(g_unichar_validate (cp) + && g_unichar_validate (cq))) + break; + + cp = g_unichar_tolower (cp); + cq = g_unichar_tolower (cq); + + if (cp != cq) + return (cp < cq) - (cp > cq); + + p = g_utf8_next_char (p); + q = g_utf8_next_char (q); + --len; + } + + if (len) { + if (*p) + return +1; + else if (*q) + return -1; + } + + return 0; +} + +static gint +e_utf8_strcasecmp (const gchar *p, const gchar *q) +{ + return e_utf8_strncasecmp (p, q, -1); +} + + static gchar * match_nickname (ESelectNamesCompletion *comp, EDestination *dest, double *score) { @@ -105,7 +155,7 @@ match_nickname (ESelectNamesCompletion *comp, EDestination *dest, double *score) ECard *card = e_destination_get_card (dest); if (card->nickname - && !g_strncasecmp (comp->priv->query_text, card->nickname, len)) { + && !e_utf8_strncasecmp (comp->priv->query_text, card->nickname, len)) { gchar *name = e_card_name_to_string (card->name); gchar *str; @@ -136,7 +186,7 @@ match_email (ESelectNamesCompletion *comp, EDestination *dest, double *score) ECard *card = e_destination_get_card (dest); const gchar *email = e_destination_get_email (dest); - if (email && !g_strncasecmp (comp->priv->query_text, email, len)) { + if (email && !e_utf8_strncasecmp (comp->priv->query_text, email, len)) { gchar *name, *str; *score = len * 2; /* 2 points for each matching character */ name = e_card_name_to_string (card->name); @@ -208,7 +258,7 @@ match_name_fragment (const gchar *fragment, const gchar *txt) gint len = strlen (txt); while (*fragment) { - if (!g_strncasecmp (fragment, txt, len)) + if (!e_utf8_strncasecmp (fragment, txt, len)) return TRUE; while (*fragment && !isspace ((gint) *fragment)) @@ -281,9 +331,9 @@ match_name (ESelectNamesCompletion *comp, EDestination *dest, double *score) /* We massively boost the score if the nickname exists and is the same as one of the "real" names. This keeps the nickname from matching ahead of the real name for this card. */ len = strlen (card->nickname); - if ((card->name->given && !g_strncasecmp (card->name->given, card->nickname, MIN (strlen (card->name->given), len))) - || (card->name->family && !g_strncasecmp (card->name->family, card->nickname, MIN (strlen (card->name->family), len))) - || (card->name->additional && !g_strncasecmp (card->name->additional, card->nickname, MIN (strlen (card->name->additional), len)))) + if ((card->name->given && !e_utf8_strncasecmp (card->name->given, card->nickname, MIN (strlen (card->name->given), len))) + || (card->name->family && !e_utf8_strncasecmp (card->name->family, card->nickname, MIN (strlen (card->name->family), len))) + || (card->name->additional && !e_utf8_strncasecmp (card->name->additional, card->nickname, MIN (strlen (card->name->additional), len)))) *score *= 100; } @@ -432,11 +482,11 @@ book_query_score (ESelectNamesCompletion *comp, EDestination *dest, double *scor if (email) { simp = e_card_simple_new (card); simp_email = e_card_simple_get_email (simp, E_CARD_SIMPLE_EMAIL_ID_EMAIL); - if (simp_email && !g_strcasecmp (simp_email, email)) { + if (simp_email && !e_utf8_strcasecmp (simp_email, email)) { best_score += 0.2; } simp_email = e_card_simple_get_email (simp, E_CARD_SIMPLE_EMAIL_ID_EMAIL_2); - if (simp_email && !g_strcasecmp (simp_email, email)) { + if (simp_email && !e_utf8_strcasecmp (simp_email, email)) { best_score += 0.1; } gtk_object_unref (GTK_OBJECT (simp)); @@ -856,7 +906,7 @@ e_select_names_completion_do_query (ESelectNamesCompletion *comp, const gchar *q can_reuse_cached_cards = (comp->priv->cached_query_text && (strlen (comp->priv->cached_query_text) <= strlen (clean)) - && !g_strncasecmp (comp->priv->cached_query_text, clean, strlen (comp->priv->cached_query_text))); + && !e_utf8_strncasecmp (comp->priv->cached_query_text, clean, strlen (comp->priv->cached_query_text))); if (can_reuse_cached_cards) { @@ -912,7 +962,7 @@ search_override_check (SearchOverride *over, const gchar *text) if (over == NULL || text == NULL) return FALSE; - return !g_strcasecmp (over->trigger, text); + return !e_utf8_strcasecmp (over->trigger, text); } diff --git a/addressbook/gui/component/select-names/e-select-names-model.c b/addressbook/gui/component/select-names/e-select-names-model.c index 1baf729b3e..74dfcb8158 100644 --- a/addressbook/gui/component/select-names/e-select-names-model.c +++ b/addressbook/gui/component/select-names/e-select-names-model.c @@ -310,14 +310,35 @@ e_select_names_model_count (ESelectNamesModel *model) const EDestination * e_select_names_model_get_destination (ESelectNamesModel *model, gint index) { - g_return_val_if_fail (model != NULL, NULL); - g_return_val_if_fail (E_IS_SELECT_NAMES_MODEL (model), NULL); + g_return_val_if_fail (model && E_IS_SELECT_NAMES_MODEL (model), NULL); g_return_val_if_fail (0 <= index, NULL); g_return_val_if_fail (index < g_list_length (model->priv->data), NULL); return E_DESTINATION (g_list_nth_data (model->priv->data, index)); } +gchar * +e_select_names_model_export_destinationv (ESelectNamesModel *model) +{ + EDestination **destv; + gchar *str; + gint i, len = 0; + GList *j; + g_return_val_if_fail (model && E_IS_SELECT_NAMES_MODEL (model), NULL); + + len = g_list_length (model->priv->data); + destv = g_new0 (EDestination *, len+1); + + for (i=0, j = model->priv->data; j != NULL; j = g_list_next (j)) { + destv[i++] = E_DESTINATION (j->data); + } + + str = e_destination_exportv (destv); + g_free (destv); + + return str; +} + ECard * e_select_names_model_get_card (ESelectNamesModel *model, gint index) { diff --git a/addressbook/gui/component/select-names/e-select-names-model.h b/addressbook/gui/component/select-names/e-select-names-model.h index 2e1c970ef7..417ec7abb1 100644 --- a/addressbook/gui/component/select-names/e-select-names-model.h +++ b/addressbook/gui/component/select-names/e-select-names-model.h @@ -49,10 +49,11 @@ ESelectNamesModel *e_select_names_model_duplicate (ESelectNamesModel *old); const gchar *e_select_names_model_get_textification (ESelectNamesModel *model); const gchar *e_select_names_model_get_address_text (ESelectNamesModel *model); -gint e_select_names_model_count (ESelectNamesModel *model); -const EDestination *e_select_names_model_get_destination (ESelectNamesModel *model, gint index); -ECard *e_select_names_model_get_card (ESelectNamesModel *model, gint index); -const gchar *e_select_names_model_get_string (ESelectNamesModel *model, gint index); +gint e_select_names_model_count (ESelectNamesModel *model); +const EDestination *e_select_names_model_get_destination (ESelectNamesModel *model, gint index); +gchar *e_select_names_model_export_destinationv (ESelectNamesModel *model); +ECard *e_select_names_model_get_card (ESelectNamesModel *model, gint index); +const gchar *e_select_names_model_get_string (ESelectNamesModel *model, gint index); void e_select_names_model_insert (ESelectNamesModel *model, gint index, EDestination *dest); void e_select_names_model_append (ESelectNamesModel *model, EDestination *dest); diff --git a/addressbook/gui/component/select-names/e-select-names-popup.c b/addressbook/gui/component/select-names/e-select-names-popup.c index f6164f0022..4f40093901 100644 --- a/addressbook/gui/component/select-names/e-select-names-popup.c +++ b/addressbook/gui/component/select-names/e-select-names-popup.c @@ -38,6 +38,8 @@ #include #include +#include +#include #include #include "e-select-names-popup.h" @@ -88,10 +90,38 @@ popup_info_cleanup (GtkWidget *w, gpointer info) popup_info_free ((PopupInfo *) info); } +/* You are in a maze of twisty little callbacks, all alike... */ + +static void +found_fields_cb (EBook *book, EBookStatus status, EList *writable_fields, gpointer user_data) +{ + EDestination *dest = E_DESTINATION (user_data); + EContactEditor *ce; + ECard *card; + + card = (ECard *) e_destination_get_card (dest); + ce = e_contact_editor_new (card, FALSE, writable_fields, FALSE); + e_contact_editor_raise (ce); + gtk_object_unref (GTK_OBJECT (dest)); +} + +static void +edit_contact_info_have_book_cb (EBook *book, gpointer user_data) +{ + if (book) { + e_book_get_supported_fields (book, found_fields_cb, user_data); + } +} + static void -do_nothing (gpointer foo) +edit_contact_info_cb (GtkWidget *w, gpointer user_data) { + PopupInfo *info = (PopupInfo *) user_data; + if (info == NULL) + return; + gtk_object_ref (GTK_OBJECT (info->dest)); + e_book_use_local_address_book (edit_contact_info_have_book_cb, info->dest); } static void @@ -147,6 +177,39 @@ add_remove_all_recipients (GnomeUIInfo *uiinfo, PopupInfo *info) uiinfo->moreinfo = remove_all_recipients_cb; } +static void +toggle_html_mail_cb (GtkWidget *w, gpointer user_data) +{ + PopupInfo *info = (PopupInfo *) user_data; + GtkCheckMenuItem *item = GTK_CHECK_MENU_ITEM (w); + const EDestination *dest; + + if (info == NULL) + return; + + dest = info->dest; + + item = GTK_CHECK_MENU_ITEM (item); + e_destination_set_html_mail_pref ((EDestination *) dest, item->active); +} + +static void +add_html_mail (GnomeUIInfo *uiinfo, PopupInfo *info) +{ + uiinfo->type = GNOME_APP_UI_TOGGLEITEM; + uiinfo->label = _("Send HTML Mail?"); + uiinfo->moreinfo = toggle_html_mail_cb; +} + +static void +init_html_mail (GnomeUIInfo *uiinfo, PopupInfo *info) +{ + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (uiinfo->widget), + e_destination_get_html_mail_pref (info->dest)); + gtk_check_menu_item_set_show_toggle (GTK_CHECK_MENU_ITEM (uiinfo->widget), TRUE); + +} + #define ARBITRARY_UIINFO_LIMIT 64 static GtkWidget * popup_menu_card (PopupInfo *info) @@ -159,6 +222,7 @@ popup_menu_card (PopupInfo *info) GtkWidget *pop; EIterator *iterator; gchar *name_str; + gint html_toggle; /* * Build up our GnomeUIInfo array. @@ -184,11 +248,14 @@ popup_menu_card (PopupInfo *info) iterator = e_list_get_iterator (card->email); for (e_iterator_reset (iterator); e_iterator_is_valid (iterator); e_iterator_next (iterator)) { + gchar *label = (gchar *)e_iterator_get (iterator); - radioinfo[j].type = GNOME_APP_UI_ITEM; - radioinfo[j].label = (gchar *)e_iterator_get (iterator); - radioinfo[j].moreinfo = change_email_num_cb; - ++j; + if (label && *label) { + radioinfo[j].type = GNOME_APP_UI_ITEM; + radioinfo[j].label = label; + radioinfo[j].moreinfo = change_email_num_cb; + ++j; + } } radioinfo[j].type = GNOME_APP_UI_ENDOFINFO; @@ -206,9 +273,13 @@ popup_menu_card (PopupInfo *info) uiinfo[i].type = GNOME_APP_UI_SEPARATOR; ++i; + add_html_mail (&(uiinfo[i]), info); + html_toggle = i; + ++i; + uiinfo[i].type = GNOME_APP_UI_ITEM; uiinfo[i].label = N_("Edit Contact Info"); - uiinfo[i].moreinfo = do_nothing; + uiinfo[i].moreinfo = edit_contact_info_cb; ++i; add_remove_recipient (&(uiinfo[i]), info); @@ -236,6 +307,8 @@ popup_menu_card (PopupInfo *info) } } + init_html_mail (&(uiinfo[html_toggle]), info); + return pop; } @@ -253,6 +326,7 @@ popup_menu_nocard (PopupInfo *info) gint i=0; GtkWidget *pop; const gchar *str; + gint html_toggle; memset (uiinfo, 0, sizeof (uiinfo)); @@ -265,6 +339,10 @@ popup_menu_nocard (PopupInfo *info) uiinfo[i].type = GNOME_APP_UI_SEPARATOR; ++i; + add_html_mail (&(uiinfo[i]), info); + html_toggle = i; + ++i; + uiinfo[i].type = GNOME_APP_UI_ITEM; uiinfo[i].label = _("Add to Contacts"); uiinfo[i].moreinfo = quick_add_cb; @@ -279,11 +357,12 @@ popup_menu_nocard (PopupInfo *info) uiinfo[i].type = GNOME_APP_UI_ENDOFINFO; pop = gnome_popup_menu_new (uiinfo); + + init_html_mail (&(uiinfo[html_toggle]), info); return pop; } - void e_select_names_popup (ESelectNamesModel *model, GdkEventButton *ev, gint pos) { diff --git a/composer/ChangeLog b/composer/ChangeLog index 4d09888796..5c78b35db6 100644 --- a/composer/ChangeLog +++ b/composer/ChangeLog @@ -1,3 +1,10 @@ +2001-05-18 Jon Trowbridge + + * e-msg-composer-hdrs.c (set_recipients): Properly unserialize the + string returned by the "text" property of the bonobo control, + convert it into EDestinations, and use them to get the e-mail + addresses of our recipients. + 2001-05-17 Dan Winship * e-msg-composer.c (save_draft): Draft messages should be marked diff --git a/composer/Makefile.am b/composer/Makefile.am index ad78500587..898c372e5e 100644 --- a/composer/Makefile.am +++ b/composer/Makefile.am @@ -48,6 +48,7 @@ INCLUDES = \ -I$(top_builddir)/widgets \ -I$(top_srcdir)/camel \ -I$(top_builddir)/camel \ + -I$(top_builddir)/addressbook/backend/ebook \ -I$(top_builddir)/addressbook/gui/component/select-names \ -I$(top_builddir)/shell \ -I$(top_srcdir)/shell \ diff --git a/composer/e-msg-composer-hdrs.c b/composer/e-msg-composer-hdrs.c index d31ac118fc..74932d1ca1 100644 --- a/composer/e-msg-composer-hdrs.c +++ b/composer/e-msg-composer-hdrs.c @@ -44,6 +44,7 @@ #include #include +#include #include "e-msg-composer-hdrs.h" #include "mail/mail-config.h" @@ -630,20 +631,37 @@ e_msg_composer_hdrs_new (gint visible_flags) static void set_recipients (CamelMimeMessage *msg, GtkWidget *entry_widget, const gchar *type) { + EDestination **destv; CamelInternetAddress *addr; - char *string; + char *string = NULL, *dest_str = NULL; + gint i=0; bonobo_widget_get_property (BONOBO_WIDGET (entry_widget), "text", &string, NULL); + destv = e_destination_importv (string); - addr = camel_internet_address_new (); - camel_address_unformat (CAMEL_ADDRESS (addr), string); + if (destv) { + + dest_str = e_destination_get_address_textv (destv); + + if (dest_str) { + addr = camel_internet_address_new (); + camel_address_unformat (CAMEL_ADDRESS (addr), dest_str); - /* TODO: In here, we could cross-reference the names with an alias book - or address book, it should be sufficient for unformat to do the parsing too */ + /* TODO: In here, we could cross-reference the names with an alias book + or address book, it should be sufficient for unformat to do the parsing too */ - camel_mime_message_set_recipients (msg, type, addr); + camel_mime_message_set_recipients (msg, type, addr); - camel_object_unref (CAMEL_OBJECT (addr)); + camel_object_unref (CAMEL_OBJECT (addr)); + + g_free (dest_str); + } + + for (i=0; destv[i]; ++i) + gtk_object_unref (GTK_OBJECT (destv[i])); + g_free (destv); + } + g_free (string); } diff --git a/doc/devel/calendar/cal-client/tmpl/cal-client.sgml b/doc/devel/calendar/cal-client/tmpl/cal-client.sgml index 06195ca454..e29fd8811f 100644 --- a/doc/devel/calendar/cal-client/tmpl/cal-client.sgml +++ b/doc/devel/calendar/cal-client/tmpl/cal-client.sgml @@ -255,49 +255,3 @@ GTK+ object for communication with personal calendar server. @Returns: - - - - - -@calclient: the object which received the signal. -@arg1: - - - - This signal is emitted when the calendar clients receives - notification of a calendar component's data being changed in the - personal calendar server. Graphical clients may want to get the - new version of the object and update their display, for example. - - -@calclient: the object which received the signal. -@arg1: - -@client: Calendar client which received the notification. -@uid: Unique identifier of the calendar component that changed in the - personal calendar server's storage. - - - - This signal is emitted when the calendar client receives - notification for a calendar component being removed from the - storage in the personal calendar server. Graphical clients may - want to delete the corresponding object from their display, for - example. - - -@calclient: the object which received the signal. -@arg1: - -@client: Calendar client which received the notification. -@uid: Unique identifier of the calendar component that was removed - from the personal calendar server's storage. - - - diff --git a/doc/devel/calendar/cal-client/tmpl/evolution-cal-client-unused.sgml b/doc/devel/calendar/cal-client/tmpl/evolution-cal-client-unused.sgml index f8f1f1408e..3d050e171b 100644 --- a/doc/devel/calendar/cal-client/tmpl/evolution-cal-client-unused.sgml +++ b/doc/devel/calendar/cal-client/tmpl/evolution-cal-client-unused.sgml @@ -16,6 +16,14 @@ @str_uri: @Returns: + + + + + +@calclient: the object which received the signal. +@arg1: + @@ -49,6 +57,20 @@ @client: @Returns: + + + This signal is emitted when the calendar clients receives + notification of a calendar component's data being changed in the + personal calendar server. Graphical clients may want to get the + new version of the object and update their display, for example. + + +@calclient: the object which received the signal. +@arg1: +@client: Calendar client which received the notification. +@uid: Unique identifier of the calendar component that changed in the + personal calendar server's storage. + @@ -82,3 +104,25 @@ @uid: @Returns: + + + This signal is emitted when the calendar client receives + notification for a calendar component being removed from the + storage in the personal calendar server. Graphical clients may + want to delete the corresponding object from their display, for + example. + + +@calclient: the object which received the signal. +@arg1: +@client: Calendar client which received the notification. +@uid: Unique identifier of the calendar component that was removed + from the personal calendar server's storage. + + + diff --git a/doc/devel/executive-summary/tmpl/evolution-services-unused.sgml b/doc/devel/executive-summary/tmpl/evolution-services-unused.sgml index e69de29bb2..9f8096db6a 100644 --- a/doc/devel/executive-summary/tmpl/evolution-services-unused.sgml +++ b/doc/devel/executive-summary/tmpl/evolution-services-unused.sgml @@ -0,0 +1,8 @@ + + + + + +@executivesummaryhtmlview: the object which received the signal. +@arg1: + diff --git a/doc/devel/executive-summary/tmpl/executive-summary-html-view.sgml b/doc/devel/executive-summary/tmpl/executive-summary-html-view.sgml index 6ff2709e15..2fb66a2035 100644 --- a/doc/devel/executive-summary/tmpl/executive-summary-html-view.sgml +++ b/doc/devel/executive-summary/tmpl/executive-summary-html-view.sgml @@ -73,11 +73,3 @@ This is the event that is emitted on the BonoboEventSource when the HTML is chan @Returns: - - - - - -@executivesummaryhtmlview: the object which received the signal. -@arg1: - diff --git a/help/devel/calendar/cal-client/tmpl/cal-client.sgml b/help/devel/calendar/cal-client/tmpl/cal-client.sgml index 06195ca454..e29fd8811f 100644 --- a/help/devel/calendar/cal-client/tmpl/cal-client.sgml +++ b/help/devel/calendar/cal-client/tmpl/cal-client.sgml @@ -255,49 +255,3 @@ GTK+ object for communication with personal calendar server. @Returns: - - - - - -@calclient: the object which received the signal. -@arg1: - - - - This signal is emitted when the calendar clients receives - notification of a calendar component's data being changed in the - personal calendar server. Graphical clients may want to get the - new version of the object and update their display, for example. - - -@calclient: the object which received the signal. -@arg1: - -@client: Calendar client which received the notification. -@uid: Unique identifier of the calendar component that changed in the - personal calendar server's storage. - - - - This signal is emitted when the calendar client receives - notification for a calendar component being removed from the - storage in the personal calendar server. Graphical clients may - want to delete the corresponding object from their display, for - example. - - -@calclient: the object which received the signal. -@arg1: - -@client: Calendar client which received the notification. -@uid: Unique identifier of the calendar component that was removed - from the personal calendar server's storage. - - - diff --git a/help/devel/calendar/cal-client/tmpl/evolution-cal-client-unused.sgml b/help/devel/calendar/cal-client/tmpl/evolution-cal-client-unused.sgml index f8f1f1408e..3d050e171b 100644 --- a/help/devel/calendar/cal-client/tmpl/evolution-cal-client-unused.sgml +++ b/help/devel/calendar/cal-client/tmpl/evolution-cal-client-unused.sgml @@ -16,6 +16,14 @@ @str_uri: @Returns: + + + + + +@calclient: the object which received the signal. +@arg1: + @@ -49,6 +57,20 @@ @client: @Returns: + + + This signal is emitted when the calendar clients receives + notification of a calendar component's data being changed in the + personal calendar server. Graphical clients may want to get the + new version of the object and update their display, for example. + + +@calclient: the object which received the signal. +@arg1: +@client: Calendar client which received the notification. +@uid: Unique identifier of the calendar component that changed in the + personal calendar server's storage. + @@ -82,3 +104,25 @@ @uid: @Returns: + + + This signal is emitted when the calendar client receives + notification for a calendar component being removed from the + storage in the personal calendar server. Graphical clients may + want to delete the corresponding object from their display, for + example. + + +@calclient: the object which received the signal. +@arg1: +@client: Calendar client which received the notification. +@uid: Unique identifier of the calendar component that was removed + from the personal calendar server's storage. + + + diff --git a/help/devel/executive-summary/tmpl/evolution-services-unused.sgml b/help/devel/executive-summary/tmpl/evolution-services-unused.sgml index e69de29bb2..9f8096db6a 100644 --- a/help/devel/executive-summary/tmpl/evolution-services-unused.sgml +++ b/help/devel/executive-summary/tmpl/evolution-services-unused.sgml @@ -0,0 +1,8 @@ + + + + + +@executivesummaryhtmlview: the object which received the signal. +@arg1: + diff --git a/help/devel/executive-summary/tmpl/executive-summary-html-view.sgml b/help/devel/executive-summary/tmpl/executive-summary-html-view.sgml index 6ff2709e15..2fb66a2035 100644 --- a/help/devel/executive-summary/tmpl/executive-summary-html-view.sgml +++ b/help/devel/executive-summary/tmpl/executive-summary-html-view.sgml @@ -73,11 +73,3 @@ This is the event that is emitted on the BonoboEventSource when the HTML is chan @Returns: - - - - - -@executivesummaryhtmlview: the object which received the signal. -@arg1: - diff --git a/mail/ChangeLog b/mail/ChangeLog index dcc8de6fd0..58fcf11930 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -1,3 +1,8 @@ +2001-05-18 Jon Trowbridge + + * Makefile.am (evolution_mail_LDADD): Added libebook.la (which is + now required by the composer.) + 2001-05-17 Dan Winship * mail-callbacks.c (composer_postpone_cb): mark Outbox messages as diff --git a/mail/Makefile.am b/mail/Makefile.am index 7a81485b0c..7940fa7484 100644 --- a/mail/Makefile.am +++ b/mail/Makefile.am @@ -110,6 +110,8 @@ evolution_mail_LDADD = \ $(top_builddir)/composer/libcomposer.a \ $(top_builddir)/widgets/misc/libemiscwidgets.a \ $(top_builddir)/camel/libcamel.la \ + $(top_builddir)/addressbook/backend/ebook/libebook.la \ + $(top_builddir)/libversit/libversit.la \ $(top_builddir)/e-util/ename/libename.la \ $(top_builddir)/libibex/libibex.la \ $(top_builddir)/filter/libfilter.la \ -- cgit v1.2.3