diff --git a/docs/reference/evolution-util/evolution-util-docs.sgml.in b/docs/reference/evolution-util/evolution-util-docs.sgml.in index 20623f090b..d530b8a08c 100644 --- a/docs/reference/evolution-util/evolution-util-docs.sgml.in +++ b/docs/reference/evolution-util/evolution-util-docs.sgml.in @@ -87,6 +87,7 @@ + @@ -323,6 +324,10 @@ Index + + Index of new symbols in 3.42 + + Index of new symbols in 3.40 diff --git a/po/POTFILES.in b/po/POTFILES.in index 546f5876ef..1eb44ae079 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -357,6 +357,7 @@ src/mail/e-mail-ui-session.c src/mail/em-composer-utils.c src/mail/em-filter-editor.c src/mail/em-filter-editor-folder-element.c +src/mail/em-filter-mail-identity-element.c src/mail/em-filter-rule.c src/mail/em-folder-properties.c src/mail/em-folder-selection-button.c diff --git a/src/e-util/CMakeLists.txt b/src/e-util/CMakeLists.txt index f31f678ff8..03b60d8e4b 100644 --- a/src/e-util/CMakeLists.txt +++ b/src/e-util/CMakeLists.txt @@ -129,6 +129,7 @@ set(SOURCES e-filter-file.c e-filter-input.c e-filter-int.c + e-filter-label.c e-filter-option.c e-filter-part.c e-filter-rule.c @@ -404,6 +405,7 @@ set(HEADERS e-filter-file.h e-filter-input.h e-filter-int.h + e-filter-label.h e-filter-option.h e-filter-part.h e-filter-rule.h diff --git a/src/e-util/e-filter-label.c b/src/e-util/e-filter-label.c new file mode 100644 index 0000000000..f6bfcefdd4 --- /dev/null +++ b/src/e-util/e-filter-label.c @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2021 Red Hat (www.redhat.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, see . + * + */ + +#include "evolution-config.h" + +#include + +#include +#include + +#include "e-filter-part.h" + +#include "e-filter-label.h" + +struct _EFilterLabelPrivate { + gchar *title; +}; + +G_DEFINE_TYPE_WITH_PRIVATE (EFilterLabel, e_filter_label, E_TYPE_FILTER_ELEMENT) + +static void +filter_label_finalize (GObject *object) +{ + EFilterLabel *label = E_FILTER_LABEL (object); + + g_free (label->priv->title); + + /* Chain up to parent's method. */ + G_OBJECT_CLASS (e_filter_label_parent_class)->finalize (object); +} + +static gint +filter_label_eq (EFilterElement *element_a, + EFilterElement *element_b) +{ + EFilterLabel *label_a = E_FILTER_LABEL (element_a); + EFilterLabel *label_b = E_FILTER_LABEL (element_b); + + /* Chain up to parent's method. */ + if (!E_FILTER_ELEMENT_CLASS (e_filter_label_parent_class)->eq (element_a, element_b)) + return FALSE; + + return g_strcmp0 (label_a->priv->title, label_b->priv->title) == 0; +} + +static void +filter_label_xml_create (EFilterElement *element, + xmlNodePtr node) +{ + EFilterLabel *label = E_FILTER_LABEL (element); + xmlNodePtr n; + + /* Chain up to parent's method. */ + E_FILTER_ELEMENT_CLASS (e_filter_label_parent_class)->xml_create (element, node); + + n = node->children; + while (n) { + if (!g_strcmp0 ((gchar *) n->name, "title") || + !g_strcmp0 ((gchar *) n->name, "_title")) { + if (!label->priv->title) { + xmlChar *tmp; + + tmp = xmlNodeGetContent (n); + label->priv->title = tmp ? g_strdup ((gchar *) tmp) : NULL; + if (tmp) + xmlFree (tmp); + } + } else if (n->type == XML_ELEMENT_NODE) { + g_warning ("Unknown xml node within 'label': %s\n", n->name); + } + n = n->next; + } +} + +static xmlNodePtr +filter_label_xml_encode (EFilterElement *element) +{ + xmlNodePtr value; + + value = xmlNewNode (NULL, (xmlChar *) "value"); + xmlSetProp (value, (xmlChar *) "name", (xmlChar *) element->name); + + return value; +} + +static gint +filter_label_xml_decode (EFilterElement *element, + xmlNodePtr node) +{ + xmlFree (element->name); + element->name = (gchar *) xmlGetProp (node, (xmlChar *) "name"); + + return 0; +} + +static EFilterElement * +filter_label_clone (EFilterElement *element) +{ + EFilterLabel *label = E_FILTER_LABEL (element); + EFilterLabel *clone_label; + EFilterElement *clone; + + /* Chain up to parent's method. */ + clone = E_FILTER_ELEMENT_CLASS (e_filter_label_parent_class)->clone (element); + + clone_label = E_FILTER_LABEL (clone); + clone_label->priv->title = g_strdup (label->priv->title); + + return clone; +} + +static GtkWidget * +filter_label_get_widget (EFilterElement *element) +{ + EFilterLabel *label = E_FILTER_LABEL (element); + GtkWidget *widget; + + widget = gtk_label_new ((label->priv->title && *label->priv->title) ? _(label->priv->title) : ""); + + return widget; +} + +static void +filter_label_build_code (EFilterElement *element, + GString *out, + EFilterPart *part) +{ +} + +static void +filter_label_format_sexp (EFilterElement *element, + GString *out) +{ +} + +static void +filter_label_describe (EFilterElement *element, + GString *out) +{ + EFilterLabel *label = E_FILTER_LABEL (element); + + if (label->priv->title && *label->priv->title) + g_string_append (out, _(label->priv->title)); +} + +static void +e_filter_label_class_init (EFilterLabelClass *class) +{ + GObjectClass *object_class; + EFilterElementClass *filter_element_class; + + object_class = G_OBJECT_CLASS (class); + object_class->finalize = filter_label_finalize; + + filter_element_class = E_FILTER_ELEMENT_CLASS (class); + filter_element_class->eq = filter_label_eq; + filter_element_class->xml_create = filter_label_xml_create; + filter_element_class->xml_encode = filter_label_xml_encode; + filter_element_class->xml_decode = filter_label_xml_decode; + filter_element_class->clone = filter_label_clone; + filter_element_class->get_widget = filter_label_get_widget; + filter_element_class->build_code = filter_label_build_code; + filter_element_class->format_sexp = filter_label_format_sexp; + filter_element_class->describe = filter_label_describe; +} + +static void +e_filter_label_init (EFilterLabel *label) +{ + label->priv = e_filter_label_get_instance_private (label); +} + +EFilterElement * +e_filter_label_new (void) +{ + return g_object_new (E_TYPE_FILTER_LABEL, NULL); +} + +void +e_filter_label_set_title (EFilterLabel *label, + const gchar *title) +{ + g_return_if_fail (E_IS_FILTER_LABEL (label)); + + if (label->priv->title != title) { + g_free (label->priv->title); + label->priv->title = g_strdup (title); + } +} + +const gchar * +e_filter_label_get_title (EFilterLabel *label) +{ + g_return_val_if_fail (E_IS_FILTER_LABEL (label), NULL); + + return label->priv->title; +} diff --git a/src/e-util/e-filter-label.h b/src/e-util/e-filter-label.h new file mode 100644 index 0000000000..865f041295 --- /dev/null +++ b/src/e-util/e-filter-label.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2021 Red Hat (www.redhat.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, see . + * + */ + +#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION) +#error "Only should be included directly." +#endif + +#ifndef E_FILTER_LABEL_H +#define E_FILTER_LABEL_H + +#include + +/* Standard GObject macros */ +#define E_TYPE_FILTER_LABEL \ + (e_filter_label_get_type ()) +#define E_FILTER_LABEL(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_FILTER_LABEL, EFilterLabel)) +#define E_FILTER_LABEL_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_FILTER_LABEL, EFilterLabelClass)) +#define E_IS_FILTER_LABEL(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_FILTER_LABEL)) +#define E_IS_FILTER_LABEL_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_FILTER_LABEL)) +#define E_FILTER_LABEL_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_FILTER_LABEL, EFilterLabelClass)) + +G_BEGIN_DECLS + +typedef struct _EFilterLabel EFilterLabel; +typedef struct _EFilterLabelClass EFilterLabelClass; +typedef struct _EFilterLabelPrivate EFilterLabelPrivate; + +struct _EFilterLabel { + EFilterElement parent; + EFilterLabelPrivate *priv; +}; + +struct _EFilterLabelClass { + EFilterElementClass parent_class; +}; + +GType e_filter_label_get_type (void) G_GNUC_CONST; +EFilterElement *e_filter_label_new (void); +void e_filter_label_set_title (EFilterLabel *option, + const gchar *title); +const gchar * e_filter_label_get_title (EFilterLabel *option); + +G_END_DECLS + +#endif /* E_FILTER_LABEL_H */ diff --git a/src/e-util/e-mail-identity-combo-box.c b/src/e-util/e-mail-identity-combo-box.c index 4bd6bb5ef1..88c78a543f 100644 --- a/src/e-util/e-mail-identity-combo-box.c +++ b/src/e-util/e-mail-identity-combo-box.c @@ -45,6 +45,8 @@ struct _EMailIdentityComboBoxPrivate { gulong source_changed_handler_id; gulong source_removed_handler_id; + gchar *none_title; + gboolean allow_none; gboolean allow_aliases; @@ -256,6 +258,7 @@ mail_identity_combo_box_dispose (GObject *object) priv->refresh_idle_id = 0; } + g_clear_pointer (&priv->none_title, g_free); g_clear_object (&priv->registry); /* Chain up to parent's dispose() method. */ @@ -691,7 +694,7 @@ e_mail_identity_combo_box_refresh (EMailIdentityComboBox *combo_box) gtk_list_store_set ( GTK_LIST_STORE (tree_model), &iter, - E_MAIL_IDENTITY_COMBO_BOX_COLUMN_DISPLAY_NAME, _("None"), + E_MAIL_IDENTITY_COMBO_BOX_COLUMN_DISPLAY_NAME, e_mail_identity_combo_box_get_none_title (combo_box), E_MAIL_IDENTITY_COMBO_BOX_COLUMN_UID, "", E_MAIL_IDENTITY_COMBO_BOX_COLUMN_COMBO_ID, "", -1); @@ -776,6 +779,47 @@ e_mail_identity_combo_box_set_allow_none (EMailIdentityComboBox *combo_box, e_mail_identity_combo_box_refresh (combo_box); } +/** + * e_mail_identity_combo_box_get_none_title: + * @combo_box: an #EMailIdentityComboBox + * + * Returns: what title the none item should have + * + * Since: 3.42 + **/ +const gchar * +e_mail_identity_combo_box_get_none_title (EMailIdentityComboBox *combo_box) +{ + g_return_val_if_fail (E_IS_MAIL_IDENTITY_COMBO_BOX (combo_box), NULL); + + if (combo_box->priv->none_title) + return combo_box->priv->none_title; + + return _("None"); +} + +/** + * e_mail_identity_combo_box_set_none_title: + * @combo_box: an #EMailIdentityComboBox + * @none_title: (nullable): a title to use, or %NULL + * + * Set what title the none item should have. This is a user visible string, thus + * it should be localized. Use %NULL to reset to the default "None" title. + * + * Since: 3.42 + **/ +void +e_mail_identity_combo_box_set_none_title (EMailIdentityComboBox *combo_box, + const gchar *none_title) +{ + g_return_if_fail (E_IS_MAIL_IDENTITY_COMBO_BOX (combo_box)); + + if (combo_box->priv->none_title != none_title) { + g_free (combo_box->priv->none_title); + combo_box->priv->none_title = g_strdup (none_title); + } +} + /** * e_mail_identity_combo_box_get_allow_aliases: * @combo_box: an #EMailIdentityComboBox diff --git a/src/e-util/e-mail-identity-combo-box.h b/src/e-util/e-mail-identity-combo-box.h index 36d75e6bed..e926190e0b 100644 --- a/src/e-util/e-mail-identity-combo-box.h +++ b/src/e-util/e-mail-identity-combo-box.h @@ -87,6 +87,11 @@ gboolean e_mail_identity_combo_box_get_allow_none void e_mail_identity_combo_box_set_allow_none (EMailIdentityComboBox *combo_box, gboolean allow_none); +const gchar * e_mail_identity_combo_box_get_none_title + (EMailIdentityComboBox *combo_box); +void e_mail_identity_combo_box_set_none_title + (EMailIdentityComboBox *combo_box, + const gchar *none_title); gboolean e_mail_identity_combo_box_get_allow_aliases (EMailIdentityComboBox *combo_box); void e_mail_identity_combo_box_set_allow_aliases diff --git a/src/e-util/e-rule-context.c b/src/e-util/e-rule-context.c index 8d73fcf1f7..4f72f7ad35 100644 --- a/src/e-util/e-rule-context.c +++ b/src/e-util/e-rule-context.c @@ -45,6 +45,7 @@ #include "e-filter-file.h" #include "e-filter-input.h" #include "e-filter-int.h" +#include "e-filter-label.h" #include "e-filter-option.h" #include "e-filter-rule.h" #include "e-rule-context.h" @@ -460,7 +461,9 @@ static EFilterElement * rule_context_new_element (ERuleContext *context, const gchar *type) { - if (!strcmp (type, "string")) { + if (!strcmp (type, "label")) { + return (EFilterElement *) e_filter_label_new (); + } else if (!strcmp (type, "string")) { return (EFilterElement *) e_filter_input_new (); } else if (!strcmp (type, "address")) { /* FIXME: temporary ... need real address type */ diff --git a/src/e-util/e-util.h b/src/e-util/e-util.h index d6a50b85d6..c430fed8bd 100644 --- a/src/e-util/e-util.h +++ b/src/e-util/e-util.h @@ -114,6 +114,7 @@ #include #include #include +#include #include #include #include diff --git a/src/libemail-engine/e-mail-session.c b/src/libemail-engine/e-mail-session.c index 8c7d410fc3..e1dbe548ff 100644 --- a/src/libemail-engine/e-mail-session.c +++ b/src/libemail-engine/e-mail-session.c @@ -1523,6 +1523,67 @@ mail_session_forget_password (CamelSession *session, return TRUE; } +/* Expects 'forward_with' encoded as: "identity_uid|alias_name|alias_address" with '\\' and '|' being backslash-escaped */ +static ESource * +mail_session_decode_forward_with (ESourceRegistry *registry, + const gchar *forward_with, + gchar **out_alias_name, + gchar **out_alias_address) +{ + ESource *source = NULL; + GString *str; + gint step; + const gchar *ptr; + + if (!forward_with || !*forward_with) + return NULL; + + str = g_string_sized_new (strlen (forward_with)); + + for (step = 0, ptr = forward_with; *ptr; ptr++) { + if (*ptr == '\\' && ptr[1]) { + g_string_append_c (str, ptr[1]); + ptr++; + g_string_append_c (str, *ptr); + } else if (*ptr == '|') { + if (step == 0) { /* identity_uid */ + source = e_source_registry_ref_source (registry, str->str); + if (!source) + break; + } else if (step == 1) { /* alias_name */ + if (str->len) + *out_alias_name = g_strdup (str->str); + } else if (step == 2) { /* alias_address */ + if (str->len) + *out_alias_address = g_strdup (str->str); + } + + g_string_truncate (str, 0); + step++; + + if (step == 3) + break; + } else { + g_string_append_c (str, *ptr); + } + } + + /* When the string doesn't end with the '|' */ + if (step < 3 && str->len) { + if (step == 0) { /* identity_uid */ + source = e_source_registry_ref_source (registry, str->str); + } else if (step == 1) { /* alias_name */ + *out_alias_name = g_strdup (str->str); + } else if (step == 2) { /* alias_address */ + *out_alias_address = g_strdup (str->str); + } + } + + g_string_free (str, TRUE); + + return source; +} + static gboolean mail_session_forward_to_sync (CamelSession *session, CamelFolder *folder, @@ -1569,9 +1630,16 @@ mail_session_forward_to_sync (CamelSession *session, registry = e_mail_session_get_registry (E_MAIL_SESSION (session)); - /* This returns a new ESource reference. */ - source = em_utils_guess_mail_identity_with_recipients ( - registry, message, folder, NULL, &alias_name, &alias_address); + source = mail_session_decode_forward_with (registry, + camel_medium_get_header (CAMEL_MEDIUM (message), "X-Evolution-Forward-With"), + &alias_name, &alias_address); + + if (!source) { + /* This returns a new ESource reference. */ + source = em_utils_guess_mail_identity_with_recipients ( + registry, message, folder, NULL, &alias_name, &alias_address); + } + if (source == NULL) { g_set_error ( error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, diff --git a/src/mail/CMakeLists.txt b/src/mail/CMakeLists.txt index 5d08d13928..0cd0a9a842 100644 --- a/src/mail/CMakeLists.txt +++ b/src/mail/CMakeLists.txt @@ -100,6 +100,7 @@ set(SOURCES em-filter-context.c em-filter-editor.c em-filter-editor-folder-element.c + em-filter-mail-identity-element.c em-filter-rule.c em-filter-source-element.c em-folder-properties.c @@ -191,6 +192,7 @@ set(HEADERS em-filter-context.h em-filter-editor.h em-filter-editor-folder-element.h + em-filter-mail-identity-element.h em-filter-rule.h em-filter-source-element.h em-folder-properties.h diff --git a/src/mail/em-filter-context.c b/src/mail/em-filter-context.c index 445327fd81..cd62dfe721 100644 --- a/src/mail/em-filter-context.c +++ b/src/mail/em-filter-context.c @@ -26,10 +26,9 @@ #include "em-filter-context.h" #include "em-filter-rule.h" -#include "em-filter-source-element.h" - -/* For poking into filter-folder guts */ #include "em-filter-editor-folder-element.h" +#include "em-filter-mail-identity-element.h" +#include "em-filter-source-element.h" #define EM_FILTER_CONTEXT_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ @@ -238,6 +237,9 @@ filter_context_new_element (ERuleContext *context, if (strcmp (type, "source") == 0) return em_filter_source_element_new (priv->session); + if (strcmp (type, "mail-identity") == 0) + return em_filter_mail_identity_element_new (e_mail_session_get_registry (priv->session)); + return E_RULE_CONTEXT_CLASS (em_filter_context_parent_class)-> new_element (context, type); } diff --git a/src/mail/em-filter-mail-identity-element.c b/src/mail/em-filter-mail-identity-element.c new file mode 100644 index 0000000000..3370c7ed79 --- /dev/null +++ b/src/mail/em-filter-mail-identity-element.c @@ -0,0 +1,350 @@ +/* + * Copyright (C) 2021 Red Hat (www.redhat.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, see . + * + */ + +#include "evolution-config.h" + +#include + +#include +#include + +#include "e-util/e-util.h" +#include "em-filter-mail-identity-element.h" + +struct _EMFilterMailIdentityElementPrivate { + ESourceRegistry *registry; + gchar *display_name; + gchar *identity_uid; + gchar *alias_name; + gchar *alias_address; +}; + +G_DEFINE_TYPE_WITH_PRIVATE (EMFilterMailIdentityElement, em_filter_mail_identity_element, E_TYPE_FILTER_ELEMENT) + +static void +filter_mail_identity_take_value (EMFilterMailIdentityElement *mail_identity, + gchar *display_name, + gchar *identity_uid, + gchar *alias_name, + gchar *alias_address) +{ + if (mail_identity->priv->display_name != display_name) { + g_free (mail_identity->priv->display_name); + mail_identity->priv->display_name = display_name; + } else { + g_free (display_name); + } + + if (mail_identity->priv->identity_uid != identity_uid) { + g_free (mail_identity->priv->identity_uid); + mail_identity->priv->identity_uid = identity_uid; + } else { + g_free (identity_uid); + } + + if (mail_identity->priv->alias_name != alias_name) { + g_free (mail_identity->priv->alias_name); + mail_identity->priv->alias_name = alias_name; + } else { + g_free (alias_name); + } + + if (mail_identity->priv->alias_address != alias_address) { + g_free (mail_identity->priv->alias_address); + mail_identity->priv->alias_address = alias_address; + } else { + g_free (alias_address); + } +} + +static void +filter_mail_identity_element_finalize (GObject *object) +{ + EMFilterMailIdentityElement *mail_identity = EM_FILTER_MAIL_IDENTITY_ELEMENT (object); + + g_clear_object (&mail_identity->priv->registry); + g_free (mail_identity->priv->display_name); + g_free (mail_identity->priv->identity_uid); + g_free (mail_identity->priv->alias_name); + g_free (mail_identity->priv->alias_address); + + /* Chain up to parent's method. */ + G_OBJECT_CLASS (em_filter_mail_identity_element_parent_class)->finalize (object); +} + +static gint +filter_mail_identity_element_eq (EFilterElement *element_a, + EFilterElement *element_b) +{ + EMFilterMailIdentityElement *mail_identity_a = EM_FILTER_MAIL_IDENTITY_ELEMENT (element_a); + EMFilterMailIdentityElement *mail_identity_b = EM_FILTER_MAIL_IDENTITY_ELEMENT (element_b); + + /* Chain up to parent's method. */ + if (!E_FILTER_ELEMENT_CLASS (em_filter_mail_identity_element_parent_class)->eq (element_a, element_b)) + return FALSE; + + return g_strcmp0 (mail_identity_a->priv->display_name, mail_identity_b->priv->display_name) == 0 && + g_strcmp0 (mail_identity_a->priv->identity_uid, mail_identity_b->priv->identity_uid) == 0 && + g_strcmp0 (mail_identity_a->priv->alias_name, mail_identity_b->priv->alias_name) == 0 && + g_strcmp0 (mail_identity_a->priv->alias_address, mail_identity_b->priv->alias_address) == 0; +} + +static void +filter_mail_identity_element_xml_create (EFilterElement *element, + xmlNodePtr node) +{ + xmlNodePtr n; + + /* Chain up to parent's method. */ + E_FILTER_ELEMENT_CLASS (em_filter_mail_identity_element_parent_class)->xml_create (element, node); + + n = node->children; + while (n) { + if (n->type == XML_ELEMENT_NODE) { + g_warning ("Unknown xml node within 'label': %s\n", n->name); + } + n = n->next; + } +} + +static xmlNodePtr +filter_mail_identity_element_xml_encode (EFilterElement *element) +{ + EMFilterMailIdentityElement *mail_identity = EM_FILTER_MAIL_IDENTITY_ELEMENT (element); + xmlNodePtr value; + + value = xmlNewNode (NULL, (xmlChar *) "value"); + xmlSetProp (value, (xmlChar *) "name", (xmlChar *) element->name); + + if (mail_identity->priv->display_name) + xmlSetProp (value, (xmlChar *) "display-name", (xmlChar *) mail_identity->priv->display_name); + + if (mail_identity->priv->identity_uid) + xmlSetProp (value, (xmlChar *) "identity-uid", (xmlChar *) mail_identity->priv->identity_uid); + + if (mail_identity->priv->alias_name) + xmlSetProp (value, (xmlChar *) "alias-name", (xmlChar *) mail_identity->priv->alias_name); + + if (mail_identity->priv->alias_address) + xmlSetProp (value, (xmlChar *) "alias-address", (xmlChar *) mail_identity->priv->alias_address); + + return value; +} + +static gint +filter_mail_identity_element_xml_decode (EFilterElement *element, + xmlNodePtr node) +{ + EMFilterMailIdentityElement *mail_identity = EM_FILTER_MAIL_IDENTITY_ELEMENT (element); + xmlChar *x_display_name, *x_identity_uid, *x_alias_name, *x_alias_address; + + xmlFree (element->name); + element->name = (gchar *) xmlGetProp (node, (xmlChar *) "name"); + + x_display_name = xmlGetProp (node, (xmlChar *) "display-name"); + x_identity_uid = xmlGetProp (node, (xmlChar *) "identity-uid"); + x_alias_name = xmlGetProp (node, (xmlChar *) "alias-name"); + x_alias_address = xmlGetProp (node, (xmlChar *) "alias-address"); + + filter_mail_identity_take_value (mail_identity, + g_strdup ((gchar *) x_display_name), + g_strdup ((gchar *) x_identity_uid), + g_strdup ((gchar *) x_alias_name), + g_strdup ((gchar *) x_alias_address)); + + g_clear_pointer (&x_display_name, xmlFree); + g_clear_pointer (&x_identity_uid, xmlFree); + g_clear_pointer (&x_alias_name, xmlFree); + g_clear_pointer (&x_alias_address, xmlFree); + + return 0; +} + +static EFilterElement * +filter_mail_identity_element_clone (EFilterElement *element) +{ + EMFilterMailIdentityElement *mail_identity = EM_FILTER_MAIL_IDENTITY_ELEMENT (element); + EMFilterMailIdentityElement *clone_mail_identity; + EFilterElement *clone; + + /* Chain up to parent's method. */ + clone = E_FILTER_ELEMENT_CLASS (em_filter_mail_identity_element_parent_class)->clone (element); + + clone_mail_identity = EM_FILTER_MAIL_IDENTITY_ELEMENT (clone); + clone_mail_identity->priv->display_name = g_strdup (mail_identity->priv->display_name); + clone_mail_identity->priv->identity_uid = g_strdup (mail_identity->priv->identity_uid); + clone_mail_identity->priv->alias_name = g_strdup (mail_identity->priv->alias_name); + clone_mail_identity->priv->alias_address = g_strdup (mail_identity->priv->alias_address); + + if (mail_identity->priv->registry) + clone_mail_identity->priv->registry = g_object_ref (mail_identity->priv->registry); + + return clone; +} + +static void +filter_mail_identity_element_changed_cb (GtkComboBox *combo_box, + gpointer user_data) +{ + EMFilterMailIdentityElement *mail_identity = user_data; + GtkTreeIter iter; + gchar *display_name = NULL, *identity_uid = NULL, *alias_name = NULL, *alias_address = NULL; + + g_return_if_fail (EM_IS_FILTER_MAIL_IDENTITY_ELEMENT (mail_identity)); + + if (!e_mail_identity_combo_box_get_active_uid (E_MAIL_IDENTITY_COMBO_BOX (combo_box), &identity_uid, &alias_name, &alias_address)) { + identity_uid = NULL; + alias_name = NULL; + alias_address = NULL; + } + + if (gtk_combo_box_get_active_iter (combo_box, &iter)) { + GtkTreeModel *model; + + model = gtk_combo_box_get_model (combo_box); + gtk_tree_model_get (model, &iter, + E_MAIL_IDENTITY_COMBO_BOX_COLUMN_DISPLAY_NAME, &display_name, + -1); + } + + filter_mail_identity_take_value (mail_identity, display_name, identity_uid, alias_name, alias_address); +} + +static GtkWidget * +filter_mail_identity_element_get_widget (EFilterElement *element) +{ + EMFilterMailIdentityElement *mail_identity = EM_FILTER_MAIL_IDENTITY_ELEMENT (element); + EMailIdentityComboBox *combo_box; + GtkWidget *widget; + + widget = e_mail_identity_combo_box_new (mail_identity->priv->registry); + combo_box = E_MAIL_IDENTITY_COMBO_BOX (widget); + e_mail_identity_combo_box_set_none_title (combo_box, _("Default Account")); + e_mail_identity_combo_box_set_allow_none (combo_box, TRUE); + e_mail_identity_combo_box_set_allow_aliases (combo_box, TRUE); + + g_signal_connect_object (combo_box, "changed", + G_CALLBACK (filter_mail_identity_element_changed_cb), mail_identity, 0); + + if (mail_identity->priv->identity_uid) { + e_mail_identity_combo_box_set_active_uid (combo_box, + mail_identity->priv->identity_uid, + mail_identity->priv->alias_name, + mail_identity->priv->alias_address); + } else { + e_mail_identity_combo_box_set_active_uid (combo_box, "", NULL, NULL); + } + + return widget; +} + +static void +filter_mail_identity_element_add_value (GString *str, + const gchar *value) +{ + const gchar *pp; + + if (!value) + return; + + for (pp = value; *pp; pp++) { + if (*pp == '\\' || *pp == '|') + g_string_append_c (str, '\\'); + g_string_append_c (str, *pp); + } +} + +static void +filter_mail_identity_element_format_sexp (EFilterElement *element, + GString *out) +{ + EMFilterMailIdentityElement *mail_identity = EM_FILTER_MAIL_IDENTITY_ELEMENT (element); + GString *value = NULL; + + if (mail_identity->priv->identity_uid && *mail_identity->priv->identity_uid) { + /* Encode the value as: "identity_uid|alias_name|alias_value" */ + value = g_string_sized_new (strlen (mail_identity->priv->identity_uid) * 2); + + filter_mail_identity_element_add_value (value, mail_identity->priv->identity_uid); + g_string_append_c (value, '|'); + filter_mail_identity_element_add_value (value, mail_identity->priv->alias_name); + g_string_append_c (value, '|'); + filter_mail_identity_element_add_value (value, mail_identity->priv->alias_address); + } + + camel_sexp_encode_string (out, value ? value->str : NULL); + + if (value) + g_string_free (value, TRUE); +} + +static void +filter_mail_identity_element_describe (EFilterElement *element, + GString *out) +{ + EMFilterMailIdentityElement *mail_identity = EM_FILTER_MAIL_IDENTITY_ELEMENT (element); + + if (mail_identity->priv->display_name && *mail_identity->priv->display_name) + g_string_append (out, mail_identity->priv->display_name); +} + +static void +em_filter_mail_identity_element_class_init (EMFilterMailIdentityElementClass *class) +{ + GObjectClass *object_class; + EFilterElementClass *filter_element_class; + + object_class = G_OBJECT_CLASS (class); + object_class->finalize = filter_mail_identity_element_finalize; + + filter_element_class = E_FILTER_ELEMENT_CLASS (class); + filter_element_class->eq = filter_mail_identity_element_eq; + filter_element_class->xml_create = filter_mail_identity_element_xml_create; + filter_element_class->xml_encode = filter_mail_identity_element_xml_encode; + filter_element_class->xml_decode = filter_mail_identity_element_xml_decode; + filter_element_class->clone = filter_mail_identity_element_clone; + filter_element_class->get_widget = filter_mail_identity_element_get_widget; + filter_element_class->format_sexp = filter_mail_identity_element_format_sexp; + filter_element_class->describe = filter_mail_identity_element_describe; +} + +static void +em_filter_mail_identity_element_init (EMFilterMailIdentityElement *mail_identity) +{ + mail_identity->priv = em_filter_mail_identity_element_get_instance_private (mail_identity); +} + +EFilterElement * +em_filter_mail_identity_element_new (ESourceRegistry *registry) +{ + EMFilterMailIdentityElement *mail_identity; + + g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL); + + mail_identity = g_object_new (EM_TYPE_FILTER_MAIL_IDENTITY_ELEMENT, NULL); + mail_identity->priv->registry = g_object_ref (registry); + + return E_FILTER_ELEMENT (mail_identity); +} + +ESourceRegistry * +em_filter_mail_identity_element_get_registry (EMFilterMailIdentityElement *mail_identity) +{ + g_return_val_if_fail (EM_IS_FILTER_MAIL_IDENTITY_ELEMENT (mail_identity), NULL); + + return mail_identity->priv->registry; +} diff --git a/src/mail/em-filter-mail-identity-element.h b/src/mail/em-filter-mail-identity-element.h new file mode 100644 index 0000000000..19d1f4a38a --- /dev/null +++ b/src/mail/em-filter-mail-identity-element.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2021 Red Hat (www.redhat.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, see . + * + */ + +#ifndef EM_FILTER_MAIL_IDENTITY_ELEMENT_H +#define EM_FILTER_MAIL_IDENTITY_ELEMENT_H + +#include +#include + +/* Standard GObject macros */ +#define EM_TYPE_FILTER_MAIL_IDENTITY_ELEMENT \ + (em_filter_mail_identity_element_get_type ()) +#define EM_FILTER_MAIL_IDENTITY_ELEMENT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), EM_TYPE_FILTER_MAIL_IDENTITY_ELEMENT, EMFilterMailIdentityElement)) +#define EM_FILTER_MAIL_IDENTITY_ELEMENT_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), EM_TYPE_FILTER_MAIL_IDENTITY_ELEMENT, EMFilterMailIdentityElementClass)) +#define EM_IS_FILTER_MAIL_IDENTITY_ELEMENT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), EM_TYPE_FILTER_MAIL_IDENTITY_ELEMENT)) +#define EM_IS_FILTER_MAIL_IDENTITY_ELEMENT_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), EM_TYPE_FILTER_MAIL_IDENTITY_ELEMENT)) +#define EM_FILTER_MAIL_IDENTITY_ELEMENT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), EM_TYPE_FILTER_MAIL_IDENTITY_ELEMENT, EMFilterMailIdentityElementClass)) + +G_BEGIN_DECLS + +typedef struct _EMFilterMailIdentityElement EMFilterMailIdentityElement; +typedef struct _EMFilterMailIdentityElementClass EMFilterMailIdentityElementClass; +typedef struct _EMFilterMailIdentityElementPrivate EMFilterMailIdentityElementPrivate; + +struct _EMFilterMailIdentityElement { + EFilterElement parent; + EMFilterMailIdentityElementPrivate *priv; +}; + +struct _EMFilterMailIdentityElementClass { + EFilterElementClass parent_class; +}; + +GType em_filter_mail_identity_element_get_type (void) G_GNUC_CONST; +EFilterElement *em_filter_mail_identity_element_new (ESourceRegistry *registry); +ESourceRegistry * + em_filter_mail_identity_element_get_registry (EMFilterMailIdentityElement *mail_identity); + +G_END_DECLS + +#endif /* EM_FILTER_MAIL_IDENTITY_ELEMENT_H */ diff --git a/src/mail/filtertypes.xml.in b/src/mail/filtertypes.xml.in index d963bc65af..c5cec3f601 100644 --- a/src/mail/filtertypes.xml.in +++ b/src/mail/filtertypes.xml.in @@ -806,8 +806,12 @@ <_title>Forward to - (forward-to ${address}) + (forward-to ${address} ${from}) + + <_title>with + +