aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--filter/e-filter-option.c85
-rw-r--r--filter/e-filter-option.h7
-rw-r--r--mail/filtertypes.xml10
-rw-r--r--mail/searchtypes.xml10
-rw-r--r--mail/vfoldertypes.xml8
-rw-r--r--modules/mail/e-mail-shell-backend.c143
-rw-r--r--modules/mail/e-mail-shell-backend.h10
7 files changed, 234 insertions, 39 deletions
diff --git a/filter/e-filter-option.c b/filter/e-filter-option.c
index 2f6c73454d..dd6d9b8874 100644
--- a/filter/e-filter-option.c
+++ b/filter/e-filter-option.c
@@ -45,6 +45,7 @@ free_option (struct _filter_option *opt)
g_free (opt->title);
g_free (opt->value);
g_free (opt->code);
+ g_free (opt->code_gen_func);
g_free (opt);
}
@@ -101,6 +102,29 @@ filter_option_get_dynamic_options (EFilterOption *option)
}
static void
+filter_option_generate_code (EFilterOption *option,
+ GString *out,
+ EFilterPart *part)
+{
+ GModule *module;
+ void (*code_gen_func) (EFilterElement *element, GString *out, EFilterPart *part);
+
+ if (!option || !option->current || !option->current->code_gen_func)
+ return;
+
+ module = g_module_open (NULL, G_MODULE_BIND_LAZY);
+
+ if (g_module_symbol (module, option->current->code_gen_func, (gpointer) &code_gen_func)) {
+ code_gen_func (E_FILTER_ELEMENT (option), out, part);
+ } else {
+ g_warning ("optionlist dynamic code function '%s' not found",
+ option->current->code_gen_func);
+ }
+
+ g_module_close (module);
+}
+
+static void
filter_option_finalize (GObject *object)
{
EFilterOption *option = E_FILTER_OPTION (object);
@@ -149,7 +173,7 @@ filter_option_xml_create (EFilterElement *element,
n = node->children;
while (n) {
if (!strcmp ((gchar *)n->name, "option")) {
- gchar *tmp, *value, *title = NULL, *code = NULL;
+ gchar *tmp, *value, *title = NULL, *code = NULL, *code_gen_func = NULL;
value = (gchar *)xmlGetProp (n, (xmlChar *)"value");
work = n->children;
@@ -164,21 +188,43 @@ filter_option_xml_create (EFilterElement *element,
xmlFree (tmp);
}
} else if (!strcmp ((gchar *)work->name, "code")) {
- if (!code) {
- if (!(tmp = (gchar *) xmlNodeGetContent (work)))
- tmp = (gchar *)xmlStrdup ((xmlChar *)"");
+ if (code || code_gen_func) {
+ g_warning ("Element 'code' defined twice in '%s'",
+ element->name);
+ } else {
+ xmlChar *fn;
+
+ /* if element 'code' has attribute 'func', then
+ the content of the element is ignored and only
+ the 'func' is used to generate actual rule code;
+ The function prototype is:
+ void code_gen_func (EFilterElement *element, GString *out, EFilterPart *part);
+ where @element is the one on which was called,
+ @out is GString where to add the code, and
+ @part is part which contains @element and other options of it.
+ */
+ fn = xmlGetProp (work, (xmlChar *)"func");
+ if (fn && *fn) {
+ code_gen_func = g_strdup ((const gchar *) fn);
+ } else {
+ if (!(tmp = (gchar *) xmlNodeGetContent (work)))
+ tmp = (gchar *)xmlStrdup ((xmlChar *)"");
+
+ code = g_strdup (tmp);
+ xmlFree (tmp);
+ }
- code = g_strdup (tmp);
- xmlFree (tmp);
+ xmlFree (fn);
}
}
work = work->next;
}
- e_filter_option_add (option, value, title, code, FALSE);
+ e_filter_option_add (option, value, title, code, code_gen_func, FALSE);
xmlFree (value);
g_free (title);
g_free (code);
+ g_free (code_gen_func);
} else if (g_str_equal ((gchar *)n->name, "dynamic")) {
if (option->dynamic_func) {
g_warning (
@@ -217,6 +263,7 @@ filter_option_xml_create (EFilterElement *element,
op->value,
op->title,
op->code,
+ op->code_gen_func,
TRUE);
free_option (op);
}
@@ -295,7 +342,7 @@ filter_option_clone (EFilterElement *element)
newop = e_filter_option_add (
clone_option, op->value,
- op->title, op->code, op->is_dynamic);
+ op->title, op->code, op->code_gen_func, op->is_dynamic);
if (option->current == op)
clone_option->current = newop;
}
@@ -335,8 +382,8 @@ filter_option_get_widget (EFilterElement *element)
break;
} else {
e_filter_option_add (
- option, op->value,
- op->title, op->code, FALSE);
+ option, op->value, op->title,
+ op->code, op->code_gen_func, FALSE);
}
}
@@ -346,8 +393,8 @@ filter_option_get_widget (EFilterElement *element)
if (op) {
e_filter_option_add (
- option, op->value,
- op->title, op->code, TRUE);
+ option, op->value, op->title,
+ op->code, op->code_gen_func, TRUE);
free_option (op);
}
}
@@ -360,8 +407,8 @@ filter_option_get_widget (EFilterElement *element)
if (!op->is_dynamic)
e_filter_option_add (
- option, op->value,
- op->title, op->code, FALSE);
+ option, op->value, op->title,
+ op->code, op->code_gen_func, FALSE);
}
if (old_cur)
@@ -402,8 +449,11 @@ filter_option_build_code (EFilterElement *element,
{
EFilterOption *option = E_FILTER_OPTION (element);
- if (option->current && option->current->code)
+ if (option->current && option->current->code_gen_func) {
+ filter_option_generate_code (option, out, part);
+ } else if (option->current && option->current->code) {
e_filter_part_expand_code (part, option->current->code, out);
+ }
}
static void
@@ -464,6 +514,7 @@ e_filter_option_add (EFilterOption *option,
const gchar *value,
const gchar *title,
const gchar *code,
+ const gchar *code_gen_func,
gboolean is_dynamic)
{
struct _filter_option *op;
@@ -471,10 +522,14 @@ e_filter_option_add (EFilterOption *option,
g_return_val_if_fail (E_IS_FILTER_OPTION (option), NULL);
g_return_val_if_fail (find_option (option, value) == NULL, NULL);
+ if (code_gen_func && !*code_gen_func)
+ code_gen_func = NULL;
+
op = g_malloc (sizeof (*op));
op->title = g_strdup (title);
op->value = g_strdup (value);
op->code = g_strdup (code);
+ op->code_gen_func = g_strdup (code_gen_func);
op->is_dynamic = is_dynamic;
option->options = g_list_append (option->options, op);
diff --git a/filter/e-filter-option.h b/filter/e-filter-option.h
index 45d426b761..84b98bd104 100644
--- a/filter/e-filter-option.h
+++ b/filter/e-filter-option.h
@@ -55,8 +55,12 @@ struct _filter_option {
gchar *title; /* button title */
gchar *value; /* value, if it has one */
gchar *code; /* used to string code segments together */
+ gchar *code_gen_func; /* function to generate the code;
+ either @code or @code_gen_func is non-NULL,
+ never both */
- gboolean is_dynamic; /* whether is the option dynamic, FALSE if static */
+ gboolean is_dynamic; /* whether is the option dynamic, FALSE if static;
+ dynamic means "generated by EFilterOption::dynamic_func" */
};
struct _EFilterOption {
@@ -84,6 +88,7 @@ struct _filter_option *
const gchar *name,
const gchar *title,
const gchar *code,
+ const gchar *code_gen_func,
gboolean is_dynamic);
void e_filter_option_remove_all (EFilterOption *option);
diff --git a/mail/filtertypes.xml b/mail/filtertypes.xml
index c655c32cb8..02bea7fadd 100644
--- a/mail/filtertypes.xml
+++ b/mail/filtertypes.xml
@@ -648,15 +648,11 @@
<input type="optionlist" name="label-type">
<option value="is">
<title>is</title>
- <code>
- (match-all (or (= (user-tag "label") ${versus}) (user-flag (+ "$Label" ${versus})) (user-flag ${versus})))
- </code>
+ <code func="e_mail_labels_get_filter_code"/>
</option>
<option value="is-not">
<title>is not</title>
- <code>
- (match-all (not (or (= (user-tag "label") ${versus}) (user-flag (+ "$Label" ${versus})) (user-flag ${versus}))))
- </code>
+ <code func="e_mail_labels_get_filter_code"/>
</option>
</input>
<input type="optionlist" name="versus">
@@ -947,7 +943,7 @@
<title>Set Label</title>
<code>(set-label ${label})</code>
<input type="optionlist" name="label">
- <dynamic func="e_mail_labels_get_filter_options"/>
+ <dynamic func="e_mail_labels_get_filter_options_without_none"/>
</input>
</part>
<part name="colour">
diff --git a/mail/searchtypes.xml b/mail/searchtypes.xml
index 0173066aa2..bf933d8342 100644
--- a/mail/searchtypes.xml
+++ b/mail/searchtypes.xml
@@ -644,16 +644,12 @@
<input type="optionlist" name="label-type">
<option value="is">
<title>is</title>
- <code>
- (match-all (or (= (user-tag "label") ${versus}) (user-flag (+ "$Label" ${versus})) (user-flag ${versus})))
- </code>
+ <code func="e_mail_labels_get_filter_code"/>
</option>
<option value="is-not">
<title>is not</title>
- <code>
- (match-all (not (or (= (user-tag "label") ${versus}) (user-flag (+ "$Label" ${versus})) (user-flag ${versus}))))
- </code>
- </option>
+ <code func="e_mail_labels_get_filter_code"/>
+ </option>
</input>
<input type="optionlist" name="versus">
<dynamic func="e_mail_labels_get_filter_options"/>
diff --git a/mail/vfoldertypes.xml b/mail/vfoldertypes.xml
index 5f8bbd19a4..9195271c9c 100644
--- a/mail/vfoldertypes.xml
+++ b/mail/vfoldertypes.xml
@@ -640,15 +640,11 @@
<input type="optionlist" name="label-type">
<option value="is">
<title>is</title>
- <code>
- (match-all (or (= (user-tag "label") ${versus}) (user-flag (+ "$Label" ${versus})) (user-flag ${versus})))
- </code>
+ <code func="e_mail_labels_get_filter_code"/>
</option>
<option value="is-not">
<title>is not</title>
- <code>
- (match-all (not (or (= (user-tag "label") ${versus}) (user-flag (+ "$Label" ${versus})) (user-flag ${versus}))))
- </code>
+ <code func="e_mail_labels_get_filter_code"/>
</option>
</input>
<input type="optionlist" name="versus">
diff --git a/modules/mail/e-mail-shell-backend.c b/modules/mail/e-mail-shell-backend.c
index 6fab84bb96..2079d28cdc 100644
--- a/modules/mail/e-mail-shell-backend.c
+++ b/modules/mail/e-mail-shell-backend.c
@@ -871,8 +871,8 @@ e_mail_shell_backend_edit_account (EMailShellBackend *mail_shell_backend,
#include "filter/e-filter-option.h"
#include "shell/e-shell-settings.h"
-GSList *
-e_mail_labels_get_filter_options (void)
+static GSList *
+mail_labels_get_filter_options (gboolean include_none)
{
EShell *shell;
EShellBackend *shell_backend;
@@ -892,6 +892,16 @@ e_mail_labels_get_filter_options (void)
label_store = e_mail_ui_session_get_label_store (
E_MAIL_UI_SESSION (session));
+ if (include_none) {
+ struct _filter_option *option;
+
+ option = g_new0 (struct _filter_option, 1);
+ /* Translators: The first item in the list, to be able to set rule: [Label] [is/is-not] [None] */
+ option->title = g_strdup (C_("label", "None"));
+ option->value = g_strdup ("");
+ list = g_slist_prepend (list, option);
+ }
+
model = GTK_TREE_MODEL (label_store);
valid = gtk_tree_model_get_iter_first (model, &iter);
@@ -923,6 +933,135 @@ e_mail_labels_get_filter_options (void)
return g_slist_reverse (list);
}
+
+GSList *
+e_mail_labels_get_filter_options (void)
+{
+ return mail_labels_get_filter_options (TRUE);
+}
+
+GSList *
+e_mail_labels_get_filter_options_without_none (void)
+{
+ return mail_labels_get_filter_options (FALSE);
+}
+
+static const gchar *
+get_filter_option_value (EFilterPart *part,
+ const gchar *name)
+{
+ EFilterElement *elem;
+ EFilterOption *opt;
+
+ g_return_val_if_fail (part != NULL, NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ elem = e_filter_part_find_element (part, name);
+ g_return_val_if_fail (elem != NULL, NULL);
+ g_return_val_if_fail (E_IS_FILTER_OPTION (elem), NULL);
+
+ opt = E_FILTER_OPTION (elem);
+ return e_filter_option_get_current (opt);
+}
+
+static void
+append_one_label_expr (GString *out,
+ const gchar *versus)
+{
+ GString *encoded;
+
+ g_return_if_fail (out != NULL);
+ g_return_if_fail (versus != NULL);
+
+ encoded = g_string_new ("");
+ camel_sexp_encode_string (encoded, versus);
+
+ g_string_append_printf (out,
+ " (= (user-tag \"label\") %s) (user-flag (+ \"$Label\" %s)) (user-flag %s)",
+ encoded->str, encoded->str, encoded->str);
+
+ g_string_free (encoded, TRUE);
+}
+
+void
+e_mail_labels_get_filter_code (EFilterElement *element,
+ GString *out,
+ EFilterPart *part)
+{
+ const gchar *label_type, *versus;
+ gboolean is_not;
+
+ label_type = get_filter_option_value (part, "label-type");
+ versus = get_filter_option_value (part, "versus");
+
+ g_return_if_fail (label_type != NULL);
+ g_return_if_fail (versus != NULL);
+
+ is_not = g_str_equal (label_type, "is-not");
+
+ if (!g_str_equal (label_type, "is") && !is_not) {
+ g_warning ("%s: Unknown label-type: '%s'", G_STRFUNC, label_type);
+ return;
+ }
+
+ /* the 'None' item has 'is-not' inverted */
+ if (!*versus)
+ is_not = !is_not;
+
+ g_string_append (out, " (match-all (");
+ if (is_not)
+ g_string_append (out, " not (");
+ g_string_append (out, "or");
+
+ /* the 'None' item; "is None" means "has not set any label" */
+ if (!*versus) {
+ EShell *shell;
+ EShellBackend *shell_backend;
+ EMailBackend *backend;
+ EMailSession *session;
+ EMailLabelListStore *label_store;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gboolean valid;
+
+ shell = e_shell_get_default ();
+ shell_backend = e_shell_get_backend_by_name (shell, "mail");
+
+ backend = E_MAIL_BACKEND (shell_backend);
+ session = e_mail_backend_get_session (backend);
+ label_store = e_mail_ui_session_get_label_store (E_MAIL_UI_SESSION (session));
+
+ model = GTK_TREE_MODEL (label_store);
+ valid = gtk_tree_model_get_iter_first (model, &iter);
+
+ while (valid) {
+ gchar *tag;
+
+ tag = e_mail_label_list_store_get_tag (label_store, &iter);
+
+ if (g_str_has_prefix (tag, "$Label")) {
+ gchar *tmp = tag;
+
+ tag = g_strdup (tag + 6);
+
+ g_free (tmp);
+ }
+
+ append_one_label_expr (out, tag);
+
+ g_free (tag);
+
+ valid = gtk_tree_model_iter_next (model, &iter);
+ }
+ } else {
+ append_one_label_expr (out, versus);
+ }
+
+ if (is_not)
+ g_string_append (out, ")");
+ g_string_append (out, " ))");
+}
+
static void
message_parsed_cb (GObject *source_object,
GAsyncResult *res,
diff --git a/modules/mail/e-mail-shell-backend.h b/modules/mail/e-mail-shell-backend.h
index 0b76ea39b6..5b2da24e5f 100644
--- a/modules/mail/e-mail-shell-backend.h
+++ b/modules/mail/e-mail-shell-backend.h
@@ -23,6 +23,8 @@
#define E_MAIL_SHELL_BACKEND_H
#include <mail/e-mail-backend.h>
+#include <filter/e-filter-element.h>
+#include <filter/e-filter-rule.h>
/* Standard GObject macros */
#define E_TYPE_MAIL_SHELL_BACKEND \
@@ -71,7 +73,13 @@ void e_mail_shell_backend_edit_account
ESource *mail_account);
/* XXX Find a better place for this function. */
-GSList * e_mail_labels_get_filter_options (void);
+GSList * e_mail_labels_get_filter_options
+ (void);
+GSList * e_mail_labels_get_filter_options_without_none
+ (void);
+void e_mail_labels_get_filter_code (EFilterElement *element,
+ GString *out,
+ EFilterPart *part);
G_END_DECLS