From d09d8de870b6697c8a8b262e7e077b871a69b315 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Mon, 10 Dec 2012 08:09:59 -0500 Subject: Consolidate base utility libraries into libeutil. Evolution consists of entirely too many small utility libraries, which increases linking and loading time, places a burden on higher layers of the application (e.g. modules) which has to remember to link to all the small in-tree utility libraries, and makes it difficult to generate API documentation for these utility libraries in one Gtk-Doc module. Merge the following utility libraries under the umbrella of libeutil, and enforce a single-include policy on libeutil so we can reorganize the files as desired without disrupting its pseudo-public API. libemail-utils/libemail-utils.la libevolution-utils/libevolution-utils.la filter/libfilter.la widgets/e-timezone-dialog/libetimezonedialog.la widgets/menus/libmenus.la widgets/misc/libemiscwidgets.la widgets/table/libetable.la widgets/text/libetext.la This also merges libedataserverui from the Evolution-Data-Server module, since Evolution is its only consumer nowadays, and I'd like to make some improvements to those APIs without concern for backward-compatibility. And finally, start a Gtk-Doc module for libeutil. It's going to be a project just getting all the symbols _listed_ much less _documented_. But the skeletal structure is in place and I'm off to a good start. --- libemail-engine/Makefile.am | 22 +- libemail-engine/e-mail-session.c | 5 +- libemail-engine/e-mail-session.h | 2 +- libemail-engine/e-mail-utils.c | 2 +- libemail-engine/em-filter-folder-element.c | 226 ++++++++++ libemail-engine/em-filter-folder-element.h | 74 ++++ libemail-engine/em-vfolder-context.c | 110 +++++ libemail-engine/em-vfolder-context.h | 70 +++ libemail-engine/em-vfolder-rule.c | 494 +++++++++++++++++++++ libemail-engine/em-vfolder-rule.h | 102 +++++ libemail-engine/libemail-engine.pc.in | 2 +- libemail-engine/mail-folder-cache.c | 2 +- libemail-engine/mail-mt.c | 663 +++++++++++++++++++++++++++++ libemail-engine/mail-mt.h | 125 ++++++ libemail-engine/mail-ops.c | 2 +- libemail-engine/mail-ops.h | 2 +- libemail-engine/mail-vfolder.c | 15 +- libemail-engine/mail-vfolder.h | 5 +- 18 files changed, 1897 insertions(+), 26 deletions(-) create mode 100644 libemail-engine/em-filter-folder-element.c create mode 100644 libemail-engine/em-filter-folder-element.h create mode 100644 libemail-engine/em-vfolder-context.c create mode 100644 libemail-engine/em-vfolder-context.h create mode 100644 libemail-engine/em-vfolder-rule.c create mode 100644 libemail-engine/em-vfolder-rule.h create mode 100644 libemail-engine/mail-mt.c create mode 100644 libemail-engine/mail-mt.h (limited to 'libemail-engine') diff --git a/libemail-engine/Makefile.am b/libemail-engine/Makefile.am index 5589fe4e73..55fbef2334 100644 --- a/libemail-engine/Makefile.am +++ b/libemail-engine/Makefile.am @@ -18,7 +18,9 @@ libemail_engine_la_CPPFLAGS = \ -I$(top_builddir) \ $(EVOLUTION_DATA_SERVER_CFLAGS) \ $(GNOME_PLATFORM_CFLAGS) \ - -DEVOLUTION_PRIVDATADIR=\""$(privdatadir)"\" \ + $(CHAMPLAIN_CFLAGS) \ + $(GTKHTML_CFLAGS) \ + -DEVOLUTION_PRIVDATADIR=\""$(privdatadir)"\" \ $(NULL) libmailengineincludedir = $(privincludedir)/libemail-engine @@ -33,11 +35,15 @@ libmailengineinclude_HEADERS = \ e-mail-session.h \ e-mail-store-utils.h \ e-mail-utils.h \ + em-filter-folder-element.h \ + em-vfolder-context.h \ + em-vfolder-rule.h \ mail-config.h \ mail-folder-cache.h \ + mail-mt.h \ mail-ops.h \ mail-tools.h \ - mail-vfolder.h \ + mail-vfolder.h \ $(NULL) libemail_engine_la_SOURCES = \ @@ -51,19 +57,23 @@ libemail_engine_la_SOURCES = \ e-mail-session.c \ e-mail-store-utils.c \ e-mail-utils.c \ + em-filter-folder-element.c \ + em-vfolder-context.c \ + em-vfolder-rule.c \ mail-config.c \ mail-folder-cache.c \ + mail-mt.c \ mail-ops.c \ mail-tools.c \ - mail-vfolder.c \ + mail-vfolder.c \ $(NULL) libemail_engine_la_LIBADD = \ - $(top_builddir)/libemail-utils/libemail-utils.la \ - $(top_builddir)/filter/libfilter.la \ - $(top_builddir)/libevolution-utils/libevolution-utils.la \ + $(top_builddir)/e-util/libeutil.la \ $(EVOLUTION_DATA_SERVER_LIBS) \ $(GNOME_PLATFORM_LIBS) \ + $(CHAMPLAIN_LIBS) \ + $(GTKHTML_LIBS) \ $(NULL) libemail_engine_la_LDFLAGS = -avoid-version $(NO_UNDEFINED) diff --git a/libemail-engine/e-mail-session.c b/libemail-engine/e-mail-session.c index aa3adefd12..18e336a5f4 100644 --- a/libemail-engine/e-mail-session.c +++ b/libemail-engine/e-mail-session.c @@ -43,9 +43,10 @@ #endif #include -#include -#include "libemail-utils/mail-mt.h" +#include "libemail-engine/mail-mt.h" + +#include "e-util/e-util.h" /* This is our hack, not part of libcamel. */ #include "camel-null-store.h" diff --git a/libemail-engine/e-mail-session.h b/libemail-engine/e-mail-session.h index bd4b2f6727..9445e0b833 100644 --- a/libemail-engine/e-mail-session.h +++ b/libemail-engine/e-mail-session.h @@ -28,8 +28,8 @@ #include #include #include +#include #include -#include /* Standard GObject macros */ #define E_TYPE_MAIL_SESSION \ diff --git a/libemail-engine/e-mail-utils.c b/libemail-engine/e-mail-utils.c index d1429661b7..33ff0d1aaa 100644 --- a/libemail-engine/e-mail-utils.c +++ b/libemail-engine/e-mail-utils.c @@ -39,7 +39,7 @@ #include #include -#include +#include #include "e-mail-folder-utils.h" #include "e-mail-session.h" diff --git a/libemail-engine/em-filter-folder-element.c b/libemail-engine/em-filter-folder-element.c new file mode 100644 index 0000000000..77569b0309 --- /dev/null +++ b/libemail-engine/em-filter-folder-element.c @@ -0,0 +1,226 @@ +/* + * + * 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; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * Not Zed + * Jeffrey Stedfast + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "em-filter-folder-element.h" + +#include + +#include +#include + +#define EM_FILTER_FOLDER_ELEMENT_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), EM_TYPE_FILTER_FOLDER_ELEMENT, EMFilterFolderElementPrivate)) + +struct _EMFilterFolderElementPrivate { + gchar *uri; +}; + +G_DEFINE_TYPE ( + EMFilterFolderElement, + em_filter_folder_element, + E_TYPE_FILTER_ELEMENT) + +static void +filter_folder_element_finalize (GObject *object) +{ + EMFilterFolderElementPrivate *priv; + + priv = EM_FILTER_FOLDER_ELEMENT_GET_PRIVATE (object); + + g_free (priv->uri); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (em_filter_folder_element_parent_class)->finalize (object); +} + +static gboolean +filter_folder_element_validate (EFilterElement *fe, + EAlert **alert) +{ + EMFilterFolderElement *ff = (EMFilterFolderElement *) fe; + + g_warn_if_fail (alert == NULL || *alert == NULL); + + if (ff->priv->uri != NULL && *ff->priv->uri != '\0') + return TRUE; + + if (alert) + *alert = e_alert_new ("mail:no-folder", NULL); + + return FALSE; +} + +static gint +filter_folder_element_eq (EFilterElement *fe, + EFilterElement *cm) +{ + return E_FILTER_ELEMENT_CLASS ( + em_filter_folder_element_parent_class)->eq (fe, cm) && + strcmp (((EMFilterFolderElement *) fe)->priv->uri, + ((EMFilterFolderElement *) cm)->priv->uri)== 0; +} + +static xmlNodePtr +filter_folder_element_xml_encode (EFilterElement *fe) +{ + xmlNodePtr value, work; + EMFilterFolderElement *ff = (EMFilterFolderElement *) fe; + + value = xmlNewNode (NULL, (xmlChar *) "value"); + xmlSetProp (value, (xmlChar *) "name", (xmlChar *) fe->name); + xmlSetProp (value, (xmlChar *) "type", (xmlChar *) "folder"); + + work = xmlNewChild (value, NULL, (xmlChar *) "folder", NULL); + xmlSetProp (work, (xmlChar *) "uri", (xmlChar *) ff->priv->uri); + + return value; +} + +static gint +filter_folder_element_xml_decode (EFilterElement *fe, + xmlNodePtr node) +{ + EMFilterFolderElement *ff = (EMFilterFolderElement *) fe; + xmlNodePtr n; + + xmlFree (fe->name); + fe->name = (gchar *) xmlGetProp (node, (xmlChar *) "name"); + + n = node->children; + while (n) { + if (!strcmp ((gchar *) n->name, "folder")) { + gchar *uri; + + uri = (gchar *) xmlGetProp (n, (xmlChar *) "uri"); + g_free (ff->priv->uri); + ff->priv->uri = g_strdup (uri); + xmlFree (uri); + break; + } + n = n->next; + } + + return 0; +} + +static GtkWidget * +filter_folder_element_get_widget (EFilterElement *fe) +{ + GtkWidget *widget; + + widget = E_FILTER_ELEMENT_CLASS (em_filter_folder_element_parent_class)-> + get_widget (fe); + + return widget; +} + +static void +filter_folder_element_build_code (EFilterElement *fe, + GString *out, + EFilterPart *ff) +{ + /* We are doing nothing on purpose. */ +} + +static void +filter_folder_element_format_sexp (EFilterElement *fe, + GString *out) +{ + EMFilterFolderElement *ff = (EMFilterFolderElement *) fe; + + camel_sexp_encode_string (out, ff->priv->uri); +} + +static void +filter_folder_element_copy_value (EFilterElement *de, + EFilterElement *se) +{ + if (EM_IS_FILTER_FOLDER_ELEMENT (se)) { + em_filter_folder_element_set_uri ( + EM_FILTER_FOLDER_ELEMENT (de), + EM_FILTER_FOLDER_ELEMENT (se)->priv->uri); + } else { + E_FILTER_ELEMENT_CLASS ( + em_filter_folder_element_parent_class)->copy_value (de, se); + } +} +static void +em_filter_folder_element_class_init (EMFilterFolderElementClass *class) +{ + GObjectClass *object_class; + EFilterElementClass *filter_element_class; + + g_type_class_add_private (class, sizeof (EMFilterFolderElementPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->finalize = filter_folder_element_finalize; + + filter_element_class = E_FILTER_ELEMENT_CLASS (class); + filter_element_class->validate = filter_folder_element_validate; + filter_element_class->eq = filter_folder_element_eq; + filter_element_class->xml_encode = filter_folder_element_xml_encode; + filter_element_class->xml_decode = filter_folder_element_xml_decode; + filter_element_class->get_widget = filter_folder_element_get_widget; + filter_element_class->build_code = filter_folder_element_build_code; + filter_element_class->format_sexp = filter_folder_element_format_sexp; + filter_element_class->copy_value = filter_folder_element_copy_value; +} + +static void +em_filter_folder_element_init (EMFilterFolderElement *element) +{ + element->priv = EM_FILTER_FOLDER_ELEMENT_GET_PRIVATE (element); +} + +EFilterElement * +em_filter_folder_element_new () +{ + return g_object_new ( + EM_TYPE_FILTER_FOLDER_ELEMENT, + NULL); +} + +const gchar * +em_filter_folder_element_get_uri (EMFilterFolderElement *element) +{ + g_return_val_if_fail (EM_IS_FILTER_FOLDER_ELEMENT (element), NULL); + + return element->priv->uri; +} + +void +em_filter_folder_element_set_uri (EMFilterFolderElement *element, + const gchar *uri) +{ + g_return_if_fail (EM_IS_FILTER_FOLDER_ELEMENT (element)); + + g_free (element->priv->uri); + element->priv->uri = g_strdup (uri); +} + diff --git a/libemail-engine/em-filter-folder-element.h b/libemail-engine/em-filter-folder-element.h new file mode 100644 index 0000000000..8c619017a6 --- /dev/null +++ b/libemail-engine/em-filter-folder-element.h @@ -0,0 +1,74 @@ +/* + * + * 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; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * Not Zed + * Jeelementrey Stedfast + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef EM_FILTER_FOLDER_ELEMENT_H +#define EM_FILTER_FOLDER_ELEMENT_H + +#include + +/* Standard GObject macros */ +#define EM_TYPE_FILTER_FOLDER_ELEMENT \ + (em_filter_folder_element_get_type ()) +#define EM_FILTER_FOLDER_ELEMENT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), EM_TYPE_FILTER_FOLDER_ELEMENT, EMFilterFolderElement)) +#define EM_FILTER_FOLDER_ELEMENT_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), EM_TYPE_FILTER_FOLDER_ELEMENT, EMFilterFolderElementClass)) +#define EM_IS_FILTER_FOLDER_ELEMENT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), EM_TYPE_FILTER_FOLDER_ELEMENT)) +#define EM_IS_FILTER_FOLDER_ELEMENT_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), EM_TYPE_FILTER_FOLDER_ELEMENT)) +#define EM_FILTER_FOLDER_ELEMENT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), EM_TYPE_FILTER_FOLDER_ELEMENT, EMFilterFolderElementClass)) + +G_BEGIN_DECLS + +typedef struct _EMFilterFolderElement EMFilterFolderElement; +typedef struct _EMFilterFolderElementClass EMFilterFolderElementClass; +typedef struct _EMFilterFolderElementPrivate EMFilterFolderElementPrivate; + +struct _EMFilterFolderElement { + EFilterElement parent; + EMFilterFolderElementPrivate *priv; +}; + +struct _EMFilterFolderElementClass { + EFilterElementClass parent_class; +}; + +GType em_filter_folder_element_get_type (void); +EFilterElement *em_filter_folder_element_new (void); +const gchar * em_filter_folder_element_get_uri + (EMFilterFolderElement *element); +void em_filter_folder_element_set_uri + (EMFilterFolderElement *element, + const gchar *uri); + +G_END_DECLS + +#endif /* EM_FILTER_FOLDER_ELEMENT_H */ diff --git a/libemail-engine/em-vfolder-context.c b/libemail-engine/em-vfolder-context.c new file mode 100644 index 0000000000..69b82eb18d --- /dev/null +++ b/libemail-engine/em-vfolder-context.c @@ -0,0 +1,110 @@ +/* + * + * 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; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * Not Zed + * Jeffrey Stedfast + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "em-vfolder-context.h" + +#include + +#include "em-filter-folder-element.h" +#include "em-vfolder-rule.h" + +#define EM_VFOLDER_CONTEXT_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), EM_TYPE_VFOLDER_CONTEXT, EMVFolderContextPrivate)) + +struct _EMVFolderContextPrivate { + gint placeholder; +}; + +enum { + PROP_0, + PROP_SESSION +}; + +G_DEFINE_TYPE ( + EMVFolderContext, + em_vfolder_context, + E_TYPE_RULE_CONTEXT) + +static EFilterElement * +vfolder_context_new_element (ERuleContext *context, + const gchar *type) +{ + if (strcmp (type, "system-flag") == 0) + return e_filter_option_new (); + + if (strcmp (type, "score") == 0) + return e_filter_int_new_type ("score", -3, 3); + + if (strcmp (type, "folder") == 0) + return em_filter_folder_element_new (); + + /* XXX Legacy type name. Same as "folder" now. */ + if (strcmp (type, "folder-curi") == 0) + return em_filter_folder_element_new (); + + return E_RULE_CONTEXT_CLASS (em_vfolder_context_parent_class)-> + new_element (context, type); +} + +static void +em_vfolder_context_class_init (EMVFolderContextClass *class) +{ + ERuleContextClass *rule_context_class; + + g_type_class_add_private (class, sizeof (EMVFolderContextPrivate)); + + rule_context_class = E_RULE_CONTEXT_CLASS (class); + rule_context_class->new_element = vfolder_context_new_element; +} + +static void +em_vfolder_context_init (EMVFolderContext *context) +{ + context->priv = EM_VFOLDER_CONTEXT_GET_PRIVATE (context); + + e_rule_context_add_part_set ( + E_RULE_CONTEXT (context), "partset", E_TYPE_FILTER_PART, + (ERuleContextPartFunc) e_rule_context_add_part, + (ERuleContextNextPartFunc) e_rule_context_next_part); + + e_rule_context_add_rule_set ( + E_RULE_CONTEXT (context), "ruleset", EM_TYPE_VFOLDER_RULE, + (ERuleContextRuleFunc) e_rule_context_add_rule, + (ERuleContextNextRuleFunc) e_rule_context_next_rule); + + E_RULE_CONTEXT (context)->flags = + E_RULE_CONTEXT_THREADING | E_RULE_CONTEXT_GROUPING; +} + +EMVFolderContext * +em_vfolder_context_new () +{ + return g_object_new ( + EM_TYPE_VFOLDER_CONTEXT, NULL); +} diff --git a/libemail-engine/em-vfolder-context.h b/libemail-engine/em-vfolder-context.h new file mode 100644 index 0000000000..9e2faf357a --- /dev/null +++ b/libemail-engine/em-vfolder-context.h @@ -0,0 +1,70 @@ +/* + * + * 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; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * Not Zed + * Jeffrey Stedfast + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef EM_VFOLDER_CONTEXT_H +#define EM_VFOLDER_CONTEXT_H + +#include + +/* Standard GObject macros */ +#define EM_TYPE_VFOLDER_CONTEXT \ + (em_vfolder_context_get_type ()) +#define EM_VFOLDER_CONTEXT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), EM_TYPE_VFOLDER_CONTEXT, EMVFolderContext)) +#define EM_VFOLDER_CONTEXT_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), EM_TYPE_VFOLDER_CONTEXT, EMVFolderContextClass)) +#define EM_IS_VFOLDER_CONTEXT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), EM_TYPE_VFOLDER_CONTEXT)) +#define EM_IS_VFOLDER_CONTEXT_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), EM_TYPE_VFOLDER_CONTEXT)) +#define EM_VFOLDER_CONTEXT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), EM_TYPE_VFOLDER_CONTEXT, EMVFolderContextClass)) + +G_BEGIN_DECLS + +typedef struct _EMVFolderContext EMVFolderContext; +typedef struct _EMVFolderContextClass EMVFolderContextClass; +typedef struct _EMVFolderContextPrivate EMVFolderContextPrivate; + +struct _EMVFolderContext { + ERuleContext parent; + EMVFolderContextPrivate *priv; +}; + +struct _EMVFolderContextClass { + ERuleContextClass parent_class; +}; + +GType em_vfolder_context_get_type (void); +EMVFolderContext * + em_vfolder_context_new (void); + +G_END_DECLS + +#endif /* EM_VFOLDER_CONTEXT_H */ diff --git a/libemail-engine/em-vfolder-rule.c b/libemail-engine/em-vfolder-rule.c new file mode 100644 index 0000000000..0d6b07a8ff --- /dev/null +++ b/libemail-engine/em-vfolder-rule.c @@ -0,0 +1,494 @@ +/* + * 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; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * Not Zed + * Jeffrey Stedfast + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include + +#include "em-vfolder-context.h" +#include "em-vfolder-rule.h" + +#define EM_VFOLDER_RULE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), EM_TYPE_VFOLDER_RULE, EMVFolderRulePrivate)) + +#define EM_VFOLDER_RULE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), EM_TYPE_VFOLDER_RULE, EMVFolderRulePrivate)) + +struct _EMVFolderRulePrivate { + em_vfolder_rule_with_t with; + GQueue sources; /* uri's of the source folders */ + gboolean autoupdate; + GHashTable *include_subfolders; +}; + +static gint validate (EFilterRule *, EAlert **alert); +static gint vfolder_eq (EFilterRule *fr, EFilterRule *cm); +static xmlNodePtr xml_encode (EFilterRule *); +static gint xml_decode (EFilterRule *, xmlNodePtr, ERuleContext *f); +static void rule_copy (EFilterRule *dest, EFilterRule *src); +static GtkWidget *get_widget (EFilterRule *fr, ERuleContext *f); + +/* DO NOT internationalise these strings */ +static const gchar *with_names[] = { + "specific", + "local_remote_active", + "remote_active", + "local" +}; + +G_DEFINE_TYPE ( + EMVFolderRule, + em_vfolder_rule, + E_TYPE_FILTER_RULE) + +static void +vfolder_rule_finalize (GObject *object) +{ + EMVFolderRule *rule = EM_VFOLDER_RULE (object); + gchar *uri; + + while ((uri = g_queue_pop_head (&rule->priv->sources)) != NULL) + g_free (uri); + + g_hash_table_destroy (rule->priv->include_subfolders); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (em_vfolder_rule_parent_class)->finalize (object); +} + +static void +em_vfolder_rule_class_init (EMVFolderRuleClass *class) +{ + GObjectClass *object_class; + EFilterRuleClass *filter_rule_class; + + g_type_class_add_private (class, sizeof (EMVFolderRulePrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->finalize = vfolder_rule_finalize; + + filter_rule_class = E_FILTER_RULE_CLASS (class); + filter_rule_class->validate = validate; + filter_rule_class->eq = vfolder_eq; + filter_rule_class->xml_encode = xml_encode; + filter_rule_class->xml_decode = xml_decode; + filter_rule_class->copy = rule_copy; + filter_rule_class->get_widget = get_widget; +} + +static void +em_vfolder_rule_init (EMVFolderRule *rule) +{ + rule->priv = EM_VFOLDER_RULE_GET_PRIVATE (rule); + rule->priv->with = EM_VFOLDER_RULE_WITH_SPECIFIC; + rule->priv->autoupdate = TRUE; + /* it's using pointers from priv::sources, and those + * included has include_subfolders set to true */ + rule->priv->include_subfolders = g_hash_table_new (g_direct_hash, g_direct_equal); + + rule->rule.source = g_strdup ("incoming"); +} + +EFilterRule * +em_vfolder_rule_new (void) +{ + return g_object_new ( + EM_TYPE_VFOLDER_RULE, NULL); +} + +void +em_vfolder_rule_add_source (EMVFolderRule *rule, + const gchar *uri) +{ + g_return_if_fail (EM_IS_VFOLDER_RULE (rule)); + g_return_if_fail (uri); + + g_queue_push_tail (&rule->priv->sources, g_strdup (uri)); + + e_filter_rule_emit_changed (E_FILTER_RULE (rule)); +} + +const gchar * +em_vfolder_rule_find_source (EMVFolderRule *rule, + const gchar *uri) +{ + GList *link; + + g_return_val_if_fail (EM_IS_VFOLDER_RULE (rule), NULL); + + /* only does a simple string or address comparison, should + * probably do a decoded url comparison */ + link = g_queue_find_custom ( + &rule->priv->sources, uri, (GCompareFunc) strcmp); + + return (link != NULL) ? link->data : NULL; +} + +void +em_vfolder_rule_remove_source (EMVFolderRule *rule, + const gchar *uri) +{ + gchar *found; + + g_return_if_fail (EM_IS_VFOLDER_RULE (rule)); + + found =(gchar *) em_vfolder_rule_find_source (rule, uri); + if (found != NULL) { + g_queue_remove (&rule->priv->sources, found); + g_hash_table_remove (rule->priv->include_subfolders, found); + g_free (found); + e_filter_rule_emit_changed (E_FILTER_RULE (rule)); + } +} + +const gchar * +em_vfolder_rule_next_source (EMVFolderRule *rule, + const gchar *last) +{ + GList *link; + + if (last == NULL) { + link = g_queue_peek_head_link (&rule->priv->sources); + } else { + link = g_queue_find (&rule->priv->sources, last); + if (link == NULL) + link = g_queue_peek_head_link (&rule->priv->sources); + else + link = g_list_next (link); + } + + return (link != NULL) ? link->data : NULL; +} + +GQueue * +em_vfolder_rule_get_sources (EMVFolderRule *rule) +{ + g_return_val_if_fail (rule != NULL, NULL); + + return &rule->priv->sources; +} + +static gboolean +check_queue_has_key (gpointer key, + gpointer value, + gpointer user_data) +{ + EMVFolderRule *rule = user_data; + + g_return_val_if_fail (rule != NULL, FALSE); + + return g_queue_find (&rule->priv->sources, key) == NULL; +} + +void +em_vfolder_rule_sources_changed (EMVFolderRule *rule) +{ + g_return_if_fail (rule != NULL); + + g_hash_table_foreach_remove (rule->priv->include_subfolders, + check_queue_has_key, rule); +} + +gboolean +em_vfolder_rule_source_get_include_subfolders (EMVFolderRule *rule, + const gchar *source) +{ + g_return_val_if_fail (rule != NULL, FALSE); + g_return_val_if_fail (source != NULL, FALSE); + + source = em_vfolder_rule_find_source (rule, source); + + return source && g_hash_table_lookup (rule->priv->include_subfolders, source); +} + +void +em_vfolder_rule_source_set_include_subfolders (EMVFolderRule *rule, + const gchar *source, + gboolean include_subfolders) +{ + g_return_if_fail (rule != NULL); + g_return_if_fail (source != NULL); + + source = em_vfolder_rule_find_source (rule, source); + g_return_if_fail (source != NULL); + + if (include_subfolders) + g_hash_table_insert (rule->priv->include_subfolders, (gpointer) source, GINT_TO_POINTER (1)); + else + g_hash_table_remove (rule->priv->include_subfolders, (gpointer) source); +} + +void +em_vfolder_rule_set_with (EMVFolderRule *rule, + em_vfolder_rule_with_t with) +{ + g_return_if_fail (rule != NULL); + + rule->priv->with = with; +} + +em_vfolder_rule_with_t +em_vfolder_rule_get_with (EMVFolderRule *rule) +{ + g_return_val_if_fail (rule != NULL, FALSE); + + return rule->priv->with; +} + +void +em_vfolder_rule_set_autoupdate (EMVFolderRule *rule, + gboolean autoupdate) +{ + g_return_if_fail (rule != NULL); + + rule->priv->autoupdate = autoupdate; +} + +gboolean +em_vfolder_rule_get_autoupdate (EMVFolderRule *rule) +{ + g_return_val_if_fail (rule != NULL, EM_VFOLDER_RULE_WITH_SPECIFIC); + + return rule->priv->autoupdate; +} + +static gint +validate (EFilterRule *fr, + EAlert **alert) +{ + g_return_val_if_fail (fr != NULL, 0); + g_warn_if_fail (alert == NULL || *alert == NULL); + + if (!fr->name || !*fr->name) { + if (alert) + *alert = e_alert_new ("mail:no-name-vfolder", NULL); + return 0; + } + + /* We have to have at least one source set in the "specific" case. + * Do not translate this string! */ + if (((EMVFolderRule *) fr)->priv->with == EM_VFOLDER_RULE_WITH_SPECIFIC && + g_queue_is_empty (&((EMVFolderRule *) fr)->priv->sources)) { + if (alert) + *alert = e_alert_new ("mail:vfolder-no-source", NULL); + return 0; + } + + return E_FILTER_RULE_CLASS (em_vfolder_rule_parent_class)->validate (fr, alert); +} + +static gint +queue_eq (GQueue *queue_a, + GQueue *queue_b) +{ + GList *link_a; + GList *link_b; + gint truth = TRUE; + + link_a = g_queue_peek_head_link (queue_a); + link_b = g_queue_peek_head_link (queue_b); + + while (truth && link_a != NULL && link_b != NULL) { + gchar *uri_a = link_a->data; + gchar *uri_b = link_b->data; + + truth = (strcmp (uri_a, uri_b)== 0); + + link_a = g_list_next (link_a); + link_b = g_list_next (link_b); + } + + return truth && link_a == NULL && link_b == NULL; +} + +static gint +vfolder_eq (EFilterRule *fr, + EFilterRule *cm) +{ + return E_FILTER_RULE_CLASS (em_vfolder_rule_parent_class)->eq (fr, cm) + && queue_eq ( + &((EMVFolderRule *) fr)->priv->sources, + &((EMVFolderRule *) cm)->priv->sources); +} + +static xmlNodePtr +xml_encode (EFilterRule *fr) +{ + EMVFolderRule *vr =(EMVFolderRule *) fr; + xmlNodePtr node, set, work; + GList *head, *link; + + node = E_FILTER_RULE_CLASS (em_vfolder_rule_parent_class)->xml_encode (fr); + g_return_val_if_fail (node != NULL, NULL); + g_return_val_if_fail (vr->priv->with < G_N_ELEMENTS (with_names), NULL); + + set = xmlNewNode (NULL, (const guchar *)"sources"); + xmlAddChild (node, set); + xmlSetProp (set, (const guchar *)"with", (guchar *) with_names[vr->priv->with]); + xmlSetProp (set, (const guchar *)"autoupdate", (guchar *) (vr->priv->autoupdate ? "true" : "false")); + + head = g_queue_peek_head_link (&vr->priv->sources); + for (link = head; link != NULL; link = g_list_next (link)) { + const gchar *uri = link->data; + + work = xmlNewNode (NULL, (const guchar *) "folder"); + xmlSetProp (work, (const guchar *) "uri", (guchar *) uri); + xmlSetProp (work, (const guchar *) "include-subfolders", (guchar *) + (em_vfolder_rule_source_get_include_subfolders (vr, uri) ? "true" : "false")); + xmlAddChild (set, work); + } + + return node; +} + +static void +set_with (EMVFolderRule *vr, + const gchar *name) +{ + gint i; + + for (i = 0; i < G_N_ELEMENTS (with_names); i++) { + if (!strcmp (name, with_names[i])) { + vr->priv->with = i; + return; + } + } + + vr->priv->with = 0; +} + +static gint +xml_decode (EFilterRule *fr, + xmlNodePtr node, + ERuleContext *f) +{ + xmlNodePtr set, work; + gint result; + EMVFolderRule *vr =(EMVFolderRule *) fr; + gchar *tmp; + + result = E_FILTER_RULE_CLASS (em_vfolder_rule_parent_class)-> + xml_decode (fr, node, f); + if (result != 0) + return result; + + /* handle old format file, vfolder source is in filterrule */ + if (strcmp (fr->source, "incoming")!= 0) { + set_with (vr, fr->source); + g_free (fr->source); + fr->source = g_strdup ("incoming"); + } + + set = node->children; + while (set) { + if (!strcmp ((gchar *) set->name, "sources")) { + tmp = (gchar *) xmlGetProp (set, (const guchar *)"with"); + if (tmp) { + set_with (vr, tmp); + xmlFree (tmp); + } + tmp = (gchar *) xmlGetProp (set, (const guchar *) "autoupdate"); + if (tmp) { + vr->priv->autoupdate = g_str_equal (tmp, "true"); + xmlFree (tmp); + } + work = set->children; + while (work) { + if (!strcmp ((gchar *) work->name, "folder")) { + tmp = (gchar *) xmlGetProp (work, (const guchar *)"uri"); + if (tmp) { + gchar *include_subfolders; + + g_queue_push_tail (&vr->priv->sources, g_strdup (tmp)); + + include_subfolders = (gchar *) xmlGetProp (work, (const guchar *) "include-subfolders"); + if (include_subfolders) { + em_vfolder_rule_source_set_include_subfolders ( + vr, + tmp, g_str_equal (include_subfolders, "true")); + xmlFree (include_subfolders); + } + + xmlFree (tmp); + } + } + work = work->next; + } + } + set = set->next; + } + return 0; +} + +static void +rule_copy (EFilterRule *dest, + EFilterRule *src) +{ + EMVFolderRule *vdest, *vsrc; + GList *head, *link; + gchar *uri; + + vdest =(EMVFolderRule *) dest; + vsrc =(EMVFolderRule *) src; + + while ((uri = g_queue_pop_head (&vdest->priv->sources)) != NULL) + g_free (uri); + + em_vfolder_rule_sources_changed (vdest); + + head = g_queue_peek_head_link (&vsrc->priv->sources); + for (link = head; link != NULL; link = g_list_next (link)) { + const gchar *uri = link->data; + g_queue_push_tail (&vdest->priv->sources, g_strdup (uri)); + + em_vfolder_rule_source_set_include_subfolders ( + vdest, uri, + em_vfolder_rule_source_get_include_subfolders (vsrc, uri)); + } + + vdest->priv->with = vsrc->priv->with; + vdest->priv->autoupdate = vsrc->priv->autoupdate; + + E_FILTER_RULE_CLASS (em_vfolder_rule_parent_class)->copy (dest, src); +} + +static GtkWidget * +get_widget (EFilterRule *fr, + ERuleContext *rc) +{ + GtkWidget *widget; + + widget = E_FILTER_RULE_CLASS (em_vfolder_rule_parent_class)-> + get_widget (fr, rc); + + return widget; +} diff --git a/libemail-engine/em-vfolder-rule.h b/libemail-engine/em-vfolder-rule.h new file mode 100644 index 0000000000..312ae175e5 --- /dev/null +++ b/libemail-engine/em-vfolder-rule.h @@ -0,0 +1,102 @@ +/* + * 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; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * NotZed + * Jeffrey Stedfast + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef EM_VFOLDER_RULE_H +#define EM_VFOLDER_RULE_H + +#include + +/* Standard GObject macros */ +#define EM_TYPE_VFOLDER_RULE \ + (em_vfolder_rule_get_type ()) +#define EM_VFOLDER_RULE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), EM_TYPE_VFOLDER_RULE, EMVFolderRule)) +#define EM_VFOLDER_RULE_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), EM_TYPE_VFOLDER_RULE, EMVFolderRuleClass)) +#define EM_IS_VFOLDER_RULE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), EM_TYPE_VFOLDER_RULE)) +#define EM_IS_VFOLDER_RULE_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), EM_TYPE_VFOLDER_RULE)) +#define EM_VFOLDER_RULE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), EM_TYPE_VFOLDER_RULE, EMVFolderRuleClass)) + +G_BEGIN_DECLS + +/* perhaps should be bits? */ +enum _em_vfolder_rule_with_t { + EM_VFOLDER_RULE_WITH_SPECIFIC, + EM_VFOLDER_RULE_WITH_LOCAL_REMOTE_ACTIVE, + EM_VFOLDER_RULE_WITH_REMOTE_ACTIVE, + EM_VFOLDER_RULE_WITH_LOCAL +}; + +typedef struct _EMVFolderRule EMVFolderRule; +typedef struct _EMVFolderRuleClass EMVFolderRuleClass; +typedef struct _EMVFolderRulePrivate EMVFolderRulePrivate; + +typedef enum _em_vfolder_rule_with_t em_vfolder_rule_with_t; + +struct _EMVFolderRule { + EFilterRule rule; + EMVFolderRulePrivate *priv; +}; + +struct _EMVFolderRuleClass { + EFilterRuleClass parent_class; +}; + +GType em_vfolder_rule_get_type (void); +EFilterRule * em_vfolder_rule_new (void); +void em_vfolder_rule_add_source (EMVFolderRule *rule, + const gchar *uri); +void em_vfolder_rule_remove_source (EMVFolderRule *rule, + const gchar *uri); +const gchar * em_vfolder_rule_find_source (EMVFolderRule *rule, + const gchar *uri); +const gchar * em_vfolder_rule_next_source (EMVFolderRule *rule, + const gchar *last); +GQueue * em_vfolder_rule_get_sources (EMVFolderRule *rule); +void em_vfolder_rule_sources_changed (EMVFolderRule *rule); +gboolean em_vfolder_rule_source_get_include_subfolders + (EMVFolderRule *rule, + const gchar *source); +void em_vfolder_rule_source_set_include_subfolders + (EMVFolderRule *rule, + const gchar *source, + gboolean include_subfolders); +void em_vfolder_rule_set_with (EMVFolderRule *rule, + em_vfolder_rule_with_t with); +em_vfolder_rule_with_t + em_vfolder_rule_get_with (EMVFolderRule *rule); +void em_vfolder_rule_set_autoupdate (EMVFolderRule *rule, + gboolean autoupdate); +gboolean em_vfolder_rule_get_autoupdate (EMVFolderRule *rule); + +G_END_DECLS + +#endif /* EM_VFOLDER_RULE_H */ diff --git a/libemail-engine/libemail-engine.pc.in b/libemail-engine/libemail-engine.pc.in index 2457e0182f..ea5ffab771 100644 --- a/libemail-engine/libemail-engine.pc.in +++ b/libemail-engine/libemail-engine.pc.in @@ -11,6 +11,6 @@ privincludedir=@privincludedir@ Name: libemail-engine Description: Client library for evolution mail Version: @VERSION@ -Requires: libemail-utils +Requires: camel-1.2 libedataserver-1.2 libebackend-1.2 gio-2.0 Libs: -L${privlibdir} -lemail-engine Cflags: -I${privincludedir} diff --git a/libemail-engine/mail-folder-cache.c b/libemail-engine/mail-folder-cache.c index 4d82557467..35e620862e 100644 --- a/libemail-engine/mail-folder-cache.c +++ b/libemail-engine/mail-folder-cache.c @@ -40,7 +40,7 @@ #include -#include +#include #include "mail-folder-cache.h" #include "e-mail-utils.h" diff --git a/libemail-engine/mail-mt.c b/libemail-engine/mail-mt.c new file mode 100644 index 0000000000..baf1476f82 --- /dev/null +++ b/libemail-engine/mail-mt.c @@ -0,0 +1,663 @@ +/* + * 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; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include + +#include "mail-mt.h" + +/*#define MALLOC_CHECK*/ +#define d(x) + +/* XXX This is a dirty hack on a dirty hack. We really need + * to rework or get rid of the functions that use this. */ +const gchar *shell_builtin_backend = "mail"; + +static guint mail_msg_seq; /* sequence number of each message */ + +/* Table of active messages. Must hold mail_msg_lock to access. */ +static GHashTable *mail_msg_active_table; +static GMutex mail_msg_lock; +static GCond mail_msg_cond; + +static MailMsgCreateActivityFunc create_activity = NULL; +static MailMsgSubmitActivityFunc submit_activity = NULL; +static MailMsgFreeActivityFunc free_activity = NULL; +static MailMsgCompleteActivityFunc complete_activity = NULL; +static MailMsgAlertErrorFunc alert_error = NULL; +static MailMsgCancelActivityFunc cancel_activity = NULL; +static MailMsgGetAlertSinkFunc get_alert_sink = NULL; + +void +mail_msg_register_activities (MailMsgCreateActivityFunc acreate, + MailMsgSubmitActivityFunc asubmit, + MailMsgFreeActivityFunc freeact, + MailMsgCompleteActivityFunc comp_act, + MailMsgCancelActivityFunc cancel_act, + MailMsgAlertErrorFunc ealert, + MailMsgGetAlertSinkFunc ealertsink) +{ + /* XXX This is an utter hack to keep EActivity out + * of EDS and still let Evolution do EActivity. */ + create_activity = acreate; + submit_activity = asubmit; + free_activity = freeact; + complete_activity = comp_act; + cancel_activity = cancel_act; + alert_error = ealert; + get_alert_sink = ealertsink; +} + +EAlertSink * +mail_msg_get_alert_sink () +{ + if (get_alert_sink) + return get_alert_sink (); + + return NULL; +} + +static void +mail_msg_cancelled (CamelOperation *operation, + gpointer user_data) +{ + mail_msg_cancel (GPOINTER_TO_UINT (user_data)); +} + +static gboolean +mail_msg_submit (CamelOperation *cancellable) +{ + + if (submit_activity) + submit_activity ((GCancellable *) cancellable); + return FALSE; +} + +gpointer +mail_msg_new (MailMsgInfo *info) +{ + MailMsg *msg; + + g_mutex_lock (&mail_msg_lock); + + msg = g_slice_alloc0 (info->size); + msg->info = info; + msg->ref_count = 1; + msg->seq = mail_msg_seq++; + + msg->cancellable = camel_operation_new (); + + if (create_activity) + create_activity (msg->cancellable); + + g_signal_connect ( + msg->cancellable, "cancelled", + G_CALLBACK (mail_msg_cancelled), + GINT_TO_POINTER (msg->seq)); + + g_hash_table_insert ( + mail_msg_active_table, GINT_TO_POINTER (msg->seq), msg); + + d (printf ("New message %p\n", msg)); + + g_mutex_unlock (&mail_msg_lock); + + return msg; +} + +#ifdef MALLOC_CHECK +#include + +static void +checkmem (gpointer p) +{ + if (p) { + gint status = mprobe (p); + + switch (status) { + case MCHECK_HEAD: + printf ("Memory underrun at %p\n", p); + abort (); + case MCHECK_TAIL: + printf ("Memory overrun at %p\n", p); + abort (); + case MCHECK_FREE: + printf ("Double free %p\n", p); + abort (); + } + } +} +#endif + +static gboolean +mail_msg_free (MailMsg *mail_msg) +{ + /* This is an idle callback. */ + + if (free_activity) + free_activity (mail_msg->cancellable); + + if (mail_msg->cancellable != NULL) + g_object_unref (mail_msg->cancellable); + + if (mail_msg->error != NULL) + g_error_free (mail_msg->error); + + g_slice_free1 (mail_msg->info->size, mail_msg); + + return FALSE; +} + +gpointer +mail_msg_ref (gpointer msg) +{ + MailMsg *mail_msg = msg; + + g_return_val_if_fail (mail_msg != NULL, msg); + g_return_val_if_fail (mail_msg->ref_count > 0, msg); + + g_atomic_int_inc (&mail_msg->ref_count); + + return msg; +} + +void +mail_msg_unref (gpointer msg) +{ + MailMsg *mail_msg = msg; + + g_return_if_fail (mail_msg != NULL); + g_return_if_fail (mail_msg->ref_count > 0); + + if (g_atomic_int_dec_and_test (&mail_msg->ref_count)) { + +#ifdef MALLOC_CHECK + checkmem (mail_msg); + checkmem (mail_msg->cancel); + checkmem (mail_msg->priv); +#endif + d (printf ("Free message %p\n", msg)); + + if (mail_msg->info->free) + mail_msg->info->free (mail_msg); + + g_mutex_lock (&mail_msg_lock); + + g_hash_table_remove ( + mail_msg_active_table, + GINT_TO_POINTER (mail_msg->seq)); + g_cond_broadcast (&mail_msg_cond); + + g_mutex_unlock (&mail_msg_lock); + + /* Destroy the message from an idle callback + * so we know we're in the main loop thread. */ + g_idle_add ((GSourceFunc) mail_msg_free, mail_msg); + } +} + +void +mail_msg_check_error (gpointer msg) +{ + MailMsg *m = msg; + +#ifdef MALLOC_CHECK + checkmem (m); + checkmem (m->cancel); + checkmem (m->priv); +#endif + + if (m->error == NULL) + return; + + if (complete_activity) + complete_activity (m->cancellable); + + if (g_error_matches (m->error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + if (cancel_activity) + cancel_activity (m->cancellable); + return; + } + + /* XXX Hmm, no explanation of why this is needed. It looks like + * a lame hack and will be removed at some point, if only to + * reintroduce whatever issue made this necessary so we can + * document it in the source code this time. */ + if (g_error_matches ( + m->error, CAMEL_FOLDER_ERROR, + CAMEL_FOLDER_ERROR_INVALID_UID)) + return; + + /* FIXME: Submit an error on the dbus */ + if (alert_error) { + gchar *what; + + if (m->info->desc && (what = m->info->desc (m))) { + alert_error (m->cancellable, what, m->error->message); + g_free (what); + } else + alert_error (m->cancellable, NULL, m->error->message); + } +} + +void +mail_msg_cancel (guint msgid) +{ + MailMsg *msg; + GCancellable *cancellable = NULL; + + g_mutex_lock (&mail_msg_lock); + + msg = g_hash_table_lookup ( + mail_msg_active_table, GINT_TO_POINTER (msgid)); + + /* Hold a reference to the GCancellable so it doesn't finalize + * itself on us between unlocking the mutex and cancelling. */ + if (msg != NULL) { + cancellable = msg->cancellable; + if (g_cancellable_is_cancelled (cancellable)) + cancellable = NULL; + else + g_object_ref (cancellable); + } + + g_mutex_unlock (&mail_msg_lock); + + if (cancellable != NULL) { + g_cancellable_cancel (cancellable); + g_object_unref (cancellable); + } +} + +gboolean +mail_msg_active (void) +{ + gboolean active; + + g_mutex_lock (&mail_msg_lock); + active = g_hash_table_size (mail_msg_active_table) > 0; + g_mutex_unlock (&mail_msg_lock); + + return active; +} + +/* **************************************** */ + +static GHookList cancel_hook_list; + +GHook * +mail_cancel_hook_add (GHookFunc func, + gpointer data) +{ + GHook *hook; + + g_mutex_lock (&mail_msg_lock); + + if (!cancel_hook_list.is_setup) + g_hook_list_init (&cancel_hook_list, sizeof (GHook)); + + hook = g_hook_alloc (&cancel_hook_list); + hook->func = func; + hook->data = data; + + g_hook_append (&cancel_hook_list, hook); + + g_mutex_unlock (&mail_msg_lock); + + return hook; +} + +void +mail_cancel_hook_remove (GHook *hook) +{ + g_mutex_lock (&mail_msg_lock); + + g_return_if_fail (cancel_hook_list.is_setup); + g_hook_destroy_link (&cancel_hook_list, hook); + + g_mutex_unlock (&mail_msg_lock); +} + +void +mail_cancel_all (void) +{ + camel_operation_cancel_all (); + + g_mutex_lock (&mail_msg_lock); + + if (cancel_hook_list.is_setup) + g_hook_list_invoke (&cancel_hook_list, FALSE); + + g_mutex_unlock (&mail_msg_lock); +} + +static guint idle_source_id = 0; +G_LOCK_DEFINE_STATIC (idle_source_id); +static GAsyncQueue *main_loop_queue = NULL; +static GAsyncQueue *msg_reply_queue = NULL; +static GThread *main_thread = NULL; + +static gboolean +mail_msg_idle_cb (void) +{ + MailMsg *msg; + + g_return_val_if_fail (main_loop_queue != NULL, FALSE); + g_return_val_if_fail (msg_reply_queue != NULL, FALSE); + + G_LOCK (idle_source_id); + idle_source_id = 0; + G_UNLOCK (idle_source_id); + /* check the main loop queue */ + while ((msg = g_async_queue_try_pop (main_loop_queue)) != NULL) { + GCancellable *cancellable; + + cancellable = msg->cancellable; + + g_idle_add_full ( + G_PRIORITY_DEFAULT, + (GSourceFunc) mail_msg_submit, + g_object_ref (msg->cancellable), + (GDestroyNotify) g_object_unref); + if (msg->info->exec != NULL) + msg->info->exec (msg, cancellable, &msg->error); + if (msg->info->done != NULL) + msg->info->done (msg); + mail_msg_unref (msg); + } + + /* check the reply queue */ + while ((msg = g_async_queue_try_pop (msg_reply_queue)) != NULL) { + if (msg->info->done != NULL) + msg->info->done (msg); + mail_msg_check_error (msg); + mail_msg_unref (msg); + } + return FALSE; +} + +static void +mail_msg_proxy (MailMsg *msg) +{ + GCancellable *cancellable; + + cancellable = msg->cancellable; + + if (msg->info->desc != NULL) { + gchar *text = msg->info->desc (msg); + camel_operation_push_message (cancellable, "%s", text); + g_free (text); + } + + g_idle_add_full ( + G_PRIORITY_DEFAULT, + (GSourceFunc) mail_msg_submit, + g_object_ref (msg->cancellable), + (GDestroyNotify) g_object_unref); + + if (msg->info->exec != NULL) + msg->info->exec (msg, cancellable, &msg->error); + + if (msg->info->desc != NULL) + camel_operation_pop_message (cancellable); + + g_async_queue_push (msg_reply_queue, msg); + + G_LOCK (idle_source_id); + if (idle_source_id == 0) + idle_source_id = g_idle_add ( + (GSourceFunc) mail_msg_idle_cb, NULL); + G_UNLOCK (idle_source_id); +} + +void +mail_msg_init (void) +{ + g_mutex_init (&mail_msg_lock); + g_cond_init (&mail_msg_cond); + + main_loop_queue = g_async_queue_new (); + msg_reply_queue = g_async_queue_new (); + + mail_msg_active_table = g_hash_table_new (NULL, NULL); + main_thread = g_thread_self (); +} + +static gint +mail_msg_compare (const MailMsg *msg1, + const MailMsg *msg2) +{ + gint priority1 = msg1->priority; + gint priority2 = msg2->priority; + + if (priority1 == priority2) + return 0; + + return (priority1 < priority2) ? 1 : -1; +} + +static gpointer +create_thread_pool (gpointer data) +{ + GThreadPool *thread_pool; + gint max_threads = GPOINTER_TO_INT (data); + + /* once created, run forever */ + thread_pool = g_thread_pool_new ( + (GFunc) mail_msg_proxy, NULL, max_threads, FALSE, NULL); + g_thread_pool_set_sort_function ( + thread_pool, (GCompareDataFunc) mail_msg_compare, NULL); + + return thread_pool; +} + +void +mail_msg_main_loop_push (gpointer msg) +{ + g_async_queue_push_sorted ( + main_loop_queue, msg, + (GCompareDataFunc) mail_msg_compare, NULL); + + G_LOCK (idle_source_id); + if (idle_source_id == 0) + idle_source_id = g_idle_add ( + (GSourceFunc) mail_msg_idle_cb, NULL); + G_UNLOCK (idle_source_id); +} + +void +mail_msg_unordered_push (gpointer msg) +{ + static GOnce once = G_ONCE_INIT; + + g_once (&once, (GThreadFunc) create_thread_pool, GINT_TO_POINTER (10)); + + g_thread_pool_push ((GThreadPool *) once.retval, msg, NULL); +} + +void +mail_msg_fast_ordered_push (gpointer msg) +{ + static GOnce once = G_ONCE_INIT; + + g_once (&once, (GThreadFunc) create_thread_pool, GINT_TO_POINTER (1)); + + g_thread_pool_push ((GThreadPool *) once.retval, msg, NULL); +} + +void +mail_msg_slow_ordered_push (gpointer msg) +{ + static GOnce once = G_ONCE_INIT; + + g_once (&once, (GThreadFunc) create_thread_pool, GINT_TO_POINTER (1)); + + g_thread_pool_push ((GThreadPool *) once.retval, msg, NULL); +} + +gboolean +mail_in_main_thread (void) +{ + return (g_thread_self () == main_thread); +} + +/* ********************************************************************** */ + +struct _call_msg { + MailMsg base; + + mail_call_t type; + MailMainFunc func; + gpointer ret; + va_list ap; + EFlag *done; +}; + +static void +do_call (struct _call_msg *m, + GCancellable *cancellable, + GError **error) +{ + gpointer p1, *p2, *p3, *p4, *p5; + gint i1; + va_list ap; + + G_VA_COPY (ap, m->ap); + + switch (m->type) { + case MAIL_CALL_p_p: + p1 = va_arg (ap, gpointer); + m->ret = m->func (p1); + break; + case MAIL_CALL_p_pp: + p1 = va_arg (ap, gpointer); + p2 = va_arg (ap, gpointer); + m->ret = m->func (p1, p2); + break; + case MAIL_CALL_p_ppp: + p1 = va_arg (ap, gpointer); + p2 = va_arg (ap, gpointer); + p3 = va_arg (ap, gpointer); + m->ret = m->func (p1, p2, p3); + break; + case MAIL_CALL_p_pppp: + p1 = va_arg (ap, gpointer); + p2 = va_arg (ap, gpointer); + p3 = va_arg (ap, gpointer); + p4 = va_arg (ap, gpointer); + m->ret = m->func (p1, p2, p3, p4); + break; + case MAIL_CALL_p_ppppp: + p1 = va_arg (ap, gpointer); + p2 = va_arg (ap, gpointer); + p3 = va_arg (ap, gpointer); + p4 = va_arg (ap, gpointer); + p5 = va_arg (ap, gpointer); + m->ret = m->func (p1, p2, p3, p4, p5); + break; + case MAIL_CALL_p_ppippp: + p1 = va_arg (ap, gpointer); + p2 = va_arg (ap, gpointer); + i1 = va_arg (ap, gint); + p3 = va_arg (ap, gpointer); + p4 = va_arg (ap, gpointer); + p5 = va_arg (ap, gpointer); + m->ret = m->func (p1, p2, i1, p3, p4, p5); + break; + } + + va_end (ap); + + if (g_cancellable_is_cancelled (cancellable)) { + if (cancel_activity) + cancel_activity (cancellable); + } else { + if (complete_activity) + complete_activity (cancellable); + } + + if (m->done != NULL) + e_flag_set (m->done); +} + +static void +do_free (struct _call_msg *msg) +{ + va_end (msg->ap); +} + +static MailMsgInfo mail_call_info = { + sizeof (struct _call_msg), + (MailMsgDescFunc) NULL, + (MailMsgExecFunc) do_call, + (MailMsgDoneFunc) NULL, + (MailMsgFreeFunc) do_free +}; + +gpointer +mail_call_main (mail_call_t type, + MailMainFunc func, + ...) +{ + GCancellable *cancellable; + struct _call_msg *m; + gpointer ret; + va_list ap; + + va_start (ap, func); + + m = mail_msg_new (&mail_call_info); + m->type = type; + m->func = func; + G_VA_COPY (m->ap, ap); + + cancellable = m->base.cancellable; + + if (mail_in_main_thread ()) + do_call (m, cancellable, &m->base.error); + else { + mail_msg_ref (m); + m->done = e_flag_new (); + mail_msg_main_loop_push (m); + e_flag_wait (m->done); + e_flag_free (m->done); + } + + va_end (ap); + + ret = m->ret; + mail_msg_unref (m); + + return ret; +} + +void +mail_mt_set_backend (gchar *backend) +{ + shell_builtin_backend = backend; +} + diff --git a/libemail-engine/mail-mt.h b/libemail-engine/mail-mt.h new file mode 100644 index 0000000000..03cea96398 --- /dev/null +++ b/libemail-engine/mail-mt.h @@ -0,0 +1,125 @@ +/* + * 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; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * Michael Zucchi + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef _MAIL_MT +#define _MAIL_MT + +#include + +#include + +typedef struct _MailMsg MailMsg; +typedef struct _MailMsgInfo MailMsgInfo; + +typedef gchar * (*MailMsgDescFunc) (MailMsg *msg); +typedef void (*MailMsgExecFunc) (MailMsg *msg, + GCancellable *cancellable, + GError **error); +typedef void (*MailMsgDoneFunc) (MailMsg *msg); +typedef void (*MailMsgFreeFunc) (MailMsg *msg); +typedef void (*MailMsgDispatchFunc) (gpointer msg); + +typedef void (*MailMsgCreateActivityFunc) (GCancellable *cancellable); +typedef void (*MailMsgSubmitActivityFunc) (GCancellable *cancellable); +typedef void (*MailMsgFreeActivityFunc) (GCancellable *cancellable); +typedef void (*MailMsgCompleteActivityFunc) (GCancellable *cancellable); +typedef void (*MailMsgCancelActivityFunc) (GCancellable *cancellable); +typedef void (*MailMsgAlertErrorFunc) (GCancellable *cancellable, + const gchar *what, + const gchar *message); +typedef EAlertSink * + (*MailMsgGetAlertSinkFunc) (void); + +struct _MailMsg { + MailMsgInfo *info; + volatile gint ref_count; + guint seq; /* seq number for synchronisation */ + gint priority; /* priority (default = 0) */ + GCancellable *cancellable; + GError *error; /* up to the caller to use this */ +}; + +struct _MailMsgInfo { + gsize size; + MailMsgDescFunc desc; + MailMsgExecFunc exec; + MailMsgDoneFunc done; + MailMsgFreeFunc free; +}; + +/* Just till we move this out to EDS */ +EAlertSink * mail_msg_get_alert_sink (void); + +/* setup ports */ +void mail_msg_init (void); +void mail_msg_register_activities (MailMsgCreateActivityFunc, + MailMsgSubmitActivityFunc, + MailMsgFreeActivityFunc, + MailMsgCompleteActivityFunc, + MailMsgCancelActivityFunc, + MailMsgAlertErrorFunc, + MailMsgGetAlertSinkFunc); + +gboolean mail_in_main_thread (void); + +/* allocate a new message */ +gpointer mail_msg_new (MailMsgInfo *info); +gpointer mail_msg_ref (gpointer msg); +void mail_msg_unref (gpointer msg); +void mail_msg_check_error (gpointer msg); +void mail_msg_cancel (guint msgid); +gboolean mail_msg_active (void); + +/* dispatch a message */ +void mail_msg_main_loop_push (gpointer msg); +void mail_msg_unordered_push (gpointer msg); +void mail_msg_fast_ordered_push (gpointer msg); +void mail_msg_slow_ordered_push (gpointer msg); + +/* To implement the stop button */ +GHook * mail_cancel_hook_add (GHookFunc func, gpointer data); +void mail_cancel_hook_remove (GHook *hook); +void mail_cancel_all (void); + +/* request a string/password */ +gchar *mail_get_password (CamelService *service, const gchar *prompt, + gboolean secret, gboolean *cache); + +void mail_mt_set_backend (gchar *backend); + +/* Call a function in the GUI thread, wait for it to return, type is + * the marshaller to use. FIXME This thing is horrible, please put + * it out of its misery. */ +typedef enum { + MAIL_CALL_p_p, + MAIL_CALL_p_pp, + MAIL_CALL_p_ppp, + MAIL_CALL_p_pppp, + MAIL_CALL_p_ppppp, + MAIL_CALL_p_ppippp +} mail_call_t; + +typedef gpointer (*MailMainFunc)(); + +gpointer mail_call_main (mail_call_t type, MailMainFunc func, ...); + +#endif /* _MAIL_MT */ diff --git a/libemail-engine/mail-ops.c b/libemail-engine/mail-ops.c index e2bcaa6894..24fc77253f 100644 --- a/libemail-engine/mail-ops.c +++ b/libemail-engine/mail-ops.c @@ -36,7 +36,7 @@ #include -#include +#include #include "e-mail-utils.h" #include "mail-ops.h" diff --git a/libemail-engine/mail-ops.h b/libemail-engine/mail-ops.h index 42f3118987..dd115ff601 100644 --- a/libemail-engine/mail-ops.h +++ b/libemail-engine/mail-ops.h @@ -27,8 +27,8 @@ G_BEGIN_DECLS #include -#include #include +#include void mail_transfer_messages (EMailSession *session, CamelFolder *source, diff --git a/libemail-engine/mail-vfolder.c b/libemail-engine/mail-vfolder.c index eef4d3899b..b23ce0cf2e 100644 --- a/libemail-engine/mail-vfolder.c +++ b/libemail-engine/mail-vfolder.c @@ -24,24 +24,21 @@ #include #endif -#include +#include "mail-vfolder.h" +#include #include -#include "libevolution-utils/e-alert-dialog.h" - -#include "libemail-utils/mail-mt.h" -#include "libemail-engine/mail-folder-cache.h" #include "libemail-engine/e-mail-folder-utils.h" #include "libemail-engine/e-mail-session.h" #include "libemail-engine/e-mail-utils.h" +#include "libemail-engine/em-vfolder-context.h" +#include "libemail-engine/em-vfolder-rule.h" +#include "libemail-engine/mail-folder-cache.h" +#include "libemail-engine/mail-mt.h" #include "libemail-engine/mail-ops.h" #include "libemail-engine/mail-tools.h" -#include -#include -#include "mail-vfolder.h" - #define d(x) /* (printf("%s:%s: ", G_STRLOC, G_STRFUNC), (x))*/ /* Note: Once we completely move mail to EDS, this context wont be available for UI. diff --git a/libemail-engine/mail-vfolder.h b/libemail-engine/mail-vfolder.h index eafd6ba1e1..8732526fef 100644 --- a/libemail-engine/mail-vfolder.h +++ b/libemail-engine/mail-vfolder.h @@ -24,10 +24,9 @@ #include -#include -#include +#include #include -#include +#include void vfolder_load_storage (EMailSession *session); -- cgit v1.2.3