diff --git a/data/org.gnome.evolution.plugin.sender-validator.gschema.xml.in b/data/org.gnome.evolution.plugin.sender-validator.gschema.xml.in index f96e37f3d3..31a2ce86a0 100644 --- a/data/org.gnome.evolution.plugin.sender-validator.gschema.xml.in +++ b/data/org.gnome.evolution.plugin.sender-validator.gschema.xml.in @@ -5,5 +5,10 @@ <_summary>List of assignments for recipient and the address to be used with it <_description>The list is of format 'recipient<tab>sender', where the recipient can be part of the address only and the sender is a full email address, which should match the From address precisely. + + <_default>[] + <_summary>List of assignments for an account, which recipients it accepts + <_description>The list is of format 'recipient<tab>sender', where the recipient can be part of the address only and the sender is a full email address, which should match the From address precisely. + diff --git a/src/plugins/sender-validation/org-gnome-sender-validation.error.xml b/src/plugins/sender-validation/org-gnome-sender-validation.error.xml index f98b338215..f6b3d78938 100644 --- a/src/plugins/sender-validation/org-gnome-sender-validation.error.xml +++ b/src/plugins/sender-validation/org-gnome-sender-validation.error.xml @@ -3,7 +3,13 @@ <_primary>Confirm sender address - <_secondary>The message contains recipient “{0}” for which it is set up to use sender account “{1}”, but the account “{2}” is used instead. + <_secondary>The message contains recipient “{0}” for which it is set to use sender account “{1}”, but the account “{2}” is used instead. + + + + <_primary>Confirm recipient address + <_secondary>The message contains recipient “{0}”, which does not match recipient pattern “{1}” for the account “{2}”. diff --git a/src/plugins/sender-validation/sender-validation.c b/src/plugins/sender-validation/sender-validation.c index f02a04ae4f..a10d6ed4c5 100644 --- a/src/plugins/sender-validation/sender-validation.c +++ b/src/plugins/sender-validation/sender-validation.c @@ -29,7 +29,8 @@ #include "mail/em-event.h" #include "shell/e-shell.h" -#define CONF_KEY_NAME "assignments" +#define RA_CONF_KEY_NAME "assignments" +#define AR_CONF_KEY_NAME "account-for-recipients" gint e_plugin_lib_enable (EPlugin *ep, gint enable); @@ -95,10 +96,10 @@ e_sender_validation_parse_assignments (gchar **in_assignments) } static gboolean -e_sender_validation_ask (GtkWindow *window, - const gchar *recipient, - const gchar *expected_account, - const gchar *used_account) +e_sender_validation_ask_ra (GtkWindow *window, + const gchar *recipient, + const gchar *expected_account, + const gchar *used_account) { gint response; @@ -110,6 +111,22 @@ e_sender_validation_ask (GtkWindow *window, return response == GTK_RESPONSE_YES; } +static gboolean +e_sender_validation_ask_ar (GtkWindow *window, + const gchar *recipient, + const gchar *expected_recipient, + const gchar *used_account) +{ + gint response; + + response = e_alert_run_dialog_for_args (window, + "org.gnome.evolution.plugins.sender-validation:sender-validation-ar", + recipient, expected_recipient, used_account, + NULL); + + return response == GTK_RESPONSE_YES; +} + static gboolean e_sender_validation_check (EMsgComposer *composer) { @@ -121,9 +138,8 @@ e_sender_validation_check (EMsgComposer *composer) g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), FALSE); settings = e_util_ref_settings ("org.gnome.evolution.plugin.sender-validation"); - strv = g_settings_get_strv (settings, CONF_KEY_NAME); - g_clear_object (&settings); + strv = g_settings_get_strv (settings, RA_CONF_KEY_NAME); assignments = e_sender_validation_parse_assignments (strv); if (assignments) { @@ -163,7 +179,7 @@ e_sender_validation_check (EMsgComposer *composer) } if (!has_match && has_mismatch) { - can_send = e_sender_validation_ask (GTK_WINDOW (composer), recipient, has_mismatch->account, from_address); + can_send = e_sender_validation_ask_ra (GTK_WINDOW (composer), recipient, has_mismatch->account, from_address); break; } } @@ -177,6 +193,76 @@ e_sender_validation_check (EMsgComposer *composer) /* Can free 'strv' only after 'assignments', because 'assignments' is using the memory from 'strv' */ g_strfreev (strv); + if (!can_send) { + g_clear_object (&settings); + return can_send; + } + + strv = g_settings_get_strv (settings, AR_CONF_KEY_NAME); + assignments = e_sender_validation_parse_assignments (strv); + + if (assignments) { + EComposerHeaderTable *header_table; + const gchar *from_address; + + header_table = e_msg_composer_get_header_table (composer); + from_address = e_composer_header_table_get_from_address (header_table); + + if (from_address && *from_address) { + GSList *link, *usable_assignments = NULL; + + for (link = assignments; link; link = g_slist_next (link)) { + const Assignment *assignment = link->data; + + /* one account can be in the list multiple times */ + if (camel_strstrcase (from_address, assignment->account)) + usable_assignments = g_slist_prepend (usable_assignments, (gpointer) assignment); + } + + usable_assignments = g_slist_reverse (usable_assignments); + + if (usable_assignments) { + EDestination **destinations; + guint ii; + + destinations = e_composer_header_table_get_destinations (header_table); + + for (ii = 0; destinations && destinations[ii]; ii++) { + EDestination *dest = destinations[ii]; + const gchar *recipient; + + recipient = e_destination_get_address (dest); + + if (recipient && *recipient) { + const Assignment *has_mismatch = NULL; + gboolean has_match = FALSE; + + for (link = usable_assignments; link && !has_match; link = g_slist_next (link)) { + const Assignment *assignment = link->data; + + if (camel_strstrcase (recipient, assignment->recipient)) + has_match = TRUE; + else if (!has_mismatch) + has_mismatch = assignment; + } + + if (!has_match && has_mismatch) { + can_send = e_sender_validation_ask_ar (GTK_WINDOW (composer), recipient, has_mismatch->recipient, from_address); + break; + } + } + } + + e_destination_freev (destinations); + } + } + } + + g_slist_free_full (assignments, e_sender_validation_free_assignment); + /* Can free 'strv' only after 'assignments', because 'assignments' is using the memory from 'strv' */ + g_strfreev (strv); + g_clear_object (&settings); + return can_send; } @@ -197,15 +283,25 @@ enum { typedef struct { GSettings *settings; - GtkWidget *treeview; - GtkWidget *button_add; - GtkWidget *button_edit; - GtkWidget *button_remove; - GtkListStore *store; + /* 'ra' for Recipients~>Account */ + GtkWidget *ra_tree_view; + GtkWidget *ra_button_add; + GtkWidget *ra_button_edit; + GtkWidget *ra_button_remove; + GtkListStore *ra_store; + + /* 'ar' for Account~>Recipients */ + GtkWidget *ar_tree_view; + GtkWidget *ar_button_add; + GtkWidget *ar_button_edit; + GtkWidget *ar_button_remove; + GtkListStore *ar_store; } UIData; static void -commit_changes (UIData *ui) +commit_changes (UIData *ui, + GtkWidget *tree_view, + const gchar *conf_key) { GtkTreeModel *model = NULL; GVariantBuilder builder; @@ -213,7 +309,7 @@ commit_changes (UIData *ui) GtkTreeIter iter; gboolean valid; - model = gtk_tree_view_get_model (GTK_TREE_VIEW (ui->treeview)); + model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view)); valid = gtk_tree_model_get_iter_first (model, &iter); g_variant_builder_init (&builder, G_VARIANT_TYPE ("as")); @@ -245,66 +341,103 @@ commit_changes (UIData *ui) /* A floating GVariant is returned, which is consumed by the g_settings_set_value() */ var = g_variant_builder_end (&builder); - g_settings_set_value (ui->settings, CONF_KEY_NAME, var); + g_settings_set_value (ui->settings, conf_key, var); } static void column_edited (UIData *ui, - gint column, + gint column_index, const gchar *path_string, - const gchar *new_text) + const gchar *new_text, + GtkWidget *tree_view, + const gchar *conf_key) { GtkTreeIter iter; + GtkTreeModel *model; - gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (ui->store), &iter, path_string); + model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view)); + gtk_tree_model_get_iter_from_string (model, &iter, path_string); - gtk_list_store_set (ui->store, &iter, column, new_text, -1); - commit_changes (ui); + gtk_list_store_set (GTK_LIST_STORE (model), &iter, column_index, new_text, -1); + commit_changes (ui, tree_view, conf_key); } static void -recipient_edited_cb (GtkCellRendererText *cell, - const gchar *path_string, - const gchar *new_text, - UIData *ui) +ra_recipient_edited_cb (GtkCellRendererText *cell, + const gchar *path_string, + const gchar *new_text, + UIData *ui) { - column_edited (ui, RECIPIENT_COLUMN, path_string, new_text); + column_edited (ui, RECIPIENT_COLUMN, path_string, new_text, ui->ra_tree_view, RA_CONF_KEY_NAME); } static void -account_edited_cb (GtkCellRendererText *cell, - const gchar *path_string, - const gchar *new_text, - UIData *ui) +ra_account_edited_cb (GtkCellRendererText *cell, + const gchar *path_string, + const gchar *new_text, + UIData *ui) { - column_edited (ui, ACCOUNT_COLUMN, path_string, new_text); + column_edited (ui, ACCOUNT_COLUMN, path_string, new_text, ui->ra_tree_view, RA_CONF_KEY_NAME); } static void -button_add_clicked (GtkButton *button, - UIData *ui) +ar_recipient_edited_cb (GtkCellRendererText *cell, + const gchar *path_string, + const gchar *new_text, + UIData *ui) +{ + column_edited (ui, RECIPIENT_COLUMN, path_string, new_text, ui->ar_tree_view, AR_CONF_KEY_NAME); +} + +static void +ar_account_edited_cb (GtkCellRendererText *cell, + const gchar *path_string, + const gchar *new_text, + UIData *ui) +{ + column_edited (ui, ACCOUNT_COLUMN, path_string, new_text, ui->ar_tree_view, AR_CONF_KEY_NAME); +} + +static void +add_clicked (GtkTreeView *tree_view, + gint column_index) { GtkTreeModel *model; - GtkTreeView *tree_view; GtkTreeViewColumn *column; GtkTreePath *path; GtkTreeIter iter; - tree_view = GTK_TREE_VIEW (ui->treeview); model = gtk_tree_view_get_model (tree_view); gtk_list_store_append (GTK_LIST_STORE (model), &iter); path = gtk_tree_model_get_path (model, &iter); - column = gtk_tree_view_get_column (tree_view, RECIPIENT_COLUMN); + column = gtk_tree_view_get_column (tree_view, column_index); gtk_tree_view_set_cursor (tree_view, path, column, TRUE); gtk_tree_view_row_activated (tree_view, path, column); gtk_tree_path_free (path); } static void -button_remove_clicked (GtkButton *button, +ra_button_add_clicked (GtkButton *button, UIData *ui) +{ + add_clicked (GTK_TREE_VIEW (ui->ra_tree_view), RECIPIENT_COLUMN); +} + +static void +ar_button_add_clicked (GtkButton *button, + UIData *ui) +{ + add_clicked (GTK_TREE_VIEW (ui->ar_tree_view), ACCOUNT_COLUMN); +} + +static void +remove_clicked (UIData *ui, + GtkTreeView *tree_view, + GtkWidget *button_edit, + GtkWidget *button_remove, + const gchar *conf_key) { GtkTreeSelection *selection; GtkTreeModel *model; @@ -314,7 +447,7 @@ button_remove_clicked (GtkButton *button, gint len; valid = FALSE; - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (ui->treeview)); + selection = gtk_tree_view_get_selection (tree_view); if (!gtk_tree_selection_get_selected (selection, &model, &iter)) return; @@ -336,19 +469,34 @@ button_remove_clicked (GtkButton *button, } } } else { - gtk_widget_set_sensitive (ui->button_edit, FALSE); - gtk_widget_set_sensitive (ui->button_remove, FALSE); + gtk_widget_set_sensitive (button_edit, FALSE); + gtk_widget_set_sensitive (button_remove, FALSE); } - gtk_widget_grab_focus (ui->treeview); + gtk_widget_grab_focus (GTK_WIDGET (tree_view)); gtk_tree_path_free (path); - commit_changes (ui); + commit_changes (ui, GTK_WIDGET (tree_view), conf_key); } static void -button_edit_clicked (GtkButton *button, - UIData *ui) +ra_button_remove_clicked (GtkButton *button, + UIData *ui) +{ + remove_clicked (ui, GTK_TREE_VIEW (ui->ra_tree_view), ui->ra_button_edit, ui->ra_button_remove, RA_CONF_KEY_NAME); +} + +static void +ar_button_remove_clicked (GtkButton *button, + UIData *ui) +{ + remove_clicked (ui, GTK_TREE_VIEW (ui->ar_tree_view), ui->ar_button_edit, ui->ar_button_remove, AR_CONF_KEY_NAME); +} + +static void +edit_clicked (UIData *ui, + GtkTreeView *tree_view, + gint column_index) { GtkTreeSelection *selection; GtkTreeModel *model; @@ -356,35 +504,63 @@ button_edit_clicked (GtkButton *button, GtkTreeIter iter; GtkTreeViewColumn *focus_col; - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (ui->treeview)); + selection = gtk_tree_view_get_selection (tree_view); if (!gtk_tree_selection_get_selected (selection, &model, &iter)) return; - focus_col = gtk_tree_view_get_column (GTK_TREE_VIEW (ui->treeview), RECIPIENT_COLUMN); + focus_col = gtk_tree_view_get_column (tree_view, column_index); path = gtk_tree_model_get_path (model, &iter); if (path) { - gtk_tree_view_set_cursor (GTK_TREE_VIEW (ui->treeview), path, focus_col, TRUE); + gtk_tree_view_set_cursor (tree_view, path, focus_col, TRUE); gtk_tree_path_free (path); } } static void -selection_changed_cb (GtkTreeSelection *selection, - UIData *ui) +ra_button_edit_clicked (GtkButton *button, + UIData *ui) +{ + edit_clicked (ui, GTK_TREE_VIEW (ui->ra_tree_view), RECIPIENT_COLUMN); +} + +static void +ar_button_edit_clicked (GtkButton *button, + UIData *ui) +{ + edit_clicked (ui, GTK_TREE_VIEW (ui->ar_tree_view), ACCOUNT_COLUMN); +} + +static void +selection_changed (GtkTreeSelection *selection, + GtkWidget *button_edit, + GtkWidget *button_remove) { - GtkTreeModel *model; GtkTreeIter iter; - if (gtk_tree_selection_get_selected (selection, &model, &iter)) { - gtk_widget_set_sensitive (ui->button_edit, TRUE); - gtk_widget_set_sensitive (ui->button_remove, TRUE); + if (gtk_tree_selection_get_selected (selection, NULL, &iter)) { + gtk_widget_set_sensitive (button_edit, TRUE); + gtk_widget_set_sensitive (button_remove, TRUE); } else { - gtk_widget_set_sensitive (ui->button_edit, FALSE); - gtk_widget_set_sensitive (ui->button_remove, FALSE); + gtk_widget_set_sensitive (button_edit, FALSE); + gtk_widget_set_sensitive (button_remove, FALSE); } } +static void +ra_selection_changed_cb (GtkTreeSelection *selection, + UIData *ui) +{ + selection_changed (selection, ui->ra_button_edit, ui->ra_button_remove); +} + +static void +ar_selection_changed_cb (GtkTreeSelection *selection, + UIData *ui) +{ + selection_changed (selection, ui->ar_button_edit, ui->ar_button_remove); +} + static void destroy_ui_data (gpointer data) { @@ -460,6 +636,7 @@ e_plugin_lib_get_configure_widget (EPlugin *plugin) GtkTreeIter iter; GtkWidget *hbox; GtkWidget *vbox; + GtkWidget *label; GtkWidget *container; GtkWidget *scrolledwindow; GtkWidget *vbuttonbox; @@ -473,6 +650,20 @@ e_plugin_lib_get_configure_widget (EPlugin *plugin) gtk_widget_show (vbox); gtk_widget_set_size_request (vbox, 385, 189); + label = gtk_label_new (_("Set which account should be used for certain recipient patterns.\n" + "For example, setting recipient as “@company.org” for account “me@company.org” will warn when a recipient containing “@company.org” is not used with the “me@company.org” account.")); + g_object_set (label, + "halign", GTK_ALIGN_START, + "hexpand", TRUE, + "valign", GTK_ALIGN_START, + "vexpand", FALSE, + "wrap", TRUE, + "wrap-mode", PANGO_WRAP_WORD, + "max-width-chars", 80, + NULL); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 6); + container = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); gtk_widget_show (container); gtk_box_pack_start (GTK_BOX (vbox), container, TRUE, TRUE, 0); @@ -482,12 +673,12 @@ e_plugin_lib_get_configure_widget (EPlugin *plugin) gtk_box_pack_start (GTK_BOX (container), scrolledwindow, TRUE, TRUE, 0); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - ui->treeview = gtk_tree_view_new (); - gtk_widget_show (ui->treeview); - gtk_container_add (GTK_CONTAINER (scrolledwindow), ui->treeview); - gtk_container_set_border_width (GTK_CONTAINER (ui->treeview), 1); - gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (ui->treeview), TRUE); - gtk_tree_view_set_headers_clickable (GTK_TREE_VIEW (ui->treeview), FALSE); + ui->ra_tree_view = gtk_tree_view_new (); + gtk_widget_show (ui->ra_tree_view); + gtk_container_add (GTK_CONTAINER (scrolledwindow), ui->ra_tree_view); + gtk_container_set_border_width (GTK_CONTAINER (ui->ra_tree_view), 1); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (ui->ra_tree_view), TRUE); + gtk_tree_view_set_headers_clickable (GTK_TREE_VIEW (ui->ra_tree_view), FALSE); vbuttonbox = gtk_button_box_new (GTK_ORIENTATION_VERTICAL); gtk_widget_show (vbuttonbox); @@ -495,74 +686,184 @@ e_plugin_lib_get_configure_widget (EPlugin *plugin) gtk_button_box_set_layout (GTK_BUTTON_BOX (vbuttonbox), GTK_BUTTONBOX_START); gtk_box_set_spacing (GTK_BOX (vbuttonbox), 6); - ui->button_add = e_dialog_button_new_with_icon ("list-add", _("_Add")); - gtk_widget_show (ui->button_add); - gtk_container_add (GTK_CONTAINER (vbuttonbox), ui->button_add); - gtk_widget_set_can_default (ui->button_add, TRUE); + ui->ra_button_add = e_dialog_button_new_with_icon ("list-add", _("_Add")); + gtk_widget_show (ui->ra_button_add); + gtk_container_add (GTK_CONTAINER (vbuttonbox), ui->ra_button_add); + gtk_widget_set_can_default (ui->ra_button_add, TRUE); - ui->button_edit = gtk_button_new_with_mnemonic (_("_Edit")); - gtk_widget_show (ui->button_edit); - gtk_container_add (GTK_CONTAINER (vbuttonbox), ui->button_edit); - gtk_widget_set_can_default (ui->button_edit, TRUE); + ui->ra_button_edit = gtk_button_new_with_mnemonic (_("_Edit")); + gtk_widget_show (ui->ra_button_edit); + gtk_container_add (GTK_CONTAINER (vbuttonbox), ui->ra_button_edit); + gtk_widget_set_can_default (ui->ra_button_edit, TRUE); - ui->button_remove = e_dialog_button_new_with_icon ("list-remove", _("_Remove")); - gtk_widget_show (ui->button_remove); - gtk_container_add (GTK_CONTAINER (vbuttonbox), ui->button_remove); - gtk_widget_set_can_default (ui->button_remove, TRUE); + ui->ra_button_remove = e_dialog_button_new_with_icon ("list-remove", _("_Remove")); + gtk_widget_show (ui->ra_button_remove); + gtk_container_add (GTK_CONTAINER (vbuttonbox), ui->ra_button_remove); + gtk_widget_set_can_default (ui->ra_button_remove, TRUE); ui->settings = e_util_ref_settings ("org.gnome.evolution.plugin.sender-validation"); - ui->store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING); + ui->ra_store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING); - gtk_tree_view_set_model (GTK_TREE_VIEW (ui->treeview), GTK_TREE_MODEL (ui->store)); + gtk_tree_view_set_model (GTK_TREE_VIEW (ui->ra_tree_view), GTK_TREE_MODEL (ui->ra_store)); renderer = gtk_cell_renderer_text_new (); gtk_tree_view_insert_column_with_attributes ( - GTK_TREE_VIEW (ui->treeview), -1, _("Recipient Contains"), + GTK_TREE_VIEW (ui->ra_tree_view), -1, _("Recipient Contains"), renderer, "text", RECIPIENT_COLUMN, NULL); g_object_set (renderer, "editable", TRUE, NULL); g_signal_connect ( renderer, "edited", - G_CALLBACK (recipient_edited_cb), ui); + G_CALLBACK (ra_recipient_edited_cb), ui); renderer = gtk_cell_renderer_combo_new (); e_sender_validation_fill_accounts (GTK_CELL_RENDERER_COMBO (renderer)); gtk_tree_view_insert_column_with_attributes ( - GTK_TREE_VIEW (ui->treeview), -1, _("Account to Use"), + GTK_TREE_VIEW (ui->ra_tree_view), -1, _("Account to Use"), renderer, "text", ACCOUNT_COLUMN, NULL); g_object_set (renderer, "editable", TRUE, NULL); g_signal_connect ( renderer, "edited", - G_CALLBACK (account_edited_cb), ui); + G_CALLBACK (ra_account_edited_cb), ui); - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (ui->treeview)); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (ui->ra_tree_view)); gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); g_signal_connect ( selection, "changed", - G_CALLBACK (selection_changed_cb), ui); - gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (ui->treeview), TRUE); + G_CALLBACK (ra_selection_changed_cb), ui); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (ui->ra_tree_view), TRUE); g_signal_connect ( - ui->button_add, "clicked", - G_CALLBACK (button_add_clicked), ui); + ui->ra_button_add, "clicked", + G_CALLBACK (ra_button_add_clicked), ui); g_signal_connect ( - ui->button_remove, "clicked", - G_CALLBACK (button_remove_clicked), ui); - gtk_widget_set_sensitive (ui->button_remove, FALSE); + ui->ra_button_remove, "clicked", + G_CALLBACK (ra_button_remove_clicked), ui); + gtk_widget_set_sensitive (ui->ra_button_remove, FALSE); g_signal_connect ( - ui->button_edit, "clicked", - G_CALLBACK (button_edit_clicked), ui); - gtk_widget_set_sensitive (ui->button_edit, FALSE); + ui->ra_button_edit, "clicked", + G_CALLBACK (ra_button_edit_clicked), ui); + gtk_widget_set_sensitive (ui->ra_button_edit, FALSE); - strv = g_settings_get_strv (ui->settings, CONF_KEY_NAME); + strv = g_settings_get_strv (ui->settings, RA_CONF_KEY_NAME); assignments = e_sender_validation_parse_assignments (strv); for (link = assignments; link; link = g_slist_next (link)) { const Assignment *assignment = link->data; - gtk_list_store_append (ui->store, &iter); - gtk_list_store_set (ui->store, &iter, + gtk_list_store_append (ui->ra_store, &iter); + gtk_list_store_set (ui->ra_store, &iter, + RECIPIENT_COLUMN, assignment->recipient, + ACCOUNT_COLUMN, assignment->account, + -1); + } + + g_slist_free_full (assignments, e_sender_validation_free_assignment); + g_strfreev (strv); + + label = gtk_label_new (_("Set which recipient patterns can be used for certain account.\n" + "For example, setting account “me@company.org” for recipients “@company.org” will warn when any of the recipients does not contain “@company.org” when sending with the “me@company.org” account.")); + g_object_set (label, + "halign", GTK_ALIGN_START, + "hexpand", TRUE, + "valign", GTK_ALIGN_START, + "vexpand", FALSE, + "wrap", TRUE, + "wrap-mode", PANGO_WRAP_WORD, + "max-width-chars", 80, + NULL); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 6); + + container = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); + gtk_widget_show (container); + gtk_box_pack_start (GTK_BOX (vbox), container, TRUE, TRUE, 0); + + scrolledwindow = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scrolledwindow); + gtk_box_pack_start (GTK_BOX (container), scrolledwindow, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + + ui->ar_tree_view = gtk_tree_view_new (); + gtk_widget_show (ui->ar_tree_view); + gtk_container_add (GTK_CONTAINER (scrolledwindow), ui->ar_tree_view); + gtk_container_set_border_width (GTK_CONTAINER (ui->ar_tree_view), 1); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (ui->ar_tree_view), TRUE); + gtk_tree_view_set_headers_clickable (GTK_TREE_VIEW (ui->ar_tree_view), FALSE); + + vbuttonbox = gtk_button_box_new (GTK_ORIENTATION_VERTICAL); + gtk_widget_show (vbuttonbox); + gtk_box_pack_start (GTK_BOX (container), vbuttonbox, FALSE, TRUE, 0); + gtk_button_box_set_layout (GTK_BUTTON_BOX (vbuttonbox), GTK_BUTTONBOX_START); + gtk_box_set_spacing (GTK_BOX (vbuttonbox), 6); + + ui->ar_button_add = e_dialog_button_new_with_icon ("list-add", _("_Add")); + gtk_widget_show (ui->ar_button_add); + gtk_container_add (GTK_CONTAINER (vbuttonbox), ui->ar_button_add); + + ui->ar_button_edit = gtk_button_new_with_mnemonic (_("_Edit")); + gtk_widget_show (ui->ar_button_edit); + gtk_container_add (GTK_CONTAINER (vbuttonbox), ui->ar_button_edit); + gtk_widget_set_can_default (ui->ar_button_edit, TRUE); + + ui->ar_button_remove = e_dialog_button_new_with_icon ("list-remove", _("_Remove")); + gtk_widget_show (ui->ar_button_remove); + gtk_container_add (GTK_CONTAINER (vbuttonbox), ui->ar_button_remove); + gtk_widget_set_can_default (ui->ar_button_remove, TRUE); + + ui->ar_store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING); + + gtk_tree_view_set_model (GTK_TREE_VIEW (ui->ar_tree_view), GTK_TREE_MODEL (ui->ar_store)); + + renderer = gtk_cell_renderer_combo_new (); + e_sender_validation_fill_accounts (GTK_CELL_RENDERER_COMBO (renderer)); + gtk_tree_view_insert_column_with_attributes ( + GTK_TREE_VIEW (ui->ar_tree_view), -1, _("Account"), + renderer, "text", ACCOUNT_COLUMN, NULL); + g_object_set (renderer, "editable", TRUE, NULL); + g_signal_connect ( + renderer, "edited", + G_CALLBACK (ar_account_edited_cb), ui); + + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_insert_column_with_attributes ( + GTK_TREE_VIEW (ui->ar_tree_view), -1, _("Allow Recipients Which Contain"), + renderer, "text", RECIPIENT_COLUMN, NULL); + g_object_set (renderer, "editable", TRUE, NULL); + g_signal_connect ( + renderer, "edited", + G_CALLBACK (ar_recipient_edited_cb), ui); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (ui->ar_tree_view)); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); + g_signal_connect ( + selection, "changed", + G_CALLBACK (ar_selection_changed_cb), ui); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (ui->ar_tree_view), TRUE); + + g_signal_connect ( + ui->ar_button_add, "clicked", + G_CALLBACK (ar_button_add_clicked), ui); + + g_signal_connect ( + ui->ar_button_remove, "clicked", + G_CALLBACK (ar_button_remove_clicked), ui); + gtk_widget_set_sensitive (ui->ar_button_remove, FALSE); + + g_signal_connect ( + ui->ar_button_edit, "clicked", + G_CALLBACK (ar_button_edit_clicked), ui); + gtk_widget_set_sensitive (ui->ar_button_edit, FALSE); + + strv = g_settings_get_strv (ui->settings, AR_CONF_KEY_NAME); + assignments = e_sender_validation_parse_assignments (strv); + + for (link = assignments; link; link = g_slist_next (link)) { + const Assignment *assignment = link->data; + + gtk_list_store_append (ui->ar_store, &iter); + gtk_list_store_set (ui->ar_store, &iter, RECIPIENT_COLUMN, assignment->recipient, ACCOUNT_COLUMN, assignment->account, -1);