aboutsummaryrefslogtreecommitdiffstats
path: root/em-format/e-mail-part-list.c
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@redhat.com>2012-12-05 21:19:04 +0800
committerMatthew Barnes <mbarnes@redhat.com>2012-12-08 03:01:04 +0800
commit91822b42dc7b5eb64cad2626f9fc620a2ee6a2c8 (patch)
tree1c06f36fa153eee0779cdfa1be1a24f62e93787d /em-format/e-mail-part-list.c
parent2f0d83cf74b94d5e6272c07179df6e6c7a929789 (diff)
downloadgsoc2013-evolution-91822b42dc7b5eb64cad2626f9fc620a2ee6a2c8.tar
gsoc2013-evolution-91822b42dc7b5eb64cad2626f9fc620a2ee6a2c8.tar.gz
gsoc2013-evolution-91822b42dc7b5eb64cad2626f9fc620a2ee6a2c8.tar.bz2
gsoc2013-evolution-91822b42dc7b5eb64cad2626f9fc620a2ee6a2c8.tar.lz
gsoc2013-evolution-91822b42dc7b5eb64cad2626f9fc620a2ee6a2c8.tar.xz
gsoc2013-evolution-91822b42dc7b5eb64cad2626f9fc620a2ee6a2c8.tar.zst
gsoc2013-evolution-91822b42dc7b5eb64cad2626f9fc620a2ee6a2c8.zip
Make EMailPartList thread-safe.
Exposing data members in the public struct is unwise, especially when EMailPartList is used from multiple threads. Instead keep the members private and provide a set of thread-safe functions to manipulate them.
Diffstat (limited to 'em-format/e-mail-part-list.c')
-rw-r--r--em-format/e-mail-part-list.c355
1 files changed, 307 insertions, 48 deletions
diff --git a/em-format/e-mail-part-list.c b/em-format/e-mail-part-list.c
index 38beeea6e2..641a88c947 100644
--- a/em-format/e-mail-part-list.c
+++ b/em-format/e-mail-part-list.c
@@ -20,36 +20,167 @@
#include "e-mail-part-list.h"
+#define E_MAIL_PART_LIST_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_PART_LIST, EMailPartListPrivate))
+
+struct _EMailPartListPrivate {
+ CamelFolder *folder;
+ CamelMimeMessage *message;
+ gchar *message_uid;
+
+ GQueue queue;
+ GMutex queue_lock;
+};
+
+enum {
+ PROP_0,
+ PROP_FOLDER,
+ PROP_MESSAGE,
+ PROP_MESSAGE_UID
+};
+
G_DEFINE_TYPE (EMailPartList, e_mail_part_list, G_TYPE_OBJECT)
static CamelObjectBag *registry = NULL;
G_LOCK_DEFINE_STATIC (registry);
static void
-unref_mail_part (gpointer user_data)
+mail_part_list_set_folder (EMailPartList *part_list,
+ CamelFolder *folder)
{
- if (user_data)
- e_mail_part_unref (user_data);
+ g_return_if_fail (part_list->priv->folder == NULL);
+
+ /* The folder property is optional. */
+ if (folder != NULL) {
+ g_return_if_fail (CAMEL_IS_FOLDER (folder));
+ part_list->priv->folder = g_object_ref (folder);
+ }
}
static void
-e_mail_part_list_finalize (GObject *object)
+mail_part_list_set_message (EMailPartList *part_list,
+ CamelMimeMessage *message)
{
- EMailPartList *part_list = E_MAIL_PART_LIST (object);
+ g_return_if_fail (part_list->priv->message == NULL);
- g_clear_object (&part_list->folder);
- g_clear_object (&part_list->message);
+ /* The message property is optional. */
+ if (message != NULL) {
+ g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
+ part_list->priv->message = g_object_ref (message);
+ }
+}
+
+static void
+mail_part_list_set_message_uid (EMailPartList *part_list,
+ const gchar *message_uid)
+{
+ g_return_if_fail (part_list->priv->message_uid == NULL);
- if (part_list->list) {
- g_slist_free_full (part_list->list, unref_mail_part);
- part_list->list = NULL;
+ /* The message_uid property is optional. */
+ part_list->priv->message_uid = g_strdup (message_uid);
+}
+
+static void
+mail_part_list_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_FOLDER:
+ mail_part_list_set_folder (
+ E_MAIL_PART_LIST (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_MESSAGE:
+ mail_part_list_set_message (
+ E_MAIL_PART_LIST (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_MESSAGE_UID:
+ mail_part_list_set_message_uid (
+ E_MAIL_PART_LIST (object),
+ g_value_get_string (value));
+ return;
}
- if (part_list->message_uid) {
- g_free (part_list->message_uid);
- part_list->message_uid = NULL;
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_part_list_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_FOLDER:
+ g_value_set_object (
+ value,
+ e_mail_part_list_get_folder (
+ E_MAIL_PART_LIST (object)));
+ return;
+
+ case PROP_MESSAGE:
+ g_value_set_object (
+ value,
+ e_mail_part_list_get_message (
+ E_MAIL_PART_LIST (object)));
+ return;
+
+ case PROP_MESSAGE_UID:
+ g_value_set_string (
+ value,
+ e_mail_part_list_get_message_uid (
+ E_MAIL_PART_LIST (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_part_list_dispose (GObject *object)
+{
+ EMailPartListPrivate *priv;
+
+ priv = E_MAIL_PART_LIST_GET_PRIVATE (object);
+
+ if (priv->folder != NULL) {
+ g_object_unref (priv->folder);
+ priv->folder = NULL;
}
+ if (priv->message != NULL) {
+ g_object_unref (priv->message);
+ priv->message = NULL;
+ }
+
+ g_mutex_lock (&priv->queue_lock);
+ while (!g_queue_is_empty (&priv->queue))
+ e_mail_part_unref (g_queue_pop_head (&priv->queue));
+ g_mutex_unlock (&priv->queue_lock);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_mail_part_list_parent_class)->dispose (object);
+}
+
+static void
+mail_part_list_finalize (GObject *object)
+{
+ EMailPartListPrivate *priv;
+
+ priv = E_MAIL_PART_LIST_GET_PRIVATE (object);
+
+ g_free (priv->message_uid);
+
+ g_warn_if_fail (g_queue_is_empty (&priv->queue));
+ g_mutex_clear (&priv->queue_lock);
+
+ /* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_mail_part_list_parent_class)->finalize (object);
}
@@ -58,78 +189,206 @@ e_mail_part_list_class_init (EMailPartListClass *class)
{
GObjectClass *object_class;
+ g_type_class_add_private (class, sizeof (EMailPartListPrivate));
+
object_class = G_OBJECT_CLASS (class);
- object_class->finalize = e_mail_part_list_finalize;
+ object_class->set_property = mail_part_list_set_property;
+ object_class->get_property = mail_part_list_get_property;
+ object_class->dispose = mail_part_list_dispose;
+ object_class->finalize = mail_part_list_finalize;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_FOLDER,
+ g_param_spec_object (
+ "folder",
+ "Folder",
+ NULL,
+ CAMEL_TYPE_FOLDER,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_MESSAGE,
+ g_param_spec_object (
+ "message",
+ "Message",
+ NULL,
+ CAMEL_TYPE_MIME_MESSAGE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_MESSAGE_UID,
+ g_param_spec_string (
+ "message-uid",
+ "Message UID",
+ NULL,
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
}
static void
e_mail_part_list_init (EMailPartList *part_list)
{
+ part_list->priv = E_MAIL_PART_LIST_GET_PRIVATE (part_list);
+ g_mutex_init (&part_list->priv->queue_lock);
}
EMailPartList *
-e_mail_part_list_new ()
+e_mail_part_list_new (CamelMimeMessage *message,
+ const gchar *message_uid,
+ CamelFolder *folder)
+{
+ if (message != NULL)
+ g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
+
+ if (folder != NULL)
+ g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
+
+ return g_object_new (
+ E_TYPE_MAIL_PART_LIST,
+ "message", message,
+ "message-uid", message_uid,
+ "folder", folder, NULL);
+}
+
+CamelFolder *
+e_mail_part_list_get_folder (EMailPartList *part_list)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART_LIST (part_list), NULL);
+
+ return part_list->priv->folder;
+}
+
+CamelMimeMessage *
+e_mail_part_list_get_message (EMailPartList *part_list)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART_LIST (part_list), NULL);
+
+ return part_list->priv->message;
+}
+
+const gchar *
+e_mail_part_list_get_message_uid (EMailPartList *part_list)
{
- return g_object_new (E_TYPE_MAIL_PART_LIST, NULL);
+ g_return_val_if_fail (E_IS_MAIL_PART_LIST (part_list), NULL);
+
+ return part_list->priv->message_uid;
+}
+
+void
+e_mail_part_list_add_part (EMailPartList *part_list,
+ EMailPart *part)
+{
+ g_return_if_fail (E_IS_MAIL_PART_LIST (part_list));
+ g_return_if_fail (part != NULL);
+
+ g_mutex_lock (&part_list->priv->queue_lock);
+
+ g_queue_push_tail (
+ &part_list->priv->queue,
+ e_mail_part_ref (part));
+
+ g_mutex_unlock (&part_list->priv->queue_lock);
}
EMailPart *
-e_mail_part_list_find_part (EMailPartList *part_list,
- const gchar *id)
+e_mail_part_list_ref_part (EMailPartList *part_list,
+ const gchar *part_id)
{
- GSList *iter;
+ EMailPart *match = NULL;
+ GList *head, *link;
gboolean by_cid;
g_return_val_if_fail (E_IS_MAIL_PART_LIST (part_list), NULL);
- g_return_val_if_fail (id && *id, NULL);
+ g_return_val_if_fail (part_id != NULL, NULL);
- by_cid = (g_str_has_prefix (id, "cid:") || g_str_has_prefix (id, "CID:"));
+ by_cid = (g_ascii_strncasecmp (part_id, "cid:", 4) == 0);
- for (iter = part_list->list; iter; iter = iter->next) {
+ g_mutex_lock (&part_list->priv->queue_lock);
- EMailPart *part = iter->data;
- if (!part)
- continue;
+ head = g_queue_peek_head_link (&part_list->priv->queue);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPart *part = link->data;
- if ((by_cid && (g_strcmp0 (part->cid, id) == 0)) ||
- (!by_cid && (g_strcmp0 (part->id, id) == 0)))
- return part;
+ if (by_cid && (g_strcmp0 (part->cid, part_id) == 0)) {
+ match = e_mail_part_ref (part);
+ break;
+ }
+
+ if (!by_cid && (g_strcmp0 (part->id, part_id) == 0)) {
+ match = e_mail_part_ref (part);
+ break;
+ }
}
- return NULL;
+ g_mutex_unlock (&part_list->priv->queue_lock);
+
+ return match;
}
/**
- * e_mail_part_list_get_iter:
- * @part_list: a #GSList of #EMailPart
- * @id: id of #EMailPart to lookup
+ * e_mail_part_list_queue_parts:
+ * @part_list: an #EMailPartList
+ * @part_id: the #EMailPart ID to begin queueing from, or %NULL
+ * @result_queue: a #GQueue in which to deposit #EMailPart instances
*
- * Returns iter of an #EMailPart within the @part_list.
+ * Populates @result_queue with a sequence of #EMailPart instances beginning
+ * with the part having @part_id. If @part_id is %NULL, the entire sequence
+ * of #EMailPart instances is queued.
*
- * Return Value: a #GSList sublist. The list is owned by #EMailPartList and
- * must not be freed or altered.
- */
-GSList *
-e_mail_part_list_get_iter (GSList *list,
- const gchar *id)
+ * Each #EMailPart is referenced for thread-safety and should be unreferenced
+ * with e_mail_part_unref().
+ *
+ * Returns: the number of parts added to @result_queue
+ **/
+guint
+e_mail_part_list_queue_parts (EMailPartList *part_list,
+ const gchar *part_id,
+ GQueue *result_queue)
{
- GSList *iter;
+ GList *link;
+ guint parts_queued = 0;
+
+ g_return_val_if_fail (E_IS_MAIL_PART_LIST (part_list), FALSE);
+ g_return_val_if_fail (result_queue != NULL, FALSE);
- g_return_val_if_fail (list != NULL, NULL);
- g_return_val_if_fail (id && *id, NULL);
+ g_mutex_lock (&part_list->priv->queue_lock);
- for (iter = list; iter; iter = iter->next) {
+ link = g_queue_peek_head_link (&part_list->priv->queue);
- EMailPart *part = iter->data;
- if (!part)
+ if (part_id != NULL) {
+ for (; link != NULL; link = g_list_next (link)) {
+ EMailPart *part = link->data;
+
+ if (g_strcmp0 (part->id, part_id) == 0)
+ break;
+ }
+ }
+
+ /* We skip the loop entirely if link is NULL. */
+ for (; link != NULL; link = g_list_next (link)) {
+ EMailPart *part = link->data;
+
+ if (part == NULL)
continue;
- if (g_strcmp0 (part->id, id) == 0)
- return iter;
+ g_queue_push_tail (result_queue, e_mail_part_ref (part));
+ parts_queued++;
}
- return NULL;
+ g_mutex_unlock (&part_list->priv->queue_lock);
+
+ return parts_queued;
}
/**