[evolution-data-server/wip/camel-more-gobject: 43/62] Initial fill-up of CamelMessageInfo and CamelMessageInfoBase
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server/wip/camel-more-gobject: 43/62] Initial fill-up of CamelMessageInfo and CamelMessageInfoBase
- Date: Mon, 19 Sep 2016 11:12:32 +0000 (UTC)
commit d81add2ca80249898d9b32956e963ffa23616b16
Author: Milan Crha <mcrha redhat com>
Date: Fri Sep 2 15:38:28 2016 +0200
Initial fill-up of CamelMessageInfo and CamelMessageInfoBase
camel/Makefile.am | 4 +-
camel/camel-folder-summary.c | 4 +
camel/camel-folder-summary.h | 44 +-
camel/camel-message-content-info.c | 16 -
camel/camel-message-content-info.h | 16 -
camel/camel-message-info-base.c | 865 ++++++++++++++
camel/camel-message-info-base.h | 67 ++
camel/camel-message-info.c | 2267 +++++++++++++++++++++++++++++++++++-
camel/camel-message-info.h | 222 ++++-
camel/camel-mime-utils.c | 822 +++++++++++++
camel/camel-mime-utils.h | 92 ++-
camel/camel.h | 2 +-
12 files changed, 4324 insertions(+), 97 deletions(-)
---
diff --git a/camel/Makefile.am b/camel/Makefile.am
index 7573bfa..646fde3 100644
--- a/camel/Makefile.am
+++ b/camel/Makefile.am
@@ -93,7 +93,7 @@ libcamel_1_2_la_SOURCES = \
camel-memchunk.c \
camel-mempool.c \
camel-message-info.c \
- camel-message-content-info.c \
+ camel-message-info-base.c \
camel-mime-filter-basic.c \
camel-mime-filter-bestenc.c \
camel-mime-filter-canon.c \
@@ -213,7 +213,7 @@ libcamelinclude_HEADERS = \
camel-memchunk.h \
camel-mempool.h \
camel-message-info.h \
- camel-message-content-info.h \
+ camel-message-info-base.h \
camel-mime-filter-basic.h \
camel-mime-filter-bestenc.h \
camel-mime-filter-canon.h \
diff --git a/camel/camel-folder-summary.c b/camel/camel-folder-summary.c
index eb46cfe..ecc0451 100644
--- a/camel/camel-folder-summary.c
+++ b/camel/camel-folder-summary.c
@@ -39,6 +39,8 @@
#include "camel-folder-summary.h"
#include "camel-folder.h"
#include "camel-iconv.h"
+#include "camel-message-info.h"
+#include "camel-message-info-base.h"
#include "camel-mime-filter-basic.h"
#include "camel-mime-filter-charset.h"
#include "camel-mime-filter-html.h"
@@ -1155,6 +1157,8 @@ camel_folder_summary_class_init (CamelFolderSummaryClass *class)
object_class->dispose = folder_summary_dispose;
object_class->finalize = folder_summary_finalize;
+ class->message_info_type = XCAMEL_TYPE_MESSAGE_INFO_BASE;
+
class->message_info_size = sizeof (CamelMessageInfoBase);
class->content_info_size = sizeof (CamelMessageContentInfo);
diff --git a/camel/camel-folder-summary.h b/camel/camel-folder-summary.h
index 192d527..7462190 100644
--- a/camel/camel-folder-summary.h
+++ b/camel/camel-folder-summary.h
@@ -80,36 +80,6 @@ struct _CamelMessageContentInfo {
guint32 size;
};
-/* system flag bits */
-typedef enum _CamelMessageFlags {
- CAMEL_MESSAGE_ANSWERED = 1 << 0,
- CAMEL_MESSAGE_DELETED = 1 << 1,
- CAMEL_MESSAGE_DRAFT = 1 << 2,
- CAMEL_MESSAGE_FLAGGED = 1 << 3,
- CAMEL_MESSAGE_SEEN = 1 << 4,
-
- /* these aren't really system flag bits, but are convenience flags */
- CAMEL_MESSAGE_ATTACHMENTS = 1 << 5,
- CAMEL_MESSAGE_ANSWERED_ALL = 1 << 6,
- CAMEL_MESSAGE_JUNK = 1 << 7,
- CAMEL_MESSAGE_SECURE = 1 << 8,
- CAMEL_MESSAGE_NOTJUNK = 1 << 9,
- CAMEL_MESSAGE_FORWARDED = 1 << 10,
-
- /* following flags are for the folder, and are not really permanent flags */
- CAMEL_MESSAGE_FOLDER_FLAGGED = 1 << 16, /* for use by the folder implementation */
- /* flags after 1 << 16 are used by camel providers,
- * if adding non permanent flags, add them to the end */
-
- CAMEL_MESSAGE_JUNK_LEARN = 1 << 30, /* used when setting CAMEL_MESSAGE_JUNK flag
- * to say that we request junk plugin
- * to learn that message as junk/non junk */
- CAMEL_MESSAGE_USER = 1 << 31 /* supports user flags */
-} CamelMessageFlags;
-
-/* Changes to system flags will NOT trigger a folder changed event */
-#define CAMEL_MESSAGE_SYSTEM_MASK (0xffff << 16)
-
typedef struct _CamelFlag {
struct _CamelFlag *next;
gchar name[1]; /* name allocated as part of the structure */
@@ -121,18 +91,6 @@ typedef struct _CamelTag {
gchar name[1]; /* name allocated as part of the structure */
} CamelTag;
-/* a summary messageid is a 64 bit identifier (partial md5 hash) */
-typedef struct _CamelSummaryMessageID {
- union {
- guint64 id;
- guchar hash[8];
- struct {
- guint32 hi;
- guint32 lo;
- } part;
- } id;
-} CamelSummaryMessageID;
-
/* summary references is a fixed size array of references */
typedef struct _CamelSummaryReferences {
gint size;
@@ -245,6 +203,8 @@ struct _CamelFIRecord;
struct _CamelFolderSummaryClass {
GObjectClass parent_class;
+ GType message_info_type;
+
/* sizes of memory objects */
gsize message_info_size;
gsize content_info_size;
diff --git a/camel/camel-message-info-base.c b/camel/camel-message-info-base.c
new file mode 100644
index 0000000..ca361de
--- /dev/null
+++ b/camel/camel-message-info-base.c
@@ -0,0 +1,865 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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 library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+
+#include "camel-folder-summary.h"
+#include "camel-message-info.h"
+
+#include "camel-message-info-base.h"
+
+struct _xCamelMessageInfoBasePrivate {
+ guint32 flags; /* bit-or of CamelMessageFlags */
+ CamelNamedFlags *user_flags;
+ CamelNameValueArray *user_tags;
+ gchar *subject;
+ gchar *preview;
+ gchar *from;
+ gchar *to;
+ gchar *cc;
+ gchar *mlist;
+ guint32 size;
+ gint64 date_sent; /* aka time_t */
+ gint64 date_received; /* aka time_t */
+ guint64 message_id;
+ GArray *references; /* guint64, aka CamelSummaryMessageID */
+ CamelNameValueArray *headers;
+};
+
+G_DEFINE_TYPE (xCamelMessageInfoBase, xcamel_message_info_base, XCAMEL_TYPE_MESSAGE_INFO)
+
+static guint32
+message_info_base_get_flags (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoBase *bmi;
+ guint32 result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), 0);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+ result = bmi->priv->flags;
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+static gboolean
+message_info_base_set_flags (xCamelMessageInfo *mi,
+ CamelMessageFlags mask,
+ guint32 set)
+{
+ xCamelMessageInfoBase *bmi;
+ guint32 old_flags;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+ old_flags = bmi->priv->flags;
+ bmi->priv->flags = (old_flags & ~mask) | (set & mask);
+ changed = old_flags != bmi->priv->flags;
+ xcamel_message_info_property_unlock (mi);
+
+ return changed;
+}
+
+static gboolean
+message_info_base_get_user_flag (const xCamelMessageInfo *mi,
+ const gchar *name)
+{
+ xCamelMessageInfoBase *bmi;
+ gboolean result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+ result = camel_named_flags_contains (bmi->priv->user_flags, name);
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+static gboolean
+message_info_base_set_user_flag (xCamelMessageInfo *mi,
+ const gchar *name,
+ gboolean state)
+{
+ xCamelMessageInfoBase *bmi;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+ if (!bmi->priv->user_flags)
+ bmi->priv->user_flags = camel_named_flags_new ();
+
+ if (state)
+ changed = camel_named_flags_insert (bmi->priv->user_flags, name);
+ else
+ changed = camel_named_flags_remove (bmi->priv->user_flags, name);
+ xcamel_message_info_property_unlock (mi);
+
+ return changed;
+}
+
+static CamelNamedFlags *
+message_info_base_dup_user_flags (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoBase *bmi;
+ CamelNamedFlags *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), NULL);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+ if (bmi->priv->user_flags)
+ result = camel_named_flags_copy (bmi->priv->user_flags);
+ else
+ result = NULL;
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+static gboolean
+message_info_base_take_user_flags (xCamelMessageInfo *mi,
+ CamelNamedFlags *user_flags)
+{
+ xCamelMessageInfoBase *bmi;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+
+ /* Consider them the same if they are the same pointer or they both are empty;
+ otherwise report change. */
+ changed = !(bmi->priv->user_flags == user_flags ||
+ (bmi->priv->user_flags && user_flags &&
+ !camel_named_flags_length (bmi->priv->user_flags) &&
+ !camel_named_flags_length (user_flags)));
+
+ if (changed) {
+ camel_named_flags_free (bmi->priv->user_flags);
+ bmi->priv->user_flags = user_flags;
+ }
+
+ xcamel_message_info_property_unlock (mi);
+
+ return changed;
+}
+
+static const gchar *
+message_info_base_get_user_tag (const xCamelMessageInfo *mi,
+ const gchar *name)
+{
+ xCamelMessageInfoBase *bmi;
+ const gchar *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+ result = camel_name_value_array_get_named (bmi->priv->user_tags, TRUE, name);
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+static gboolean
+message_info_base_set_user_tag (xCamelMessageInfo *mi,
+ const gchar *name,
+ const gchar *value)
+{
+ xCamelMessageInfoBase *bmi;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+ if (value)
+ changed = camel_name_value_array_set_named (bmi->priv->user_tags, TRUE, name, value);
+ else
+ changed = camel_name_value_array_remove_named (bmi->priv->user_tags, TRUE, name, FALSE);
+ xcamel_message_info_property_unlock (mi);
+
+ return changed;
+}
+
+static CamelNameValueArray *
+message_info_base_dup_user_tags (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoBase *bmi;
+ CamelNameValueArray *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), NULL);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+ result = camel_name_value_array_copy (bmi->priv->user_tags);
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+static gboolean
+message_info_base_take_user_tags (xCamelMessageInfo *mi,
+ CamelNameValueArray *user_tags)
+{
+ xCamelMessageInfoBase *bmi;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+
+ /* Consider them the same if they are the same pointer or they both are empty;
+ otherwise report change. */
+ changed = !(bmi->priv->user_tags == user_tags ||
+ (bmi->priv->user_tags && user_tags &&
+ !camel_name_value_array_length (bmi->priv->user_tags) &&
+ !camel_name_value_array_length (user_tags)));
+
+ if (changed) {
+ camel_name_value_array_free (bmi->priv->user_tags);
+ bmi->priv->user_tags = user_tags;
+ }
+
+ xcamel_message_info_property_unlock (mi);
+
+ return changed;
+}
+
+static const gchar *
+message_info_base_get_subject (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoBase *bmi;
+ const gchar *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), NULL);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+ result = bmi->priv->subject;
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+static gboolean
+message_info_base_set_subject (xCamelMessageInfo *mi,
+ const gchar *subject)
+{
+ xCamelMessageInfoBase *bmi;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+
+ changed = g_strcmp0 (bmi->priv->subject, subject) != 0;
+
+ if (changed) {
+ g_free (bmi->priv->subject);
+ bmi->priv->subject = g_strdup (subject);
+ }
+
+ xcamel_message_info_property_unlock (mi);
+
+ return changed;
+}
+
+static const gchar *
+message_info_base_get_preview (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoBase *bmi;
+ const gchar *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), NULL);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+ result = bmi->priv->preview;
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+static gboolean
+message_info_base_set_preview (xCamelMessageInfo *mi,
+ const gchar *preview)
+{
+ xCamelMessageInfoBase *bmi;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+
+ changed = g_strcmp0 (bmi->priv->preview, preview) != 0;
+
+ if (changed) {
+ g_free (bmi->priv->preview);
+ bmi->priv->preview = g_strdup (preview);
+ }
+
+ xcamel_message_info_property_unlock (mi);
+
+ return changed;
+}
+
+static const gchar *
+message_info_base_get_from (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoBase *bmi;
+ const gchar *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), NULL);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+ result = bmi->priv->from;
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+static gboolean
+message_info_base_set_from (xCamelMessageInfo *mi,
+ const gchar *from)
+{
+ xCamelMessageInfoBase *bmi;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+
+ changed = g_strcmp0 (bmi->priv->from, from) != 0;
+
+ if (changed) {
+ g_free (bmi->priv->from);
+ bmi->priv->from = g_strdup (from);
+ }
+
+ xcamel_message_info_property_unlock (mi);
+
+ return changed;
+}
+
+static const gchar *
+message_info_base_get_to (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoBase *bmi;
+ const gchar *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), NULL);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+ result = bmi->priv->to;
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+static gboolean
+message_info_base_set_to (xCamelMessageInfo *mi,
+ const gchar *to)
+{
+ xCamelMessageInfoBase *bmi;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+
+ changed = g_strcmp0 (bmi->priv->to, to) != 0;
+
+ if (changed) {
+ g_free (bmi->priv->to);
+ bmi->priv->to = g_strdup (to);
+ }
+
+ xcamel_message_info_property_unlock (mi);
+
+ return changed;
+}
+
+static const gchar *
+message_info_base_get_cc (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoBase *bmi;
+ const gchar *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), NULL);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+ result = bmi->priv->cc;
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+static gboolean
+message_info_base_set_cc (xCamelMessageInfo *mi,
+ const gchar *cc)
+{
+ xCamelMessageInfoBase *bmi;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+
+ changed = g_strcmp0 (bmi->priv->cc, cc) != 0;
+
+ if (changed) {
+ g_free (bmi->priv->cc);
+ bmi->priv->cc = g_strdup (cc);
+ }
+
+ xcamel_message_info_property_unlock (mi);
+
+ return changed;
+}
+
+static const gchar *
+message_info_base_get_mlist (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoBase *bmi;
+ const gchar *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), NULL);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+ result = bmi->priv->mlist;
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+static gboolean
+message_info_base_set_mlist (xCamelMessageInfo *mi,
+ const gchar *mlist)
+{
+ xCamelMessageInfoBase *bmi;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+
+ changed = g_strcmp0 (bmi->priv->mlist, mlist) != 0;
+
+ if (changed) {
+ g_free (bmi->priv->mlist);
+ bmi->priv->mlist = g_strdup (mlist);
+ }
+
+ xcamel_message_info_property_unlock (mi);
+
+ return changed;
+}
+
+static guint32
+message_info_base_get_size (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoBase *bmi;
+ guint32 result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), 0);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+ result = bmi->priv->size;
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+static gboolean
+message_info_base_set_size (xCamelMessageInfo *mi,
+ guint32 size)
+{
+ xCamelMessageInfoBase *bmi;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+
+ changed = bmi->priv->size != size;
+
+ if (changed)
+ bmi->priv->size = size;
+
+ xcamel_message_info_property_unlock (mi);
+
+ return changed;
+}
+
+static gint64
+message_info_base_get_date_sent (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoBase *bmi;
+ gint64 result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), 0);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+ result = bmi->priv->date_sent;
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+static gboolean
+message_info_base_set_date_sent (xCamelMessageInfo *mi,
+ gint64 date_sent)
+{
+ xCamelMessageInfoBase *bmi;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+
+ changed = bmi->priv->date_sent != date_sent;
+
+ if (changed)
+ bmi->priv->date_sent = date_sent;
+
+ xcamel_message_info_property_unlock (mi);
+
+ return changed;
+}
+
+static gint64
+message_info_base_get_date_received (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoBase *bmi;
+ gint64 result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), 0);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+ result = bmi->priv->date_received;
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+static gboolean
+message_info_base_set_date_received (xCamelMessageInfo *mi,
+ gint64 date_received)
+{
+ xCamelMessageInfoBase *bmi;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+
+ changed = bmi->priv->date_received != date_received;
+
+ if (changed)
+ bmi->priv->date_received = date_received;
+
+ xcamel_message_info_property_unlock (mi);
+
+ return changed;
+}
+
+static guint64
+message_info_base_get_message_id (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoBase *bmi;
+ guint64 result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), 0);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+ result = bmi->priv->message_id;
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+static gboolean
+message_info_base_set_message_id (xCamelMessageInfo *mi,
+ guint64 message_id)
+{
+ xCamelMessageInfoBase *bmi;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+
+ changed = bmi->priv->message_id != message_id;
+
+ if (changed)
+ bmi->priv->message_id = message_id;
+
+ xcamel_message_info_property_unlock (mi);
+
+ return changed;
+}
+
+static const GArray *
+message_info_base_get_references (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoBase *bmi;
+ const GArray *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), NULL);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+ result = bmi->priv->references;
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+static gboolean
+message_info_base_take_references (xCamelMessageInfo *mi,
+ GArray *references)
+{
+ xCamelMessageInfoBase *bmi;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+
+ /* Consider them the same if they are the same pointer or they both are empty;
+ otherwise report change. */
+ changed = !(bmi->priv->references == references ||
+ (bmi->priv->references && references &&
+ !bmi->priv->references->len &&
+ !references->len));
+
+ if (changed) {
+ if (bmi->priv->references)
+ g_array_unref (bmi->priv->references);
+ bmi->priv->references = references;
+ }
+
+ xcamel_message_info_property_unlock (mi);
+
+ return changed;
+}
+
+static const CamelNameValueArray *
+message_info_base_get_headers (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoBase *bmi;
+ const CamelNameValueArray *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), NULL);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+ result = bmi->priv->headers;
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+static gboolean
+message_info_base_take_headers (xCamelMessageInfo *mi,
+ CamelNameValueArray *headers)
+{
+ xCamelMessageInfoBase *bmi;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+ bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+ xcamel_message_info_property_lock (mi);
+
+ /* Consider them the same if they are the same pointer or they both are empty;
+ otherwise report change. */
+ changed = !(bmi->priv->headers == headers ||
+ (bmi->priv->headers && headers &&
+ !camel_name_value_array_length (bmi->priv->headers) &&
+ !camel_name_value_array_length (headers)));
+
+ if (changed) {
+ if (bmi->priv->headers)
+ camel_name_value_array_free (bmi->priv->headers);
+ bmi->priv->headers = headers;
+ }
+
+ xcamel_message_info_property_unlock (mi);
+
+ return changed;
+}
+
+static void
+message_info_base_dispose (GObject *object)
+{
+ xCamelMessageInfoBase *bmi = XCAMEL_MESSAGE_INFO_BASE (object);
+
+ camel_name_value_array_free (bmi->priv->user_tags);
+ bmi->priv->user_tags = NULL;
+
+ camel_named_flags_free (bmi->priv->user_flags);
+ bmi->priv->user_flags = NULL;
+
+ #define free_ptr(x) G_STMT_START { g_free (x); x = NULL; } G_STMT_END
+
+ free_ptr (bmi->priv->subject);
+ free_ptr (bmi->priv->preview);
+ free_ptr (bmi->priv->from);
+ free_ptr (bmi->priv->to);
+ free_ptr (bmi->priv->cc);
+ free_ptr (bmi->priv->mlist);
+
+ #undef free_ptr
+
+ if (bmi->priv->references) {
+ g_array_unref (bmi->priv->references);
+ bmi->priv->references = NULL;
+ }
+
+ camel_name_value_array_free (bmi->priv->headers);
+ bmi->priv->headers = NULL;
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (xcamel_message_info_base_parent_class)->dispose (object);
+}
+
+static void
+xcamel_message_info_base_class_init (xCamelMessageInfoBaseClass *class)
+{
+ xCamelMessageInfoClass *mi_class;
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (xCamelMessageInfoBasePrivate));
+
+ mi_class = XCAMEL_MESSAGE_INFO_CLASS (class);
+ mi_class->get_flags = message_info_base_get_flags;
+ mi_class->set_flags = message_info_base_set_flags;
+ mi_class->get_user_flag = message_info_base_get_user_flag;
+ mi_class->set_user_flag = message_info_base_set_user_flag;
+ mi_class->dup_user_flags = message_info_base_dup_user_flags;
+ mi_class->take_user_flags = message_info_base_take_user_flags;
+ mi_class->get_user_tag = message_info_base_get_user_tag;
+ mi_class->set_user_tag = message_info_base_set_user_tag;
+ mi_class->dup_user_tags = message_info_base_dup_user_tags;
+ mi_class->take_user_tags = message_info_base_take_user_tags;
+ mi_class->get_subject = message_info_base_get_subject;
+ mi_class->set_subject = message_info_base_set_subject;
+ mi_class->get_preview = message_info_base_get_preview;
+ mi_class->set_preview = message_info_base_set_preview;
+ mi_class->get_from = message_info_base_get_from;
+ mi_class->set_from = message_info_base_set_from;
+ mi_class->get_to = message_info_base_get_to;
+ mi_class->set_to = message_info_base_set_to;
+ mi_class->get_cc = message_info_base_get_cc;
+ mi_class->set_cc = message_info_base_set_cc;
+ mi_class->get_mlist = message_info_base_get_mlist;
+ mi_class->set_mlist = message_info_base_set_mlist;
+ mi_class->get_size = message_info_base_get_size;
+ mi_class->set_size = message_info_base_set_size;
+ mi_class->get_date_sent = message_info_base_get_date_sent;
+ mi_class->set_date_sent = message_info_base_set_date_sent;
+ mi_class->get_date_received = message_info_base_get_date_received;
+ mi_class->set_date_received = message_info_base_set_date_received;
+ mi_class->get_message_id = message_info_base_get_message_id;
+ mi_class->set_message_id = message_info_base_set_message_id;
+ mi_class->get_references = message_info_base_get_references;
+ mi_class->take_references = message_info_base_take_references;
+ mi_class->get_headers = message_info_base_get_headers;
+ mi_class->take_headers = message_info_base_take_headers;
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = message_info_base_dispose;
+}
+
+static void
+xcamel_message_info_base_init (xCamelMessageInfoBase *bmi)
+{
+ bmi->priv = G_TYPE_INSTANCE_GET_PRIVATE (bmi, XCAMEL_TYPE_MESSAGE_INFO_BASE,
xCamelMessageInfoBasePrivate);
+}
diff --git a/camel/camel-message-info-base.h b/camel/camel-message-info-base.h
new file mode 100644
index 0000000..dc0a975
--- /dev/null
+++ b/camel/camel-message-info-base.h
@@ -0,0 +1,67 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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 library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__CAMEL_H_INSIDE__) && !defined (CAMEL_COMPILATION)
+#error "Only <camel/camel.h> can be included directly."
+#endif
+
+#ifndef XCAMEL_MESSAGE_INFO_BASE_H
+#define XCAMEL_MESSAGE_INFO_BASE_H
+
+#include <glib-object.h>
+
+#include <camel/camel-message-info.h>
+
+/* Standard GObject macros */
+#define XCAMEL_TYPE_MESSAGE_INFO_BASE \
+ (xcamel_message_info_base_get_type ())
+#define XCAMEL_MESSAGE_INFO_BASE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), XCAMEL_TYPE_MESSAGE_INFO_BASE, xCamelMessageInfoBase))
+#define XCAMEL_MESSAGE_INFO_BASE_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), XCAMEL_TYPE_MESSAGE_INFO_BASE, xCamelMessageInfoBaseClass))
+#define XCAMEL_IS_MESSAGE_INFO_BASE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), XCAMEL_TYPE_MESSAGE_INFO_BASE))
+#define XCAMEL_IS_MESSAGE_INFO_BASE_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), XCAMEL_TYPE_MESSAGE_INFO_BASE))
+#define XCAMEL_MESSAGE_INFO_BASE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), XCAMEL_TYPE_MESSAGE_INFO_BASE, xCamelMessageInfoBaseClass))
+
+G_BEGIN_DECLS
+
+typedef struct _xCamelMessageInfoBase xCamelMessageInfoBase;
+typedef struct _xCamelMessageInfoBaseClass xCamelMessageInfoBaseClass;
+typedef struct _xCamelMessageInfoBasePrivate xCamelMessageInfoBasePrivate;
+
+struct _xCamelMessageInfoBase {
+ xCamelMessageInfo parent;
+ xCamelMessageInfoBasePrivate *priv;
+};
+
+struct _xCamelMessageInfoBaseClass {
+ xCamelMessageInfoClass parent_class;
+};
+
+GType xcamel_message_info_base_get_type (void);
+
+G_END_DECLS
+
+#endif /* XCAMEL_MESSAGE_INFO_BASE_H */
diff --git a/camel/camel-message-info.c b/camel/camel-message-info.c
index fe0717e..179b0e9 100644
--- a/camel/camel-message-info.c
+++ b/camel/camel-message-info.c
@@ -21,22 +21,116 @@
#include <stdio.h>
+#include "camel-folder.h"
#include "camel-folder-summary.h"
+#include "camel-message-info-base.h"
+#include "camel-string-utils.h"
#include "camel-message-info.h"
struct _xCamelMessageInfoPrivate {
- GMutex property_lock;
+ GRecMutex property_lock;
- GWeakRef summary; /* CamelFolderSummary * */
+ GWeakRef summary; /* CamelFolderSummary * */
+ gboolean dirty; /* whether requires save to local disk/summary */
+ const gchar *uid; /* allocated in the string pool */
};
enum {
PROP_0,
- PROP_SUMMARY
+ PROP_SUMMARY,
+ PROP_DIRTY,
+ PROP_FOLDER_FLAGGED,
+ PROP_UID,
+ PROP_FLAGS,
+ PROP_USER_FLAGS,
+ PROP_USER_TAGS,
+ PROP_SUBJECT,
+ PROP_PREVIEW,
+ PROP_FROM,
+ PROP_TO,
+ PROP_CC,
+ PROP_MLIST,
+ PROP_SIZE,
+ PROP_DATE_SENT,
+ PROP_DATE_RECEIVED,
+ PROP_MESSAGE_ID,
+ PROP_REFERENCES,
+ PROP_HEADERS
};
-G_DEFINE_TYPE (xCamelMessageInfo, xcamel_message_info, G_TYPE_OBJECT)
+G_DEFINE_ABSTRACT_TYPE (xCamelMessageInfo, xcamel_message_info, G_TYPE_OBJECT)
+
+static xCamelMessageInfo *
+message_info_clone (const xCamelMessageInfo *mi,
+ CamelFolderSummary *assign_summary)
+{
+ xCamelMessageInfo *result;
+ const gchar *uid;
+ const GArray *references;
+ const CamelNameValueArray *headers;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), NULL);
+ if (assign_summary)
+ g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (assign_summary), NULL);
+
+ /* Make sure the 'mi' doesn't change while copying the values. */
+ xcamel_message_info_property_lock (mi);
+
+ result = xcamel_message_info_new (assign_summary);
+
+ g_object_freeze_notify (G_OBJECT (result));
+
+ uid = xcamel_message_info_pooldup_uid (mi);
+ xcamel_message_info_set_uid (result, uid);
+ camel_pstring_free (uid);
+
+ xcamel_message_info_take_user_flags (result, xcamel_message_info_dup_user_flags (mi));
+ xcamel_message_info_take_user_tags (result, xcamel_message_info_dup_user_tags (mi));
+ xcamel_message_info_set_subject (result, xcamel_message_info_get_subject (mi));
+ xcamel_message_info_set_preview (result, xcamel_message_info_get_preview (mi));
+ xcamel_message_info_set_from (result, xcamel_message_info_get_from (mi));
+ xcamel_message_info_set_to (result, xcamel_message_info_get_to (mi));
+ xcamel_message_info_set_cc (result, xcamel_message_info_get_cc (mi));
+ xcamel_message_info_set_mlist (result, xcamel_message_info_get_mlist (mi));
+ xcamel_message_info_set_size (result, xcamel_message_info_get_size (mi));
+ xcamel_message_info_set_date_sent (result, xcamel_message_info_get_date_sent (mi));
+ xcamel_message_info_set_date_received (result, xcamel_message_info_get_date_received (mi));
+ xcamel_message_info_set_message_id (result, xcamel_message_info_get_message_id (mi));
+
+ references = xcamel_message_info_get_references (mi);
+ if (references && references->len) {
+ GArray *copy;
+ guint ii;
+
+ copy = g_array_sized_new (FALSE, FALSE, references->len, sizeof (guint64));
+
+ for (ii = 0; ii < references->len; ii++) {
+ g_array_append_val (copy, g_array_index (references, guint64, ii));
+ }
+
+ xcamel_message_info_take_references (result, copy);
+ }
+
+ headers = xcamel_message_info_get_headers (mi);
+ if (headers) {
+ xcamel_message_info_take_headers (result,
+ camel_name_value_array_copy (headers));
+ }
+
+ /* Set flags as the last, to not overwrite 'folder-flagged' flag by
+ the "changes" when copying fields. */
+ xcamel_message_info_set_flags (result, ~0, xcamel_message_info_get_flags (mi));
+
+ xcamel_message_info_property_unlock (mi);
+
+ /* Also ensure 'dirty' flag, thus it can be eventually saved. */
+ xcamel_message_info_set_dirty (result, TRUE);
+
+ g_object_thaw_notify (G_OBJECT (result));
+
+ return result;
+}
static void
message_info_set_property (GObject *object,
@@ -47,9 +141,81 @@ message_info_set_property (GObject *object,
xCamelMessageInfo *mi = XCAMEL_MESSAGE_INFO (object);
switch (property_id) {
- case PROP_SUMMARY:
- g_weak_ref_set (&mi->priv->summary, g_value_get_object (value));
- return;
+ case PROP_SUMMARY:
+ g_weak_ref_set (&mi->priv->summary, g_value_get_object (value));
+ return;
+
+ case PROP_DIRTY:
+ xcamel_message_info_set_dirty (mi, g_value_get_boolean (value));
+ return;
+
+ case PROP_FOLDER_FLAGGED:
+ xcamel_message_info_set_folder_flagged (mi, g_value_get_boolean (value));
+ return;
+
+ case PROP_UID:
+ xcamel_message_info_set_uid (mi, g_value_get_string (value));
+ return;
+
+ case PROP_FLAGS:
+ xcamel_message_info_set_flags (mi, ~0, g_value_get_uint (value));
+ return;
+
+ case PROP_USER_FLAGS:
+ xcamel_message_info_take_user_flags (mi, g_value_dup_boxed (value));
+ return;
+
+ case PROP_USER_TAGS:
+ xcamel_message_info_take_user_tags (mi, g_value_dup_boxed (value));
+ return;
+
+ case PROP_SUBJECT:
+ xcamel_message_info_set_subject (mi, g_value_get_string (value));
+ return;
+
+ case PROP_PREVIEW:
+ xcamel_message_info_set_preview (mi, g_value_get_string (value));
+ return;
+
+ case PROP_FROM:
+ xcamel_message_info_set_from (mi, g_value_get_string (value));
+ return;
+
+ case PROP_TO:
+ xcamel_message_info_set_to (mi, g_value_get_string (value));
+ return;
+
+ case PROP_CC:
+ xcamel_message_info_set_cc (mi, g_value_get_string (value));
+ return;
+
+ case PROP_MLIST:
+ xcamel_message_info_set_mlist (mi, g_value_get_string (value));
+ return;
+
+ case PROP_SIZE:
+ xcamel_message_info_set_size (mi, g_value_get_uint (value));
+ return;
+
+ case PROP_DATE_SENT:
+ xcamel_message_info_set_date_sent (mi, g_value_get_int64 (value));
+ return;
+
+ case PROP_DATE_RECEIVED:
+ xcamel_message_info_set_date_received (mi, g_value_get_int64 (value));
+ return;
+
+ case PROP_MESSAGE_ID:
+ xcamel_message_info_set_message_id (mi, g_value_get_uint64 (value));
+ return;
+
+ case PROP_REFERENCES:
+ xcamel_message_info_take_references (mi, g_value_dup_boxed (value));
+ return;
+
+ case PROP_HEADERS:
+ xcamel_message_info_take_headers (mi, g_value_dup_boxed (value));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -61,13 +227,84 @@ message_info_get_property (GObject *object,
GValue *value,
GParamSpec *pspec)
{
+ xCamelMessageInfo *mi = XCAMEL_MESSAGE_INFO (object);
+
switch (property_id) {
- case PROP_SUMMARY:
- g_value_take_object (
- value,
- xcamel_message_info_ref_summary (
- XCAMEL_MESSAGE_INFO (object)));
- return;
+ case PROP_SUMMARY:
+ g_value_take_object (value, xcamel_message_info_ref_summary (mi));
+ return;
+
+ case PROP_DIRTY:
+ xcamel_message_info_set_dirty (mi, g_value_get_boolean (value));
+ return;
+
+ case PROP_FOLDER_FLAGGED:
+ xcamel_message_info_set_folder_flagged (mi, g_value_get_boolean (value));
+ return;
+
+ case PROP_UID:
+ g_value_set_string (value, xcamel_message_info_get_uid (mi));
+ return;
+
+ case PROP_FLAGS:
+ g_value_set_uint (value, xcamel_message_info_get_flags (mi));
+ return;
+
+ case PROP_USER_FLAGS:
+ g_value_take_boxed (value, xcamel_message_info_dup_user_flags (mi));
+ return;
+
+ case PROP_USER_TAGS:
+ g_value_take_boxed (value, xcamel_message_info_dup_user_tags (mi));
+ return;
+
+ case PROP_SUBJECT:
+ g_value_set_string (value, xcamel_message_info_get_subject (mi));
+ return;
+
+ case PROP_PREVIEW:
+ g_value_set_string (value, xcamel_message_info_get_preview (mi));
+ return;
+
+ case PROP_FROM:
+ g_value_set_string (value, xcamel_message_info_get_from (mi));
+ return;
+
+ case PROP_TO:
+ g_value_set_string (value, xcamel_message_info_get_to (mi));
+ return;
+
+ case PROP_CC:
+ g_value_set_string (value, xcamel_message_info_get_cc (mi));
+ return;
+
+ case PROP_MLIST:
+ g_value_set_string (value, xcamel_message_info_get_mlist (mi));
+ return;
+
+ case PROP_SIZE:
+ g_value_set_uint (value, xcamel_message_info_get_size (mi));
+ return;
+
+ case PROP_DATE_SENT:
+ g_value_set_int64 (value, xcamel_message_info_get_date_sent (mi));
+ return;
+
+ case PROP_DATE_RECEIVED:
+ g_value_set_int64 (value, xcamel_message_info_get_date_received (mi));
+ return;
+
+ case PROP_MESSAGE_ID:
+ g_value_set_uint64 (value, xcamel_message_info_get_message_id (mi));
+ return;
+
+ case PROP_REFERENCES:
+ g_value_take_boxed (value, xcamel_message_info_dup_references (mi));
+ return;
+
+ case PROP_HEADERS:
+ g_value_take_boxed (value, xcamel_message_info_dup_headers (mi));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -79,6 +316,8 @@ message_info_dispose (GObject *object)
xCamelMessageInfo *mi = XCAMEL_MESSAGE_INFO (object);
g_weak_ref_set (&mi->priv->summary, NULL);
+ camel_pstring_free (mi->priv->uid);
+ mi->priv->uid = NULL;
/* Chain up to parent's method. */
G_OBJECT_CLASS (xcamel_message_info_parent_class)->dispose (object);
@@ -90,7 +329,7 @@ message_info_finalize (GObject *object)
xCamelMessageInfo *mi = XCAMEL_MESSAGE_INFO (object);
g_weak_ref_clear (&mi->priv->summary);
- g_mutex_clear (&mi->priv->property_lock);
+ g_rec_mutex_clear (&mi->priv->property_lock);
/* Chain up to parent's method. */
G_OBJECT_CLASS (xcamel_message_info_parent_class)->finalize (object);
@@ -103,6 +342,8 @@ xcamel_message_info_class_init (xCamelMessageInfoClass *class)
g_type_class_add_private (class, sizeof (xCamelMessageInfoPrivate));
+ class->clone = message_info_clone;
+
object_class = G_OBJECT_CLASS (class);
object_class->set_property = message_info_set_property;
object_class->get_property = message_info_get_property;
@@ -113,6 +354,9 @@ xcamel_message_info_class_init (xCamelMessageInfoClass *class)
* xCamelMessageInfo:summary
*
* The #CamelFolderSummary to which the message info belongs, or %NULL.
+ * It can be set only during construction of the object.
+ *
+ * Since: 3.24
**/
g_object_class_install_property (
object_class,
@@ -120,10 +364,327 @@ xcamel_message_info_class_init (xCamelMessageInfoClass *class)
g_param_spec_object (
"summary",
"Summary",
- "The summary to which the message info belongs",
+ NULL,
CAMEL_TYPE_FOLDER_SUMMARY,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
+
+ /**
+ * xCamelMessageInfo:uid
+ *
+ * A unique ID of the message in its folder.
+ *
+ * Since: 3.24
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_UID,
+ g_param_spec_string (
+ "uid",
+ "UID",
+ NULL,
+ NULL,
+ G_PARAM_READWRITE));
+
+ /**
+ * xCamelMessageInfo:dirty
+ *
+ * Flag, whether the info is changed and requires save to disk.
+ * Compare with CamelMessageInfo:folder-flagged
+ *
+ * Since: 3.24
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_DIRTY,
+ g_param_spec_boolean (
+ "dirty",
+ "Dirty",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ /**
+ * xCamelMessageInfo:folder-flagged
+ *
+ * Flag, whether the info is changed and requires save to
+ * the destination store/server. This is different from
+ * the CamelMessageInfo:dirty, which takes care of the local
+ * information only.
+ *
+ * Since: 3.24
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_FOLDER_FLAGGED,
+ g_param_spec_boolean (
+ "folder-flagged",
+ "Folder Flagged",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ /**
+ * xCamelMessageInfo:flags
+ *
+ * Bit-or of #CamelMessageFlags.
+ *
+ * Since: 3.24
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_FLAGS,
+ g_param_spec_uint (
+ "flags",
+ "Flags",
+ NULL,
+ 0, G_MAXUINT32, 0,
+ G_PARAM_READWRITE));
+
+ /**
+ * xCamelMessageInfo:user-flags
+ *
+ * User flags for the associated message. Can be %NULL.
+ * Unlike user-tags, which can contain various values, the user-flags
+ * can only be set or not.
+ *
+ * Since: 3.24
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_USER_FLAGS,
+ g_param_spec_boxed (
+ "user-flags",
+ "User Flags",
+ NULL,
+ CAMEL_TYPE_NAMED_FLAGS,
+ G_PARAM_READWRITE));
+
+ /**
+ * xCamelMessageInfo:user-tags
+ *
+ * User tags for the associated message. Can be %NULL.
+ * Unlike user-flags, which can be set or not, the user-tags
+ * can contain various values.
+ *
+ * Since: 3.24
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_USER_TAGS,
+ g_param_spec_boxed (
+ "user-tags",
+ "User tags",
+ NULL,
+ CAMEL_TYPE_NAME_VALUE_ARRAY,
+ G_PARAM_READWRITE));
+
+ /**
+ * xCamelMessageInfo:subject
+ *
+ * Subject of the associated message.
+ *
+ * Since: 3.24
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_SUBJECT,
+ g_param_spec_string (
+ "subject",
+ "Subject",
+ NULL,
+ NULL,
+ G_PARAM_READWRITE));
+
+ /**
+ * xCamelMessageInfo:preview
+ *
+ * Preview of the associated message.
+ *
+ * Since: 3.24
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_PREVIEW,
+ g_param_spec_string (
+ "preview",
+ "Preview",
+ NULL,
+ NULL,
+ G_PARAM_READWRITE));
+
+ /**
+ * xCamelMessageInfo:from
+ *
+ * From address of the associated message.
+ *
+ * Since: 3.24
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_FROM,
+ g_param_spec_string (
+ "from",
+ "From",
+ NULL,
+ NULL,
+ G_PARAM_READWRITE));
+
+ /**
+ * xCamelMessageInfo:to
+ *
+ * To address of the associated message.
+ *
+ * Since: 3.24
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_TO,
+ g_param_spec_string (
+ "to",
+ "To",
+ NULL,
+ NULL,
+ G_PARAM_READWRITE));
+
+ /**
+ * xCamelMessageInfo:cc
+ *
+ * CC address of the associated message.
+ *
+ * Since: 3.24
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_CC,
+ g_param_spec_string (
+ "cc",
+ "CC",
+ NULL,
+ NULL,
+ G_PARAM_READWRITE));
+
+ /**
+ * xCamelMessageInfo:mlist
+ *
+ * Mailing list address of the associated message.
+ *
+ * Since: 3.24
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_MLIST,
+ g_param_spec_string (
+ "mlist",
+ "mlist",
+ NULL,
+ NULL,
+ G_PARAM_READWRITE));
+
+ /**
+ * xCamelMessageInfo:size
+ *
+ * Size of the associated message.
+ *
+ * Since: 3.24
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_SIZE,
+ g_param_spec_uint (
+ "size",
+ "Size",
+ NULL,
+ 0, G_MAXUINT32, 0,
+ G_PARAM_READWRITE));
+
+ /**
+ * xCamelMessageInfo:date-sent
+ *
+ * Sent Date of the associated message.
+ *
+ * Since: 3.24
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_DATE_SENT,
+ g_param_spec_int64 (
+ "date-sent",
+ "Date Sent",
+ NULL,
+ G_MININT64, G_MAXINT64, 0,
+ G_PARAM_READWRITE));
+
+ /**
+ * xCamelMessageInfo:date-received
+ *
+ * Received date of the associated message.
+ *
+ * Since: 3.24
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_DATE_RECEIVED,
+ g_param_spec_int64 (
+ "date-received",
+ "Date Received",
+ NULL,
+ G_MININT64, G_MAXINT64, 0,
+ G_PARAM_READWRITE));
+
+ /**
+ * xCamelMessageInfo:message-id
+ *
+ * Encoded Message-ID of the associated message as a guint64 number,
+ * partial MD5 sum. The value can be cast to #CamelSummaryMessageID.
+ *
+ * Since: 3.24
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_MESSAGE_ID,
+ g_param_spec_uint64 (
+ "message-id",
+ "Message ID",
+ NULL,
+ 0, G_MAXUINT64, 0,
+ G_PARAM_READWRITE));
+
+ /**
+ * xCamelMessageInfo:references
+ *
+ * Encoded In-Reply-To and References headers of the associated message
+ * as an array of guint64 numbers, partial MD5 sums. Each value can be
+ * cast to #CamelSummaryMessageID.
+ *
+ * Since: 3.24
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_REFERENCES,
+ g_param_spec_boxed (
+ "references",
+ "References",
+ NULL,
+ G_TYPE_ARRAY,
+ G_PARAM_READWRITE));
+
+ /**
+ * xCamelMessageInfo:headers
+ *
+ * Headers of the associated message. Can be %NULL.
+ *
+ * Since: 3.24
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_HEADERS,
+ g_param_spec_boxed (
+ "headers",
+ "Headers",
+ NULL,
+ CAMEL_TYPE_NAME_VALUE_ARRAY,
+ G_PARAM_READWRITE));
}
static void
@@ -131,7 +692,7 @@ xcamel_message_info_init (xCamelMessageInfo *mi)
{
mi->priv = G_TYPE_INSTANCE_GET_PRIVATE (mi, XCAMEL_TYPE_MESSAGE_INFO, xCamelMessageInfoPrivate);
- g_mutex_init (&mi->priv->property_lock);
+ g_rec_mutex_init (&mi->priv->property_lock);
g_weak_ref_init (&mi->priv->summary, NULL);
}
@@ -148,7 +709,50 @@ xcamel_message_info_init (xCamelMessageInfo *mi)
xCamelMessageInfo *
xcamel_message_info_new (CamelFolderSummary *summary)
{
- return g_object_new (XCAMEL_TYPE_MESSAGE_INFO, "summary", summary, NULL);
+ GType type = XCAMEL_TYPE_MESSAGE_INFO_BASE;
+
+ if (summary) {
+ CamelFolderSummaryClass *klass;
+
+ g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), NULL);
+
+ klass = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary);
+ g_return_val_if_fail (klass != NULL, NULL);
+
+ type = klass->message_info_type;
+ }
+
+ return g_object_new (type, "summary", summary, NULL);
+}
+
+/**
+ * xcamel_message_info_clone:
+ * @mi: a #CamelMessageInfo to clone
+ * @assign_summary: (nullable): parent #CamelFolderSummary object, or %NULL, to set on the clone
+ *
+ * Clones the @mi as a new #CamelMessageInfo and eventually assigns
+ * a new #CamelFolderSummary to it. If it's not set, then the new
+ * clone will not have assigned any summary.
+ *
+ * Returns: (transfer-full): a new #xCamelMessageInfo object, clone of the @mi
+ *
+ * Since: 3.24
+ **/
+xCamelMessageInfo *
+xcamel_message_info_clone (const xCamelMessageInfo *mi,
+ CamelFolderSummary *assign_summary)
+{
+ xCamelMessageInfoClass *klass;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), NULL);
+ if (assign_summary)
+ g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (assign_summary), NULL);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, NULL);
+ g_return_val_if_fail (klass->clone != NULL, NULL);
+
+ return klass->clone (mi, assign_summary);
}
/**
@@ -161,9 +765,1636 @@ xcamel_message_info_new (CamelFolderSummary *summary)
* Since: 3.24
**/
CamelFolderSummary *
-xcamel_message_info_ref_summary (xCamelMessageInfo *mi)
+xcamel_message_info_ref_summary (const xCamelMessageInfo *mi)
{
g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), NULL);
return g_weak_ref_get (&mi->priv->summary);
}
+
+/**
+ * xcamel_message_info_property_lock:
+ * @mi: a #xCamelMessageInfo
+ *
+ * Acquires a property lock, which is used to ensure thread safety
+ * when properties are changing. Release the lock with
+ * xcamel_message_info_property_unlock().
+ *
+ * Since: 3.24
+ **/
+void
+xcamel_message_info_property_lock (const xCamelMessageInfo *mi)
+{
+ g_return_if_fail (XCAMEL_IS_MESSAGE_INFO (mi));
+
+ g_rec_mutex_lock (&mi->priv->property_lock);
+}
+
+/**
+ * xcamel_message_info_property_unlock:
+ * @mi: a #xCamelMessageInfo
+ *
+ * Releases a property lock, previously acquired with
+ * xcamel_message_info_property_lock().
+ *
+ * Since: 3.24
+ **/
+void
+xcamel_message_info_property_unlock (const xCamelMessageInfo *mi)
+{
+ g_return_if_fail (XCAMEL_IS_MESSAGE_INFO (mi));
+
+ g_rec_mutex_unlock (&mi->priv->property_lock);
+}
+
+static void
+xcamel_message_info_update_summary_and_folder (xCamelMessageInfo *mi,
+ gboolean update_counts)
+{
+ CamelFolderSummary *summary;
+
+ g_return_if_fail (XCAMEL_IS_MESSAGE_INFO (mi));
+
+ summary = xcamel_message_info_ref_summary (mi);
+ if (summary) {
+ CamelFolder *folder;
+
+ if (update_counts) {
+ camel_folder_summary_lock (summary);
+ g_object_freeze_notify (G_OBJECT (summary));
+
+ camel_folder_summary_replace_flags (summary, mi);
+
+ g_object_thaw_notify (G_OBJECT (summary));
+ camel_folder_summary_unlock (summary);
+ }
+
+ folder = camel_folder_summary_get_folder (summary);
+ if (folder) {
+ const gchar *uid;
+
+ uid = xcamel_message_info_pooldup_uid (mi);
+ if (uid) {
+ CamelFolderChangeInfo *changes = camel_folder_change_info_new ();
+
+ camel_folder_change_info_change_uid (changes, uid);
+ camel_folder_changed (folder, changes);
+ camel_folder_change_info_free (changes);
+ camel_pstring_free (uid);
+ }
+ }
+
+ g_clear_object (&summary);
+ }
+}
+
+/**
+ * xcamel_message_info_get_dirty:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: Whether the @mi is dirty, which means that it had been
+ * changed and a save to the local summary is required.
+ *
+ * Since: 3.24
+ **/
+gboolean
+xcamel_message_info_get_dirty (const xCamelMessageInfo *mi)
+{
+ gboolean result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+ xcamel_message_info_property_lock (mi);
+ result = mi->priv->dirty;
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+/**
+ * xcamel_message_info_set_dirty:
+ * @mi: a #CamelMessageInfo
+ * @dirty: a dirty state to set
+ *
+ * Marks the @mi as dirty, which means a save to the local summary
+ * is required.
+ *
+ * Since: 3.24
+ **/
+void
+xcamel_message_info_set_dirty (const xCamelMessageInfo *mi,
+ gboolean dirty)
+{
+ gboolean changed;
+ g_return_if_fail (XCAMEL_IS_MESSAGE_INFO (mi));
+
+ xcamel_message_info_property_lock (mi);
+ changed = (!mi->priv->dirty) != (!dirty);
+ if (changed)
+ mi->priv->dirty = dirty;
+ xcamel_message_info_property_unlock (mi);
+
+ if (changed) {
+ g_object_notify (G_OBJECT (mi), "dirty");
+
+ if (dirty) {
+ CamelFolderSummary *summary;
+
+ summary = xcamel_message_info_ref_summary (mi);
+ if (summary)
+ camel_folder_summary_touch (summary);
+
+ g_clear_object (&summary);
+ }
+
+ }
+}
+
+/**
+ * xcamel_message_info_get_folder_flagged:
+ * @mi: a #CamelMessageInfo
+ *
+ * The folder flagged flag is used to mark the message infor as being changed
+ * and this change should be propagated to the remote store (server). This is
+ * different from the 'dirty' flag, which is set for local changes only. It
+ * can happen that the 'folder-flagged' flag is set, but the 'dirty' flag not.
+ *
+ * This is only a convenient wrapper around CAMEL_MESSAGE_FOLDER_FLAGGED flag,
+ * for better readiness of the code.
+ *
+ * Returns: Whether requires save of the local changes into the remote store.
+ *
+ * Since: 3.24
+ **/
+gboolean
+xcamel_message_info_get_folder_flagged (const xCamelMessageInfo *mi)
+{
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+ return (xcamel_message_info_get_flags (mi) & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0;
+}
+
+/**
+ * xcamel_message_info_set_folder_flagged:
+ * @mi: a #CamelMessageInfo
+ * folder_flagged: a value to set to
+ *
+ * Changes the folder-flagged flag to the @folder_flagged value. See
+ * xcamel_message_info_get_folder_flagged() for more information about
+ * the use of this flag.
+ *
+ * This is only a convenient wrapper around CAMEL_MESSAGE_FOLDER_FLAGGED flag,
+ * for better readiness of the code.
+ *
+ * Returns: Whether the flag had been changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+xcamel_message_info_set_folder_flagged (xCamelMessageInfo *mi,
+ gboolean folder_flagged)
+{
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+ /* g_object_notify (G_OBJECT (mi), "folder-flagged");
+ is called as part of the set_flags function */
+
+ return xcamel_message_info_set_flags (mi, CAMEL_MESSAGE_FOLDER_FLAGGED,
+ folder_flagged ? CAMEL_MESSAGE_FOLDER_FLAGGED : 0);
+}
+
+/**
+ * xcamel_message_info_get_uid:
+ * @mi: a #CamelMessageInfo
+ *
+ * Get the UID of the #mi.
+ *
+ * Returns: (transfer none): The UID of the @mi.
+ *
+ * Since: 3.24
+ **/
+const gchar *
+xcamel_message_info_get_uid (const xCamelMessageInfo *mi)
+{
+ const gchar *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+ xcamel_message_info_property_lock (mi);
+ result = mi->priv->uid;
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+/**
+ * xcamel_message_info_pooldup_uid:
+ * @mi: a #CamelMessageInfo
+ *
+ * Get the UID of the #mi, duplicated on the Camel's string pool.
+ * This is good for thread safety, though the UID should not change once set.
+ *
+ * Returns: A newly references string in the string pool, the #mi UID.
+ * Free it with camel_pstring_free() when no longer needed.
+ *
+ * Since: 3.24
+ **/
+const gchar *
+xcamel_message_info_pooldup_uid (const xCamelMessageInfo *mi)
+{
+ const gchar *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+ xcamel_message_info_property_lock (mi);
+ result = camel_pstring_strdup (mi->priv->uid);
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+/**
+ * xcamel_message_info_set_uid:
+ * @mi: a #CamelMessageInfo
+ * @uid: a UID to set
+ *
+ * Changes UID of the @mi to @uid. If it changes, the 'dirty' flag
+ * of the @mi is set too. This change does not influence the 'folder-flagged'
+ * flag.
+ *
+ * Returns: Whether the UID changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+xcamel_message_info_set_uid (xCamelMessageInfo *mi,
+ const gchar *uid)
+{
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+ xcamel_message_info_property_lock (mi);
+ changed = mi->priv->uid != uid && g_strcmp0 (mi->priv->uid, uid) != 0;
+ if (changed) {
+ camel_pstring_free (mi->priv->uid);
+ mi->priv->uid = camel_pstring_strdup (uid);
+ }
+ xcamel_message_info_property_unlock (mi);
+
+ if (changed) {
+ g_object_notify (G_OBJECT (mi), "uid");
+ xcamel_message_info_set_dirty (mi, TRUE);
+ }
+
+ return changed;
+}
+
+/**
+ * xcamel_message_info_get_flags:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: Bit-or of #CamelMessageFlags set on the @mi.
+ *
+ * Since: 3.24
+ **/
+guint32
+xcamel_message_info_get_flags (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoClass *klass;
+ guint32 result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), 0);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, 0);
+ g_return_val_if_fail (klass->get_flags != NULL, 0);
+
+ xcamel_message_info_property_lock (mi);
+ result = klass->get_flags (mi);
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+/**
+ * xcamel_message_info_set_flags:
+ * @mi: a #CamelMessageInfo
+ * @mask: mask of flags to change
+ * @set: state the flags should be changed to
+ *
+ * Change the state of the flags on the @mi.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically. There is also emitted folder's "changed" signal
+ * for this @mi, if necessary.
+ *
+ * Returns: Whether the flags changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+xcamel_message_info_set_flags (xCamelMessageInfo *mi,
+ CamelMessageFlags mask,
+ guint32 set)
+{
+ xCamelMessageInfoClass *klass;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->set_flags != NULL, FALSE);
+
+ xcamel_message_info_property_lock (mi);
+ changed = klass->set_flags (mi, mask, set);
+ xcamel_message_info_property_unlock (mi);
+
+ if (changed) {
+ g_object_notify (G_OBJECT (mi), "flags");
+ xcamel_message_info_set_dirty (mi, TRUE);
+
+ /* Only if the folder-flagged was not part of the change */
+ if (!(mask & CAMEL_MESSAGE_FOLDER_FLAGGED))
+ xcamel_message_info_set_folder_flagged (mi, TRUE);
+ else
+ g_object_notify (G_OBJECT (mi), "folder-flagged");
+
+ xcamel_message_info_update_summary_and_folder (mi, TRUE);
+ }
+
+ return changed;
+}
+
+/**
+ * xcamel_message_info_get_user_flag:
+ * @mi: a #CamelMessageInfo
+ * @name: user flag name
+ *
+ * Returns: Whther the user flag named @name is set.
+ *
+ * Since: 3.24
+ **/
+gboolean
+xcamel_message_info_get_user_flag (const xCamelMessageInfo *mi,
+ const gchar *name)
+{
+ xCamelMessageInfoClass *klass;
+ gboolean result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->get_user_flag != NULL, FALSE);
+
+ xcamel_message_info_property_lock (mi);
+ result = klass->get_user_flag (mi, name);
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+/**
+ * xcamel_message_info_set_user_flag:
+ * @mi: a #CamelMessageInfo
+ * @name: user flag name
+ * @state: state to set for the flag
+ *
+ * Change @state of the flag named @name. Unlike user tags, user flags
+ * can only be set or unset, while the user tags can contain certain values.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically. There is also emitted folder's "changed" signal
+ * for this @mi, if necessary.
+ *
+ * Returns: Whether the message info changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+xcamel_message_info_set_user_flag (xCamelMessageInfo *mi,
+ const gchar *name,
+ gboolean state)
+{
+ xCamelMessageInfoClass *klass;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->set_user_flag != NULL, FALSE);
+
+ xcamel_message_info_property_lock (mi);
+ changed = klass->set_user_flag (mi, name, state);
+ xcamel_message_info_property_unlock (mi);
+
+ if (changed) {
+ g_object_notify (G_OBJECT (mi), "user-flags");
+ xcamel_message_info_set_dirty (mi, TRUE);
+ xcamel_message_info_set_folder_flagged (mi, TRUE);
+
+ xcamel_message_info_update_summary_and_folder (mi, FALSE);
+ }
+
+ return changed;
+}
+
+/**
+ * xcamel_message_info_dup_user_flags:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: (transfer full): A newly allocated #CamelNamedFlags with all the currently set
+ * user flags on the @mi. Free the returned structure with camel_named_flags_free()
+ * when no londer needed.
+ *
+ * Since: 3.24
+ **/
+CamelNamedFlags *
+xcamel_message_info_dup_user_flags (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoClass *klass;
+ CamelNamedFlags *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, NULL);
+ g_return_val_if_fail (klass->dup_user_flags != NULL, NULL);
+
+ xcamel_message_info_property_lock (mi);
+ result = klass->dup_user_flags (mi);
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+/**
+ * xcamel_message_info_take_user_flags:
+ * @mi: a #CamelMessageInfo
+ * @user_flags: (transfer full): (nullable): user flags to set
+ *
+ * Takes all the @user_flags, which replaces any current user flags on the @mi.
+ * The passed-in @user_flags is consumed by the @mi, which becomes an owner
+ * of it. The caller should not change @user_flags afterwards.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically. There is also emitted folder's "changed" signal
+ * for this @mi, if necessary.
+ *
+ * Returns: Whether the message info changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+xcamel_message_info_take_user_flags (xCamelMessageInfo *mi,
+ CamelNamedFlags *user_flags)
+{
+ xCamelMessageInfoClass *klass;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->take_user_flags != NULL, FALSE);
+
+ xcamel_message_info_property_lock (mi);
+ changed = klass->take_user_flags (mi, user_flags);
+ xcamel_message_info_property_unlock (mi);
+
+ if (changed) {
+ g_object_notify (G_OBJECT (mi), "user-flags");
+ xcamel_message_info_set_dirty (mi, TRUE);
+ xcamel_message_info_set_folder_flagged (mi, TRUE);
+
+ xcamel_message_info_update_summary_and_folder (mi, FALSE);
+ }
+
+ return changed;
+}
+
+/**
+ * xcamel_message_info_get_user_tag:
+ * @mi: a #CamelMessageInfo
+ * @name: user tag name
+ *
+ * Returns: (transfer none): (nullable): Value of the user tag, or %NULL when
+ * it is not set.
+ *
+ * Since: 3.24
+ **/
+const gchar *
+xcamel_message_info_get_user_tag (const xCamelMessageInfo *mi,
+ const gchar *name)
+{
+ xCamelMessageInfoClass *klass;
+ const gchar *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, NULL);
+ g_return_val_if_fail (klass->get_user_tag != NULL, NULL);
+
+ xcamel_message_info_property_lock (mi);
+ result = klass->get_user_tag (mi, name);
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+/**
+ * xcamel_message_info_dup_user_tag:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: (transfer full): (nullable): Value of the user tag as newly allocated
+ * string, or %NULL when it is not set. Free it with g_free() when no longer needed.
+ *
+ * Since: 3.24
+ **/
+gchar *
+xcamel_message_info_dup_user_tag (const xCamelMessageInfo *mi,
+ const gchar *name)
+{
+ gchar *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ xcamel_message_info_property_lock (mi);
+ result = g_strdup (xcamel_message_info_get_user_tag (mi, name));
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+/**
+ * xcamel_message_info_set_user_tag:
+ * @mi: a #CamelMessageInfo
+ * @name: user tag name
+ * @value: (nullable): user tag value, or %NULL to remove the user tag
+ *
+ * Set user tag @name to @value, or remove it, if @value is %NULL.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically. There is also emitted folder's "changed" signal
+ * for this @mi, if necessary.
+ *
+ * Returns: Whether the @mi changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+xcamel_message_info_set_user_tag (xCamelMessageInfo *mi,
+ const gchar *name,
+ const gchar *value)
+{
+ xCamelMessageInfoClass *klass;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->set_user_tag != NULL, FALSE);
+
+ xcamel_message_info_property_lock (mi);
+ changed = klass->set_user_tag (mi, name, value);
+ xcamel_message_info_property_unlock (mi);
+
+ if (changed) {
+ g_object_notify (G_OBJECT (mi), "user-tags");
+ xcamel_message_info_set_dirty (mi, TRUE);
+ xcamel_message_info_set_folder_flagged (mi, TRUE);
+
+ xcamel_message_info_update_summary_and_folder (mi, FALSE);
+ }
+
+ return changed;
+}
+
+/**
+ * xcamel_message_info_dup_user_tags:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: (transfer full): a newly allocated #CamelNameValueArray containing all set
+ * user tags of the @mi. Free it with camel_name_value_array_free() when no longer needed.
+ *
+ * Since: 3.24
+ **/
+CamelNameValueArray *
+xcamel_message_info_dup_user_tags (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoClass *klass;
+ CamelNameValueArray *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, NULL);
+ g_return_val_if_fail (klass->dup_user_tags != NULL, NULL);
+
+ xcamel_message_info_property_lock (mi);
+ result = klass->dup_user_tags (mi);
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+/**
+ * xcamel_message_info_take_user_tags:
+ * @mi: a #CamelMessageInfo
+ * @user_tags: (transfer full): (nullable): user tags to set
+ *
+ * Takes all the @user_tags, which replaces any current user tags on the @mi.
+ * The passed-in @user_tags is consumed by the @mi, which becomes an owner
+ * of it. The caller should not change @user_tags afterwards.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically. There is also emitted folder's "changed" signal
+ * for this @mi, if necessary.
+ *
+ * Returns: Whether the @mi changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+xcamel_message_info_take_user_tags (xCamelMessageInfo *mi,
+ CamelNameValueArray *user_tags)
+{
+ xCamelMessageInfoClass *klass;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->take_user_tags != NULL, FALSE);
+
+ xcamel_message_info_property_lock (mi);
+ changed = klass->take_user_tags (mi, user_tags);
+ xcamel_message_info_property_unlock (mi);
+
+ if (changed) {
+ g_object_notify (G_OBJECT (mi), "user-tags");
+ xcamel_message_info_set_dirty (mi, TRUE);
+ xcamel_message_info_set_folder_flagged (mi, TRUE);
+
+ xcamel_message_info_update_summary_and_folder (mi, FALSE);
+ }
+
+ return changed;
+}
+
+/**
+ * xcamel_message_info_get_subject:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: (transfer none): Subject of the #mi.
+ *
+ * Since: 3.24
+ **/
+const gchar *
+xcamel_message_info_get_subject (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoClass *klass;
+ const gchar *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, NULL);
+ g_return_val_if_fail (klass->get_subject != NULL, NULL);
+
+ xcamel_message_info_property_lock (mi);
+ result = klass->get_subject (mi);
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+/**
+ * xcamel_message_info_set_subject:
+ * @mi: a #xCamelMessageInfo
+ * @subject: (nullable): a Subject to set
+ *
+ * Sets Subject from the associated message.
+ *
+ * This property is considered static, in a meaning that it should
+ * not change during the life-time of the @mi, the same as it doesn't
+ * change in the associated message.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically. There is not emitted folder's "changed" signal
+ * for this @mi.
+ *
+ * Returns: Whether the value changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+xcamel_message_info_set_subject (xCamelMessageInfo *mi,
+ const gchar *subject)
+{
+ xCamelMessageInfoClass *klass;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->set_subject != NULL, FALSE);
+
+ xcamel_message_info_property_lock (mi);
+ changed = klass->set_subject (mi, subject);
+ xcamel_message_info_property_unlock (mi);
+
+ if (changed) {
+ g_object_notify (G_OBJECT (mi), "subject");
+ xcamel_message_info_set_dirty (mi, TRUE);
+ xcamel_message_info_set_folder_flagged (mi, TRUE);
+ }
+
+ return changed;
+}
+
+/**
+ * xcamel_message_info_get_preview:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: (transfer none): Preview of the @mi.
+ *
+ * Since: 3.24
+ **/
+const gchar *
+xcamel_message_info_get_preview (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoClass *klass;
+ const gchar *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, NULL);
+ g_return_val_if_fail (klass->get_preview != NULL, NULL);
+
+ xcamel_message_info_property_lock (mi);
+ result = klass->get_preview (mi);
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+/**
+ * xcamel_message_info_set_preview:
+ * @mi: a #xCamelMessageInfo
+ * @preview: (nullable): a preview to set
+ *
+ * Sets preview of the associated message.
+ *
+ * This property is considered static, in a meaning that it should
+ * not change during the life-time of the @mi, the same as it doesn't
+ * change in the associated message.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically. There is not emitted folder's "changed" signal
+ * for this @mi.
+ *
+ * Returns: Whether the value changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+xcamel_message_info_set_preview (xCamelMessageInfo *mi,
+ const gchar *preview)
+{
+ xCamelMessageInfoClass *klass;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->set_preview != NULL, FALSE);
+
+ xcamel_message_info_property_lock (mi);
+ changed = klass->set_preview (mi, preview);
+ xcamel_message_info_property_unlock (mi);
+
+ if (changed) {
+ g_object_notify (G_OBJECT (mi), "preview");
+ xcamel_message_info_set_dirty (mi, TRUE);
+ xcamel_message_info_set_folder_flagged (mi, TRUE);
+ }
+
+ return changed;
+}
+
+/**
+ * xcamel_message_info_get_from:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: (transfer none): From address of the @mi.
+ *
+ * Since: 3.24
+ **/
+const gchar *
+xcamel_message_info_get_from (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoClass *klass;
+ const gchar *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, NULL);
+ g_return_val_if_fail (klass->get_from != NULL, NULL);
+
+ xcamel_message_info_property_lock (mi);
+ result = klass->get_from (mi);
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+/**
+ * xcamel_message_info_set_from:
+ * @mi: a #xCamelMessageInfo
+ * @from: (nullable): a From to set
+ *
+ * Sets From from the associated message.
+ *
+ * This property is considered static, in a meaning that it should
+ * not change during the life-time of the @mi, the same as it doesn't
+ * change in the associated message.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically. There is not emitted folder's "changed" signal
+ * for this @mi.
+ *
+ * Returns: Whether the value changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+xcamel_message_info_set_from (xCamelMessageInfo *mi,
+ const gchar *from)
+{
+ xCamelMessageInfoClass *klass;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->set_from != NULL, FALSE);
+
+ xcamel_message_info_property_lock (mi);
+ changed = klass->set_from (mi, from);
+ xcamel_message_info_property_unlock (mi);
+
+ if (changed) {
+ g_object_notify (G_OBJECT (mi), "from");
+ xcamel_message_info_set_dirty (mi, TRUE);
+ xcamel_message_info_set_folder_flagged (mi, TRUE);
+ }
+
+ return changed;
+}
+
+/**
+ * xcamel_message_info_get_to:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: (transfer none): To address of the @mi.
+ *
+ * Since: 3.24
+ **/
+const gchar *
+xcamel_message_info_get_to (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoClass *klass;
+ const gchar *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, NULL);
+ g_return_val_if_fail (klass->get_to != NULL, NULL);
+
+ xcamel_message_info_property_lock (mi);
+ result = klass->get_to (mi);
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+/**
+ * xcamel_message_info_set_to:
+ * @mi: a #xCamelMessageInfo
+ * @to: (nullable): a To to set
+ *
+ * Sets To from the associated message.
+ *
+ * This property is considered static, in a meaning that it should
+ * not change during the life-time of the @mi, the same as it doesn't
+ * change in the associated message.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically. There is not emitted folder's "changed" signal
+ * for this @mi.
+ *
+ * Returns: Whether the value changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+xcamel_message_info_set_to (xCamelMessageInfo *mi,
+ const gchar *to)
+{
+ xCamelMessageInfoClass *klass;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->set_to != NULL, FALSE);
+
+ xcamel_message_info_property_lock (mi);
+ changed = klass->set_to (mi, to);
+ xcamel_message_info_property_unlock (mi);
+
+ if (changed) {
+ g_object_notify (G_OBJECT (mi), "to");
+ xcamel_message_info_set_dirty (mi, TRUE);
+ xcamel_message_info_set_folder_flagged (mi, TRUE);
+ }
+
+ return changed;
+}
+
+/**
+ * xcamel_message_info_get_cc:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: (transfer none): CC address of the @mi.
+ *
+ * Since: 3.24
+ **/
+const gchar *
+xcamel_message_info_get_cc (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoClass *klass;
+ const gchar *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, NULL);
+ g_return_val_if_fail (klass->get_cc != NULL, NULL);
+
+ xcamel_message_info_property_lock (mi);
+ result = klass->get_cc (mi);
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+/**
+ * xcamel_message_info_set_cc:
+ * @mi: a #xCamelMessageInfo
+ * @cc: (nullable): a CC to set
+ *
+ * Sets CC from the associated message.
+ *
+ * This property is considered static, in a meaning that it should
+ * not change during the life-time of the @mi, the same as it doesn't
+ * change in the associated message.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically. There is not emitted folder's "changed" signal
+ * for this @mi.
+ *
+ * Returns: Whether the value changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+xcamel_message_info_set_cc (xCamelMessageInfo *mi,
+ const gchar *cc)
+{
+ xCamelMessageInfoClass *klass;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->set_cc != NULL, FALSE);
+
+ xcamel_message_info_property_lock (mi);
+ changed = klass->set_cc (mi, cc);
+ xcamel_message_info_property_unlock (mi);
+
+ if (changed) {
+ g_object_notify (G_OBJECT (mi), "cc");
+ xcamel_message_info_set_dirty (mi, TRUE);
+ xcamel_message_info_set_folder_flagged (mi, TRUE);
+ }
+
+ return changed;
+}
+
+/**
+ * xcamel_message_info_get_mlist:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: (transfer none): Mailing list address of the @mi.
+ *
+ * Since: 3.24
+ **/
+const gchar *
+xcamel_message_info_get_mlist (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoClass *klass;
+ const gchar *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, NULL);
+ g_return_val_if_fail (klass->get_mlist != NULL, NULL);
+
+ xcamel_message_info_property_lock (mi);
+ result = klass->get_mlist (mi);
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+/**
+ * xcamel_message_info_set_mlist:
+ * @mi: a #xCamelMessageInfo
+ * @mlist: (nullable): a message list address to set
+ *
+ * Sets mesage list address from the associated message.
+ *
+ * This property is considered static, in a meaning that it should
+ * not change during the life-time of the @mi, the same as it doesn't
+ * change in the associated message.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically. There is not emitted folder's "changed" signal
+ * for this @mi.
+ *
+ * Returns: Whether the value changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+xcamel_message_info_set_mlist (xCamelMessageInfo *mi,
+ const gchar *mlist)
+{
+ xCamelMessageInfoClass *klass;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->set_mlist != NULL, FALSE);
+
+ xcamel_message_info_property_lock (mi);
+ changed = klass->set_mlist (mi, mlist);
+ xcamel_message_info_property_unlock (mi);
+
+ if (changed) {
+ g_object_notify (G_OBJECT (mi), "mlist");
+ xcamel_message_info_set_dirty (mi, TRUE);
+ xcamel_message_info_set_folder_flagged (mi, TRUE);
+ }
+
+ return changed;
+}
+
+/**
+ * xcamel_message_info_get_size:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: Size of the associated message.
+ *
+ * Since: 3.24
+ **/
+guint32
+xcamel_message_info_get_size (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoClass *klass;
+ guint32 result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), 0);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, 0);
+ g_return_val_if_fail (klass->get_size != NULL, 0);
+
+ xcamel_message_info_property_lock (mi);
+ result = klass->get_size (mi);
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+/**
+ * xcamel_message_info_set_size:
+ * @mi: a #xCamelMessageInfo
+ * @size: a size to set
+ *
+ * Sets size of the associated message.
+ *
+ * This property is considered static, in a meaning that it should
+ * not change during the life-time of the @mi, the same as it doesn't
+ * change in the associated message.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically. There is not emitted folder's "changed" signal
+ * for this @mi.
+ *
+ * Returns: Whether the value changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+xcamel_message_info_set_size (xCamelMessageInfo *mi,
+ guint32 size)
+{
+ xCamelMessageInfoClass *klass;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->set_size != NULL, FALSE);
+
+ xcamel_message_info_property_lock (mi);
+ changed = klass->set_size (mi, size);
+ xcamel_message_info_property_unlock (mi);
+
+ if (changed) {
+ g_object_notify (G_OBJECT (mi), "size");
+ xcamel_message_info_set_dirty (mi, TRUE);
+ xcamel_message_info_set_folder_flagged (mi, TRUE);
+ }
+
+ return changed;
+}
+
+/**
+ * xcamel_message_info_get_date_sent:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: time_t of the Date header of the message, encoded as gint64.
+ *
+ * Since: 3.24
+ **/
+gint64
+xcamel_message_info_get_date_sent (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoClass *klass;
+ gint64 result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), 0);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, 0);
+ g_return_val_if_fail (klass->get_date_sent != NULL, 0);
+
+ xcamel_message_info_property_lock (mi);
+ result = klass->get_date_sent (mi);
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+/**
+ * xcamel_message_info_set_date_sent:
+ * @mi: a #xCamelMessageInfo
+ * @date_sent: a sent date to set
+ *
+ * Sets sent date (the Date header) of the associated message.
+ *
+ * This property is considered static, in a meaning that it should
+ * not change during the life-time of the @mi, the same as it doesn't
+ * change in the associated message.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically. There is not emitted folder's "changed" signal
+ * for this @mi.
+ *
+ * Returns: Whether the value changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+xcamel_message_info_set_date_sent (xCamelMessageInfo *mi,
+ gint64 date_sent)
+{
+ xCamelMessageInfoClass *klass;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->set_date_sent != NULL, FALSE);
+
+ xcamel_message_info_property_lock (mi);
+ changed = klass->set_date_sent (mi, date_sent);
+ xcamel_message_info_property_unlock (mi);
+
+ if (changed) {
+ g_object_notify (G_OBJECT (mi), "date-sent");
+ xcamel_message_info_set_dirty (mi, TRUE);
+ xcamel_message_info_set_folder_flagged (mi, TRUE);
+ }
+
+ return changed;
+}
+
+/**
+ * xcamel_message_info_get_date_received:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: time_t of the Received header of the message, encoded as gint64.
+ *
+ * Since: 3.24
+ **/
+gint64
+xcamel_message_info_get_date_received (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoClass *klass;
+ gint64 result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), 0);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, 0);
+ g_return_val_if_fail (klass->get_date_received != NULL, 0);
+
+ xcamel_message_info_property_lock (mi);
+ result = klass->get_date_received (mi);
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+/**
+ * xcamel_message_info_set_date_received:
+ * @mi: a #xCamelMessageInfo
+ * @date_received: a received date to set
+ *
+ * Sets received date (the Received header) of the associated message.
+ *
+ * This property is considered static, in a meaning that it should
+ * not change during the life-time of the @mi, the same as it doesn't
+ * change in the associated message.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically. There is not emitted folder's "changed" signal
+ * for this @mi.
+ *
+ * Returns: Whether the value changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+xcamel_message_info_set_date_received (xCamelMessageInfo *mi,
+ gint64 date_received)
+{
+ xCamelMessageInfoClass *klass;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->set_date_received != NULL, FALSE);
+
+ xcamel_message_info_property_lock (mi);
+ changed = klass->set_date_received (mi, date_received);
+ xcamel_message_info_property_unlock (mi);
+
+ if (changed) {
+ g_object_notify (G_OBJECT (mi), "date-received");
+ xcamel_message_info_set_dirty (mi, TRUE);
+ xcamel_message_info_set_folder_flagged (mi, TRUE);
+ }
+
+ return changed;
+}
+
+/**
+ * xcamel_message_info_get_message_id:
+ * @mi: a #CamelMessageInfo
+ *
+ * Encoded Message-ID of the associated message as a guint64 number,
+ * partial MD5 sum. The value can be cast to #CamelSummaryMessageID.
+ *
+ * Returns: Partial MD5 hash of the Message-ID header of the associated message.
+ *
+ * Since: 3.24
+ **/
+guint64
+xcamel_message_info_get_message_id (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoClass *klass;
+ guint64 result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), 0);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, 0);
+ g_return_val_if_fail (klass->get_message_id != NULL, 0);
+
+ xcamel_message_info_property_lock (mi);
+ result = klass->get_message_id (mi);
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+/**
+ * xcamel_message_info_set_message_id:
+ * @mi: a #xCamelMessageInfo
+ * @message_id: a message id to set
+ *
+ * Sets encoded Message-ID of the associated message as a guint64 number,
+ * partial MD5 sum. The value can be cast to #CamelSummaryMessageID.
+ *
+ * This property is considered static, in a meaning that it should
+ * not change during the life-time of the @mi, the same as it doesn't
+ * change in the associated message.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically. There is not emitted folder's "changed" signal
+ * for this @mi.
+ *
+ * Returns: Whether the value changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+xcamel_message_info_set_message_id (xCamelMessageInfo *mi,
+ guint64 message_id)
+{
+ xCamelMessageInfoClass *klass;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->set_message_id != NULL, FALSE);
+
+ xcamel_message_info_property_lock (mi);
+ changed = klass->set_message_id (mi, message_id);
+ xcamel_message_info_property_unlock (mi);
+
+ if (changed) {
+ g_object_notify (G_OBJECT (mi), "message-id");
+ xcamel_message_info_set_dirty (mi, TRUE);
+ xcamel_message_info_set_folder_flagged (mi, TRUE);
+ }
+
+ return changed;
+}
+
+/**
+ * xcamel_message_info_get_references:
+ * @mi: a #CamelMessageInfo
+ *
+ * Gets encoded In-Reply-To and References headers of the associated
+ * message as an array of guint64 numbers, partial MD5 sums. Each value
+ * can be cast to #CamelSummaryMessageID.
+ *
+ * Returns: (transfer none): (nullable): A #GArray of guint64 encoded
+ * Message-ID-s; or %NULL when none are available.
+ *
+ * Since: 3.24
+ **/
+const GArray *
+xcamel_message_info_get_references (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoClass *klass;
+ const GArray *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, NULL);
+ g_return_val_if_fail (klass->get_references != NULL, NULL);
+
+ xcamel_message_info_property_lock (mi);
+ result = klass->get_references (mi);
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+/**
+ * xcamel_message_info_dup_references:
+ * @mi: a #CamelMessageInfo
+ *
+ * Duplicates encoded In-Reply-To and References headers of the associated
+ * message as an array of guint64 numbers, partial MD5 sums. Each value
+ * can be cast to #CamelSummaryMessageID.
+ *
+ * Returns: (transfer full): (nullable): A #GArray of guint64 encoded
+ * Message-ID-s; or %NULL when none are available. Free returned array
+ * with g_array_unref() when no longer needed.
+ *
+ * Since: 3.24
+ **/
+GArray *
+xcamel_message_info_dup_references (const xCamelMessageInfo *mi)
+{
+ const GArray *arr;
+ GArray *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+ xcamel_message_info_property_lock (mi);
+ arr = xcamel_message_info_get_references (mi);
+ if (arr) {
+ guint ii;
+
+ result = g_array_sized_new (FALSE, FALSE, sizeof (guint64), arr->len);
+ for (ii = 0; ii < arr->len; ii++) {
+ g_array_append_val (result, g_array_index (arr, guint64, ii));
+ }
+ } else {
+ result = NULL;
+ }
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+/**
+ * xcamel_message_info_take_references:
+ * @mi: a #xCamelMessageInfo
+ * @references: (transfer full): (nullable): a references to set
+ *
+ * Takes encoded In-Reply-To and References headers of the associated message
+ * as an array of guint64 numbers, partial MD5 sums. Each value can be
+ * cast to #CamelSummaryMessageID.
+ *
+ * This property is considered static, in a meaning that it should
+ * not change during the life-time of the @mi, the same as it doesn't
+ * change in the associated message.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically. There is not emitted folder's "changed" signal
+ * for this @mi.
+ *
+ * Returns: Whether the value changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+xcamel_message_info_take_references (xCamelMessageInfo *mi,
+ GArray *references)
+{
+ xCamelMessageInfoClass *klass;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->take_references != NULL, FALSE);
+
+ xcamel_message_info_property_lock (mi);
+ changed = klass->take_references (mi, references);
+ xcamel_message_info_property_unlock (mi);
+
+ if (changed) {
+ g_object_notify (G_OBJECT (mi), "references");
+ xcamel_message_info_set_dirty (mi, TRUE);
+ xcamel_message_info_set_folder_flagged (mi, TRUE);
+ }
+
+ return changed;
+}
+
+/**
+ * xcamel_message_info_get_headers:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: (transfer none): (nullable): All the message headers of the associated
+ * message, or %NULL, when none are available.
+ *
+ * Since: 3.24
+ **/
+const CamelNameValueArray *
+xcamel_message_info_get_headers (const xCamelMessageInfo *mi)
+{
+ xCamelMessageInfoClass *klass;
+ const CamelNameValueArray *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, NULL);
+ g_return_val_if_fail (klass->get_headers != NULL, NULL);
+
+ xcamel_message_info_property_lock (mi);
+ result = klass->get_headers (mi);
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+/**
+ * xcamel_message_info_dup_headers:
+ * @mi: a #CamelMessageInfo
+ *
+ * Duplicates array of headers for the @mi.
+ *
+ * Returns: (transfer full): (nullable): All the message headers of the associated
+ * message, or %NULL, when none are available. Free returned array with
+ * camel_name_value_array_free() when no longer needed.
+ *
+ * Since: 3.24
+ **/
+CamelNameValueArray *
+xcamel_message_info_dup_headers (const xCamelMessageInfo *mi)
+{
+ const CamelNameValueArray *arr;
+ CamelNameValueArray *result;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+ xcamel_message_info_property_lock (mi);
+ arr = xcamel_message_info_get_headers (mi);
+ if (arr) {
+ result = camel_name_value_array_copy (arr);
+ } else {
+ result = NULL;
+ }
+ xcamel_message_info_property_unlock (mi);
+
+ return result;
+}
+
+/**
+ * xcamel_message_info_take_headers:
+ * @mi: a #xCamelMessageInfo
+ * @headers: (transfer full): (nullable): headers to set, as #CamelNameValueArray, or %NULL
+ *
+ * Takes headers of the associated message.
+ *
+ * This property is considered static, in a meaning that it should
+ * not change during the life-time of the @mi, the same as it doesn't
+ * change in the associated message.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically. There is not emitted folder's "changed" signal
+ * for this @mi.
+ *
+ * Returns: Whether the value changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+xcamel_message_info_take_headers (xCamelMessageInfo *mi,
+ CamelNameValueArray *headers)
+{
+ xCamelMessageInfoClass *klass;
+ gboolean changed;
+
+ g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+ klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->take_headers != NULL, FALSE);
+
+ xcamel_message_info_property_lock (mi);
+ changed = klass->take_headers (mi, headers);
+ xcamel_message_info_property_unlock (mi);
+
+ if (changed) {
+ g_object_notify (G_OBJECT (mi), "headers");
+ xcamel_message_info_set_dirty (mi, TRUE);
+ xcamel_message_info_set_folder_flagged (mi, TRUE);
+ }
+
+ return changed;
+}
diff --git a/camel/camel-message-info.h b/camel/camel-message-info.h
index 2fc20cf..5863d1d 100644
--- a/camel/camel-message-info.h
+++ b/camel/camel-message-info.h
@@ -24,6 +24,8 @@
#include <glib-object.h>
+#include <camel/camel-mime-utils.h>
+
/* Standard GObject macros */
#define XCAMEL_TYPE_MESSAGE_INFO \
(xcamel_message_info_get_type ())
@@ -48,6 +50,48 @@ G_BEGIN_DECLS
/* Forward declarations */
struct _CamelFolderSummary;
+/* A summary messageid is a 64 bit identifier (partial md5 hash) */
+typedef struct _CamelSummaryMessageID {
+ union {
+ guint64 id;
+ guchar hash[8];
+ struct {
+ guint32 hi;
+ guint32 lo;
+ } part;
+ } id;
+} CamelSummaryMessageID;
+
+/* system flag bits */
+typedef enum _CamelMessageFlags {
+ CAMEL_MESSAGE_ANSWERED = 1 << 0,
+ CAMEL_MESSAGE_DELETED = 1 << 1,
+ CAMEL_MESSAGE_DRAFT = 1 << 2,
+ CAMEL_MESSAGE_FLAGGED = 1 << 3,
+ CAMEL_MESSAGE_SEEN = 1 << 4,
+
+ /* these aren't really system flag bits, but are convenience flags */
+ CAMEL_MESSAGE_ATTACHMENTS = 1 << 5,
+ CAMEL_MESSAGE_ANSWERED_ALL = 1 << 6,
+ CAMEL_MESSAGE_JUNK = 1 << 7,
+ CAMEL_MESSAGE_SECURE = 1 << 8,
+ CAMEL_MESSAGE_NOTJUNK = 1 << 9,
+ CAMEL_MESSAGE_FORWARDED = 1 << 10,
+
+ /* following flags are for the folder, and are not really permanent flags */
+ CAMEL_MESSAGE_FOLDER_FLAGGED = 1 << 16, /* for use by the folder implementation */
+ /* flags after 1 << 16 are used by camel providers,
+ * if adding non permanent flags, add them to the end */
+
+ CAMEL_MESSAGE_JUNK_LEARN = 1 << 30, /* used when setting CAMEL_MESSAGE_JUNK flag
+ * to say that we request junk plugin
+ * to learn that message as junk/non junk */
+ CAMEL_MESSAGE_USER = 1 << 31 /* supports user flags */
+} CamelMessageFlags;
+
+/* Changes to system flags will NOT trigger a folder changed event */
+#define CAMEL_MESSAGE_SYSTEM_MASK (0xffff << 16)
+
typedef struct _xCamelMessageInfo xCamelMessageInfo;
typedef struct _xCamelMessageInfoClass xCamelMessageInfoClass;
typedef struct _xCamelMessageInfoPrivate xCamelMessageInfoPrivate;
@@ -59,13 +103,189 @@ struct _xCamelMessageInfo {
struct _xCamelMessageInfoClass {
GObjectClass parent_class;
+
+ xCamelMessageInfo * (* clone) (const xCamelMessageInfo *mi,
+ struct _CamelFolderSummary *summary);
+ guint32 (* get_flags) (const xCamelMessageInfo *mi);
+ gboolean (* set_flags) (xCamelMessageInfo *mi,
+ CamelMessageFlags flags,
+ guint32 set);
+ gboolean (* get_user_flag)
+ (const xCamelMessageInfo *mi,
+ const gchar *name);
+ gboolean (* set_user_flag)
+ (xCamelMessageInfo *mi,
+ const gchar *name,
+ gboolean state);
+ CamelNamedFlags * (* dup_user_flags)
+ (const xCamelMessageInfo *mi);
+ gboolean (* take_user_flags)
+ (xCamelMessageInfo *mi,
+ CamelNamedFlags *user_flags);
+ const gchar * (* get_user_tag)(const xCamelMessageInfo *mi,
+ const gchar *name);
+ gboolean (* set_user_tag)(xCamelMessageInfo *mi,
+ const gchar *name,
+ const gchar *value);
+ CamelNameValueArray * (* dup_user_tags)
+ (const xCamelMessageInfo *mi);
+ gboolean (* take_user_tags)
+ (xCamelMessageInfo *mi,
+ CamelNameValueArray *user_tags);
+ const gchar * (* get_subject) (const xCamelMessageInfo *mi);
+ gboolean (* set_subject) (xCamelMessageInfo *mi,
+ const gchar *subject);
+ const gchar * (* get_preview) (const xCamelMessageInfo *mi);
+ gboolean (* set_preview) (xCamelMessageInfo *mi,
+ const gchar *preview);
+ const gchar * (* get_from) (const xCamelMessageInfo *mi);
+ gboolean (* set_from) (xCamelMessageInfo *mi,
+ const gchar *from);
+ const gchar * (* get_to) (const xCamelMessageInfo *mi);
+ gboolean (* set_to) (xCamelMessageInfo *mi,
+ const gchar *to);
+ const gchar * (* get_cc) (const xCamelMessageInfo *mi);
+ gboolean (* set_cc) (xCamelMessageInfo *mi,
+ const gchar *cc);
+ const gchar * (* get_mlist) (const xCamelMessageInfo *mi);
+ gboolean (* set_mlist) (xCamelMessageInfo *mi,
+ const gchar *mlist);
+ guint32 (* get_size) (const xCamelMessageInfo *mi);
+ gboolean (* set_size) (xCamelMessageInfo *mi,
+ guint32 size);
+ gint64 (* get_date_sent)
+ (const xCamelMessageInfo *mi);
+ gboolean (* set_date_sent)
+ (xCamelMessageInfo *mi,
+ gint64 date_sent);
+ gint64 (* get_date_received)
+ (const xCamelMessageInfo *mi);
+ gboolean (* set_date_received)
+ (xCamelMessageInfo *mi,
+ gint64 date_received);
+ guint64 (* get_message_id)
+ (const xCamelMessageInfo *mi);
+ gboolean (* set_message_id)
+ (xCamelMessageInfo *mi,
+ guint64 message_id);
+ const GArray * (* get_references)
+ (const xCamelMessageInfo *mi);
+ gboolean (* take_references)
+ (xCamelMessageInfo *mi,
+ GArray *references);
+ const CamelNameValueArray *
+ (* get_headers) (const xCamelMessageInfo *mi);
+ gboolean (* take_headers)(xCamelMessageInfo *mi,
+ CamelNameValueArray *headers);
+
+ /* Padding for future expansion */
+ gpointer reserved[20];
};
GType xcamel_message_info_get_type (void);
xCamelMessageInfo *
xcamel_message_info_new (struct _CamelFolderSummary *summary);
+xCamelMessageInfo *
+ xcamel_message_info_clone (const xCamelMessageInfo *mi,
+ struct _CamelFolderSummary *summary);
struct _CamelFolderSummary *
- xcamel_message_info_ref_summary (xCamelMessageInfo *mi);
+ xcamel_message_info_ref_summary (const xCamelMessageInfo *mi);
+void xcamel_message_info_property_lock
+ (const xCamelMessageInfo *mi);
+void xcamel_message_info_property_unlock
+ (const xCamelMessageInfo *mi);
+gboolean xcamel_message_info_get_dirty (const xCamelMessageInfo *mi);
+void xcamel_message_info_set_dirty (const xCamelMessageInfo *mi,
+ gboolean dirty);
+gboolean xcamel_message_info_get_folder_flagged
+ (const xCamelMessageInfo *mi);
+gboolean xcamel_message_info_set_folder_flagged
+ (xCamelMessageInfo *mi,
+ gboolean folder_flagged);
+const gchar * xcamel_message_info_get_uid (const xCamelMessageInfo *mi);
+const gchar * xcamel_message_info_pooldup_uid (const xCamelMessageInfo *mi);
+gboolean xcamel_message_info_set_uid (xCamelMessageInfo *mi,
+ const gchar *uid);
+guint32 xcamel_message_info_get_flags (const xCamelMessageInfo *mi);
+gboolean xcamel_message_info_set_flags (xCamelMessageInfo *mi,
+ CamelMessageFlags mask,
+ guint32 set);
+gboolean xcamel_message_info_get_user_flag
+ (const xCamelMessageInfo *mi,
+ const gchar *name);
+gboolean xcamel_message_info_set_user_flag
+ (xCamelMessageInfo *mi,
+ const gchar *name,
+ gboolean state);
+CamelNamedFlags *
+ xcamel_message_info_dup_user_flags
+ (const xCamelMessageInfo *mi);
+gboolean
+ xcamel_message_info_take_user_flags
+ (xCamelMessageInfo *mi,
+ CamelNamedFlags *user_flags);
+const gchar * xcamel_message_info_get_user_tag (const xCamelMessageInfo *mi,
+ const gchar *name);
+gchar * xcamel_message_info_dup_user_tag (const xCamelMessageInfo *mi,
+ const gchar *name);
+gboolean xcamel_message_info_set_user_tag (xCamelMessageInfo *mi,
+ const gchar *name,
+ const gchar *value);
+CamelNameValueArray *
+ xcamel_message_info_dup_user_tags
+ (const xCamelMessageInfo *mi);
+gboolean xcamel_message_info_take_user_tags
+ (xCamelMessageInfo *mi,
+ CamelNameValueArray *user_tags);
+const gchar * xcamel_message_info_get_subject (const xCamelMessageInfo *mi);
+gboolean xcamel_message_info_set_subject (xCamelMessageInfo *mi,
+ const gchar *subject);
+const gchar * xcamel_message_info_get_preview (const xCamelMessageInfo *mi);
+gboolean xcamel_message_info_set_preview (xCamelMessageInfo *mi,
+ const gchar *preview);
+const gchar * xcamel_message_info_get_from (const xCamelMessageInfo *mi);
+gboolean xcamel_message_info_set_from (xCamelMessageInfo *mi,
+ const gchar *from);
+const gchar * xcamel_message_info_get_to (const xCamelMessageInfo *mi);
+gboolean xcamel_message_info_set_to (xCamelMessageInfo *mi,
+ const gchar *to);
+const gchar * xcamel_message_info_get_cc (const xCamelMessageInfo *mi);
+gboolean xcamel_message_info_set_cc (xCamelMessageInfo *mi,
+ const gchar *cc);
+const gchar * xcamel_message_info_get_mlist (const xCamelMessageInfo *mi);
+gboolean xcamel_message_info_set_mlist (xCamelMessageInfo *mi,
+ const gchar *mlist);
+guint32 xcamel_message_info_get_size (const xCamelMessageInfo *mi);
+gboolean xcamel_message_info_set_size (xCamelMessageInfo *mi,
+ guint32 size);
+gint64 xcamel_message_info_get_date_sent
+ (const xCamelMessageInfo *mi);
+gboolean xcamel_message_info_set_date_sent
+ (xCamelMessageInfo *mi,
+ gint64 date_sent);
+gint64 xcamel_message_info_get_date_received
+ (const xCamelMessageInfo *mi);
+gboolean xcamel_message_info_set_date_received
+ (xCamelMessageInfo *mi,
+ gint64 date_received);
+guint64 xcamel_message_info_get_message_id
+ (const xCamelMessageInfo *mi);
+gboolean xcamel_message_info_set_message_id
+ (xCamelMessageInfo *mi,
+ guint64 message_id);
+const GArray * xcamel_message_info_get_references
+ (const xCamelMessageInfo *mi);
+GArray * xcamel_message_info_dup_references
+ (const xCamelMessageInfo *mi);
+gboolean xcamel_message_info_take_references
+ (xCamelMessageInfo *mi,
+ GArray *references);
+const CamelNameValueArray *
+ xcamel_message_info_get_headers (const xCamelMessageInfo *mi);
+CamelNameValueArray *
+ xcamel_message_info_dup_headers (const xCamelMessageInfo *mi);
+gboolean xcamel_message_info_take_headers (xCamelMessageInfo *mi,
+ CamelNameValueArray *headers);
G_END_DECLS
diff --git a/camel/camel-mime-utils.c b/camel/camel-mime-utils.c
index c64f54f..b872fdc 100644
--- a/camel/camel-mime-utils.c
+++ b/camel/camel-mime-utils.c
@@ -43,6 +43,7 @@
#include "camel-iconv.h"
#include "camel-mime-utils.h"
#include "camel-net-utils.h"
+#include "camel-string-utils.h"
#ifdef G_OS_WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
@@ -104,6 +105,827 @@ G_DEFINE_BOXED_TYPE (CamelHeaderAddress,
camel_header_address_ref,
camel_header_address_unref)
+G_DEFINE_BOXED_TYPE (CamelNameValueArray,
+ camel_name_value_array,
+ camel_name_value_array_copy,
+ camel_name_value_array_free)
+
+typedef struct _CamelNameValuePair {
+ gchar *name;
+ gchar *value;
+} CamelNameValuePair;
+
+static void
+free_name_value_content (gpointer ptr)
+{
+ CamelNameValuePair *pair = ptr;
+
+ if (pair) {
+ g_free (pair->name);
+ g_free (pair->value);
+
+ pair->name = NULL;
+ pair->value = NULL;
+ }
+}
+
+/**
+ * camel_name_value_array_new:
+ *
+ * Created a new #CamelNameValueArray. The returned pointer should be freed
+ * with camel_name_value_array_free() when no longer needed.
+ *
+ * Returns: (transfer-full): A new #CamelNameValueArray.
+ *
+ * See: camel_name_value_array_new_sized, camel_name_value_array_copy
+ *
+ * Since: 3.24
+ **/
+CamelNameValueArray *
+camel_name_value_array_new (void)
+{
+ GArray *arr;
+
+ arr = g_array_new (FALSE, FALSE, sizeof (CamelNameValuePair));
+ g_array_set_clear_func (arr, free_name_value_content);
+
+ return (CamelNameValueArray *) arr;
+}
+
+/**
+ * camel_name_value_array_new_sized:
+ * @reserve_size: an array size to reserve
+ *
+ * Created a new #CamelNameValueArray, which has reserved @reserve_size
+ * elements. This value doesn't influence the camel_name_value_array_length(),
+ * which returns zero on the array returned from this function. The returned
+ * pointer should be freed with camel_name_value_array_free() when no longer needed.
+ *
+ * Returns: (transfer-full): A new #CamelNameValueArray.
+ *
+ * See: camel_name_value_array_new, camel_name_value_array_copy
+ *
+ * Since: 3.24
+ **/
+CamelNameValueArray *
+camel_name_value_array_new_sized (guint reserve_size)
+{
+ GArray *arr;
+
+ arr = g_array_sized_new (FALSE, FALSE, sizeof (CamelNameValuePair), reserve_size);
+ g_array_set_clear_func (arr, free_name_value_content);
+
+ return (CamelNameValueArray *) arr;
+}
+
+/**
+ * camel_name_value_array_copy:
+ * @array: a #CamelNameValueArray
+ *
+ * Created a new copy of the @array. The returned pointer should be freed
+ * with camel_name_value_array_free() when no longer needed.
+ *
+ * Returns: (transfer-full): A new copy of the @array.
+ *
+ * See: camel_name_value_array_new, camel_name_value_array_new_sized
+ *
+ * Since: 3.24
+ **/
+CamelNameValueArray *
+camel_name_value_array_copy (const CamelNameValueArray *array)
+{
+ CamelNameValueArray *copy;
+ guint ii, len;
+
+ if (!array)
+ return NULL;
+
+ len = camel_name_value_array_length (array);
+ copy = camel_name_value_array_new_sized (len);
+
+ for (ii = 0; ii < len; ii++) {
+ const gchar *name = NULL, *value = NULL;
+
+ if (camel_name_value_array_get (array, ii, &name, &value))
+ camel_name_value_array_append (copy, name, value);
+ }
+
+ return copy;
+}
+
+/**
+ * camel_name_value_array_free:
+ * @array: (nullable): a #CamelNameValueArray, or %NULL
+ *
+ * Frees the @array, previously allocated by camel_name_value_array_new(),
+ * camel_name_value_array_new_sized() or camel_name_value_array_copy().
+ * If the @array is %NULL, then does nothing.
+ *
+ * Since: 3.24
+ **/
+void
+camel_name_value_array_free (CamelNameValueArray *array)
+{
+ if (array) {
+ g_array_free ((GArray *) array, TRUE);
+ }
+}
+
+/**
+ * camel_name_value_array_length:
+ * @array: a #CamelNameValueArray
+ *
+ * Returns: Length of the @array, aka how many elements are stored in the @array.
+ *
+ * Since: 3.24
+ **/
+guint
+camel_name_value_array_length (const CamelNameValueArray *array)
+{
+ GArray *arr = (GArray *) array;
+
+ g_return_val_if_fail (array != NULL, 0);
+
+ return arr->len;
+}
+
+/**
+ * camel_name_value_array_get:
+ * @array: a #CamelNameValueArray
+ * @index: an index
+ * @out_name: (out): (nullable): A place to store the name of the element, or %NULL
+ * @out_value: (out): (nullable): A place to store the value of the element, or %NULL
+ *
+ * Returns the name and the value of the element at index @index. Either
+ * of the @out_name and @out_value can be %NULL, to not return that part.
+ *
+ * Returns: %TRUE on success, %FALSE otherwise.
+ *
+ * See: camel_name_value_array_get_name, camel_name_value_array_get_value, camel_name_value_array_get_named
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_name_value_array_get (const CamelNameValueArray *array,
+ guint index,
+ const gchar **out_name,
+ const gchar **out_value)
+{
+ GArray *arr = (GArray *) array;
+ CamelNameValuePair *pair;
+
+ g_return_val_if_fail (array != NULL, FALSE);
+ g_return_val_if_fail (index < camel_name_value_array_length (array), FALSE);
+
+ pair = &g_array_index (arr, CamelNameValuePair, index);
+
+ if (out_name)
+ *out_name = pair->name;
+ if (out_value)
+ *out_value= pair->value;
+
+ return TRUE;
+}
+
+static guint
+camel_name_value_array_find_named (const CamelNameValueArray *array,
+ gboolean case_sensitive,
+ const gchar *name)
+{
+ GArray *arr = (GArray *) array;
+ gint ii;
+
+ g_return_val_if_fail (array != NULL, (guint) -1);
+ g_return_val_if_fail (name != NULL, (guint) -1);
+
+ for (ii = 0; ii < arr->len; ii++) {
+ CamelNameValuePair *pair = &g_array_index (arr, CamelNameValuePair, ii);
+
+ if ((case_sensitive && g_strcmp0 (name, pair->name) == 0) ||
+ (!case_sensitive && pair->name && camel_strcase_equal (name, pair->name))) {
+ return ii;
+ }
+ }
+
+ return (guint) -1;
+}
+
+/**
+ * camel_name_value_array_set_named:
+ * @array: a #CamelNameValueArray
+ * @case_sensitive: whether to compare names case sensitively
+ * @name: a name
+ *
+ * Returns the value of the first element named @name, or %NULL when there
+ * is no element of such @name in the @array. The @case_sensitive determines
+ * whether compare names case sensitively (%TRUE) or insensitively (%FALSE).
+ *
+ * Returns: (transfer-none): (nullable): Value of the first element named @name, or %NULL.
+ *
+ * See: camel_name_value_array_get, camel_name_value_array_get_name
+ *
+ * Since: 3.24
+ **/
+const gchar *
+camel_name_value_array_get_named (const CamelNameValueArray *array,
+ gboolean case_sensitive,
+ const gchar *name)
+{
+ guint index;
+
+ g_return_val_if_fail (array != NULL, NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ index = camel_name_value_array_find_named (array, case_sensitive, name);
+ if (index == (guint) -1)
+ return NULL;
+
+ return camel_name_value_array_get_value (array, index);
+}
+
+/**
+ * camel_name_value_array_get_name:
+ * @array: a #CamelNameValueArray
+ * @index: an index
+ *
+ * Returns the name of the element at index @index.
+ *
+ * Returns: (transfer-none): (nullable): Name of the element at the given @index,
+ * or %NULL on error.
+ *
+ * See: camel_name_value_array_get, camel_name_value_array_get_value
+ *
+ * Since: 3.24
+ **/
+const gchar *
+camel_name_value_array_get_name (const CamelNameValueArray *array,
+ guint index)
+{
+ const gchar *name = NULL;
+
+ g_return_val_if_fail (array != NULL, NULL);
+ g_return_val_if_fail (index < camel_name_value_array_length (array), NULL);
+
+ if (!camel_name_value_array_get (array, index, &name, NULL))
+ return NULL;
+
+ return name;
+}
+
+/**
+ * camel_name_value_array_get_value:
+ * @array: a #CamelNameValueArray
+ * @index: an index
+ *
+ * Returns the value of the element at index @index.
+ *
+ * Returns: (transfer-none): (nullable): Value of the element at the given @index,
+ * or %NULL on error.
+ *
+ * See: camel_name_value_array_get, camel_name_value_array_get_name
+ *
+ * Since: 3.24
+ **/
+const gchar *
+camel_name_value_array_get_value (const CamelNameValueArray *array,
+ guint index)
+{
+ const gchar *value = NULL;
+
+ g_return_val_if_fail (array != NULL, NULL);
+ g_return_val_if_fail (index < camel_name_value_array_length (array), NULL);
+
+ if (!camel_name_value_array_get (array, index, NULL, &value))
+ return NULL;
+
+ return value;
+}
+
+/**
+ * camel_name_value_array_append:
+ * @array: a #CamelNameValueArray
+ * @name: a name
+ * @value: a value
+ *
+ * Appends a new element of the name @name and the value @value
+ * at the end of @array.
+ *
+ * See: camel_name_value_array_set_named
+ *
+ * Since: 3.24
+ **/
+void
+camel_name_value_array_append (CamelNameValueArray *array,
+ const gchar *name,
+ const gchar *value)
+{
+ GArray *arr = (GArray *) array;
+ CamelNameValuePair pair;
+
+ g_return_if_fail (array != NULL);
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (value != NULL);
+
+ pair.name = g_strdup (name);
+ pair.value = g_strdup (value);
+
+ g_array_append_val (arr, pair);
+}
+
+static gboolean
+camel_name_value_array_set_internal (CamelNameValueArray *array,
+ guint index,
+ const gchar *name,
+ const gchar *value)
+{
+ GArray *arr = (GArray *) array;
+ CamelNameValuePair *pair;
+ gboolean changed = FALSE;
+
+ g_return_val_if_fail (array != NULL, FALSE);
+ g_return_val_if_fail (index < camel_name_value_array_length (array), FALSE);
+
+ pair = &g_array_index (arr, CamelNameValuePair, index);
+
+ if (name && g_strcmp0 (pair->name, name) != 0) {
+ g_free (pair->name);
+ pair->name = g_strdup (name);
+ changed = TRUE;
+ }
+
+ if (value && g_strcmp0 (pair->value, value) != 0) {
+ g_free (pair->value);
+ pair->value = g_strdup (value);
+ changed = TRUE;
+ }
+
+ return changed;
+}
+
+/**
+ * camel_name_value_array_set:
+ * @array: a #CamelNameValueArray
+ * @index: an index
+ * @name: a name
+ * @value: a value
+ *
+ * Sets both the @name and the @value of the element at index @index.
+ *
+ * Returns: Whether the @array changed.
+ *
+ * See: camel_name_value_array_append, camel_name_value_array_set_name, camel_name_value_array_set_value
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_name_value_array_set (CamelNameValueArray *array,
+ guint index,
+ const gchar *name,
+ const gchar *value)
+{
+ g_return_val_if_fail (array != NULL, FALSE);
+ g_return_val_if_fail (index < camel_name_value_array_length (array), FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ return camel_name_value_array_set_internal (array, index, name, value);
+}
+
+/**
+ * camel_name_value_array_set_name:
+ * @array: a #CamelNameValueArray
+ * @index: an index
+ * @name: a name
+ *
+ * Sets the @name of the element at index @index.
+ *
+ * Returns: Whether the @array changed.
+ *
+ * See: camel_name_value_array_set, camel_name_value_array_set_value
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_name_value_array_set_name (CamelNameValueArray *array,
+ guint index,
+ const gchar *name)
+{
+ g_return_val_if_fail (array != NULL, FALSE);
+ g_return_val_if_fail (index < camel_name_value_array_length (array), FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+
+ return camel_name_value_array_set_internal (array, index, name, NULL);
+}
+
+/**
+ * camel_name_value_array_set_value:
+ * @array: a #CamelNameValueArray
+ * @index: an index
+ * @value: a value
+ *
+ * Sets the @value of the element at index @index.
+ *
+ * Returns: Whether the @array changed.
+ *
+ * See: camel_name_value_array_set, camel_name_value_array_set_name
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_name_value_array_set_value (CamelNameValueArray *array,
+ guint index,
+ const gchar *value)
+{
+ g_return_val_if_fail (array != NULL, FALSE);
+ g_return_val_if_fail (index < camel_name_value_array_length (array), FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ return camel_name_value_array_set_internal (array, index, NULL, value);
+}
+
+/**
+ * camel_name_value_array_set_named:
+ * @array: a #CamelNameValueArray
+ * @case_sensitive: whether to compare names case sensitively
+ * @name: a name
+ * @value: a value
+ *
+ * Finds an element named @name and sets its value to @value, or appends
+ * a new element, in case no such named lement exists in the @array yet.
+ * In case there are more elements named with @name only the first
+ * occurrence is changed. The @case_sensitive determines whether compare
+ * names case sensitively (%TRUE) or insensitively (%FALSE).
+ *
+ * Returns: Whether the @array changed.
+ *
+ * See: camel_name_value_array_append, camel_name_value_array_set
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_name_value_array_set_named (CamelNameValueArray *array,
+ gboolean case_sensitive,
+ const gchar *name,
+ const gchar *value)
+{
+ gboolean changed = FALSE;
+ guint index;
+
+ g_return_val_if_fail (array != NULL, FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ index = camel_name_value_array_find_named (array, case_sensitive, name);
+ if (index == (guint) -1) {
+ camel_name_value_array_append (array, name, value);
+ changed = TRUE;
+ } else {
+ changed = camel_name_value_array_set_value (array, index, value);
+ }
+
+ return changed;
+}
+
+/**
+ * camel_name_value_array_remove:
+ * @array: a #CamelNameValueArray
+ * @index: an index to remove
+ *
+ * Removes element at index @index.
+ *
+ * Returns: Whether the element was removed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_name_value_array_remove (CamelNameValueArray *array,
+ guint index)
+{
+ g_return_val_if_fail (array != NULL, FALSE);
+ g_return_val_if_fail (index < camel_name_value_array_length (array), FALSE);
+
+ g_array_remove_index ((GArray *) array, index);
+
+ return TRUE;
+}
+
+/**
+ * camel_name_value_array_remove_named:
+ * @array: a #CamelNameValueArray
+ * @case_sensitive: whether to compare names case sensitively
+ * @name: a name to remove
+ * @all_occurrences: whether to remove all occurrences of the @name
+ *
+ * Removes elements of the @array with the given @name. The @case_sensitive
+ * determines whether compare case sensitively (%TRUE) or insensitively (%FALSE).
+ * If the @all_occurrences is set to %TRUE, then every elements with the @name
+ * are removed, otherwise only the first occurrence is removed.
+ *
+ * Returns: How many elements had been removed.
+ *
+ * Since: 3.24
+ **/
+guint
+camel_name_value_array_remove_named (CamelNameValueArray *array,
+ gboolean case_sensitive,
+ const gchar *name,
+ gboolean all_occurrences)
+{
+ guint index, removed = 0;
+
+ g_return_val_if_fail (array != NULL, 0);
+ g_return_val_if_fail (name != NULL, 0);
+
+ while (index = camel_name_value_array_find_named (array, case_sensitive, name), index != (guint) -1) {
+ if (!camel_name_value_array_remove (array, index))
+ break;
+
+ removed++;
+
+ if (!all_occurrences)
+ break;
+ }
+
+ return removed;
+}
+
+/**
+ * camel_name_value_array_clear:
+ * @array: a #CamelNameValueArray
+ *
+ * Removes all elements of the @array.
+ *
+ * Since: 3.24
+ **/
+void
+camel_name_value_array_clear (CamelNameValueArray *array)
+{
+ GArray *arr = (GArray *) array;
+
+ g_return_if_fail (array != NULL);
+
+ g_array_remove_range (arr, 0, arr->len);
+}
+
+/* ------------------------------------------------------------------------ */
+
+G_DEFINE_BOXED_TYPE (CamelNamedFlags,
+ camel_named_flags,
+ camel_named_flags_copy,
+ camel_named_flags_free)
+
+/**
+ * camel_named_flags_new:
+ *
+ * Creates a new #CamelNamedFlags.
+ *
+ * Returns: (transfer-full): A newly allocated #CamelNamedFlags.
+ * Free it with camel_named_flags_free() when done with it.
+ *
+ * Since: 3.24
+ **/
+CamelNamedFlags *
+camel_named_flags_new (void)
+{
+ return (CamelNamedFlags *) g_ptr_array_new_with_free_func (g_free);
+}
+
+/**
+ * camel_named_flags_new_sized:
+ * @reserve_size: an array size to reserve
+ *
+ * Created a new #CamelNamedFlags, which has reserved @reserve_size
+ * elements. This value doesn't influence the camel_named_flags_length(),
+ * which returns zero on the array returned from this function.
+ *
+ * Returns: (transfer-full): A newly allocated #CamelNameValueArray.
+ * Free it with camel_named_flags_free() when done with it.
+ *
+ * See: camel_name_value_array_new, camel_name_value_array_copy
+ *
+ * Since: 3.24
+ **/
+CamelNamedFlags *
+camel_named_flags_new_sized (guint reserve_size)
+{
+ return (CamelNamedFlags *) g_ptr_array_new_full (reserve_size, g_free);
+}
+
+/**
+ * camel_named_flags_copy:
+ * @named_flags: a #CamelNamedFlags
+ *
+ * Creates a copy of the @named_flags and returns it.
+ *
+ * Returns: (transfer-full): A newly allocated #CamelNamedFlags.
+ * Free it with camel_named_flags_free() when done with it.
+ *
+ * Since: 3.24
+ **/
+CamelNamedFlags *
+camel_named_flags_copy (const CamelNamedFlags *named_flags)
+{
+ const GPtrArray *src = (const GPtrArray *) named_flags;
+ GPtrArray *arr;
+ guint ii;
+
+ if (!src)
+ return NULL;
+
+ arr = (GPtrArray *) camel_named_flags_new_sized (src->len);
+ for (ii = 0; ii < src->len; ii++) {
+ const gchar *name = g_ptr_array_index (src, ii);
+
+ if (name && *name)
+ g_ptr_array_add (arr, g_strdup (name));
+ }
+
+ return (CamelNamedFlags *) arr;
+}
+
+/**
+ * camel_named_flags_free:
+ * @named_flags: (nullable): a #CamelNamedFlags, or %NULL
+ *
+ * Frees memory associated iwth the @named_flags. Does nothing,
+ * if @named_flags is %NULL.
+ *
+ * Since: 3.24
+ **/
+void
+camel_named_flags_free (CamelNamedFlags *named_flags)
+{
+ if (named_flags)
+ g_ptr_array_unref ((GPtrArray *) named_flags);
+}
+
+static guint
+camel_named_flags_find (CamelNamedFlags *named_flags,
+ const gchar *name)
+{
+ GPtrArray *arr = (GPtrArray *) named_flags;
+ guint ii;
+
+ g_return_val_if_fail (named_flags != NULL, (guint) -1);
+ g_return_val_if_fail (name != NULL, (guint) -1);
+
+ for (ii = 0; ii < arr->len; ii++) {
+ const gchar *nm = g_ptr_array_index (arr, ii);
+
+ if (g_strcmp0 (nm, name) == 0)
+ return ii;
+ }
+
+ return (guint) -1;
+}
+
+/**
+ * camel_named_flags_insert:
+ * @named_flags: a #CamelNamedFlags
+ * @name: name of the flag
+ *
+ * Inserts a flag named @name into the @named_flags, if it is not included
+ * already (comparing case sensitively), or does nothing otherwise.
+ *
+ * Returns: %TRUE the flag named @name was inserted; %FALSE otherwise.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_named_flags_insert (CamelNamedFlags *named_flags,
+ const gchar *name)
+{
+ GPtrArray *arr = (GPtrArray *) named_flags;
+ guint index;
+
+ g_return_val_if_fail (named_flags != NULL, FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+
+ index = camel_named_flags_find (named_flags, name);
+
+ /* already there */
+ if (index != (guint) -1)
+ return FALSE;
+
+ g_ptr_array_add (arr, g_strdup (name));
+
+ return TRUE;
+}
+
+/**
+ * camel_named_flags_remove:
+ * @named_flags: a #CamelNamedFlags
+ * @name: name of the flag
+ *
+ * Removes a flag named @name from the @named_flags.
+ *
+ * Returns: %TRUE when the @named_flags contained a flag named @name,
+ * comparing case sensitively, and it was removed; %FALSE otherwise.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_named_flags_remove (CamelNamedFlags *named_flags,
+ const gchar *name)
+{
+ GPtrArray *arr = (GPtrArray *) named_flags;
+ guint index;
+
+ g_return_val_if_fail (named_flags != NULL, FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+
+ index = camel_named_flags_find (named_flags, name);
+
+ /* not there */
+ if (index == (guint) -1)
+ return FALSE;
+
+ g_ptr_array_remove_index (arr, index);
+
+ return TRUE;
+}
+
+/**
+ * camel_named_flags_contains:
+ * @named_flags: a #CamelNamedFlags
+ * @name: name of the flag
+ *
+ * Returns: Whether the @named_flags contains a flag named @name,
+ * comparing case sensitively.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_named_flags_contains (CamelNamedFlags *named_flags,
+ const gchar *name)
+{
+ g_return_val_if_fail (named_flags != NULL, FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+
+ return camel_named_flags_find (named_flags, name) != (guint) -1;
+}
+
+/**
+ * camel_named_flags_clear:
+ * @named_flags: a #CamelNamedFlags
+ *
+ * Removes all the elements of the array.
+ *
+ * Since: 3.24
+ **/
+void
+camel_named_flags_clear (CamelNamedFlags *named_flags)
+{
+ GPtrArray *arr = (GPtrArray *) named_flags;
+
+ g_return_if_fail (named_flags != NULL);
+
+ if (arr->len)
+ g_ptr_array_remove_range (arr, 0, arr->len);
+}
+
+/**
+ * camel_named_flags_length:
+ * @named_flags: a #CamelNamedFlags
+ *
+ * Returns: Length of the array, aka how many named flags are stored there.
+ *
+ * Since: 3.24
+ **/
+guint
+camel_named_flags_length (const CamelNamedFlags *named_flags)
+{
+ const GPtrArray *arr = (const GPtrArray *) named_flags;
+
+ g_return_val_if_fail (named_flags != NULL, 0);
+
+ return arr->len;
+}
+
+/**
+ * camel_named_flags_get:
+ * @named_flags: a #CamelNamedFlags
+ * @index: an index of an element
+ *
+ * Returns: (transfer-none): (nullable): Name of the flag in at the given @index,
+ * or %NULL on error.
+ *
+ * Since: 3.24
+ **/
+const gchar *
+camel_named_flags_get (const CamelNamedFlags *named_flags,
+ guint index)
+{
+ const GPtrArray *arr = (const GPtrArray *) named_flags;
+
+ g_return_val_if_fail (named_flags != NULL, NULL);
+ g_return_val_if_fail (index < camel_named_flags_length (named_flags), NULL);
+
+ return g_ptr_array_index (arr, index);
+}
+
+/* ------------------------------------------------------------------------ */
+
/**
* camel_mktime_utc:
* @tm: the #tm to convert to a calendar time representation
diff --git a/camel/camel-mime-utils.h b/camel/camel-mime-utils.h
index 2a51044..0cd2101 100644
--- a/camel/camel-mime-utils.h
+++ b/camel/camel-mime-utils.h
@@ -30,6 +30,8 @@
#include <glib-object.h>
#include <camel/camel-enums.h>
+G_BEGIN_DECLS
+
/* maximum recommended size of a line from camel_header_fold() */
#define CAMEL_FOLD_SIZE (77)
/* maximum hard size of a line from camel_header_fold() */
@@ -43,7 +45,95 @@ typedef enum {
#define CAMEL_UUDECODE_STATE_MASK (CAMEL_UUDECODE_STATE_BEGIN | CAMEL_UUDECODE_STATE_END)
-G_BEGIN_DECLS
+/**
+ * CamelNameValueArray:
+ *
+ * Since: 3.24
+ **/
+struct _CamelNameValueArray;
+typedef struct _CamelNameValueArray CamelNameValueArray;
+
+#define CAMEL_TYPE_NAME_VALUE_ARRAY (camel_name_value_array_get_type ())
+
+GType camel_name_value_array_get_type (void) G_GNUC_CONST;
+CamelNameValueArray *
+ camel_name_value_array_new (void);
+CamelNameValueArray *
+ camel_name_value_array_new_sized
+ (guint reserve_size);
+CamelNameValueArray *
+ camel_name_value_array_copy (const CamelNameValueArray *array);
+void camel_name_value_array_free (CamelNameValueArray *array);
+guint camel_name_value_array_length (const CamelNameValueArray *array);
+gboolean camel_name_value_array_get (const CamelNameValueArray *array,
+ guint index,
+ const gchar **out_name,
+ const gchar **out_value);
+const gchar * camel_name_value_array_get_named
+ (const CamelNameValueArray *array,
+ gboolean case_sensitive,
+ const gchar *name);
+const gchar * camel_name_value_array_get_name (const CamelNameValueArray *array,
+ guint index);
+const gchar * camel_name_value_array_get_value
+ (const CamelNameValueArray *array,
+ guint index);
+void camel_name_value_array_append (CamelNameValueArray *array,
+ const gchar *name,
+ const gchar *value);
+gboolean camel_name_value_array_set (CamelNameValueArray *array,
+ guint index,
+ const gchar *name,
+ const gchar *value);
+gboolean camel_name_value_array_set_name (CamelNameValueArray *array,
+ guint index,
+ const gchar *name);
+gboolean camel_name_value_array_set_value
+ (CamelNameValueArray *array,
+ guint index,
+ const gchar *value);
+gboolean camel_name_value_array_set_named
+ (CamelNameValueArray *array,
+ gboolean case_sensitive,
+ const gchar *name,
+ const gchar *value);
+gboolean camel_name_value_array_remove (CamelNameValueArray *array,
+ guint index);
+guint camel_name_value_array_remove_named
+ (CamelNameValueArray *array,
+ gboolean case_sensitive,
+ const gchar *name,
+ gboolean all_occurrences);
+void camel_name_value_array_clear (CamelNameValueArray *array);
+
+/**
+ * CamelNamedFlags:
+ *
+ * Since: 3.24
+ **/
+struct _CamelNamedFlags;
+typedef struct _CamelNamedFlags CamelNamedFlags;
+
+#define CAMEL_TYPE_NAMED_FLAGS (camel_named_flags_get_type ())
+
+GType camel_named_flags_get_type (void) G_GNUC_CONST;
+CamelNamedFlags *
+ camel_named_flags_new (void);
+CamelNamedFlags *
+ camel_named_flags_new_sized (guint reserve_size);
+CamelNamedFlags *
+ camel_named_flags_copy (const CamelNamedFlags *named_flags);
+void camel_named_flags_free (CamelNamedFlags *named_flags);
+gboolean camel_named_flags_insert (CamelNamedFlags *named_flags,
+ const gchar *name);
+gboolean camel_named_flags_remove (CamelNamedFlags *named_flags,
+ const gchar *name);
+gboolean camel_named_flags_contains (CamelNamedFlags *named_flags,
+ const gchar *name);
+void camel_named_flags_clear (CamelNamedFlags *named_flags);
+guint camel_named_flags_length (const CamelNamedFlags *named_flags);
+const gchar * camel_named_flags_get (const CamelNamedFlags *named_flags,
+ guint index);
typedef struct _camel_header_param {
struct _camel_header_param *next;
diff --git a/camel/camel.h b/camel/camel.h
index 1c6eead..4e6f621 100644
--- a/camel/camel.h
+++ b/camel/camel.h
@@ -57,7 +57,7 @@
#include <camel/camel-memchunk.h>
#include <camel/camel-mempool.h>
#include <camel/camel-message-info.h>
-#include <camel/camel-message-content-info.h>
+#include <camel/camel-message-info-base.h>
#include <camel/camel-mime-filter.h>
#include <camel/camel-mime-filter-basic.h>
#include <camel/camel-mime-filter-bestenc.h>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]