diff options
-rw-r--r-- | composer/e-composer-from-header.c | 130 | ||||
-rw-r--r-- | composer/e-composer-from-header.h | 24 | ||||
-rw-r--r-- | composer/e-composer-header-table.c | 625 | ||||
-rw-r--r-- | composer/e-composer-header-table.h | 43 | ||||
-rw-r--r-- | composer/e-composer-header.c | 175 | ||||
-rw-r--r-- | composer/e-composer-header.h | 5 | ||||
-rw-r--r-- | composer/e-composer-name-header.c | 116 | ||||
-rw-r--r-- | composer/e-composer-name-header.h | 3 | ||||
-rw-r--r-- | composer/e-composer-post-header.c | 168 | ||||
-rw-r--r-- | composer/e-composer-post-header.h | 15 | ||||
-rw-r--r-- | composer/e-composer-private.c | 211 | ||||
-rw-r--r-- | composer/e-composer-private.h | 9 | ||||
-rw-r--r-- | composer/e-composer-spell-header.c | 20 | ||||
-rw-r--r-- | composer/e-composer-spell-header.h | 18 | ||||
-rw-r--r-- | composer/e-composer-text-header.c | 33 | ||||
-rw-r--r-- | composer/e-composer-text-header.h | 6 | ||||
-rw-r--r-- | composer/e-msg-composer.c | 711 | ||||
-rw-r--r-- | composer/e-msg-composer.h | 4 |
18 files changed, 1206 insertions, 1110 deletions
diff --git a/composer/e-composer-from-header.c b/composer/e-composer-from-header.c index 0b569717c2..a844ca3d6a 100644 --- a/composer/e-composer-from-header.c +++ b/composer/e-composer-from-header.c @@ -24,16 +24,7 @@ #include "e-composer-from-header.h" -/* Convenience macro */ -#define E_COMPOSER_FROM_HEADER_GET_COMBO_BOX(header) \ - (E_ACCOUNT_COMBO_BOX (E_COMPOSER_HEADER (header)->input_widget)) - -enum { - REFRESHED, - LAST_SIGNAL -}; - -static guint signal_ids[LAST_SIGNAL]; +#include <misc/e-mail-identity-combo-box.h> G_DEFINE_TYPE ( EComposerFromHeader, @@ -41,119 +32,82 @@ G_DEFINE_TYPE ( E_TYPE_COMPOSER_HEADER) static void -composer_from_header_changed_cb (EAccountComboBox *combo_box, +composer_from_header_changed_cb (EMailIdentityComboBox *combo_box, EComposerFromHeader *header) { g_signal_emit_by_name (header, "changed"); } static void -composer_from_header_refreshed_cb (EAccountComboBox *combo_box, - EComposerFromHeader *header) +composer_from_header_constructed (GObject *object) { - g_signal_emit (header, signal_ids[REFRESHED], 0); -} + ESourceRegistry *registry; + EComposerHeader *header; + GtkWidget *widget; -static void -e_composer_from_header_class_init (EComposerFromHeaderClass *class) -{ - signal_ids[REFRESHED] = g_signal_new ( - "refreshed", - G_TYPE_FROM_CLASS (class), - G_SIGNAL_RUN_LAST, - 0, NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); -} + header = E_COMPOSER_HEADER (object); + registry = e_composer_header_get_registry (header); -static void -e_composer_from_header_init (EComposerFromHeader *header) -{ - GtkWidget *widget; + /* Input widget must be set before chaining up. */ - widget = g_object_ref_sink (e_account_combo_box_new ()); + widget = e_mail_identity_combo_box_new (registry); g_signal_connect ( widget, "changed", G_CALLBACK (composer_from_header_changed_cb), header); - g_signal_connect ( - widget, "refreshed", - G_CALLBACK (composer_from_header_refreshed_cb), header); - E_COMPOSER_HEADER (header)->input_widget = widget; -} - -EComposerHeader * -e_composer_from_header_new (const gchar *label) -{ - return g_object_new ( - E_TYPE_COMPOSER_FROM_HEADER, "label", label, - "button", FALSE, NULL); -} - -EAccountList * -e_composer_from_header_get_account_list (EComposerFromHeader *header) -{ - EAccountComboBox *combo_box; - - g_return_val_if_fail (E_IS_COMPOSER_FROM_HEADER (header), NULL); + header->input_widget = g_object_ref_sink (widget); - combo_box = E_COMPOSER_FROM_HEADER_GET_COMBO_BOX (header); - return e_account_combo_box_get_account_list (combo_box); + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (e_composer_from_header_parent_class)-> + constructed (object); } -void -e_composer_from_header_set_account_list (EComposerFromHeader *header, - EAccountList *account_list) +static void +e_composer_from_header_class_init (EComposerFromHeaderClass *class) { - EAccountComboBox *combo_box; - - g_return_if_fail (E_IS_COMPOSER_FROM_HEADER (header)); + GObjectClass *object_class; - combo_box = E_COMPOSER_FROM_HEADER_GET_COMBO_BOX (header); - e_account_combo_box_set_account_list (combo_box, account_list); + object_class = G_OBJECT_CLASS (class); + object_class->constructed = composer_from_header_constructed; } -EAccount * -e_composer_from_header_get_active (EComposerFromHeader *header) +static void +e_composer_from_header_init (EComposerFromHeader *from_header) { - EAccountComboBox *combo_box; - - g_return_val_if_fail (E_IS_COMPOSER_FROM_HEADER (header), NULL); - - combo_box = E_COMPOSER_FROM_HEADER_GET_COMBO_BOX (header); - return e_account_combo_box_get_active (combo_box); } -gboolean -e_composer_from_header_set_active (EComposerFromHeader *header, - EAccount *account) +EComposerHeader * +e_composer_from_header_new (ESourceRegistry *registry, + const gchar *label) { - EAccountComboBox *combo_box; + g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL); - g_return_val_if_fail (E_IS_COMPOSER_FROM_HEADER (header), FALSE); - - combo_box = E_COMPOSER_FROM_HEADER_GET_COMBO_BOX (header); - return e_account_combo_box_set_active (combo_box, account); + return g_object_new ( + E_TYPE_COMPOSER_FROM_HEADER, + "label", label, "button", FALSE, + "registry", registry, NULL); } const gchar * -e_composer_from_header_get_active_name (EComposerFromHeader *header) +e_composer_from_header_get_active_id (EComposerFromHeader *header) { - EAccountComboBox *combo_box; + GtkComboBox *combo_box; g_return_val_if_fail (E_IS_COMPOSER_FROM_HEADER (header), NULL); - combo_box = E_COMPOSER_FROM_HEADER_GET_COMBO_BOX (header); - return e_account_combo_box_get_active_name (combo_box); + combo_box = GTK_COMBO_BOX (E_COMPOSER_HEADER (header)->input_widget); + + return gtk_combo_box_get_active_id (combo_box); } -gboolean -e_composer_from_header_set_active_name (EComposerFromHeader *header, - const gchar *account_name) +void +e_composer_from_header_set_active_id (EComposerFromHeader *header, + const gchar *active_id) { - EAccountComboBox *combo_box; + GtkComboBox *combo_box; + + g_return_if_fail (E_IS_COMPOSER_FROM_HEADER (header)); - g_return_val_if_fail (E_IS_COMPOSER_FROM_HEADER (header), FALSE); + combo_box = GTK_COMBO_BOX (E_COMPOSER_HEADER (header)->input_widget); - combo_box = E_COMPOSER_FROM_HEADER_GET_COMBO_BOX (header); - return e_account_combo_box_set_active_name (combo_box, account_name); + gtk_combo_box_set_active_id (combo_box, active_id); } diff --git a/composer/e-composer-from-header.h b/composer/e-composer-from-header.h index 182a75134b..b4116e6183 100644 --- a/composer/e-composer-from-header.h +++ b/composer/e-composer-from-header.h @@ -21,10 +21,6 @@ #ifndef E_COMPOSER_FROM_HEADER_H #define E_COMPOSER_FROM_HEADER_H -#include <libedataserver/e-account.h> -#include <libedataserver/e-account-list.h> - -#include <misc/e-account-combo-box.h> #include <composer/e-composer-header.h> /* Standard GObject macros */ @@ -60,22 +56,14 @@ struct _EComposerFromHeaderClass { }; GType e_composer_from_header_get_type (void); -EComposerHeader * e_composer_from_header_new (const gchar *label); -EAccountList * e_composer_from_header_get_account_list - (EComposerFromHeader *header); -void e_composer_from_header_set_account_list - (EComposerFromHeader *header, - EAccountList *account_list); -EAccount * e_composer_from_header_get_active - (EComposerFromHeader *header); -gboolean e_composer_from_header_set_active - (EComposerFromHeader *header, - EAccount *account); -const gchar * e_composer_from_header_get_active_name +EComposerHeader * + e_composer_from_header_new (ESourceRegistry *registry, + const gchar *label); +const gchar * e_composer_from_header_get_active_id (EComposerFromHeader *header); -gboolean e_composer_from_header_set_active_name +void e_composer_from_header_set_active_id (EComposerFromHeader *header, - const gchar *account_name); + const gchar *active_id); G_END_DECLS diff --git a/composer/e-composer-header-table.c b/composer/e-composer-header-table.c index 51a217d286..742ab11a9d 100644 --- a/composer/e-composer-header-table.c +++ b/composer/e-composer-header-table.c @@ -23,9 +23,12 @@ #include <glib/gi18n-lib.h> #include <libedataserverui/e-name-selector.h> +#include <libedataserver/e-source-mail-account.h> +#include <libedataserver/e-source-mail-composition.h> +#include <libedataserver/e-source-mail-identity.h> #include <shell/e-shell.h> -#include <misc/e-signature-combo-box.h> +#include <misc/e-mail-signature-combo-box.h> #include "e-msg-composer.h" #include "e-composer-private.h" @@ -53,30 +56,30 @@ (G_TYPE_INSTANCE_GET_PRIVATE \ ((obj), E_TYPE_COMPOSER_HEADER_TABLE, EComposerHeaderTablePrivate)) +struct _EComposerHeaderTablePrivate { + EComposerHeader *headers[E_COMPOSER_NUM_HEADERS]; + GtkWidget *signature_label; + GtkWidget *signature_combo_box; + ENameSelector *name_selector; + ESourceRegistry *registry; + EShell *shell; +}; + enum { PROP_0, - PROP_ACCOUNT, - PROP_ACCOUNT_LIST, - PROP_ACCOUNT_NAME, PROP_DESTINATIONS_BCC, PROP_DESTINATIONS_CC, PROP_DESTINATIONS_TO, + PROP_IDENTITY_UID, PROP_POST_TO, + PROP_REGISTRY, PROP_REPLY_TO, PROP_SHELL, - PROP_SIGNATURE, - PROP_SIGNATURE_LIST, + PROP_SIGNATURE_COMBO_BOX, + PROP_SIGNATURE_UID, PROP_SUBJECT }; -struct _EComposerHeaderTablePrivate { - EComposerHeader *headers[E_COMPOSER_NUM_HEADERS]; - GtkWidget *signature_label; - GtkWidget *signature_combo_box; - ENameSelector *name_selector; - EShell *shell; -}; - G_DEFINE_TYPE ( EComposerHeaderTable, e_composer_header_table, @@ -217,13 +220,13 @@ composer_header_table_bind_widget (const gchar *property_name, static EDestination ** composer_header_table_update_destinations (EDestination **old_destinations, - const gchar *auto_addresses) + const gchar * const *auto_addresses) { CamelAddress *address; CamelInternetAddress *inet_address; EDestination **new_destinations; EDestination *destination; - GList *list = NULL; + GQueue queue = G_QUEUE_INIT; guint length; gint ii; @@ -235,25 +238,29 @@ composer_header_table_update_destinations (EDestination **old_destinations, inet_address = camel_internet_address_new (); address = CAMEL_ADDRESS (inet_address); - if (camel_address_decode (address, auto_addresses) != -1) { - for (ii = 0; ii < camel_address_length (address); ii++) { - const gchar *name, *email; + /* XXX Calling camel_address_decode() multiple times on the same + * CamelInternetAddress has a cumulative effect, which isn't + * well documented. */ + for (ii = 0; auto_addresses[ii] != NULL; ii++) + camel_address_decode (address, auto_addresses[ii]); + + for (ii = 0; ii < camel_address_length (address); ii++) { + const gchar *name, *email; - if (!camel_internet_address_get ( - inet_address, ii, &name, &email)) - continue; + if (!camel_internet_address_get ( + inet_address, ii, &name, &email)) + continue; - destination = e_destination_new (); - e_destination_set_auto_recipient (destination, TRUE); + destination = e_destination_new (); + e_destination_set_auto_recipient (destination, TRUE); - if (name != NULL) - e_destination_set_name (destination, name); + if (name != NULL) + e_destination_set_name (destination, name); - if (email != NULL) - e_destination_set_email (destination, email); + if (email != NULL) + e_destination_set_email (destination, email); - list = g_list_prepend (list, destination); - } + g_queue_push_tail (&queue, destination); } g_object_unref (inet_address); @@ -270,20 +277,19 @@ skip_auto: continue; destination = e_destination_copy (old_destinations[ii]); - list = g_list_prepend (list, destination); + g_queue_push_tail (&queue, destination); } skip_custom: - list = g_list_reverse (list); - length = g_list_length (list); - + length = g_queue_get_length (&queue); new_destinations = g_new0 (EDestination *, length + 1); - for (ii = 0; list != NULL; ii++) { - new_destinations[ii] = E_DESTINATION (list->data); - list = g_list_delete_link (list, list); - } + for (ii = 0; ii < length; ii++) + new_destinations[ii] = g_queue_pop_head (&queue); + + /* Sanity check. */ + g_warn_if_fail (g_queue_is_empty (&queue)); return new_destinations; } @@ -294,7 +300,8 @@ from_header_should_be_visible (EComposerHeaderTable *table) EShell *shell; EComposerHeader *header; EComposerHeaderType type; - EAccountComboBox *combo_box; + GtkComboBox *combo_box; + GtkTreeModel *tree_model; shell = e_composer_header_table_get_shell (table); @@ -304,9 +311,11 @@ from_header_should_be_visible (EComposerHeaderTable *table) type = E_COMPOSER_HEADER_FROM; header = e_composer_header_table_get_header (table, type); - combo_box = E_ACCOUNT_COMBO_BOX (header->input_widget); - return (e_account_combo_box_count_displayed_accounts (combo_box) > 1); + combo_box = GTK_COMBO_BOX (header->input_widget); + tree_model = gtk_combo_box_get_model (combo_box); + + return (gtk_tree_model_iter_n_children (tree_model, NULL) > 1); } static void @@ -436,46 +445,127 @@ composer_header_table_setup_post_headers (EComposerHeaderTable *table) g_object_unref (settings); } +static gboolean +composer_header_table_show_post_headers (EComposerHeaderTable *table) +{ + ESourceRegistry *registry; + GList *list, *link; + const gchar *extension_name; + const gchar *target_uid; + gboolean show_post_headers = FALSE; + + registry = e_composer_header_table_get_registry (table); + target_uid = e_composer_header_table_get_identity_uid (table); + + extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT; + list = e_source_registry_list_sources (registry, extension_name); + + /* Look for a mail account referencing this mail identity. + * If the mail account's backend name is "nntp", show the + * post headers. Otherwise show the mail headers. + * + * XXX What if multiple accounts use this identity but only + * one is "nntp"? Maybe it should be indicated by the + * transport somehow? + */ + for (link = list; link != NULL; link = link->next) { + ESource *source = E_SOURCE (link->data); + ESourceExtension *extension; + const gchar *backend_name; + const gchar *identity_uid; + + extension = e_source_get_extension (source, extension_name); + + backend_name = e_source_backend_get_backend_name ( + E_SOURCE_BACKEND (extension)); + identity_uid = e_source_mail_account_get_identity_uid ( + E_SOURCE_MAIL_ACCOUNT (extension)); + + if (g_strcmp0 (identity_uid, target_uid) != 0) + continue; + + if (g_strcmp0 (backend_name, "nntp") != 0) + continue; + + show_post_headers = TRUE; + break; + } + + g_list_free_full (list, (GDestroyNotify) g_object_unref); + + return show_post_headers; +} + static void composer_header_table_from_changed_cb (EComposerHeaderTable *table) { - EAccount *account; + ESource *source = NULL; + ESource *mail_account = NULL; + ESourceRegistry *registry; EComposerHeader *header; EComposerHeaderType type; EComposerPostHeader *post_header; EComposerTextHeader *text_header; EDestination **old_destinations; EDestination **new_destinations; - const gchar *reply_to; - const gchar *source_url; - gboolean always_cc; - gboolean always_bcc; + const gchar *reply_to = NULL; + const gchar * const *bcc = NULL; + const gchar * const *cc = NULL; + const gchar *uid; /* Keep "Post-To" and "Reply-To" synchronized with "From" */ - account = e_composer_header_table_get_account (table); - source_url = e_account_get_string (account, E_ACCOUNT_SOURCE_URL); + registry = e_composer_header_table_get_registry (table); + uid = e_composer_header_table_get_identity_uid (table); + + if (uid != NULL) + source = e_source_registry_ref_source (registry, uid); + + /* Make sure this is really a mail identity source. */ + if (source != NULL) { + const gchar *extension_name; + + extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY; + if (!e_source_has_extension (source, extension_name)) { + g_object_unref (source); + source = NULL; + } + } + + if (source != NULL) { + ESourceMailIdentity *mi; + ESourceMailComposition *mc; + const gchar *extension_name; + + extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY; + mi = e_source_get_extension (source, extension_name); + + extension_name = E_SOURCE_EXTENSION_MAIL_COMPOSITION; + mc = e_source_get_extension (source, extension_name); + + reply_to = e_source_mail_identity_get_reply_to (mi); + bcc = e_source_mail_composition_get_bcc (mc); + cc = e_source_mail_composition_get_cc (mc); + + g_object_unref (source); + } type = E_COMPOSER_HEADER_POST_TO; header = e_composer_header_table_get_header (table, type); post_header = E_COMPOSER_POST_HEADER (header); - e_composer_post_header_set_account (post_header, account); + e_composer_post_header_set_mail_account (post_header, mail_account); type = E_COMPOSER_HEADER_REPLY_TO; header = e_composer_header_table_get_header (table, type); - reply_to = (account != NULL) ? account->id->reply_to : NULL; text_header = E_COMPOSER_TEXT_HEADER (header); e_composer_text_header_set_text (text_header, reply_to); - always_cc = (account != NULL && account->always_cc); - always_bcc = (account != NULL && account->always_bcc); - /* Update automatic CC destinations. */ old_destinations = e_composer_header_table_get_destinations_cc (table); new_destinations = composer_header_table_update_destinations ( - old_destinations, always_cc ? account->cc_addrs : NULL); + old_destinations, cc); e_composer_header_table_set_destinations_cc (table, new_destinations); e_destination_freev (old_destinations); e_destination_freev (new_destinations); @@ -485,34 +575,28 @@ composer_header_table_from_changed_cb (EComposerHeaderTable *table) e_composer_header_table_get_destinations_bcc (table); new_destinations = composer_header_table_update_destinations ( - old_destinations, always_bcc ? account->bcc_addrs : NULL); + old_destinations, bcc); e_composer_header_table_set_destinations_bcc (table, new_destinations); e_destination_freev (old_destinations); e_destination_freev (new_destinations); - /* XXX We should NOT be checking specific account types here. - * Would prefer EAccount have a "send_method" enum item: - * - * E_ACCOUNT_SEND_METHOD_MAIL - * E_ACCOUNT_SEND_METHOD_POST - * - * And that would dictate which set of headers we show - * in the composer when an account is selected. Alas, - * EAccount has no private storage, so it would require - * an ABI break and I don't want to deal with that now. - * (But would anything besides Evolution be affected?) - * - * Currently only NNTP accounts use the "POST" fields. - */ - if (source_url == NULL) - composer_header_table_setup_mail_headers (table); - else if (g_ascii_strncasecmp (source_url, "nntp:", 5) == 0) + if (composer_header_table_show_post_headers (table)) composer_header_table_setup_post_headers (table); else composer_header_table_setup_mail_headers (table); } static void +composer_header_table_set_registry (EComposerHeaderTable *table, + ESourceRegistry *registry) +{ + g_return_if_fail (E_IS_SOURCE_REGISTRY (registry)); + g_return_if_fail (table->priv->registry == NULL); + + table->priv->registry = g_object_ref (registry); +} + +static void composer_header_table_set_shell (EComposerHeaderTable *table, EShell *shell) { @@ -532,24 +616,6 @@ composer_header_table_set_property (GObject *object, GList *list; switch (property_id) { - case PROP_ACCOUNT: - e_composer_header_table_set_account ( - E_COMPOSER_HEADER_TABLE (object), - g_value_get_object (value)); - return; - - case PROP_ACCOUNT_LIST: - e_composer_header_table_set_account_list ( - E_COMPOSER_HEADER_TABLE (object), - g_value_get_object (value)); - return; - - case PROP_ACCOUNT_NAME: - e_composer_header_table_set_account_name ( - E_COMPOSER_HEADER_TABLE (object), - g_value_get_string (value)); - return; - case PROP_DESTINATIONS_BCC: destinations = g_value_dup_destinations (value); e_composer_header_table_set_destinations_bcc ( @@ -574,6 +640,12 @@ composer_header_table_set_property (GObject *object, e_destination_freev (destinations); return; + case PROP_IDENTITY_UID: + e_composer_header_table_set_identity_uid ( + E_COMPOSER_HEADER_TABLE (object), + g_value_get_string (value)); + return; + case PROP_POST_TO: list = g_value_dup_string_list (value); e_composer_header_table_set_post_to_list ( @@ -582,6 +654,12 @@ composer_header_table_set_property (GObject *object, g_list_free (list); return; + case PROP_REGISTRY: + composer_header_table_set_registry ( + E_COMPOSER_HEADER_TABLE (object), + g_value_get_object (value)); + return; + case PROP_REPLY_TO: e_composer_header_table_set_reply_to ( E_COMPOSER_HEADER_TABLE (object), @@ -594,16 +672,10 @@ composer_header_table_set_property (GObject *object, g_value_get_object (value)); return; - case PROP_SIGNATURE: - e_composer_header_table_set_signature ( + case PROP_SIGNATURE_UID: + e_composer_header_table_set_signature_uid ( E_COMPOSER_HEADER_TABLE (object), - g_value_get_object (value)); - return; - - case PROP_SIGNATURE_LIST: - e_composer_header_table_set_signature_list ( - E_COMPOSER_HEADER_TABLE (object), - g_value_get_object (value)); + g_value_get_string (value)); return; case PROP_SUBJECT: @@ -626,27 +698,6 @@ composer_header_table_get_property (GObject *object, GList *list; switch (property_id) { - case PROP_ACCOUNT: - g_value_set_object ( - value, - e_composer_header_table_get_account ( - E_COMPOSER_HEADER_TABLE (object))); - return; - - case PROP_ACCOUNT_LIST: - g_value_set_object ( - value, - e_composer_header_table_get_account_list ( - E_COMPOSER_HEADER_TABLE (object))); - return; - - case PROP_ACCOUNT_NAME: - g_value_set_string ( - value, - e_composer_header_table_get_account_name ( - E_COMPOSER_HEADER_TABLE (object))); - return; - case PROP_DESTINATIONS_BCC: destinations = e_composer_header_table_get_destinations_bcc ( @@ -671,6 +722,13 @@ composer_header_table_get_property (GObject *object, e_destination_freev (destinations); return; + case PROP_IDENTITY_UID: + g_value_set_string ( + value, + e_composer_header_table_get_identity_uid ( + E_COMPOSER_HEADER_TABLE (object))); + return; + case PROP_POST_TO: list = e_composer_header_table_get_post_to ( E_COMPOSER_HEADER_TABLE (object)); @@ -679,6 +737,13 @@ composer_header_table_get_property (GObject *object, g_list_free (list); return; + case PROP_REGISTRY: + g_value_set_object ( + value, + e_composer_header_table_get_registry ( + E_COMPOSER_HEADER_TABLE (object))); + return; + case PROP_REPLY_TO: g_value_set_string ( value, @@ -693,17 +758,17 @@ composer_header_table_get_property (GObject *object, E_COMPOSER_HEADER_TABLE (object))); return; - case PROP_SIGNATURE: + case PROP_SIGNATURE_COMBO_BOX: g_value_set_object ( value, - e_composer_header_table_get_signature ( + e_composer_header_table_get_signature_combo_box ( E_COMPOSER_HEADER_TABLE (object))); return; - case PROP_SIGNATURE_LIST: - g_value_set_object ( + case PROP_SIGNATURE_UID: + g_value_set_string ( value, - e_composer_header_table_get_signature_list ( + e_composer_header_table_get_signature_uid ( E_COMPOSER_HEADER_TABLE (object))); return; @@ -744,6 +809,11 @@ composer_header_table_dispose (GObject *object) priv->name_selector = NULL; } + if (priv->registry != NULL) { + g_object_unref (priv->registry); + priv->registry = NULL; + } + if (priv->shell != NULL) { g_object_unref (priv->shell); priv->shell = NULL; @@ -758,6 +828,7 @@ composer_header_table_constructed (GObject *object) { EComposerHeaderTable *table; ENameSelector *name_selector; + ESourceRegistry *registry; EComposerHeader *header; GtkWidget *widget; EShell *shell; @@ -771,51 +842,52 @@ composer_header_table_constructed (GObject *object) table = E_COMPOSER_HEADER_TABLE (object); shell = e_composer_header_table_get_shell (table); + registry = e_composer_header_table_get_registry (table); small_screen_mode = e_shell_get_small_screen_mode (shell); - name_selector = e_name_selector_new (); + name_selector = e_name_selector_new (registry); table->priv->name_selector = name_selector; - header = e_composer_from_header_new (_("Fr_om:")); - composer_header_table_bind_header ("account", "changed", header); - composer_header_table_bind_header ("account-list", "refreshed", header); - composer_header_table_bind_header ("account-name", "changed", header); + header = e_composer_from_header_new (registry, _("Fr_om:")); + composer_header_table_bind_header ("identity-uid", "changed", header); g_signal_connect_swapped ( header, "changed", G_CALLBACK ( composer_header_table_from_changed_cb), table); table->priv->headers[E_COMPOSER_HEADER_FROM] = header; - header = e_composer_text_header_new_label (_("_Reply-To:")); + header = e_composer_text_header_new_label (registry, _("_Reply-To:")); composer_header_table_bind_header ("reply-to", "changed", header); table->priv->headers[E_COMPOSER_HEADER_REPLY_TO] = header; - header = e_composer_name_header_new (_("_To:"), name_selector); + header = e_composer_name_header_new ( + registry, _("_To:"), name_selector); e_composer_header_set_input_tooltip (header, HEADER_TOOLTIP_TO); composer_header_table_bind_header ("destinations-to", "changed", header); table->priv->headers[E_COMPOSER_HEADER_TO] = header; - header = e_composer_name_header_new (_("_Cc:"), name_selector); + header = e_composer_name_header_new ( + registry, _("_Cc:"), name_selector); e_composer_header_set_input_tooltip (header, HEADER_TOOLTIP_CC); composer_header_table_bind_header ("destinations-cc", "changed", header); table->priv->headers[E_COMPOSER_HEADER_CC] = header; - header = e_composer_name_header_new (_("_Bcc:"), name_selector); + header = e_composer_name_header_new ( + registry, _("_Bcc:"), name_selector); e_composer_header_set_input_tooltip (header, HEADER_TOOLTIP_BCC); composer_header_table_bind_header ("destinations-bcc", "changed", header); table->priv->headers[E_COMPOSER_HEADER_BCC] = header; - header = e_composer_post_header_new (_("_Post To:")); + header = e_composer_post_header_new (registry, _("_Post To:")); composer_header_table_bind_header ("post-to", "changed", header); table->priv->headers[E_COMPOSER_HEADER_POST_TO] = header; - header = e_composer_spell_header_new_label (_("S_ubject:")); + header = e_composer_spell_header_new_label (registry, _("S_ubject:")); composer_header_table_bind_header ("subject", "changed", header); table->priv->headers[E_COMPOSER_HEADER_SUBJECT] = header; - widget = e_signature_combo_box_new (); - composer_header_table_bind_widget ("signature", "changed", widget); - composer_header_table_bind_widget ("signature-list", "refreshed", widget); + widget = e_mail_signature_combo_box_new (registry); + composer_header_table_bind_widget ("signature-uid", "changed", widget); table->priv->signature_combo_box = g_object_ref_sink (widget); widget = gtk_label_new_with_mnemonic (_("Si_gnature:")); @@ -823,20 +895,6 @@ composer_header_table_constructed (GObject *object) GTK_LABEL (widget), table->priv->signature_combo_box); table->priv->signature_label = g_object_ref_sink (widget); - /* XXX EComposerHeader ought to do this itself, but I need to - * make the title_widget and input_widget members private. */ - for (ii = 0; ii < E_COMPOSER_NUM_HEADERS; ii++) { - header = table->priv->headers[ii]; - g_object_bind_property ( - header, "visible", - header->title_widget, "visible", - G_BINDING_SYNC_CREATE); - g_object_bind_property ( - header, "visible", - header->input_widget, "visible", - G_BINDING_SYNC_CREATE); - } - /* Use "ypadding" instead of "row-spacing" because some rows may * be invisible and we don't want spacing around them. */ @@ -899,6 +957,9 @@ composer_header_table_constructed (GObject *object) 3, 4, ii, ii + 1, GTK_FILL, 0, 0, row_padding); gtk_widget_hide (box); } + + /* Initialize the headers. */ + composer_header_table_from_changed_cb (table); } static void @@ -915,36 +976,6 @@ e_composer_header_table_class_init (EComposerHeaderTableClass *class) object_class->dispose = composer_header_table_dispose; object_class->constructed = composer_header_table_constructed; - g_object_class_install_property ( - object_class, - PROP_ACCOUNT, - g_param_spec_object ( - "account", - NULL, - NULL, - E_TYPE_ACCOUNT, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_ACCOUNT_LIST, - g_param_spec_object ( - "account-list", - NULL, - NULL, - E_TYPE_ACCOUNT_LIST, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_ACCOUNT_NAME, - g_param_spec_string ( - "account-name", - NULL, - NULL, - NULL, - G_PARAM_READWRITE)); - /* floating reference */ element_spec = g_param_spec_object ( "value-array-element", @@ -987,6 +1018,17 @@ e_composer_header_table_class_init (EComposerHeaderTableClass *class) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property ( + object_class, + PROP_IDENTITY_UID, + g_param_spec_string ( + "identity-uid", + NULL, + NULL, + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /* floating reference */ element_spec = g_param_spec_string ( "value-array-element", @@ -1009,6 +1051,18 @@ e_composer_header_table_class_init (EComposerHeaderTableClass *class) g_object_class_install_property ( object_class, + PROP_REGISTRY, + g_param_spec_object ( + "registry", + NULL, + NULL, + E_TYPE_SOURCE_REGISTRY, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property ( + object_class, PROP_REPLY_TO, g_param_spec_string ( "reply-to", @@ -1032,23 +1086,23 @@ e_composer_header_table_class_init (EComposerHeaderTableClass *class) g_object_class_install_property ( object_class, - PROP_SIGNATURE, - g_param_spec_object ( - "signature", + PROP_SIGNATURE_COMBO_BOX, + g_param_spec_string ( + "signature-combo-box", NULL, NULL, - E_TYPE_SIGNATURE, - G_PARAM_READWRITE | + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property ( object_class, - PROP_SIGNATURE_LIST, - g_param_spec_object ( - "signature-list", + PROP_SIGNATURE_UID, + g_param_spec_string ( + "signature-uid", + NULL, NULL, NULL, - E_TYPE_SIGNATURE_LIST, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -1095,13 +1149,15 @@ e_composer_header_table_init (EComposerHeaderTable *table) } GtkWidget * -e_composer_header_table_new (EShell *shell) +e_composer_header_table_new (EShell *shell, + ESourceRegistry *registry) { g_return_val_if_fail (E_IS_SHELL (shell), NULL); + g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL); return g_object_new ( E_TYPE_COMPOSER_HEADER_TABLE, - "shell", shell, NULL); + "shell", shell, "registry", registry, NULL); } EShell * @@ -1112,113 +1168,30 @@ e_composer_header_table_get_shell (EComposerHeaderTable *table) return table->priv->shell; } -EComposerHeader * -e_composer_header_table_get_header (EComposerHeaderTable *table, - EComposerHeaderType type) -{ - g_return_val_if_fail (E_IS_COMPOSER_HEADER_TABLE (table), NULL); - g_return_val_if_fail (type < E_COMPOSER_NUM_HEADERS, NULL); - - return table->priv->headers[type]; -} - -EAccount * -e_composer_header_table_get_account (EComposerHeaderTable *table) +ESourceRegistry * +e_composer_header_table_get_registry (EComposerHeaderTable *table) { - EComposerHeader *header; - EComposerHeaderType type; - EComposerFromHeader *from_header; - g_return_val_if_fail (E_IS_COMPOSER_HEADER_TABLE (table), NULL); - type = E_COMPOSER_HEADER_FROM; - header = e_composer_header_table_get_header (table, type); - from_header = E_COMPOSER_FROM_HEADER (header); - - return e_composer_from_header_get_active (from_header); -} - -gboolean -e_composer_header_table_set_account (EComposerHeaderTable *table, - EAccount *account) -{ - EComposerHeader *header; - EComposerHeaderType type; - EComposerFromHeader *from_header; - - g_return_val_if_fail (E_IS_COMPOSER_HEADER_TABLE (table), FALSE); - - type = E_COMPOSER_HEADER_FROM; - header = e_composer_header_table_get_header (table, type); - from_header = E_COMPOSER_FROM_HEADER (header); - - return e_composer_from_header_set_active (from_header, account); + return table->priv->registry; } -EAccountList * -e_composer_header_table_get_account_list (EComposerHeaderTable *table) +EComposerHeader * +e_composer_header_table_get_header (EComposerHeaderTable *table, + EComposerHeaderType type) { - EComposerHeader *header; - EComposerHeaderType type; - EComposerFromHeader *from_header; - g_return_val_if_fail (E_IS_COMPOSER_HEADER_TABLE (table), NULL); + g_return_val_if_fail (type < E_COMPOSER_NUM_HEADERS, NULL); - type = E_COMPOSER_HEADER_FROM; - header = e_composer_header_table_get_header (table, type); - from_header = E_COMPOSER_FROM_HEADER (header); - - return e_composer_from_header_get_account_list (from_header); -} - -void -e_composer_header_table_set_account_list (EComposerHeaderTable *table, - EAccountList *account_list) -{ - EComposerHeader *header; - EComposerHeaderType type; - EComposerFromHeader *from_header; - - g_return_if_fail (E_IS_COMPOSER_HEADER_TABLE (table)); - - type = E_COMPOSER_HEADER_FROM; - header = e_composer_header_table_get_header (table, type); - from_header = E_COMPOSER_FROM_HEADER (header); - - e_composer_from_header_set_account_list (from_header, account_list); + return table->priv->headers[type]; } -const gchar * -e_composer_header_table_get_account_name (EComposerHeaderTable *table) +EMailSignatureComboBox * +e_composer_header_table_get_signature_combo_box (EComposerHeaderTable *table) { - EComposerHeader *header; - EComposerHeaderType type; - EComposerFromHeader *from_header; - g_return_val_if_fail (E_IS_COMPOSER_HEADER_TABLE (table), NULL); - type = E_COMPOSER_HEADER_FROM; - header = e_composer_header_table_get_header (table, type); - from_header = E_COMPOSER_FROM_HEADER (header); - - return e_composer_from_header_get_active_name (from_header); -} - -gboolean -e_composer_header_table_set_account_name (EComposerHeaderTable *table, - const gchar *account_name) -{ - EComposerHeader *header; - EComposerHeaderType type; - EComposerFromHeader *from_header; - - g_return_val_if_fail (E_IS_COMPOSER_HEADER_TABLE (table), FALSE); - - type = E_COMPOSER_HEADER_FROM; - header = e_composer_header_table_get_header (table, type); - from_header = E_COMPOSER_FROM_HEADER (header); - - return e_composer_from_header_set_active_name (from_header, account_name); + return E_MAIL_SIGNATURE_COMBO_BOX (table->priv->signature_combo_box); } EDestination ** @@ -1423,6 +1396,39 @@ e_composer_header_table_set_destinations_to (EComposerHeaderTable *table, e_composer_name_header_set_destinations (name_header, destinations); } +const gchar * +e_composer_header_table_get_identity_uid (EComposerHeaderTable *table) +{ + EComposerHeader *header; + EComposerHeaderType type; + EComposerFromHeader *from_header; + + g_return_val_if_fail (E_IS_COMPOSER_HEADER_TABLE (table), NULL); + + type = E_COMPOSER_HEADER_FROM; + header = e_composer_header_table_get_header (table, type); + from_header = E_COMPOSER_FROM_HEADER (header); + + return e_composer_from_header_get_active_id (from_header); +} + +void +e_composer_header_table_set_identity_uid (EComposerHeaderTable *table, + const gchar *identity_uid) +{ + EComposerHeader *header; + EComposerHeaderType type; + EComposerFromHeader *from_header; + + g_return_if_fail (E_IS_COMPOSER_HEADER_TABLE (table)); + + type = E_COMPOSER_HEADER_FROM; + header = e_composer_header_table_get_header (table, type); + from_header = E_COMPOSER_FROM_HEADER (header); + + e_composer_from_header_set_active_id (from_header, identity_uid); +} + GList * e_composer_header_table_get_post_to (EComposerHeaderTable *table) { @@ -1510,50 +1516,29 @@ e_composer_header_table_set_reply_to (EComposerHeaderTable *table, e_composer_header_set_visible (header, TRUE); } -ESignature * -e_composer_header_table_get_signature (EComposerHeaderTable *table) +const gchar * +e_composer_header_table_get_signature_uid (EComposerHeaderTable *table) { - ESignatureComboBox *combo_box; + EMailSignatureComboBox *combo_box; g_return_val_if_fail (E_IS_COMPOSER_HEADER_TABLE (table), NULL); - combo_box = E_SIGNATURE_COMBO_BOX (table->priv->signature_combo_box); - return e_signature_combo_box_get_active (combo_box); -} - -gboolean -e_composer_header_table_set_signature (EComposerHeaderTable *table, - ESignature *signature) -{ - ESignatureComboBox *combo_box; + combo_box = e_composer_header_table_get_signature_combo_box (table); - g_return_val_if_fail (E_IS_COMPOSER_HEADER_TABLE (table), FALSE); - - combo_box = E_SIGNATURE_COMBO_BOX (table->priv->signature_combo_box); - return e_signature_combo_box_set_active (combo_box, signature); -} - -ESignatureList * -e_composer_header_table_get_signature_list (EComposerHeaderTable *table) -{ - ESignatureComboBox *combo_box; - - g_return_val_if_fail (E_IS_COMPOSER_HEADER_TABLE (table), NULL); - - combo_box = E_SIGNATURE_COMBO_BOX (table->priv->signature_combo_box); - return e_signature_combo_box_get_signature_list (combo_box); + return gtk_combo_box_get_active_id (GTK_COMBO_BOX (combo_box)); } void -e_composer_header_table_set_signature_list (EComposerHeaderTable *table, - ESignatureList *signature_list) +e_composer_header_table_set_signature_uid (EComposerHeaderTable *table, + const gchar *signature_uid) { - ESignatureComboBox *combo_box; + EMailSignatureComboBox *combo_box; g_return_if_fail (E_IS_COMPOSER_HEADER_TABLE (table)); - combo_box = E_SIGNATURE_COMBO_BOX (table->priv->signature_combo_box); - e_signature_combo_box_set_signature_list (combo_box, signature_list); + combo_box = e_composer_header_table_get_signature_combo_box (table); + + gtk_combo_box_set_active_id (GTK_COMBO_BOX (combo_box), signature_uid); } const gchar * diff --git a/composer/e-composer-header-table.h b/composer/e-composer-header-table.h index 9d6a83fb9a..b76e9b6395 100644 --- a/composer/e-composer-header-table.h +++ b/composer/e-composer-header-table.h @@ -18,14 +18,11 @@ #ifndef E_COMPOSER_HEADER_TABLE_H #define E_COMPOSER_HEADER_TABLE_H -#include <libedataserver/e-account.h> -#include <libedataserver/e-account-list.h> #include <libebook/e-destination.h> #include <shell/e-shell.h> #include <composer/e-composer-header.h> -#include <libemail-utils/e-signature.h> -#include <libemail-utils/e-signature-list.h> +#include <misc/e-mail-signature-combo-box.h> /* Standard GObject macros */ #define E_TYPE_COMPOSER_HEADER_TABLE \ @@ -74,28 +71,20 @@ struct _EComposerHeaderTableClass { }; GType e_composer_header_table_get_type (void); -GtkWidget * e_composer_header_table_new (EShell *shell); +GtkWidget * e_composer_header_table_new (EShell *shell, + ESourceRegistry *registry); EShell * e_composer_header_table_get_shell (EComposerHeaderTable *table); +ESourceRegistry * + e_composer_header_table_get_registry + (EComposerHeaderTable *table); EComposerHeader * e_composer_header_table_get_header (EComposerHeaderTable *table, EComposerHeaderType type); -EAccount * e_composer_header_table_get_account - (EComposerHeaderTable *table); -gboolean e_composer_header_table_set_account - (EComposerHeaderTable *table, - EAccount *account); -EAccountList * e_composer_header_table_get_account_list - (EComposerHeaderTable *table); -void e_composer_header_table_set_account_list - (EComposerHeaderTable *table, - EAccountList *account_list); -const gchar * e_composer_header_table_get_account_name +EMailSignatureComboBox * + e_composer_header_table_get_signature_combo_box (EComposerHeaderTable *table); -gboolean e_composer_header_table_set_account_name - (EComposerHeaderTable *table, - const gchar *account_name); EDestination ** e_composer_header_table_get_destinations (EComposerHeaderTable *table); EDestination ** e_composer_header_table_get_destinations_bcc @@ -122,6 +111,11 @@ void e_composer_header_table_add_destinations_to void e_composer_header_table_set_destinations_to (EComposerHeaderTable *table, EDestination **destinations); +const gchar * e_composer_header_table_get_identity_uid + (EComposerHeaderTable *table); +void e_composer_header_table_set_identity_uid + (EComposerHeaderTable *table, + const gchar *identity_uid); GList * e_composer_header_table_get_post_to (EComposerHeaderTable *table); void e_composer_header_table_set_post_to_base @@ -136,16 +130,11 @@ const gchar * e_composer_header_table_get_reply_to void e_composer_header_table_set_reply_to (EComposerHeaderTable *table, const gchar *reply_to); -ESignature * e_composer_header_table_get_signature - (EComposerHeaderTable *table); -gboolean e_composer_header_table_set_signature - (EComposerHeaderTable *table, - ESignature *signature); -ESignatureList *e_composer_header_table_get_signature_list +const gchar * e_composer_header_table_get_signature_uid (EComposerHeaderTable *table); -void e_composer_header_table_set_signature_list +void e_composer_header_table_set_signature_uid (EComposerHeaderTable *table, - ESignatureList *signature_list); + const gchar *signature_uid); const gchar * e_composer_header_table_get_subject (EComposerHeaderTable *table); void e_composer_header_table_set_subject diff --git a/composer/e-composer-header.c b/composer/e-composer-header.c index c92b069113..5ef5e41d15 100644 --- a/composer/e-composer-header.c +++ b/composer/e-composer-header.c @@ -36,12 +36,8 @@ struct _EComposerHeaderPrivate { gchar *label; gboolean button; - GtkWidget *action_label; - GtkWidget *add_icon; - GtkWidget *remove_icon; - GtkWidget *show_label; - GtkWidget *hide_label; + ESourceRegistry *registry; guint sensitive : 1; guint visible : 1; @@ -55,6 +51,7 @@ enum { PROP_0, PROP_BUTTON, PROP_LABEL, + PROP_REGISTRY, PROP_SENSITIVE, PROP_VISIBLE }; @@ -80,48 +77,14 @@ composer_header_button_clicked_cb (GtkButton *button, g_signal_emit (header, signal_ids[CLICKED], 0); } -static GObject * -composer_header_constructor (GType type, - guint n_construct_properties, - GObjectConstructParam *construct_properties) +static void +composer_header_set_registry (EComposerHeader *header, + ESourceRegistry *registry) { - GObject *object; - GtkWidget *widget; - EComposerHeader *header; - GtkWidget *label; - - /* Chain up to parent's constructor() method. */ - object = G_OBJECT_CLASS ( - e_composer_header_parent_class)->constructor ( - type, n_construct_properties, construct_properties); - - header = E_COMPOSER_HEADER (object); - - if (header->priv->button) { - widget = gtk_button_new_with_mnemonic (header->priv->label); - gtk_widget_set_can_focus (widget, FALSE); - g_signal_connect ( - widget, "clicked", - G_CALLBACK (composer_header_button_clicked_cb), - header); - label = gtk_bin_get_child (GTK_BIN (widget)); - } else { - widget = gtk_label_new_with_mnemonic (header->priv->label); - gtk_label_set_mnemonic_widget ( - GTK_LABEL (widget), header->input_widget); - label = widget; - } - - gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); - - header->priv->action_label = NULL; - - header->title_widget = g_object_ref_sink (widget); - - g_free (header->priv->label); - header->priv->label = NULL; + g_return_if_fail (E_IS_SOURCE_REGISTRY (registry)); + g_return_if_fail (header->priv->registry == NULL); - return object; + header->priv->registry = g_object_ref (registry); } static void @@ -143,6 +106,12 @@ composer_header_set_property (GObject *object, priv->label = g_value_dup_string (value); return; + case PROP_REGISTRY: + composer_header_set_registry ( + E_COMPOSER_HEADER (object), + g_value_get_object (value)); + return; + case PROP_SENSITIVE: e_composer_header_set_sensitive ( E_COMPOSER_HEADER (object), @@ -175,8 +144,12 @@ composer_header_get_property (GObject *object, return; case PROP_LABEL: /* construct only */ - g_value_take_string ( - value, e_composer_header_get_label ( + g_value_set_string (value, priv->label); + return; + + case PROP_REGISTRY: + g_value_set_object ( + value, e_composer_header_get_registry ( E_COMPOSER_HEADER (object))); return; @@ -211,11 +184,75 @@ composer_header_dispose (GObject *object) header->input_widget = NULL; } + if (header->priv->registry != NULL) { + g_object_unref (header->priv->registry); + header->priv->registry = NULL; + } + /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (e_composer_header_parent_class)->dispose (object); } static void +composer_header_finalize (GObject *object) +{ + EComposerHeaderPrivate *priv; + + priv = E_COMPOSER_HEADER_GET_PRIVATE (object); + + g_free (priv->label); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (e_composer_header_parent_class)->finalize (object); +} + +static void +composer_header_constructed (GObject *object) +{ + EComposerHeader *header; + GtkWidget *widget; + GtkWidget *label; + + header = E_COMPOSER_HEADER (object); + + if (header->input_widget == NULL) { + g_critical ( + "EComposerHeader's input_widget " + "must be set before chaining up"); + return; + } + + if (header->priv->button) { + widget = gtk_button_new_with_mnemonic (header->priv->label); + gtk_widget_set_can_focus (widget, FALSE); + g_signal_connect ( + widget, "clicked", + G_CALLBACK (composer_header_button_clicked_cb), + header); + label = gtk_bin_get_child (GTK_BIN (widget)); + } else { + widget = gtk_label_new_with_mnemonic (header->priv->label); + gtk_label_set_mnemonic_widget ( + GTK_LABEL (widget), header->input_widget); + label = widget; + } + + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + + header->title_widget = g_object_ref_sink (widget); + + g_object_bind_property ( + header, "visible", + header->title_widget, "visible", + G_BINDING_SYNC_CREATE); + + g_object_bind_property ( + header, "visible", + header->input_widget, "visible", + G_BINDING_SYNC_CREATE); +} + +static void e_composer_header_class_init (EComposerHeaderClass *class) { GObjectClass *object_class; @@ -223,10 +260,11 @@ e_composer_header_class_init (EComposerHeaderClass *class) g_type_class_add_private (class, sizeof (EComposerHeaderPrivate)); object_class = G_OBJECT_CLASS (class); - object_class->constructor = composer_header_constructor; object_class->set_property = composer_header_set_property; object_class->get_property = composer_header_get_property; object_class->dispose = composer_header_dispose; + object_class->finalize = composer_header_finalize; + object_class->constructed = composer_header_constructed; g_object_class_install_property ( object_class, @@ -254,6 +292,18 @@ e_composer_header_class_init (EComposerHeaderClass *class) g_object_class_install_property ( object_class, + PROP_REGISTRY, + g_param_spec_object ( + "registry", + NULL, + NULL, + E_TYPE_SOURCE_REGISTRY, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property ( + object_class, PROP_SENSITIVE, g_param_spec_boolean ( "sensitive", @@ -299,17 +349,20 @@ e_composer_header_init (EComposerHeader *header) header->priv = E_COMPOSER_HEADER_GET_PRIVATE (header); } -gchar * +const gchar * e_composer_header_get_label (EComposerHeader *header) { - gchar *label; - g_return_val_if_fail (E_IS_COMPOSER_HEADER (header), NULL); - /* GtkButton and GtkLabel both have a "label" property. */ - g_object_get (header->title_widget, "label", &label, NULL); + return header->priv->label; +} - return label; +ESourceRegistry * +e_composer_header_get_registry (EComposerHeader *header) +{ + g_return_val_if_fail (E_IS_COMPOSER_HEADER (header), NULL); + + return header->priv->registry; } gboolean @@ -347,20 +400,6 @@ e_composer_header_set_visible (EComposerHeader *header, header->priv->visible = visible; - if (header->priv->action_label) { - if (!visible) { - gtk_widget_show (header->priv->add_icon); - gtk_widget_show (header->priv->show_label); - gtk_widget_hide (header->priv->remove_icon); - gtk_widget_hide (header->priv->hide_label); - } else { - gtk_widget_hide (header->priv->add_icon); - gtk_widget_hide (header->priv->show_label); - gtk_widget_show (header->priv->remove_icon); - gtk_widget_show (header->priv->hide_label); - } - } - g_object_notify (G_OBJECT (header), "visible"); } diff --git a/composer/e-composer-header.h b/composer/e-composer-header.h index 08db97a2d4..24bfb7d5bc 100644 --- a/composer/e-composer-header.h +++ b/composer/e-composer-header.h @@ -19,6 +19,7 @@ #define E_COMPOSER_HEADER_H #include <composer/e-composer-common.h> +#include <libedataserver/e-source-registry.h> /* Standard GObject macros */ #define E_TYPE_COMPOSER_HEADER \ @@ -61,7 +62,9 @@ struct _EComposerHeaderClass { }; GType e_composer_header_get_type (void); -gchar * e_composer_header_get_label (EComposerHeader *header); +const gchar * e_composer_header_get_label (EComposerHeader *header); +ESourceRegistry * + e_composer_header_get_registry (EComposerHeader *header); gboolean e_composer_header_get_sensitive (EComposerHeader *header); void e_composer_header_set_sensitive (EComposerHeader *header, gboolean sensitive); diff --git a/composer/e-composer-name-header.c b/composer/e-composer-name-header.c index 740eceef27..3857f3954d 100644 --- a/composer/e-composer-name-header.c +++ b/composer/e-composer-name-header.c @@ -110,63 +110,6 @@ composer_name_header_entry_query_tooltip_cb (GtkEntry *entry, return TRUE; } -static GObject * -composer_name_header_constructor (GType type, - guint n_construct_properties, - GObjectConstructParam *construct_properties) -{ - EComposerNameHeaderPrivate *priv; - ENameSelectorModel *model; - ENameSelectorEntry *entry; - GObject *object; - GList *sections; - gchar *label; - - /* Chain up to parent's constructor() method. */ - object = G_OBJECT_CLASS ( - e_composer_name_header_parent_class)->constructor ( - type, n_construct_properties, construct_properties); - - priv = E_COMPOSER_NAME_HEADER_GET_PRIVATE (object); - g_assert (E_IS_NAME_SELECTOR (priv->name_selector)); - - model = e_name_selector_peek_model (priv->name_selector); - label = e_composer_header_get_label (E_COMPOSER_HEADER (object)); - g_assert (label != NULL); - - sections = e_name_selector_model_list_sections (model); - priv->destination_index = g_list_length (sections); - e_name_selector_model_add_section (model, label, label, NULL); - g_list_foreach (sections, (GFunc) g_free, NULL); - g_list_free (sections); - - e_composer_header_set_title_tooltip ( - E_COMPOSER_HEADER (object), - _("Click here for the address book")); - - entry = E_NAME_SELECTOR_ENTRY ( - e_name_selector_peek_section_list ( - priv->name_selector, label)); - - e_name_selector_entry_set_contact_editor_func ( - entry, contact_editor_fudge_new); - e_name_selector_entry_set_contact_list_editor_func ( - entry, contact_list_editor_fudge_new); - - g_signal_connect ( - entry, "changed", - G_CALLBACK (composer_name_header_entry_changed_cb), object); - g_signal_connect ( - entry, "query-tooltip", - G_CALLBACK (composer_name_header_entry_query_tooltip_cb), - NULL); - E_COMPOSER_HEADER (object)->input_widget = g_object_ref_sink (entry); - - g_free (label); - - return object; -} - static void composer_name_header_set_property (GObject *object, guint property_id, @@ -222,6 +165,57 @@ composer_name_header_dispose (GObject *object) } static void +composer_name_header_constructed (GObject *object) +{ + EComposerNameHeaderPrivate *priv; + ENameSelectorModel *model; + ENameSelectorEntry *entry; + GList *sections; + const gchar *label; + + /* Input widget must be set before chaining up. */ + + priv = E_COMPOSER_NAME_HEADER_GET_PRIVATE (object); + g_assert (E_IS_NAME_SELECTOR (priv->name_selector)); + + model = e_name_selector_peek_model (priv->name_selector); + label = e_composer_header_get_label (E_COMPOSER_HEADER (object)); + g_assert (label != NULL); + + sections = e_name_selector_model_list_sections (model); + priv->destination_index = g_list_length (sections); + e_name_selector_model_add_section (model, label, label, NULL); + g_list_foreach (sections, (GFunc) g_free, NULL); + g_list_free (sections); + + entry = E_NAME_SELECTOR_ENTRY ( + e_name_selector_peek_section_list ( + priv->name_selector, label)); + + e_name_selector_entry_set_contact_editor_func ( + entry, contact_editor_fudge_new); + e_name_selector_entry_set_contact_list_editor_func ( + entry, contact_list_editor_fudge_new); + + g_signal_connect ( + entry, "changed", + G_CALLBACK (composer_name_header_entry_changed_cb), object); + g_signal_connect ( + entry, "query-tooltip", + G_CALLBACK (composer_name_header_entry_query_tooltip_cb), + NULL); + E_COMPOSER_HEADER (object)->input_widget = g_object_ref_sink (entry); + + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (e_composer_name_header_parent_class)-> + constructed (object); + + e_composer_header_set_title_tooltip ( + E_COMPOSER_HEADER (object), + _("Click here for the address book")); +} + +static void composer_name_header_clicked (EComposerHeader *header) { EComposerNameHeaderPrivate *priv; @@ -247,10 +241,10 @@ e_composer_name_header_class_init (EComposerNameHeaderClass *class) g_type_class_add_private (class, sizeof (EComposerNameHeaderPrivate)); object_class = G_OBJECT_CLASS (class); - object_class->constructor = composer_name_header_constructor; object_class->set_property = composer_name_header_set_property; object_class->get_property = composer_name_header_get_property; object_class->dispose = composer_name_header_dispose; + object_class->constructed = composer_name_header_constructed; header_class = E_COMPOSER_HEADER_CLASS (class); header_class->clicked = composer_name_header_clicked; @@ -274,16 +268,18 @@ e_composer_name_header_init (EComposerNameHeader *header) } EComposerHeader * -e_composer_name_header_new (const gchar *label, +e_composer_name_header_new (ESourceRegistry *registry, + const gchar *label, ENameSelector *name_selector) { + g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL); g_return_val_if_fail (E_IS_NAME_SELECTOR (name_selector), NULL); return g_object_new ( E_TYPE_COMPOSER_NAME_HEADER, "label", label, "button", TRUE, "name-selector", name_selector, - NULL); + "registry", registry, NULL); } ENameSelector * diff --git a/composer/e-composer-name-header.h b/composer/e-composer-name-header.h index e2f5e0044c..cb4dc03abf 100644 --- a/composer/e-composer-name-header.h +++ b/composer/e-composer-name-header.h @@ -58,7 +58,8 @@ struct _EComposerNameHeaderClass { }; GType e_composer_name_header_get_type (void); -EComposerHeader * e_composer_name_header_new (const gchar *label, +EComposerHeader * e_composer_name_header_new (ESourceRegistry *registry, + const gchar *label, ENameSelector *name_selector); ENameSelector * e_composer_name_header_get_name_selector (EComposerNameHeader *header); diff --git a/composer/e-composer-post-header.c b/composer/e-composer-post-header.c index a2a4f4893f..cc013244bc 100644 --- a/composer/e-composer-post-header.c +++ b/composer/e-composer-post-header.c @@ -34,11 +34,11 @@ enum { PROP_0, - PROP_ACCOUNT + PROP_MAIL_ACCOUNT }; struct _EComposerPostHeaderPrivate { - EAccount *account; + ESource *mail_account; gchar *base_url; /* derived from account */ gboolean custom; }; @@ -77,26 +77,16 @@ composer_post_header_folder_name_to_string (EComposerPostHeader *header, static void composer_post_header_set_base_url (EComposerPostHeader *header) { - EAccount *account = header->priv->account; - CamelURL *camel_url; - gchar *url; + ESource *source; + const gchar *uid; - if (account == NULL || account->source == NULL) + source = header->priv->mail_account; + if (source == NULL) return; - url = account->source->url; - if (url == NULL || *url == '\0') - return; - - camel_url = camel_url_new (url, NULL); - if (camel_url == NULL) - return; - - url = camel_url_to_string (camel_url, CAMEL_URL_HIDE_ALL); - camel_url_free (camel_url); - + uid = e_source_get_uid (source); g_free (header->priv->base_url); - header->priv->base_url = url; + header->priv->base_url = g_strdup_printf ("folder://%s", uid); } static GList * @@ -118,25 +108,6 @@ composer_post_header_split_csv (const gchar *csv) return g_list_reverse (list); } -static GObject * -composer_post_header_constructor (GType type, - guint n_construct_properties, - GObjectConstructParam *construct_properties) -{ - GObject *object; - - /* Chain up to parent's constructor() method. */ - object = G_OBJECT_CLASS ( - e_composer_post_header_parent_class)->constructor ( - type, n_construct_properties, construct_properties); - - e_composer_header_set_title_tooltip ( - E_COMPOSER_HEADER (object), - _("Click here to select folders to post to")); - - return object; -} - static void composer_post_header_set_property (GObject *object, guint property_id, @@ -144,8 +115,8 @@ composer_post_header_set_property (GObject *object, GParamSpec *pspec) { switch (property_id) { - case PROP_ACCOUNT: - e_composer_post_header_set_account ( + case PROP_MAIL_ACCOUNT: + e_composer_post_header_set_mail_account ( E_COMPOSER_POST_HEADER (object), g_value_get_object (value)); return; @@ -161,9 +132,10 @@ composer_post_header_get_property (GObject *object, GParamSpec *pspec) { switch (property_id) { - case PROP_ACCOUNT: + case PROP_MAIL_ACCOUNT: g_value_set_object ( - value, e_composer_post_header_get_account ( + value, + e_composer_post_header_get_mail_account ( E_COMPOSER_POST_HEADER (object))); return; } @@ -178,9 +150,9 @@ composer_post_header_dispose (GObject *object) priv = E_COMPOSER_POST_HEADER_GET_PRIVATE (object); - if (priv->account != NULL) { - g_object_unref (priv->account); - priv->account = NULL; + if (priv->mail_account != NULL) { + g_object_unref (priv->mail_account); + priv->mail_account = NULL; } /* Chain up to parent's dispose() method. */ @@ -201,6 +173,18 @@ composer_post_header_finalize (GObject *object) } static void +composer_post_header_constructed (GObject *object) +{ + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (e_composer_post_header_parent_class)-> + constructed (object); + + e_composer_header_set_title_tooltip ( + E_COMPOSER_HEADER (object), + _("Click here to select folders to post to")); +} + +static void composer_post_header_changed (EComposerHeader *header) { EComposerPostHeaderPrivate *priv; @@ -229,11 +213,11 @@ e_composer_post_header_class_init (EComposerPostHeaderClass *class) g_type_class_add_private (class, sizeof (EComposerPostHeaderPrivate)); object_class = G_OBJECT_CLASS (class); - object_class->constructor = composer_post_header_constructor; object_class->set_property = composer_post_header_set_property; object_class->get_property = composer_post_header_get_property; object_class->dispose = composer_post_header_dispose; object_class->finalize = composer_post_header_finalize; + object_class->constructed = composer_post_header_constructed; header_class = E_COMPOSER_HEADER_CLASS (class); header_class->changed = composer_post_header_changed; @@ -241,12 +225,12 @@ e_composer_post_header_class_init (EComposerPostHeaderClass *class) g_object_class_install_property ( object_class, - PROP_ACCOUNT, + PROP_MAIL_ACCOUNT, g_param_spec_object ( - "account", + "mail-account", NULL, NULL, - E_TYPE_ACCOUNT, + E_TYPE_SOURCE, G_PARAM_READWRITE)); } @@ -257,51 +241,15 @@ e_composer_post_header_init (EComposerPostHeader *header) } EComposerHeader * -e_composer_post_header_new (const gchar *label) +e_composer_post_header_new (ESourceRegistry *registry, + const gchar *label) { + g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL); + return g_object_new ( E_TYPE_COMPOSER_POST_HEADER, - "label", label, "button", TRUE, NULL); -} - -EAccount * -e_composer_post_header_get_account (EComposerPostHeader *header) -{ - g_return_val_if_fail (E_IS_COMPOSER_POST_HEADER (header), NULL); - - return header->priv->account; -} - -void -e_composer_post_header_set_account (EComposerPostHeader *header, - EAccount *account) -{ - GList *folders = NULL; - - g_return_if_fail (E_IS_COMPOSER_POST_HEADER (header)); - - if (account != NULL) { - g_return_if_fail (E_IS_ACCOUNT (account)); - g_object_ref (account); - } - - if (!header->priv->custom) - folders = e_composer_post_header_get_folders (header); - - if (header->priv->account != NULL) - g_object_unref (header->priv->account); - - header->priv->account = account; - composer_post_header_set_base_url (header); - - /* Make folders relative to the new account. */ - if (!header->priv->custom) { - e_composer_post_header_set_folders (header, folders); - g_list_foreach (folders, (GFunc) g_free, NULL); - g_list_free (folders); - } - - g_object_notify (G_OBJECT (header), "account"); + "label", label, "button", TRUE, + "registry", registry, NULL); } GList * @@ -385,3 +333,43 @@ e_composer_post_header_set_folders_base (EComposerPostHeader *header, g_list_foreach (list, (GFunc) g_free, NULL); g_list_free (list); } + +ESource * +e_composer_post_header_get_mail_account (EComposerPostHeader *header) +{ + g_return_val_if_fail (E_IS_COMPOSER_POST_HEADER (header), NULL); + + return header->priv->mail_account; +} + +void +e_composer_post_header_set_mail_account (EComposerPostHeader *header, + ESource *mail_account) +{ + GList *folders = NULL; + + g_return_if_fail (E_IS_COMPOSER_POST_HEADER (header)); + + if (mail_account != NULL) { + g_return_if_fail (E_IS_SOURCE (mail_account)); + g_object_ref (mail_account); + } + + if (!header->priv->custom) + folders = e_composer_post_header_get_folders (header); + + if (header->priv->mail_account != NULL) + g_object_unref (header->priv->mail_account); + + header->priv->mail_account = mail_account; + composer_post_header_set_base_url (header); + + /* Make folders relative to the new account. */ + if (!header->priv->custom) { + e_composer_post_header_set_folders (header, folders); + g_list_foreach (folders, (GFunc) g_free, NULL); + g_list_free (folders); + } + + g_object_notify (G_OBJECT (header), "mail-account"); +} diff --git a/composer/e-composer-post-header.h b/composer/e-composer-post-header.h index c6fff3e751..999f1eb28a 100644 --- a/composer/e-composer-post-header.h +++ b/composer/e-composer-post-header.h @@ -21,8 +21,6 @@ #ifndef E_COMPOSER_POST_HEADER_H #define E_COMPOSER_POST_HEADER_H -#include <libedataserver/e-account.h> - #include <composer/e-composer-text-header.h> /* Standard GObject macros */ @@ -63,12 +61,8 @@ struct _EComposerPostHeaderClass { GType e_composer_post_header_get_type (void); EComposerHeader * - e_composer_post_header_new (const gchar *label); -EAccount * e_composer_post_header_get_account - (EComposerPostHeader *header); -void e_composer_post_header_set_account - (EComposerPostHeader *header, - EAccount *account); + e_composer_post_header_new (ESourceRegistry *registry, + const gchar *label); GList * e_composer_post_header_get_folders (EComposerPostHeader *header); void e_composer_post_header_set_folders @@ -78,6 +72,11 @@ void e_composer_post_header_set_folders_base (EComposerPostHeader *header, const gchar *base_url, const gchar *folders); +ESource * e_composer_post_header_get_mail_account + (EComposerPostHeader *header); +void e_composer_post_header_set_mail_account + (EComposerPostHeader *header, + ESource *mail_account); G_END_DECLS diff --git a/composer/e-composer-private.c b/composer/e-composer-private.c index 03cfbf16f4..5a4ac31aed 100644 --- a/composer/e-composer-private.c +++ b/composer/e-composer-private.c @@ -142,6 +142,7 @@ e_composer_private_constructed (EMsgComposer *composer) EShell *shell; EShellSettings *shell_settings; EWebViewGtkHTML *web_view; + ESourceRegistry *registry; GtkhtmlEditor *editor; GtkUIManager *ui_manager; GtkAction *action; @@ -160,6 +161,7 @@ e_composer_private_constructed (EMsgComposer *composer) ui_manager = gtkhtml_editor_get_ui_manager (editor); shell = e_msg_composer_get_shell (composer); + registry = e_shell_get_registry (shell); shell_settings = e_shell_get_shell_settings (shell); web_view = e_msg_composer_get_web_view (composer); small_screen_mode = e_shell_get_small_screen_mode (shell); @@ -283,7 +285,7 @@ e_composer_private_constructed (EMsgComposer *composer) /* Construct the header table. */ - widget = e_composer_header_table_new (shell); + widget = e_composer_header_table_new (shell, registry); gtk_container_set_border_width (GTK_CONTAINER (widget), 6); gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); if (small_screen_mode) @@ -930,3 +932,210 @@ e_composer_selection_is_image_uris (EMsgComposer *composer, return all_image_uris; } + +static gboolean +add_signature_delimiter (EMsgComposer *composer) +{ + EShell *shell; + EShellSettings *shell_settings; + + /* FIXME This preference should be an EMsgComposer property. */ + + shell = e_msg_composer_get_shell (composer); + shell_settings = e_shell_get_shell_settings (shell); + + return !e_shell_settings_get_boolean ( + shell_settings, "composer-no-signature-delim"); +} + +static gboolean +use_top_signature (EMsgComposer *composer) +{ + EShell *shell; + EShellSettings *shell_settings; + + /* FIXME This preference should be an EMsgComposer property. */ + + shell = e_msg_composer_get_shell (composer); + shell_settings = e_shell_get_shell_settings (shell); + + return e_shell_settings_get_boolean ( + shell_settings, "composer-top-signature"); +} + +static void +composer_load_signature_cb (EMailSignatureComboBox *combo_box, + GAsyncResult *result, + EMsgComposer *composer) +{ + GString *html_buffer = NULL; + GtkhtmlEditor *editor; + gchar *contents = NULL; + gsize length = 0; + const gchar *active_id; + gchar *encoded_uid = NULL; + gboolean top_signature; + gboolean is_html; + GError *error = NULL; + + e_mail_signature_combo_box_load_selected_finish ( + combo_box, result, &contents, &length, &is_html, &error); + + /* FIXME Use an EAlert here. */ + if (error != NULL) { + g_warning ("%s: %s", G_STRFUNC, error->message); + g_error_free (error); + goto exit; + } + + /* "Edit as New Message" sets "priv->is_from_message". + * Always put the signature at the bottom for that case. */ + top_signature = + use_top_signature (composer) && + !composer->priv->is_from_message; + + if (contents == NULL) + goto insert; + + /* Generate HTML code for the signature. */ + + html_buffer = g_string_sized_new (1024); + + /* The combo box active ID is the signature's ESource UID. */ + active_id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (combo_box)); + + if (active_id != NULL && *active_id != '\0') + encoded_uid = e_composer_encode_clue_value (active_id); + + g_string_append_printf ( + html_buffer, + "<!--+GtkHTML:<DATA class=\"ClueFlow\" " + " key=\"signature\" value=\"1\">-->" + "<!--+GtkHTML:<DATA class=\"ClueFlow\" " + " key=\"signature_name\" value=\"uid:%s\"-->", + (encoded_uid != NULL) ? encoded_uid : ""); + + g_string_append ( + html_buffer, + "<TABLE WIDTH=\"100%%\" CELLSPACING=\"0\"" + " CELLPADDING=\"0\"><TR><TD>"); + + if (!is_html) + g_string_append (html_buffer, "<PRE>\n"); + + /* The signature dash convention ("-- \n") is specified + * in the "Son of RFC 1036", section 4.3.2. + * http://www.chemie.fu-berlin.de/outerspace/netnews/son-of-1036.html + */ + if (add_signature_delimiter (composer)) { + const gchar *delim; + const gchar *delim_nl; + + if (is_html) { + delim = "-- \n<BR>"; + delim_nl = "\n-- \n<BR>"; + } else { + delim = "-- \n"; + delim_nl = "\n-- \n"; + } + + /* Skip the delimiter if the signature already has one. */ + if (g_ascii_strncasecmp (contents, delim, strlen (delim)) == 0) + ; /* skip */ + else if (e_util_strstrcase (contents, delim_nl) != NULL) + ; /* skip */ + else + g_string_append (html_buffer, delim); + } + + g_string_append_len (html_buffer, contents, length); + + if (!is_html) + g_string_append (html_buffer, "</PRE>\n"); + + if (top_signature) + g_string_append (html_buffer, "<BR>"); + + g_string_append (html_buffer, "</TD></TR></TABLE>"); + + g_free (encoded_uid); + g_free (contents); + +insert: + /* Remove the old signature and insert the new one. */ + + editor = GTKHTML_EDITOR (composer); + + /* This prevents our command before/after callbacks from + * screwing around with the signature as we insert it. */ + composer->priv->in_signature_insert = TRUE; + + gtkhtml_editor_freeze (editor); + gtkhtml_editor_run_command (editor, "cursor-position-save"); + gtkhtml_editor_undo_begin (editor, "Set signature", "Reset signature"); + + gtkhtml_editor_run_command (editor, "block-selection"); + gtkhtml_editor_run_command (editor, "cursor-bod"); + if (gtkhtml_editor_search_by_data (editor, 1, "ClueFlow", "signature", "1")) { + gtkhtml_editor_run_command (editor, "select-paragraph"); + gtkhtml_editor_run_command (editor, "delete"); + gtkhtml_editor_set_paragraph_data (editor, "signature", "0"); + gtkhtml_editor_run_command (editor, "delete-back"); + } + gtkhtml_editor_run_command (editor, "unblock-selection"); + + if (html_buffer != NULL) { + gtkhtml_editor_run_command (editor, "insert-paragraph"); + if (!gtkhtml_editor_run_command (editor, "cursor-backward")) + gtkhtml_editor_run_command (editor, "insert-paragraph"); + else + gtkhtml_editor_run_command (editor, "cursor-forward"); + + gtkhtml_editor_set_paragraph_data (editor, "orig", "0"); + gtkhtml_editor_run_command (editor, "indent-zero"); + gtkhtml_editor_run_command (editor, "style-normal"); + gtkhtml_editor_insert_html (editor, html_buffer->str); + + g_string_free (html_buffer, TRUE); + + } else if (top_signature) { + /* Insert paragraph after the signature ClueFlow stuff. */ + if (gtkhtml_editor_run_command (editor, "cursor-forward")) + gtkhtml_editor_run_command (editor, "insert-paragraph"); + } + + gtkhtml_editor_undo_end (editor); + gtkhtml_editor_run_command (editor, "cursor-position-restore"); + gtkhtml_editor_thaw (editor); + + composer->priv->in_signature_insert = FALSE; + +exit: + g_object_unref (composer); +} + +void +e_composer_update_signature (EMsgComposer *composer) +{ + EComposerHeaderTable *table; + EMailSignatureComboBox *combo_box; + + g_return_if_fail (E_IS_MSG_COMPOSER (composer)); + + /* Do nothing if we're redirecting a message. */ + if (composer->priv->redirect) + return; + + table = e_msg_composer_get_header_table (composer); + combo_box = e_composer_header_table_get_signature_combo_box (table); + + /* XXX Signature files should be local and therefore load quickly, + * so while we do load them asynchronously we don't allow for + * user cancellation and we keep the composer alive until the + * asynchronous loading is complete. */ + e_mail_signature_combo_box_load_selected ( + combo_box, G_PRIORITY_DEFAULT, NULL, + (GAsyncReadyCallback) composer_load_signature_cb, + g_object_ref (composer)); +} + diff --git a/composer/e-composer-private.h b/composer/e-composer-private.h index 990c5b64bc..4c40872797 100644 --- a/composer/e-composer-private.h +++ b/composer/e-composer-private.h @@ -31,6 +31,12 @@ #include <glib/gi18n-lib.h> #include <libebackend/e-extensible.h> +#include <libedataserver/e-source-mail-composition.h> +#include <libedataserver/e-source-mail-identity.h> +#include <libedataserver/e-source-mail-signature.h> +#include <libedataserver/e-source-mail-submission.h> +#include <libedataserver/e-source-openpgp.h> +#include <libedataserver/e-source-smime.h> #include "e-composer-actions.h" #include "e-composer-activity.h" @@ -48,9 +54,9 @@ #include "widgets/misc/e-attachment-icon-view.h" #include "widgets/misc/e-attachment-paned.h" #include "widgets/misc/e-attachment-store.h" +#include "widgets/misc/e-mail-signature-combo-box.h" #include "widgets/misc/e-picture-gallery.h" #include "widgets/misc/e-preferences-window.h" -#include "widgets/misc/e-signature-combo-box.h" #include "widgets/misc/e-web-view-gtkhtml.h" #include "shell/e-shell.h" @@ -141,6 +147,7 @@ gboolean e_composer_paste_uris (EMsgComposer *composer, gboolean e_composer_selection_is_image_uris (EMsgComposer *composer, GtkSelectionData *selection); +void e_composer_update_signature (EMsgComposer *composer); G_END_DECLS diff --git a/composer/e-composer-spell-header.c b/composer/e-composer-spell-header.c index aff5dbfd2b..ad4ddca6dd 100644 --- a/composer/e-composer-spell-header.c +++ b/composer/e-composer-spell-header.c @@ -43,32 +43,38 @@ e_composer_spell_header_init (EComposerSpellHeader *header) } EComposerHeader * -e_composer_spell_header_new_label (const gchar *label) +e_composer_spell_header_new_label (ESourceRegistry *registry, + const gchar *label) { + g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL); + return g_object_new ( E_TYPE_COMPOSER_SPELL_HEADER, "label", label, "button", FALSE, - NULL); + "registry", registry, NULL); } EComposerHeader * -e_composer_spell_header_new_button (const gchar *label) +e_composer_spell_header_new_button (ESourceRegistry *registry, + const gchar *label) { + g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL); + return g_object_new ( E_TYPE_COMPOSER_SPELL_HEADER, "label", label, "button", TRUE, - NULL); + "registry", registry, NULL); } void -e_composer_spell_header_set_languages (EComposerSpellHeader *spell_header, +e_composer_spell_header_set_languages (EComposerSpellHeader *header, GList *languages) { ESpellEntry *spell_entry; - g_return_if_fail (spell_header != NULL); + g_return_if_fail (header != NULL); - spell_entry = E_SPELL_ENTRY (E_COMPOSER_HEADER (spell_header)->input_widget); + spell_entry = E_SPELL_ENTRY (E_COMPOSER_HEADER (header)->input_widget); g_return_if_fail (spell_entry != NULL); e_spell_entry_set_languages (spell_entry, languages); diff --git a/composer/e-composer-spell-header.h b/composer/e-composer-spell-header.h index 44ac8d165e..b8812e8533 100644 --- a/composer/e-composer-spell-header.h +++ b/composer/e-composer-spell-header.h @@ -57,11 +57,19 @@ struct _EComposerSpellHeaderClass { GType entry_type; }; -GType e_composer_spell_header_get_type (void); -EComposerHeader * e_composer_spell_header_new_label (const gchar *label); -EComposerHeader * e_composer_spell_header_new_button (const gchar *label); -void e_composer_spell_header_set_languages (EComposerSpellHeader *spell_header, - GList *languages); +GType e_composer_spell_header_get_type + (void) G_GNUC_CONST; +EComposerHeader * + e_composer_spell_header_new_label + (ESourceRegistry *registry, + const gchar *label); +EComposerHeader * + e_composer_spell_header_new_button + (ESourceRegistry *registry, + const gchar *label); +void e_composer_spell_header_set_languages + (EComposerSpellHeader *header, + GList *languages); G_END_DECLS diff --git a/composer/e-composer-text-header.c b/composer/e-composer-text-header.c index 8506541ef0..7bcd26d6e6 100644 --- a/composer/e-composer-text-header.c +++ b/composer/e-composer-text-header.c @@ -66,17 +66,18 @@ composer_text_header_query_tooltip_cb (GtkEntry *entry, } static void -e_composer_text_header_constructed (GObject *object) +composer_text_header_constructed (GObject *object) { GtkWidget *widget; EComposerTextHeader *header; - - G_OBJECT_CLASS (e_composer_text_header_parent_class)->constructed (object); + EComposerTextHeaderClass *class; header = E_COMPOSER_TEXT_HEADER (object); - g_return_if_fail (header != NULL); + class = E_COMPOSER_TEXT_HEADER_GET_CLASS (header); + + /* Input widget must be set before chaining up. */ - widget = g_object_ref_sink (g_object_new (E_COMPOSER_TEXT_HEADER_GET_CLASS (header)->entry_type, NULL)); + widget = g_object_new (class->entry_type, NULL); g_signal_connect ( widget, "changed", G_CALLBACK (composer_text_header_changed_cb), header); @@ -84,7 +85,11 @@ e_composer_text_header_constructed (GObject *object) widget, "query-tooltip", G_CALLBACK (composer_text_header_query_tooltip_cb), NULL); gtk_widget_set_has_tooltip (widget, TRUE); - E_COMPOSER_HEADER (header)->input_widget = widget; + E_COMPOSER_HEADER (object)->input_widget = g_object_ref_sink (widget); + + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (e_composer_text_header_parent_class)-> + constructed (object); } static void @@ -95,7 +100,7 @@ e_composer_text_header_class_init (EComposerTextHeaderClass *class) class->entry_type = GTK_TYPE_ENTRY; object_class = G_OBJECT_CLASS (class); - object_class->constructed = e_composer_text_header_constructed; + object_class->constructed = composer_text_header_constructed; } static void @@ -104,21 +109,27 @@ e_composer_text_header_init (EComposerTextHeader *header) } EComposerHeader * -e_composer_text_header_new_label (const gchar *label) +e_composer_text_header_new_label (ESourceRegistry *registry, + const gchar *label) { + g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL); + return g_object_new ( E_TYPE_COMPOSER_TEXT_HEADER, "label", label, "button", FALSE, - NULL); + "registry", registry, NULL); } EComposerHeader * -e_composer_text_header_new_button (const gchar *label) +e_composer_text_header_new_button (ESourceRegistry *registry, + const gchar *label) { + g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL); + return g_object_new ( E_TYPE_COMPOSER_TEXT_HEADER, "label", label, "button", TRUE, - NULL); + "registry", registry, NULL); } const gchar * diff --git a/composer/e-composer-text-header.h b/composer/e-composer-text-header.h index af97e7a12c..5fd8c21f04 100644 --- a/composer/e-composer-text-header.h +++ b/composer/e-composer-text-header.h @@ -60,10 +60,12 @@ struct _EComposerTextHeaderClass { GType e_composer_text_header_get_type (void); EComposerHeader * e_composer_text_header_new_label - (const gchar *label); + (ESourceRegistry *registry, + const gchar *label); EComposerHeader * e_composer_text_header_new_button - (const gchar *label); + (ESourceRegistry *registry, + const gchar *label); const gchar * e_composer_text_header_get_text (EComposerTextHeader *header); void e_composer_text_header_set_text (EComposerTextHeader *header, const gchar *text); diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c index 50c51b60bc..ae5048208e 100644 --- a/composer/e-msg-composer.c +++ b/composer/e-msg-composer.c @@ -42,8 +42,6 @@ #include <e-util/e-util-private.h> #include <em-format/em-format.h> #include <em-format/em-format-quote.h> -#include <libemail-utils/e-account-utils.h> -#include <libemail-utils/e-signature-utils.h> #include "e-composer-private.h" @@ -56,7 +54,7 @@ struct _AsyncContext { CamelDataWrapper *top_level_part; CamelDataWrapper *text_plain_part; - EAccount *account; + ESource *source; CamelSession *session; CamelInternetAddress *from; @@ -151,8 +149,8 @@ async_context_free (AsyncContext *context) if (context->text_plain_part != NULL) g_object_unref (context->text_plain_part); - if (context->account != NULL) - g_object_unref (context->account); + if (context->source != NULL) + g_object_unref (context->source); if (context->session != NULL) g_object_unref (context->session); @@ -515,27 +513,47 @@ build_message_headers (EMsgComposer *composer, { EComposerHeaderTable *table; EComposerHeader *header; - EAccount *account; + ESourceRegistry *registry; + ESource *source; const gchar *subject; const gchar *reply_to; + const gchar *uid; g_return_if_fail (E_IS_MSG_COMPOSER (composer)); g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message)); table = e_msg_composer_get_header_table (composer); + registry = e_composer_header_table_get_registry (table); + uid = e_composer_header_table_get_identity_uid (table); + source = e_source_registry_ref_source (registry, uid); + /* Subject: */ subject = e_composer_header_table_get_subject (table); camel_mime_message_set_subject (message, subject); - account = e_composer_header_table_get_account (table); - if (account != NULL) { + if (source != NULL) { CamelMedium *medium; CamelInternetAddress *addr; + ESourceMailIdentity *mi; + ESourceMailSubmission *ms; + const gchar *extension_name; const gchar *header_name; - const gchar *name = account->id->name; - const gchar *address = account->id->address; - gchar *transport_uid; + const gchar *name, *address; + const gchar *transport_uid; + const gchar *sent_folder; + + extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY; + mi = e_source_get_extension (source, extension_name); + + name = e_source_mail_identity_get_name (mi); + address = e_source_mail_identity_get_address (mi); + + extension_name = E_SOURCE_EXTENSION_MAIL_SUBMISSION; + ms = e_source_get_extension (source, extension_name); + + sent_folder = e_source_mail_submission_get_sent_folder (ms); + transport_uid = e_source_mail_submission_get_transport_uid (ms); medium = CAMEL_MEDIUM (message); @@ -554,18 +572,17 @@ build_message_headers (EMsgComposer *composer, /* X-Evolution-Account */ header_name = "X-Evolution-Account"; - camel_medium_set_header (medium, header_name, account->uid); + camel_medium_set_header (medium, header_name, uid); /* X-Evolution-Fcc */ header_name = "X-Evolution-Fcc"; - camel_medium_set_header (medium, header_name, account->sent_folder_uri); + camel_medium_set_header (medium, header_name, sent_folder); /* X-Evolution-Transport */ header_name = "X-Evolution-Transport"; - transport_uid = g_strconcat ( - account->uid, "-transport", NULL); camel_medium_set_header (medium, header_name, transport_uid); - g_free (transport_uid); + + g_object_unref (source); } /* Reply-To: */ @@ -672,20 +689,27 @@ composer_build_message_pgp (AsyncContext *context, GCancellable *cancellable, GError **error) { + ESourceOpenPGP *extension; CamelCipherContext *cipher; CamelDataWrapper *content; CamelMimePart *mime_part; - const gchar *pgp_userid; - gboolean have_pgp_key; + const gchar *extension_name; + const gchar *pgp_key_id; + const gchar *signing_algorithm; + gboolean always_trust; + gboolean encrypt_to_self; /* Return silently if we're not signing or encrypting with PGP. */ if (!context->pgp_sign && !context->pgp_encrypt) return TRUE; - have_pgp_key = - (context->account != NULL) && - (context->account->pgp_key != NULL) && - (context->account->pgp_key[0] != '\0'); + extension_name = E_SOURCE_EXTENSION_OPENPGP; + extension = e_source_get_extension (context->source, extension_name); + + always_trust = e_source_openpgp_get_always_trust (extension); + encrypt_to_self = e_source_openpgp_get_encrypt_to_self (extension); + pgp_key_id = e_source_openpgp_get_key_id (extension); + signing_algorithm = e_source_openpgp_get_signing_algorithm (extension); mime_part = camel_mime_part_new (); @@ -700,11 +724,9 @@ composer_build_message_pgp (AsyncContext *context, g_object_unref (context->top_level_part); context->top_level_part = NULL; - if (have_pgp_key) - pgp_userid = context->account->pgp_key; - else + if (pgp_key_id == NULL || *pgp_key_id == '\0') camel_internet_address_get ( - context->from, 0, NULL, &pgp_userid); + context->from, 0, NULL, &pgp_key_id); if (context->pgp_sign) { CamelMimePart *npart; @@ -713,17 +735,12 @@ composer_build_message_pgp (AsyncContext *context, npart = camel_mime_part_new (); cipher = camel_gpg_context_new (context->session); - if (context->account != NULL) - camel_gpg_context_set_always_trust ( - CAMEL_GPG_CONTEXT (cipher), - context->account->pgp_always_trust); + camel_gpg_context_set_always_trust ( + CAMEL_GPG_CONTEXT (cipher), always_trust); success = camel_cipher_context_sign_sync ( - cipher, pgp_userid, - account_hash_algo_to_camel_hash ( - (context->account != NULL) ? - e_account_get_string (context->account, - E_ACCOUNT_PGP_HASH_ALGORITHM) : NULL), + cipher, pgp_key_id, + account_hash_algo_to_camel_hash (signing_algorithm), mime_part, npart, cancellable, error); g_object_unref (cipher); @@ -740,36 +757,28 @@ composer_build_message_pgp (AsyncContext *context, if (context->pgp_encrypt) { CamelMimePart *npart; - gboolean encrypt_to_self; gboolean success; - encrypt_to_self = - (context->account != NULL) && - (context->account->pgp_encrypt_to_self) && - (pgp_userid != NULL); - npart = camel_mime_part_new (); /* Check to see if we should encrypt to self. - * NB gets removed immediately after use */ - if (encrypt_to_self) + * NB: Gets removed immediately after use. */ + if (encrypt_to_self && pgp_key_id != NULL) g_ptr_array_add ( context->recipients, - g_strdup (pgp_userid)); + g_strdup (pgp_key_id)); cipher = camel_gpg_context_new (context->session); - if (context->account != NULL) - camel_gpg_context_set_always_trust ( - CAMEL_GPG_CONTEXT (cipher), - context->account->pgp_always_trust); + camel_gpg_context_set_always_trust ( + CAMEL_GPG_CONTEXT (cipher), always_trust); success = camel_cipher_context_encrypt_sync ( - cipher, pgp_userid, context->recipients, + cipher, pgp_key_id, context->recipients, mime_part, npart, cancellable, error); g_object_unref (cipher); - if (encrypt_to_self) + if (encrypt_to_self && pgp_key_id != NULL) g_ptr_array_set_size ( context->recipients, context->recipients->len - 1); @@ -798,8 +807,14 @@ composer_build_message_smime (AsyncContext *context, GCancellable *cancellable, GError **error) { + ESourceSMIME *extension; CamelCipherContext *cipher; CamelMimePart *mime_part; + const gchar *extension_name; + const gchar *signing_algorithm; + const gchar *signing_certificate; + const gchar *encryption_certificate; + gboolean encrypt_to_self; gboolean have_signing_certificate; gboolean have_encryption_certificate; @@ -807,15 +822,28 @@ composer_build_message_smime (AsyncContext *context, if (!context->smime_sign && !context->smime_encrypt) return TRUE; + extension_name = E_SOURCE_EXTENSION_SMIME; + extension = e_source_get_extension (context->source, extension_name); + + encrypt_to_self = + e_source_smime_get_encrypt_to_self (extension); + + signing_algorithm = + e_source_smime_get_signing_algorithm (extension); + + signing_certificate = + e_source_smime_get_signing_certificate (extension); + + encryption_certificate = + e_source_smime_get_encryption_certificate (extension); + have_signing_certificate = - (context->account != NULL) && - (context->account->smime_sign_key != NULL) && - (context->account->smime_sign_key[0] != '\0'); + (signing_certificate != NULL) && + (*signing_certificate != '\0'); have_encryption_certificate = - (context->account != NULL) && - (context->account->smime_encrypt_key != NULL) && - (context->account->smime_encrypt_key[0] != '\0'); + (encryption_certificate != NULL) && + (*encryption_certificate != '\0'); if (context->smime_sign && !have_signing_certificate) { g_set_error ( @@ -862,20 +890,17 @@ composer_build_message_smime (AsyncContext *context, (CamelSMIMEContext *) cipher, CAMEL_SMIME_SIGN_ENVELOPED); camel_smime_context_set_encrypt_key ( - (CamelSMIMEContext *) cipher, TRUE, - context->account->smime_encrypt_key); + (CamelSMIMEContext *) cipher, + TRUE, encryption_certificate); } else if (have_encryption_certificate) { camel_smime_context_set_encrypt_key ( - (CamelSMIMEContext *) cipher, TRUE, - context->account->smime_encrypt_key); + (CamelSMIMEContext *) cipher, + TRUE, encryption_certificate); } success = camel_cipher_context_sign_sync ( - cipher, context->account->smime_sign_key, - account_hash_algo_to_camel_hash ( - (context->account != NULL) ? - e_account_get_string (context->account, - E_ACCOUNT_SMIME_HASH_ALGORITHM) : NULL), + cipher, signing_certificate, + account_hash_algo_to_camel_hash (signing_algorithm), mime_part, npart, cancellable, error); g_object_unref (cipher); @@ -893,16 +918,17 @@ composer_build_message_smime (AsyncContext *context, if (context->smime_encrypt) { gboolean success; - /* check to see if we should encrypt to self, NB removed after use */ - if (context->account->smime_encrypt_to_self) + /* Check to see if we should encrypt to self. + * NB: Gets removed immediately after use. */ + if (encrypt_to_self) g_ptr_array_add ( context->recipients, g_strdup ( - context->account->smime_encrypt_key)); + encryption_certificate)); cipher = camel_smime_context_new (context->session); camel_smime_context_set_encrypt_key ( (CamelSMIMEContext *) cipher, TRUE, - context->account->smime_encrypt_key); + encryption_certificate); success = camel_cipher_context_encrypt_sync ( cipher, NULL, @@ -915,7 +941,7 @@ composer_build_message_smime (AsyncContext *context, if (!success) return FALSE; - if (context->account->smime_encrypt_to_self) + if (encrypt_to_self) g_ptr_array_set_size ( context->recipients, context->recipients->len - 1); @@ -1033,7 +1059,12 @@ composer_build_message (EMsgComposer *composer, EAttachmentStore *store; EComposerHeaderTable *table; CamelDataWrapper *html; + ESourceMailIdentity *mi; + ESourceRegistry *registry; + const gchar *extension_name; const gchar *iconv_charset = NULL; + const gchar *identity_uid; + const gchar *organization; CamelMultipart *body = NULL; CamelContentType *type; CamelSession *session; @@ -1041,23 +1072,27 @@ composer_build_message (EMsgComposer *composer, CamelStream *mem_stream; CamelMimePart *part; GByteArray *data; - EAccount *account; + ESource *source; gchar *charset; gint i; priv = composer->priv; editor = GTKHTML_EDITOR (composer); table = e_msg_composer_get_header_table (composer); - account = e_composer_header_table_get_account (table); view = e_msg_composer_get_attachment_view (composer); store = e_attachment_view_get_store (view); session = e_msg_composer_get_session (composer); + registry = e_composer_header_table_get_registry (table); + identity_uid = e_composer_header_table_get_identity_uid (table); + source = e_source_registry_ref_source (registry, identity_uid); + g_return_if_fail (source != NULL); + /* Do all the non-blocking work here, and defer * any blocking operations to a separate thread. */ context = g_slice_new0 (AsyncContext); - context->account = g_object_ref (account); + context->source = source; /* takes the reference */ context->session = g_object_ref (session); context->from = e_msg_composer_get_from (composer); @@ -1110,16 +1145,21 @@ composer_build_message (EMsgComposer *composer, priv->extra_hdr_values->pdata[i]); } + extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY; + mi = e_source_get_extension (source, extension_name); + organization = e_source_mail_identity_get_organization (mi); + /* Disposition-Notification-To */ if (flags & COMPOSER_FLAG_REQUEST_READ_RECEIPT) { - gchar *mdn_address = account->id->reply_to; - - if (mdn_address == NULL || *mdn_address == '\0') - mdn_address = account->id->address; - - camel_medium_add_header ( - CAMEL_MEDIUM (context->message), - "Disposition-Notification-To", mdn_address); + const gchar *mdn_address; + + mdn_address = e_source_mail_identity_get_reply_to (mi); + if (mdn_address == NULL) + mdn_address = e_source_mail_identity_get_address (mi); + if (mdn_address != NULL) + camel_medium_add_header ( + CAMEL_MEDIUM (context->message), + "Disposition-Notification-To", mdn_address); } /* X-Priority */ @@ -1129,15 +1169,15 @@ composer_build_message (EMsgComposer *composer, "X-Priority", "1"); /* Organization */ - if (account != NULL && account->id->organization != NULL) { - gchar *organization; + if (organization != NULL && *organization != '\0') { + gchar *encoded_organization; - organization = camel_header_encode_string ( - (const guchar *) account->id->organization); + encoded_organization = camel_header_encode_string ( + (const guchar *) organization); camel_medium_set_header ( CAMEL_MEDIUM (context->message), - "Organization", organization); - g_free (organization); + "Organization", encoded_organization); + g_free (encoded_organization); } /* X-Evolution-Format */ @@ -1402,7 +1442,7 @@ composer_build_message_finish (EMsgComposer *composer, /* Signatures */ static gboolean -is_top_signature (EMsgComposer *composer) +use_top_signature (EMsgComposer *composer) { EShell *shell; EShellSettings *shell_settings; @@ -1424,20 +1464,6 @@ is_top_signature (EMsgComposer *composer) shell_settings, "composer-top-signature"); } -static gboolean -add_signature_delim (EMsgComposer *composer) -{ - EShell *shell; - EShellSettings *shell_settings; - - shell = e_msg_composer_get_shell (composer); - shell_settings = e_shell_get_shell_settings (shell); - - return !e_shell_settings_get_boolean ( - shell_settings, "composer-no-signature-delim"); -} - -#define CONVERT_SPACES CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES #define NO_SIGNATURE_TEXT \ "<!--+GtkHTML:<DATA class=\"ClueFlow\" " \ " key=\"signature\" " \ @@ -1446,115 +1472,6 @@ add_signature_delim (EMsgComposer *composer) " key=\"signature_name\" " \ " value=\"uid:Noname\">--><BR>" -static gchar * -get_signature_html (EMsgComposer *composer) -{ - EComposerHeaderTable *table; - gchar *text = NULL, *html = NULL; - ESignature *signature; - gboolean format_html, add_delim; - - table = e_msg_composer_get_header_table (composer); - signature = e_composer_header_table_get_signature (table); - - if (!signature) - return NULL; - - add_delim = add_signature_delim (composer); - - if (!e_signature_get_autogenerated (signature)) { - const gchar *filename; - - filename = e_signature_get_filename (signature); - if (filename == NULL) - return NULL; - - format_html = e_signature_get_is_html (signature); - - if (e_signature_get_is_script (signature)) - text = e_run_signature_script (filename); - else - text = e_read_signature_file (signature, TRUE, NULL); - } else { - EAccount *account; - EAccountIdentity *id; - gchar *organization = NULL; - gchar *address = NULL; - gchar *name = NULL; - - account = e_composer_header_table_get_account (table); - if (!account) - return NULL; - - id = account->id; - if (id->address != NULL) - address = camel_text_to_html ( - id->address, CONVERT_SPACES, 0); - if (id->name != NULL) - name = camel_text_to_html ( - id->name, CONVERT_SPACES, 0); - if (id->organization != NULL) - organization = camel_text_to_html ( - id->organization, CONVERT_SPACES, 0); - - text = g_strdup_printf ("%s%s%s%s%s%s%s%s%s", - add_delim ? "-- \n<BR>" : "", - name ? name : "", - (address && *address) ? " <<A HREF=\"mailto:" : "", - address ? address : "", - (address && *address) ? "\">" : "", - address ? address : "", - (address && *address) ? "</A>>" : "", - (organization && *organization) ? "<BR>" : "", - organization ? organization : ""); - g_free (address); - g_free (name); - g_free (organization); - format_html = TRUE; - } - - /* printf ("text: %s\n", text); */ - if (text) { - gchar *encoded_uid = NULL; - const gchar *sig_delim = format_html ? "-- \n<BR>" : "-- \n"; - const gchar *sig_delim_ent = format_html ? "\n-- \n<BR>" : "\n-- \n"; - - if (signature != NULL) { - const gchar *uid = e_signature_get_uid (signature); - encoded_uid = e_composer_encode_clue_value (uid); - } - - /* The signature dash convention ("-- \n") is specified - * in the "Son of RFC 1036", section 4.3.2. - * http://www.chemie.fu-berlin.de/outerspace/netnews/son-of-1036.html - */ - html = g_strdup_printf ( - "<!--+GtkHTML:<DATA class=\"ClueFlow\" " - " key=\"signature\" value=\"1\">-->" - "<!--+GtkHTML:<DATA class=\"ClueFlow\" " - " key=\"signature_name\" value=\"uid:%s\">-->" - "<TABLE WIDTH=\"100%%\" CELLSPACING=\"0\"" - " CELLPADDING=\"0\"><TR><TD>" - "%s%s%s%s" - "%s</TD></TR></TABLE>", - encoded_uid ? encoded_uid : "", - format_html ? "" : "<PRE>\n", - !add_delim ? "" : - (!strncmp ( - sig_delim, text, strlen (sig_delim)) || - strstr (text, sig_delim_ent)) - ? "" : sig_delim, - text, - format_html ? "" : "</PRE>\n", - is_top_signature (composer) ? "<BR>" : ""); - g_free (text); - g_free (encoded_uid); - text = html; - } - - return text; -} - static void set_editor_text (EMsgComposer *composer, const gchar *text, @@ -1579,7 +1496,9 @@ set_editor_text (EMsgComposer *composer, * */ - if (is_top_signature (composer)) { + /* "Edit as New Message" sets "priv->is_from_message". + * Always put the signature at the bottom for that case. */ + if (!composer->priv->is_from_message && use_top_signature (composer)) { /* put marker to the top */ body = g_strdup_printf ("<BR>" NO_SIGNATURE_TEXT "%s", text); } else { @@ -1590,7 +1509,7 @@ set_editor_text (EMsgComposer *composer, gtkhtml_editor_set_text_html (GTKHTML_EDITOR (composer), body, -1); if (set_signature) - e_msg_composer_show_sig_file (composer); + e_composer_update_signature (composer); g_free (body); } @@ -1624,43 +1543,65 @@ msg_composer_subject_changed_cb (EMsgComposer *composer) } static void -msg_composer_account_changed_cb (EMsgComposer *composer) +msg_composer_mail_identity_changed_cb (EMsgComposer *composer) { EMsgComposerPrivate *p = composer->priv; + EMailSignatureComboBox *combo_box; + ESourceRegistry *registry; + ESourceMailComposition *mc; + ESourceOpenPGP *pgp; + ESourceSMIME *smime; EComposerHeaderTable *table; GtkToggleAction *action; - ESignature *signature; - EAccount *account; - gboolean active, can_sign; + ESource *source; + gboolean can_sign; + gboolean pgp_sign; + gboolean smime_sign; + gboolean smime_encrypt; + const gchar *extension_name; const gchar *uid; table = e_msg_composer_get_header_table (composer); - account = e_composer_header_table_get_account (table); + registry = e_composer_header_table_get_registry (table); + uid = e_composer_header_table_get_identity_uid (table); - if (account == NULL) { - e_msg_composer_show_sig_file (composer); + /* Silently return if no identity is selected. */ + if (uid == NULL) return; - } - can_sign = (!account->pgp_no_imip_sign || p->mime_type == NULL || - g_ascii_strncasecmp (p->mime_type, "text/calendar", 13) != 0); + source = e_source_registry_ref_source (registry, uid); + g_return_if_fail (source != NULL); + + extension_name = E_SOURCE_EXTENSION_MAIL_COMPOSITION; + mc = e_source_get_extension (source, extension_name); + + extension_name = E_SOURCE_EXTENSION_OPENPGP; + pgp = e_source_get_extension (source, extension_name); + pgp_sign = e_source_openpgp_get_sign_by_default (pgp); + + extension_name = E_SOURCE_EXTENSION_SMIME; + smime = e_source_get_extension (source, extension_name); + smime_sign = e_source_smime_get_sign_by_default (smime); + smime_encrypt = e_source_smime_get_encrypt_by_default (smime); + + can_sign = + (p->mime_type == NULL) || + e_source_mail_composition_get_sign_imip (mc) || + (g_ascii_strncasecmp (p->mime_type, "text/calendar", 13) != 0); action = GTK_TOGGLE_ACTION (ACTION (PGP_SIGN)); - active = account->pgp_always_sign && can_sign; - gtk_toggle_action_set_active (action, active); + gtk_toggle_action_set_active (action, can_sign && pgp_sign); action = GTK_TOGGLE_ACTION (ACTION (SMIME_SIGN)); - active = account->smime_sign_default && can_sign; - gtk_toggle_action_set_active (action, active); + gtk_toggle_action_set_active (action, can_sign && smime_sign); action = GTK_TOGGLE_ACTION (ACTION (SMIME_ENCRYPT)); - active = account->smime_encrypt_default; - gtk_toggle_action_set_active (action, active); + gtk_toggle_action_set_active (action, smime_encrypt); + + combo_box = e_composer_header_table_get_signature_combo_box (table); + e_mail_signature_combo_box_set_identity_uid (combo_box, uid); - uid = account->id->sig_uid; - signature = uid ? e_get_signature_by_uid (uid) : NULL; - e_composer_header_table_set_signature (table, signature); - e_msg_composer_show_sig_file (composer); + g_object_unref (source); } static void @@ -2066,14 +2007,6 @@ msg_composer_constructed (GObject *object) /* Configure Headers */ - e_composer_header_table_set_account_list ( - table, e_get_account_list ()); - e_composer_header_table_set_signature_list ( - table, e_get_signature_list ()); - - g_signal_connect_swapped ( - table, "notify::account", - G_CALLBACK (msg_composer_account_changed_cb), composer); g_signal_connect_swapped ( table, "notify::destinations-bcc", G_CALLBACK (msg_composer_notify_header_cb), composer); @@ -2084,11 +2017,14 @@ msg_composer_constructed (GObject *object) table, "notify::destinations-to", G_CALLBACK (msg_composer_notify_header_cb), composer); g_signal_connect_swapped ( + table, "notify::identity-uid", + G_CALLBACK (msg_composer_mail_identity_changed_cb), composer); + g_signal_connect_swapped ( table, "notify::reply-to", G_CALLBACK (msg_composer_notify_header_cb), composer); g_signal_connect_swapped ( - table, "notify::signature", - G_CALLBACK (e_msg_composer_show_sig_file), composer); + table, "notify::signature-uid", + G_CALLBACK (e_composer_update_signature), composer); g_signal_connect_swapped ( table, "notify::subject", G_CALLBACK (msg_composer_subject_changed_cb), composer); @@ -2096,7 +2032,7 @@ msg_composer_constructed (GObject *object) table, "notify::subject", G_CALLBACK (msg_composer_notify_header_cb), composer); - msg_composer_account_changed_cb (composer); + msg_composer_mail_identity_changed_cb (composer); /* Attachments */ @@ -3031,28 +2967,75 @@ set_signature_gui (EMsgComposer *composer) { GtkhtmlEditor *editor; EComposerHeaderTable *table; - ESignature *signature = NULL; + EMailSignatureComboBox *combo_box; const gchar *data; - gchar *decoded; + gchar *uid; editor = GTKHTML_EDITOR (composer); table = e_msg_composer_get_header_table (composer); + combo_box = e_composer_header_table_get_signature_combo_box (table); if (!gtkhtml_editor_search_by_data (editor, 1, "ClueFlow", "signature", "1")) return; data = gtkhtml_editor_get_paragraph_data (editor, "signature_name"); - if (g_str_has_prefix (data, "uid:")) { - decoded = e_composer_decode_clue_value (data + 4); - signature = e_get_signature_by_uid (decoded); - g_free (decoded); - } else if (g_str_has_prefix (data, "name:")) { - decoded = e_composer_decode_clue_value (data + 5); - signature = e_get_signature_by_name (decoded); - g_free (decoded); + + if (!g_str_has_prefix (data, "uid:")) + return; + + /* The combo box active ID is the signature's ESource UID. */ + uid = e_composer_decode_clue_value (data + 4); + gtk_combo_box_set_active_id (GTK_COMBO_BOX (combo_box), uid); + g_free (uid); +} + +static void +composer_add_auto_recipients (ESource *source, + const gchar *property_name, + GHashTable *hash_table) +{ + ESourceMailComposition *extension; + CamelInternetAddress *inet_addr; + const gchar *extension_name; + gchar *comma_separated_addrs; + gchar **addr_array = NULL; + gint length, ii; + gint retval; + + extension_name = E_SOURCE_EXTENSION_MAIL_COMPOSITION; + extension = e_source_get_extension (source, extension_name); + + g_object_get (extension, property_name, &addr_array, NULL); + + if (addr_array == NULL) + return; + + inet_addr = camel_internet_address_new (); + comma_separated_addrs = g_strjoinv (", ", addr_array); + + retval = camel_address_decode ( + CAMEL_ADDRESS (inet_addr), comma_separated_addrs); + + g_free (comma_separated_addrs); + g_strfreev (addr_array); + + if (retval == -1) + return; + + length = camel_address_length (CAMEL_ADDRESS (inet_addr)); + + for (ii = 0; ii < length; ii++) { + const gchar *name; + const gchar *addr; + + if (camel_internet_address_get (inet_addr, ii, &name, &addr)) + g_hash_table_insert ( + hash_table, + g_strdup (addr), + GINT_TO_POINTER (1)); } - e_composer_header_table_set_signature (table, signature); + g_object_unref (inet_addr); } /** @@ -3080,13 +3063,14 @@ e_msg_composer_new_with_message (EShell *shell, struct _camel_header_raw *headers; CamelDataWrapper *content; CamelSession *session; - EAccount *account = NULL; - gchar *account_name; EMsgComposer *composer; EMsgComposerPrivate *priv; EComposerHeaderTable *table; + ESourceRegistry *registry; + ESource *source = NULL; GtkToggleAction *action; struct _camel_header_raw *xev; + gchar *identity_uid; gint len, i; g_return_val_if_fail (E_IS_SHELL (shell), NULL); @@ -3107,6 +3091,7 @@ e_msg_composer_new_with_message (EShell *shell, priv = E_MSG_COMPOSER_GET_PRIVATE (composer); session = e_msg_composer_get_session (composer); table = e_msg_composer_get_header_table (composer); + registry = e_composer_header_table_get_registry (table); if (postto) { e_composer_header_table_set_post_to_list (table, postto); @@ -3115,22 +3100,12 @@ e_msg_composer_new_with_message (EShell *shell, postto = NULL; } - /* Restore the Account preference */ - account_name = (gchar *) camel_medium_get_header ( - CAMEL_MEDIUM (message), "X-Evolution-Account"); - if (account_name) { - account_name = g_strdup (account_name); - g_strstrip (account_name); - - account = e_get_account_by_uid (account_name); - if (account == NULL) - /* XXX Backwards compatibility */ - account = e_get_account_by_name (account_name); - - if (account != NULL) { - g_free (account_name); - account_name = g_strdup (account->name); - } + /* Restore the mail identity preference. */ + identity_uid = (gchar *) camel_medium_get_header ( + CAMEL_MEDIUM (message), "X-Evolution-Identity"); + if (identity_uid != NULL) { + identity_uid = g_strstrip (g_strdup (identity_uid)); + source = e_source_registry_ref_source (registry, identity_uid); } if (postto == NULL) { @@ -3144,45 +3119,9 @@ e_msg_composer_new_with_message (EShell *shell, (GDestroyNotify) g_free, (GDestroyNotify) NULL); - if (account) { - CamelInternetAddress *iaddr; - - /* hash our auto-recipients for this account */ - if (account->always_cc) { - iaddr = camel_internet_address_new (); - if (camel_address_decode (CAMEL_ADDRESS (iaddr), account->cc_addrs) != -1) { - for (i = 0; i < camel_address_length (CAMEL_ADDRESS (iaddr)); i++) { - const gchar *name, *addr; - - if (!camel_internet_address_get (iaddr, i, &name, &addr)) - continue; - - g_hash_table_insert ( - auto_cc, - g_strdup (addr), - GINT_TO_POINTER (TRUE)); - } - } - g_object_unref (iaddr); - } - - if (account->always_bcc) { - iaddr = camel_internet_address_new (); - if (camel_address_decode (CAMEL_ADDRESS (iaddr), account->bcc_addrs) != -1) { - for (i = 0; i < camel_address_length (CAMEL_ADDRESS (iaddr)); i++) { - const gchar *name, *addr; - - if (!camel_internet_address_get (iaddr, i, &name, &addr)) - continue; - - g_hash_table_insert ( - auto_bcc, - g_strdup (addr), - GINT_TO_POINTER (TRUE)); - } - } - g_object_unref (iaddr); - } + if (source != NULL) { + composer_add_auto_recipients (source, "cc", auto_cc); + composer_add_auto_recipients (source, "bcc", auto_bcc); } to = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_TO); @@ -3200,6 +3139,7 @@ e_msg_composer_new_with_message (EShell *shell, To = g_list_append (To, dest); } } + Tov = destination_list_to_vector (To); g_list_free (To); @@ -3248,15 +3188,18 @@ e_msg_composer_new_with_message (EShell *shell, Bccv = NULL; } + if (source != NULL) + g_object_unref (source); + subject = camel_mime_message_get_subject (message); - e_composer_header_table_set_account_name (table, account_name); + e_composer_header_table_set_identity_uid (table, identity_uid); e_composer_header_table_set_destinations_to (table, Tov); e_composer_header_table_set_destinations_cc (table, Ccv); e_composer_header_table_set_destinations_bcc (table, Bccv); e_composer_header_table_set_subject (table, subject); - g_free (account_name); + g_free (identity_uid); e_destination_freev (Tov); e_destination_freev (Ccv); @@ -3410,7 +3353,7 @@ e_msg_composer_new_with_message (EShell *shell, EMsgComposer * e_msg_composer_new_redirect (EShell *shell, CamelMimeMessage *message, - const gchar *resent_from, + const gchar *identity_uid, GCancellable *cancellable) { EMsgComposer *composer; @@ -3430,7 +3373,7 @@ e_msg_composer_new_redirect (EShell *shell, composer->priv->redirect = message; g_object_ref (message); - e_composer_header_table_set_account_name (table, resent_from); + e_composer_header_table_set_identity_uid (table, identity_uid); e_composer_header_table_set_subject (table, subject); web_view = e_msg_composer_get_web_view (composer); @@ -4198,16 +4141,24 @@ e_msg_composer_set_body (EMsgComposer *composer, const gchar *body, const gchar *mime_type) { - EMsgComposerPrivate *p = composer->priv; + EMsgComposerPrivate *priv = composer->priv; EComposerHeaderTable *table; EWebViewGtkHTML *web_view; + ESourceRegistry *registry; + ESource *source; + const gchar *identity_uid; gchar *buff; g_return_if_fail (E_IS_MSG_COMPOSER (composer)); table = e_msg_composer_get_header_table (composer); + registry = e_composer_header_table_get_registry (table); + + identity_uid = e_composer_header_table_get_identity_uid (table); + source = e_source_registry_ref_source (registry, identity_uid); - buff = g_markup_printf_escaped ("<b>%s</b>", + buff = g_markup_printf_escaped ( + "<b>%s</b>", _("The composer contains a non-text " "message body, which cannot be edited.")); set_editor_text (composer, buff, FALSE); @@ -4218,16 +4169,19 @@ e_msg_composer_set_body (EMsgComposer *composer, web_view = e_msg_composer_get_web_view (composer); e_web_view_gtkhtml_set_editable (web_view, FALSE); - g_free (p->mime_body); - p->mime_body = g_strdup (body); - g_free (p->mime_type); - p->mime_type = g_strdup (mime_type); + g_free (priv->mime_body); + priv->mime_body = g_strdup (body); + g_free (priv->mime_type); + priv->mime_type = g_strdup (mime_type); + + if (g_ascii_strncasecmp (priv->mime_type, "text/calendar", 13) == 0) { + ESourceMailComposition *extension; + const gchar *extension_name; - if (g_ascii_strncasecmp (p->mime_type, "text/calendar", 13) == 0) { - EAccount *account; + extension_name = E_SOURCE_EXTENSION_MAIL_COMPOSITION; + extension = e_source_get_extension (source, extension_name); - account = e_composer_header_table_get_account (table); - if (account && account->pgp_no_imip_sign) { + if (!e_source_mail_composition_get_sign_imip (extension)) { GtkToggleAction *action; action = GTK_TOGGLE_ACTION (ACTION (PGP_SIGN)); @@ -4237,6 +4191,8 @@ e_msg_composer_set_body (EMsgComposer *composer, gtk_toggle_action_set_active (action, FALSE); } } + + g_object_unref (source); } /** @@ -4739,88 +4695,45 @@ e_msg_composer_get_message_draft_finish (EMsgComposer *composer, return g_object_ref (message); } -/** - * e_msg_composer_show_sig: - * @composer: A message composer widget - * - * Set a signature - **/ -void -e_msg_composer_show_sig_file (EMsgComposer *composer) -{ - GtkhtmlEditor *editor; - gchar *html_text; - - g_return_if_fail (E_IS_MSG_COMPOSER (composer)); - - editor = GTKHTML_EDITOR (composer); - - if (composer->priv->redirect) - return; - - composer->priv->in_signature_insert = TRUE; - - gtkhtml_editor_freeze (editor); - gtkhtml_editor_run_command (editor, "cursor-position-save"); - gtkhtml_editor_undo_begin (editor, "Set signature", "Reset signature"); - - /* Delete the old signature. */ - gtkhtml_editor_run_command (editor, "block-selection"); - gtkhtml_editor_run_command (editor, "cursor-bod"); - if (gtkhtml_editor_search_by_data (editor, 1, "ClueFlow", "signature", "1")) { - gtkhtml_editor_run_command (editor, "select-paragraph"); - gtkhtml_editor_run_command (editor, "delete"); - gtkhtml_editor_set_paragraph_data (editor, "signature", "0"); - gtkhtml_editor_run_command (editor, "delete-back"); - } - gtkhtml_editor_run_command (editor, "unblock-selection"); - - html_text = get_signature_html (composer); - if (html_text) { - gtkhtml_editor_run_command (editor, "insert-paragraph"); - if (!gtkhtml_editor_run_command (editor, "cursor-backward")) - gtkhtml_editor_run_command (editor, "insert-paragraph"); - else - gtkhtml_editor_run_command (editor, "cursor-forward"); - - gtkhtml_editor_set_paragraph_data (editor, "orig", "0"); - gtkhtml_editor_run_command (editor, "indent-zero"); - gtkhtml_editor_run_command (editor, "style-normal"); - gtkhtml_editor_insert_html (editor, html_text); - g_free (html_text); - } else if (is_top_signature (composer)) { - /* insert paragraph after the signature ClueFlow things */ - if (gtkhtml_editor_run_command (editor, "cursor-forward")) - gtkhtml_editor_run_command (editor, "insert-paragraph"); - } - - gtkhtml_editor_undo_end (editor); - gtkhtml_editor_run_command (editor, "cursor-position-restore"); - gtkhtml_editor_thaw (editor); - - composer->priv->in_signature_insert = FALSE; -} - CamelInternetAddress * e_msg_composer_get_from (EMsgComposer *composer) { - CamelInternetAddress *address; + CamelInternetAddress *inet_address = NULL; + ESourceMailIdentity *mail_identity; EComposerHeaderTable *table; - EAccount *account; + ESourceRegistry *registry; + ESource *source; + const gchar *extension_name; + const gchar *uid; + gchar *name; + gchar *address; g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL); table = e_msg_composer_get_header_table (composer); - account = e_composer_header_table_get_account (table); - if (account == NULL) - return NULL; + registry = e_composer_header_table_get_registry (table); + uid = e_composer_header_table_get_identity_uid (table); + source = e_source_registry_ref_source (registry, uid); + g_return_val_if_fail (source != NULL, NULL); - address = camel_internet_address_new (); - camel_internet_address_add ( - address, account->id->name, account->id->address); + extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY; + mail_identity = e_source_get_extension (source, extension_name); - return address; + name = e_source_mail_identity_dup_name (mail_identity); + address = e_source_mail_identity_dup_address (mail_identity); + + g_object_unref (source); + + if (name != NULL && address != NULL) { + inet_address = camel_internet_address_new (); + camel_internet_address_add (inet_address, name, address); + } + + g_free (name); + g_free (address); + + return inet_address; } CamelInternetAddress * @@ -4840,8 +4753,8 @@ e_msg_composer_get_reply_to (EMsgComposer *composer) address = camel_internet_address_new (); if (camel_address_unformat (CAMEL_ADDRESS (address), reply_to) == -1) { - g_object_unref (CAMEL_OBJECT (address)); - return NULL; + g_object_unref (address); + address = NULL; } return address; diff --git a/composer/e-msg-composer.h b/composer/e-msg-composer.h index aa63b0e894..318165d740 100644 --- a/composer/e-msg-composer.h +++ b/composer/e-msg-composer.h @@ -25,7 +25,6 @@ #define E_MSG_COMPOSER_H #include <camel/camel.h> -#include <libedataserver/e-account.h> #include <libebook/e-destination.h> #include <gtkhtml-editor.h> #include <misc/e-attachment-view.h> @@ -94,7 +93,7 @@ EMsgComposer * e_msg_composer_new_from_url (EShell *shell, const gchar *url); EMsgComposer * e_msg_composer_new_redirect (EShell *shell, CamelMimeMessage *message, - const gchar *resent_from, + const gchar *identity_uid, GCancellable *cancellable); EFocusTracker * e_msg_composer_get_focus_tracker (EMsgComposer *composer); @@ -172,7 +171,6 @@ CamelMimeMessage * (EMsgComposer *composer, GAsyncResult *result, GError **error); -void e_msg_composer_show_sig_file (EMsgComposer *composer); CamelInternetAddress * e_msg_composer_get_from (EMsgComposer *composer); |