/* * e-mail-part-list.c * * 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 * */ #include #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 mail_part_list_set_folder (EMailPartList *part_list, CamelFolder *folder) { 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 mail_part_list_set_message (EMailPartList *part_list, CamelMimeMessage *message) { g_return_if_fail (part_list->priv->message == NULL); /* 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); /* 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; } 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)) g_object_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); } static void 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->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 (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) { 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 (E_IS_MAIL_PART (part)); g_mutex_lock (&part_list->priv->queue_lock); g_queue_push_tail ( &part_list->priv->queue, g_object_ref (part)); g_mutex_unlock (&part_list->priv->queue_lock); e_mail_part_set_part_list (part, part_list); } EMailPart * e_mail_part_list_ref_part (EMailPartList *part_list, const gchar *part_id) { 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 (part_id != NULL, NULL); by_cid = (g_ascii_strncasecmp (part_id, "cid:", 4) == 0); g_mutex_lock (&part_list->priv->queue_lock); head = g_queue_peek_head_link (&part_list->priv->queue); for (link = head; link != NULL; link = g_list_next (link)) { EMailPart *candidate = E_MAIL_PART (link->data); const gchar *candidate_id; if (by_cid) candidate_id = e_mail_part_get_cid (candidate); else candidate_id = e_mail_part_get_id (candidate); if (g_strcmp0 (candidate_id, part_id) == 0) { match = g_object_ref (candidate); break; } } g_mutex_unlock (&part_list->priv->queue_lock); return match; } /** * 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 * * 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. * * Each #EMailPart is referenced for thread-safety and should be unreferenced * with g_object_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) { 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_mutex_lock (&part_list->priv->queue_lock); link = g_queue_peek_head_link (&part_list->priv->queue); if (part_id != NULL) { for (; link != NULL; link = g_list_next (link)) { EMailPart *candidate = E_MAIL_PART (link->data); const gchar *candidate_id; candidate_id = e_mail_part_get_id (candidate); if (g_strcmp0 (candidate_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; g_queue_push_tail (result_queue, g_object_ref (part)); parts_queued++; } g_mutex_unlock (&part_list->priv->queue_lock); return parts_queued; } /** * e_mail_part_list_get_registry: * * Returns a #CamelObjectBag where parsed #EMailPartLists can be stored. */ CamelObjectBag * e_mail_part_list_get_registry (void) { G_LOCK (registry); if (registry == NULL) { registry = camel_object_bag_new ( g_str_hash, g_str_equal, (CamelCopyFunc) g_strdup, g_free); } G_UNLOCK (registry); return registry; }