/* -*- 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 . */ #include "evolution-data-server-config.h" #include #include #include "camel-db.h" #include "camel-enumtypes.h" #include "camel-folder.h" #include "camel-folder-summary.h" #include "camel-message-info-base.h" #include "camel-string-utils.h" #include "camel-weak-ref-group.h" #include "camel-message-info.h" struct _CamelMessageInfoPrivate { GRecMutex property_lock; CamelWeakRefGroup *summary_wrg; /* CamelFolderSummary * */ gboolean dirty; /* whether requires save to local disk/summary */ const gchar *uid; /* allocated in the string pool */ gboolean abort_notifications; gboolean thaw_notify_folder; gboolean thaw_notify_folder_with_counts; guint freeze_notifications; guint folder_flagged_stamp; }; enum { PROP_0, PROP_SUMMARY, PROP_DIRTY, PROP_FOLDER_FLAGGED, PROP_FOLDER_FLAGGED_STAMP, PROP_ABORT_NOTIFICATIONS, PROP_UID, PROP_FLAGS, PROP_USER_FLAGS, PROP_USER_TAGS, PROP_SUBJECT, PROP_FROM, PROP_TO, PROP_CC, PROP_MLIST, PROP_SIZE, PROP_DATE_SENT, PROP_DATE_RECEIVED, PROP_MESSAGE_ID, PROP_REFERENCES, PROP_HEADERS, PROP_USER_HEADERS, PROP_PREVIEW }; G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (CamelMessageInfo, camel_message_info, G_TYPE_OBJECT) static CamelMessageInfo * message_info_clone (const CamelMessageInfo *mi, CamelFolderSummary *assign_summary) { CamelMessageInfo *result; const gchar *uid; const GArray *references; const CamelNameValueArray *headers; g_return_val_if_fail (CAMEL_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. */ camel_message_info_property_lock (mi); if (!assign_summary) { CamelFolderSummary *mi_summary; mi_summary = camel_message_info_ref_summary (mi); result = camel_message_info_new (mi_summary); g_clear_object (&mi_summary); } else { result = camel_message_info_new (assign_summary); } g_object_freeze_notify (G_OBJECT (result)); camel_message_info_set_abort_notifications (result, TRUE); uid = camel_message_info_pooldup_uid (mi); camel_message_info_set_uid (result, uid); camel_pstring_free (uid); camel_message_info_take_user_flags (result, camel_message_info_dup_user_flags (mi)); camel_message_info_take_user_tags (result, camel_message_info_dup_user_tags (mi)); camel_message_info_set_subject (result, camel_message_info_get_subject (mi)); camel_message_info_set_from (result, camel_message_info_get_from (mi)); camel_message_info_set_to (result, camel_message_info_get_to (mi)); camel_message_info_set_cc (result, camel_message_info_get_cc (mi)); camel_message_info_set_mlist (result, camel_message_info_get_mlist (mi)); camel_message_info_set_preview (result, camel_message_info_get_preview (mi)); camel_message_info_set_size (result, camel_message_info_get_size (mi)); camel_message_info_set_date_sent (result, camel_message_info_get_date_sent (mi)); camel_message_info_set_date_received (result, camel_message_info_get_date_received (mi)); camel_message_info_set_message_id (result, camel_message_info_get_message_id (mi)); references = camel_message_info_get_references (mi); if (references && references->len) { GArray *copy; guint ii; copy = g_array_sized_new (FALSE, FALSE, sizeof (guint64), references->len); for (ii = 0; ii < references->len; ii++) { guint64 refr = g_array_index (references, guint64, ii); g_array_append_val (copy, refr); } camel_message_info_take_references (result, copy); } headers = camel_message_info_get_headers (mi); if (headers) { camel_message_info_take_headers (result, camel_name_value_array_copy (headers)); } headers = camel_message_info_get_user_headers (mi); if (headers) { camel_message_info_take_user_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. */ camel_message_info_set_flags (result, ~0, camel_message_info_get_flags (mi)); camel_message_info_property_unlock (mi); /* Also ensure 'dirty' flag, thus it can be eventually saved. */ camel_message_info_set_dirty (result, TRUE); camel_message_info_set_abort_notifications (result, FALSE); g_object_thaw_notify (G_OBJECT (result)); return result; } static gboolean message_info_load (CamelMessageInfo *mi, const CamelMIRecord *record, /* const */ gchar **bdata_ptr) { gint ii, count; gchar *part, *label; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); g_return_val_if_fail (record != NULL, FALSE); g_return_val_if_fail (bdata_ptr != NULL, FALSE); camel_message_info_set_uid (mi, record->uid); camel_message_info_set_flags (mi, ~0, record->flags); camel_message_info_set_size (mi, record->size); camel_message_info_set_date_sent (mi, record->dsent); camel_message_info_set_date_received (mi, record->dreceived); camel_message_info_set_subject (mi, record->subject); camel_message_info_set_from (mi, record->from); camel_message_info_set_to (mi, record->to); camel_message_info_set_cc (mi, record->cc); camel_message_info_set_mlist (mi, record->mlist); camel_message_info_set_preview (mi, record->preview); /* Extract Message id & References */ part = record->part; if (part) { CamelSummaryMessageID message_id; message_id.id.part.hi = camel_util_bdata_get_number (&part, 0); message_id.id.part.lo = camel_util_bdata_get_number (&part, 0); camel_message_info_set_message_id (mi, message_id.id.id); count = camel_util_bdata_get_number (&part, 0); if (count > 0) { GArray *references = g_array_sized_new (FALSE, FALSE, sizeof (guint64), count); for (ii = 0; ii < count; ii++) { message_id.id.part.hi = camel_util_bdata_get_number (&part, 0); message_id.id.part.lo = camel_util_bdata_get_number (&part, 0); g_array_append_val (references, message_id.id.id); } camel_message_info_take_references (mi, references); } } /* Extract User flags/labels */ part = record->labels; if (part) { CamelNamedFlags *user_flags; user_flags = camel_named_flags_new (); label = part; for (ii = 0; part[ii]; ii++) { if (part[ii] == ' ') { part[ii] = 0; if (label && *label) camel_named_flags_insert (user_flags, label); label = &(part[ii + 1]); part[ii] = ' '; } } if (label && *label) camel_named_flags_insert (user_flags, label); if (camel_named_flags_get_length (user_flags) == 0) { camel_named_flags_free (user_flags); user_flags = NULL; } camel_message_info_take_user_flags (mi, user_flags); } /* Extract User tags */ part = record->usertags; if (part) { CamelNameValueArray *user_tags; count = camel_util_bdata_get_number (&part, 0); user_tags = camel_name_value_array_new_sized (count); for (ii = 0; ii < count; ii++) { gchar *name, *value; name = camel_util_bdata_get_string (&part, NULL); value = camel_util_bdata_get_string (&part, NULL); if (name) camel_name_value_array_set_named (user_tags, CAMEL_COMPARE_CASE_SENSITIVE, name, value ? value : ""); g_free (name); g_free (value); } if (camel_name_value_array_get_length (user_tags) == 0) { camel_name_value_array_free (user_tags); user_tags = NULL; } camel_message_info_take_user_tags (mi, user_tags); } /* Extract User headers */ part = record->userheaders; if (part) { CamelNameValueArray *user_headers; count = camel_util_bdata_get_number (&part, 0); user_headers = camel_name_value_array_new_sized (count); for (ii = 0; ii < count; ii++) { gchar *name, *value; name = camel_util_bdata_get_string (&part, NULL); value = camel_util_bdata_get_string (&part, NULL); if (name) camel_name_value_array_set_named (user_headers, CAMEL_COMPARE_CASE_SENSITIVE, name, value ? value : ""); g_free (name); g_free (value); } if (camel_name_value_array_get_length (user_headers) == 0) { camel_name_value_array_free (user_headers); user_headers = NULL; } camel_message_info_take_user_headers (mi, user_headers); } return TRUE; } static gboolean message_info_save (const CamelMessageInfo *mi, CamelMIRecord *record, GString *bdata_str) { GString *tmp; CamelSummaryMessageID message_id; const CamelNamedFlags *user_flags; const CamelNameValueArray *user_tags; const GArray *references; guint32 read_or_flags = CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_JUNK; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); g_return_val_if_fail (record != NULL, FALSE); g_return_val_if_fail (bdata_str != NULL, FALSE); record->uid = camel_pstring_strdup (camel_message_info_get_uid (mi)); record->flags = camel_message_info_get_flags (mi); if ((record->flags & CAMEL_MESSAGE_JUNK) != 0) { CamelFolderSummary *folder_summary; folder_summary = camel_message_info_ref_summary (mi); if (folder_summary) { CamelFolder *folder; folder = camel_folder_summary_get_folder (folder_summary); if (folder) { guint32 folder_flags = camel_folder_get_flags (folder); /* Do not consider Junk flag as message being read when it's a Junk folder */ if ((folder_flags & CAMEL_FOLDER_IS_JUNK) != 0) read_or_flags = read_or_flags & (~CAMEL_MESSAGE_JUNK); } g_object_unref (folder_summary); } } record->read = ((record->flags & (CAMEL_MESSAGE_SEEN | read_or_flags))) ? 1 : 0; record->deleted = (record->flags & CAMEL_MESSAGE_DELETED) != 0 ? 1 : 0; record->replied = (record->flags & CAMEL_MESSAGE_ANSWERED) != 0 ? 1 : 0; record->important = (record->flags & CAMEL_MESSAGE_FLAGGED) != 0 ? 1 : 0; record->junk = (record->flags & CAMEL_MESSAGE_JUNK) != 0 ? 1 : 0; record->dirty = (record->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0 ? 1 : 0; record->attachment = (record->flags & CAMEL_MESSAGE_ATTACHMENTS) != 0 ? 1 : 0; record->size = camel_message_info_get_size (mi); record->dsent = camel_message_info_get_date_sent (mi); record->dreceived = camel_message_info_get_date_received (mi); record->subject = camel_pstring_strdup (camel_message_info_get_subject (mi)); record->from = camel_pstring_strdup (camel_message_info_get_from (mi)); record->to = camel_pstring_strdup (camel_message_info_get_to (mi)); record->cc = camel_pstring_strdup (camel_message_info_get_cc (mi)); record->mlist = camel_pstring_strdup (camel_message_info_get_mlist (mi)); record->preview = g_strdup (camel_message_info_get_preview (mi)); record->followup_flag = g_strdup (camel_message_info_get_user_tag (mi, "follow-up")); record->followup_completed_on = g_strdup (camel_message_info_get_user_tag (mi, "completed-on")); record->followup_due_by = g_strdup (camel_message_info_get_user_tag (mi, "due-by")); tmp = g_string_new (NULL); message_id.id.id = camel_message_info_get_message_id (mi); g_string_append_printf (tmp, "%lu %lu ", (gulong) message_id.id.part.hi, (gulong) message_id.id.part.lo); references = camel_message_info_get_references (mi); if (references) { guint ii; g_string_append_printf (tmp, "%lu", (gulong) references->len); for (ii = 0; ii < references->len; ii++) { message_id.id.id = g_array_index (references, guint64, ii); g_string_append_printf (tmp, " %lu %lu", (gulong) message_id.id.part.hi, (gulong) message_id.id.part.lo); } } else { g_string_append_c (tmp, '0'); } record->part = g_string_free (tmp, FALSE); tmp = g_string_new (NULL); user_flags = camel_message_info_get_user_flags (mi); if (user_flags) { guint ii, count; count = camel_named_flags_get_length (user_flags); for (ii = 0; ii < count; ii++) { const gchar *name = camel_named_flags_get (user_flags, ii); if (name && *name) { if (tmp->len) g_string_append_c (tmp, ' '); g_string_append (tmp, name); } } } record->labels = g_string_free (tmp, FALSE); tmp = g_string_new (NULL); user_tags = camel_message_info_get_user_tags (mi); if (user_tags) { guint ii, count; count = camel_name_value_array_get_length (user_tags); g_string_append_printf (tmp, "%lu", (gulong) count); for (ii = 0; ii < count; ii++) { const gchar *name = NULL, *value = NULL; if (camel_name_value_array_get (user_tags, ii, &name, &value)) { if (!name) name = ""; if (!value) value = ""; g_string_append_printf (tmp, " %lu-%s %lu-%s", (gulong) strlen (name), name, (gulong) strlen (value), value); } } } else { g_string_append_c (tmp, '0'); } record->usertags = g_string_free (tmp, FALSE); tmp = g_string_new (NULL); user_tags = camel_message_info_get_user_headers (mi); if (user_tags) { guint32 ii, count; count = camel_name_value_array_get_length (user_tags); g_string_append_printf (tmp, "%" G_GUINT32_FORMAT, count); for (ii = 0; ii < count; ii++) { const gchar *name = NULL, *value = NULL; if (camel_name_value_array_get (user_tags, ii, &name, &value) && name && value) { g_string_append_printf (tmp, " %" G_GUINT32_FORMAT "-%s %" G_GUINT32_FORMAT "-%s", (guint32) strlen (name), name, (guint32) strlen (value), value); } } } else { g_string_append_c (tmp, '0'); } record->userheaders = g_string_free (tmp, FALSE); return TRUE; } static void message_info_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { CamelMessageInfo *mi = CAMEL_MESSAGE_INFO (object); switch (property_id) { case PROP_SUMMARY: camel_weak_ref_group_set (mi->priv->summary_wrg, g_value_get_object (value)); return; case PROP_DIRTY: camel_message_info_set_dirty (mi, g_value_get_boolean (value)); return; case PROP_FOLDER_FLAGGED: camel_message_info_set_folder_flagged (mi, g_value_get_boolean (value)); return; case PROP_ABORT_NOTIFICATIONS: camel_message_info_set_abort_notifications (mi, g_value_get_boolean (value)); return; case PROP_UID: camel_message_info_set_uid (mi, g_value_get_string (value)); return; case PROP_FLAGS: camel_message_info_set_flags (mi, ~0, g_value_get_flags (value)); return; case PROP_USER_FLAGS: camel_message_info_take_user_flags (mi, g_value_dup_boxed (value)); return; case PROP_USER_TAGS: camel_message_info_take_user_tags (mi, g_value_dup_boxed (value)); return; case PROP_SUBJECT: camel_message_info_set_subject (mi, g_value_get_string (value)); return; case PROP_FROM: camel_message_info_set_from (mi, g_value_get_string (value)); return; case PROP_TO: camel_message_info_set_to (mi, g_value_get_string (value)); return; case PROP_CC: camel_message_info_set_cc (mi, g_value_get_string (value)); return; case PROP_MLIST: camel_message_info_set_mlist (mi, g_value_get_string (value)); return; case PROP_SIZE: camel_message_info_set_size (mi, g_value_get_uint (value)); return; case PROP_DATE_SENT: camel_message_info_set_date_sent (mi, g_value_get_int64 (value)); return; case PROP_DATE_RECEIVED: camel_message_info_set_date_received (mi, g_value_get_int64 (value)); return; case PROP_MESSAGE_ID: camel_message_info_set_message_id (mi, g_value_get_uint64 (value)); return; case PROP_REFERENCES: camel_message_info_take_references (mi, g_value_dup_boxed (value)); return; case PROP_HEADERS: camel_message_info_take_headers (mi, g_value_dup_boxed (value)); return; case PROP_USER_HEADERS: camel_message_info_take_user_headers (mi, g_value_dup_boxed (value)); return; case PROP_PREVIEW: camel_message_info_set_preview (mi, g_value_get_string (value)); return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } static void message_info_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { CamelMessageInfo *mi = CAMEL_MESSAGE_INFO (object); switch (property_id) { case PROP_SUMMARY: g_value_take_object (value, camel_message_info_ref_summary (mi)); return; case PROP_DIRTY: g_value_set_boolean (value, camel_message_info_get_dirty (mi)); return; case PROP_FOLDER_FLAGGED: g_value_set_boolean (value, camel_message_info_get_folder_flagged (mi)); return; case PROP_FOLDER_FLAGGED_STAMP: g_value_set_uint (value, camel_message_info_get_folder_flagged_stamp (mi)); return; case PROP_ABORT_NOTIFICATIONS: g_value_set_boolean (value, camel_message_info_get_abort_notifications (mi)); return; case PROP_UID: g_value_set_string (value, camel_message_info_get_uid (mi)); return; case PROP_FLAGS: g_value_set_flags (value, camel_message_info_get_flags (mi)); return; case PROP_USER_FLAGS: g_value_take_boxed (value, camel_message_info_dup_user_flags (mi)); return; case PROP_USER_TAGS: g_value_take_boxed (value, camel_message_info_dup_user_tags (mi)); return; case PROP_SUBJECT: g_value_set_string (value, camel_message_info_get_subject (mi)); return; case PROP_FROM: g_value_set_string (value, camel_message_info_get_from (mi)); return; case PROP_TO: g_value_set_string (value, camel_message_info_get_to (mi)); return; case PROP_CC: g_value_set_string (value, camel_message_info_get_cc (mi)); return; case PROP_MLIST: g_value_set_string (value, camel_message_info_get_mlist (mi)); return; case PROP_SIZE: g_value_set_uint (value, camel_message_info_get_size (mi)); return; case PROP_DATE_SENT: g_value_set_int64 (value, camel_message_info_get_date_sent (mi)); return; case PROP_DATE_RECEIVED: g_value_set_int64 (value, camel_message_info_get_date_received (mi)); return; case PROP_MESSAGE_ID: g_value_set_uint64 (value, camel_message_info_get_message_id (mi)); return; case PROP_REFERENCES: g_value_take_boxed (value, camel_message_info_dup_references (mi)); return; case PROP_HEADERS: g_value_take_boxed (value, camel_message_info_dup_headers (mi)); return; case PROP_USER_HEADERS: g_value_take_boxed (value, camel_message_info_dup_user_headers (mi)); return; case PROP_PREVIEW: g_value_take_string (value, camel_message_info_dup_preview (mi)); return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } static void message_info_dispose (GObject *object) { CamelMessageInfo *mi = CAMEL_MESSAGE_INFO (object); camel_weak_ref_group_set (mi->priv->summary_wrg, NULL); camel_pstring_free (mi->priv->uid); mi->priv->uid = NULL; /* Chain up to parent's method. */ G_OBJECT_CLASS (camel_message_info_parent_class)->dispose (object); } static void message_info_finalize (GObject *object) { CamelMessageInfo *mi = CAMEL_MESSAGE_INFO (object); camel_weak_ref_group_unref (mi->priv->summary_wrg); g_rec_mutex_clear (&mi->priv->property_lock); /* Chain up to parent's method. */ G_OBJECT_CLASS (camel_message_info_parent_class)->finalize (object); } static void camel_message_info_class_init (CamelMessageInfoClass *class) { GObjectClass *object_class; class->clone = message_info_clone; class->load = message_info_load; class->save = message_info_save; object_class = G_OBJECT_CLASS (class); object_class->set_property = message_info_set_property; object_class->get_property = message_info_get_property; object_class->dispose = message_info_dispose; object_class->finalize = message_info_finalize; /** * CamelMessageInfo: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, PROP_SUMMARY, g_param_spec_object ( "summary", "Summary", NULL, CAMEL_TYPE_FOLDER_SUMMARY, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); /** * CamelMessageInfo: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 | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); /** * CamelMessageInfo: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 | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); /** * CamelMessageInfo: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 | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); /** * CamelMessageInfo:folder-flagged-stamp * * The 'folder-flagged-stamp' is a stamp of the 'folder-flagged' flag. This stamp * changes whenever anything would mark the @mi 'folder-flagged', regardless the @mi * being already 'folder-flagged'. It can be used to recognize changes * on the 'folder-flagged' flag during the time. * * Since: 3.24 **/ g_object_class_install_property ( object_class, PROP_FOLDER_FLAGGED_STAMP, g_param_spec_uint ( "folder-flagged-stamp", "Folder Flagged Stamp", NULL, 0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /** * CamelMessageInfo:abort-notifications * * Flag, whether the info is currently aborting notifications. It is used to avoid * unnecessary 'folder-flagged' and 'dirty' flags changes and also to avoid * associated folder's "changed" signal. *f * Since: 3.24 **/ g_object_class_install_property ( object_class, PROP_ABORT_NOTIFICATIONS, g_param_spec_boolean ( "abort-notifications", "Abort Notifications", NULL, FALSE, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); /** * CamelMessageInfo:flags * * Bit-or of #CamelMessageFlags. * * Since: 3.24 **/ g_object_class_install_property ( object_class, PROP_FLAGS, g_param_spec_flags ( "flags", "Flags", NULL, CAMEL_TYPE_MESSAGE_FLAGS, 0, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); /** * CamelMessageInfo: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 | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); /** * CamelMessageInfo: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 | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); /** * CamelMessageInfo: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 | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); /** * CamelMessageInfo: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 | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); /** * CamelMessageInfo: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 | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); /** * CamelMessageInfo: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 | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); /** * CamelMessageInfo: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 | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); /** * CamelMessageInfo: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 | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); /** * CamelMessageInfo: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 | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); /** * CamelMessageInfo: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 | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); /** * CamelMessageInfo: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 | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); /** * CamelMessageInfo: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 | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); /** * CamelMessageInfo: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 | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); /** * CamelMessageInfo:user-headers * * User-defined headers of the associated message. Can be %NULL. * * Since: 3.42 **/ g_object_class_install_property ( object_class, PROP_USER_HEADERS, g_param_spec_boxed ( "user-headers", "User Headers", NULL, CAMEL_TYPE_NAME_VALUE_ARRAY, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); /** * CamelMessageInfo:preview * * Body preview of the associated message. Can be %NULL. * * Since: 3.42 **/ g_object_class_install_property ( object_class, PROP_PREVIEW, g_param_spec_string ( "preview", "Preview", NULL, NULL, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); } static void camel_message_info_init (CamelMessageInfo *mi) { mi->priv = camel_message_info_get_instance_private (mi); mi->priv->summary_wrg = camel_weak_ref_group_new (); g_rec_mutex_init (&mi->priv->property_lock); } /* Private function */ void _camel_message_info_unset_summary (CamelMessageInfo *mi); void _camel_message_info_unset_summary (CamelMessageInfo *mi) { g_return_if_fail (CAMEL_IS_MESSAGE_INFO (mi)); camel_weak_ref_group_set (mi->priv->summary_wrg, NULL); } /** * camel_message_info_new: * @summary: (nullable) (type CamelFolderSummary): parent #CamelFolderSummary object, or %NULL * * Create a new #CamelMessageInfo object, optionally for given @summary. * * Returns: (transfer full): a new #CamelMessageInfo object * * Since: 3.24 **/ CamelMessageInfo * camel_message_info_new (CamelFolderSummary *summary) { GType type = CAMEL_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); } /** * camel_message_info_clone: * @mi: a #CamelMessageInfo to clone * @assign_summary: (nullable) (type CamelFolderSummary): 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 same * summary as the one with @mi is used. * * Returns: (transfer full): a new #CamelMessageInfo object, clone of the @mi * * Since: 3.24 **/ CamelMessageInfo * camel_message_info_clone (const CamelMessageInfo *mi, CamelFolderSummary *assign_summary) { CamelMessageInfoClass *klass; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL); if (assign_summary) g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (assign_summary), NULL); klass = CAMEL_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); } /** * camel_message_info_load: * @mi: a #CamelMessageInfo to load * @record: (type CamelMIRecord): a #CamelMIRecord to load the @mi from * @bdata_ptr: a backend specific data (bdata) pointer * * Load content of @mi from the data stored in @record. The @bdata_ptr points * to the current position of the record->bdata, where the read can continue. * Use helper functions camel_util_bdata_get_number() and camel_util_bdata_get_string() * to read data from it and also move forward the *bdata_ptr. * * After successful load of the @mi, the 'dirty' flag is unset. * * Returns: Whether the load was successful. * * Since: 3.24 **/ gboolean camel_message_info_load (CamelMessageInfo *mi, const CamelMIRecord *record, /* const */ gchar **bdata_ptr) { CamelMessageInfoClass *klass; gboolean success; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); g_return_val_if_fail (record != NULL, FALSE); g_return_val_if_fail (bdata_ptr != NULL, FALSE); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, FALSE); g_return_val_if_fail (klass->load != NULL, FALSE); g_object_freeze_notify (G_OBJECT (mi)); camel_message_info_property_lock (mi); camel_message_info_set_abort_notifications (mi, TRUE); success = klass->load (mi, record, bdata_ptr); if (success) camel_message_info_set_dirty (mi, FALSE); camel_message_info_set_abort_notifications (mi, FALSE); camel_message_info_property_unlock (mi); g_object_thaw_notify (G_OBJECT (mi)); return success; } /** * camel_message_info_save: * @mi: a #CamelMessageInfo * @record: (type CamelMIRecord): a #CamelMIRecord to populate * @bdata_str: a #GString with a string to save as backend specific data (bdata) * * Save the @mi content to the message info record @record. It can populate all * but the record->bdata value, which is set fro mthe @bdata_str. Use helper functions * camel_util_bdata_put_number() and camel_util_bdata_put_string() to put data into the @bdata_str. * * Returns: Whether the save succeeded. * * Since: 3.24 **/ gboolean camel_message_info_save (const CamelMessageInfo *mi, CamelMIRecord *record, GString *bdata_str) { CamelMessageInfoClass *klass; gboolean success; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); g_return_val_if_fail (record != NULL, FALSE); g_return_val_if_fail (bdata_str != NULL, FALSE); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, FALSE); g_return_val_if_fail (klass->save != NULL, FALSE); camel_message_info_property_lock (mi); success = klass->save (mi, record, bdata_str); camel_message_info_property_unlock (mi); return success; } /** * camel_message_info_ref_summary: * @mi: a #CamelMessageInfo * * Returns: (transfer full): Referenced #CamelFolderSummary to which the @mi belongs, or %NULL, * if there is none. Use g_object_unref() for non-NULL returned values when done with it. * * Since: 3.24 **/ CamelFolderSummary * camel_message_info_ref_summary (const CamelMessageInfo *mi) { g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL); return camel_weak_ref_group_get (mi->priv->summary_wrg); } /** * camel_message_info_property_lock: * @mi: a #CamelMessageInfo * * Acquires a property lock, which is used to ensure thread safety * when properties are changing. Release the lock with * camel_message_info_property_unlock(). * * Note: Make sure the CamelFolderSummary lock is held before this lock, * if there will be called any 'set' function on the @mi, to avoid deadlock * when the summary would be set as dirty while another thread might try * to read values from the @mi, waiting for the property lock and holding * the summary lock at the same time. * * Since: 3.24 **/ void camel_message_info_property_lock (const CamelMessageInfo *mi) { g_return_if_fail (CAMEL_IS_MESSAGE_INFO (mi)); g_rec_mutex_lock (&mi->priv->property_lock); } /** * camel_message_info_property_unlock: * @mi: a #CamelMessageInfo * * Releases a property lock, previously acquired with * camel_message_info_property_lock(). * * Since: 3.24 **/ void camel_message_info_property_unlock (const CamelMessageInfo *mi) { g_return_if_fail (CAMEL_IS_MESSAGE_INFO (mi)); g_rec_mutex_unlock (&mi->priv->property_lock); } static void camel_message_info_update_summary_and_folder (CamelMessageInfo *mi, gboolean update_counts) { CamelFolderSummary *summary; g_return_if_fail (CAMEL_IS_MESSAGE_INFO (mi)); camel_message_info_property_lock (mi); if (camel_message_info_get_notifications_frozen (mi)) { mi->priv->thaw_notify_folder = TRUE; mi->priv->thaw_notify_folder_with_counts |= update_counts; camel_message_info_property_unlock (mi); return; } camel_message_info_property_unlock (mi); summary = camel_message_info_ref_summary (mi); if (summary) { CamelFolder *folder; CamelMessageInfo *in_summary_mi = NULL; const gchar *uid; uid = camel_message_info_pooldup_uid (mi); /* This is for cases when a new message info had been created, but not added into the summary yet. */ if (uid && camel_folder_summary_check_uid (summary, uid) && (in_summary_mi = camel_folder_summary_peek_loaded (summary, uid)) == mi) { 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) { 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); } } g_clear_object (&in_summary_mi); g_clear_object (&summary); camel_pstring_free (uid); } } /** * camel_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 camel_message_info_get_dirty (const CamelMessageInfo *mi) { gboolean result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); camel_message_info_property_lock (mi); result = mi->priv->dirty; camel_message_info_property_unlock (mi); return result; } /** * camel_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 camel_message_info_set_dirty (CamelMessageInfo *mi, gboolean dirty) { gboolean changed, abort_notifications; g_return_if_fail (CAMEL_IS_MESSAGE_INFO (mi)); camel_message_info_property_lock (mi); changed = (!mi->priv->dirty) != (!dirty); if (changed) mi->priv->dirty = dirty; abort_notifications = mi->priv->abort_notifications; camel_message_info_property_unlock (mi); if (changed && !abort_notifications) { g_object_notify (G_OBJECT (mi), "dirty"); if (dirty) { CamelFolderSummary *summary; summary = camel_message_info_ref_summary (mi); if (summary) camel_folder_summary_touch (summary); g_clear_object (&summary); } } } /** * camel_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 camel_message_info_get_folder_flagged (const CamelMessageInfo *mi) { g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); return (camel_message_info_get_flags (mi) & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0; } /** * camel_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 * camel_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 camel_message_info_set_folder_flagged (CamelMessageInfo *mi, gboolean folder_flagged) { g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); /* g_object_notify (G_OBJECT (mi), "folder-flagged"); is called as part of the set_flags function */ return camel_message_info_set_flags (mi, CAMEL_MESSAGE_FOLDER_FLAGGED, folder_flagged ? CAMEL_MESSAGE_FOLDER_FLAGGED : 0); } /** * camel_message_info_get_folder_flagged_stamp: * @mi: a #CamelMessageInfo * * The 'folder-flagged-stamp' is a stamp of the 'folder-flagged' flag. This stamp * changes whenever anything would mark the @mi as 'folder-flagged', regardless * the @mi being already 'folder-flagged'. It can be used to recognize changes * on the 'folder-flagged' flag during the time. * * Returns: Stamp of the 'folder-flagged' flag. * * Since: 3.24 **/ guint camel_message_info_get_folder_flagged_stamp (const CamelMessageInfo *mi) { guint result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), ~0); camel_message_info_property_lock (mi); result = mi->priv->folder_flagged_stamp; camel_message_info_property_unlock (mi); return result; } /** * camel_message_info_get_abort_notifications: * @mi: a #CamelMessageInfo * * Returns: Whether the @mi is aborting notifications, which means * that it will not influence 'dirty' and 'folder-flagged' flags * in the set/take functions, neither it will emit any GObject::notify * signals on change, nor associated folder's "changed" signal. * * Since: 3.24 **/ gboolean camel_message_info_get_abort_notifications (const CamelMessageInfo *mi) { gboolean result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); camel_message_info_property_lock (mi); result = mi->priv->abort_notifications; camel_message_info_property_unlock (mi); return result; } /** * camel_message_info_set_abort_notifications: * @mi: a #CamelMessageInfo * @abort_notifications: a state to set * * Marks the @mi to abort any notifications, which means that it * will not influence 'dirty' and 'folder-flagged' flags in * the set/take functions, neither it will emit any GObject::notify * signals on change, nor associated folder's "changed" signal. * * Since: 3.24 **/ void camel_message_info_set_abort_notifications (CamelMessageInfo *mi, gboolean abort_notifications) { gboolean changed; g_return_if_fail (CAMEL_IS_MESSAGE_INFO (mi)); camel_message_info_property_lock (mi); changed = (!mi->priv->abort_notifications) != (!abort_notifications); if (changed) mi->priv->abort_notifications = abort_notifications; camel_message_info_property_unlock (mi); if (changed) g_object_notify (G_OBJECT (mi), "abort-notifications"); } /** * camel_message_info_freeze_notifications: * @mi: a #CamelMessageInfo * * Freezes all the notifications until the camel_message_info_thaw_notifications() is called. * This function can be called multiple times, where the last thaw will do the notifications. * * Since: 3.24 **/ void camel_message_info_freeze_notifications (CamelMessageInfo *mi) { g_return_if_fail (CAMEL_IS_MESSAGE_INFO (mi)); camel_message_info_property_lock (mi); mi->priv->freeze_notifications++; if (mi->priv->freeze_notifications == 1) { mi->priv->thaw_notify_folder = FALSE; mi->priv->thaw_notify_folder_with_counts = FALSE; g_object_freeze_notify (G_OBJECT (mi)); } camel_message_info_property_unlock (mi); } /** * camel_message_info_thaw_notifications: * @mi: a #CamelMessageInfo * * Reverses the call of the camel_message_info_freeze_notifications(). * If this is the last freeze, then the associated folder is also notified * about the change, if any happened during the freeze. * * Since: 3.24 **/ void camel_message_info_thaw_notifications (CamelMessageInfo *mi) { g_return_if_fail (CAMEL_IS_MESSAGE_INFO (mi)); camel_message_info_property_lock (mi); if (!mi->priv->freeze_notifications) { camel_message_info_property_unlock (mi); g_warn_if_reached (); return; } mi->priv->freeze_notifications--; if (!mi->priv->freeze_notifications) { gboolean notify_folder, notify_folder_with_counts; notify_folder = mi->priv->thaw_notify_folder; notify_folder_with_counts = mi->priv->thaw_notify_folder_with_counts; camel_message_info_property_unlock (mi); g_object_thaw_notify (G_OBJECT (mi)); if (notify_folder) camel_message_info_update_summary_and_folder (mi, notify_folder_with_counts); } else { camel_message_info_property_unlock (mi); } } /** * camel_message_info_get_notifications_frozen: * @mi: a #CamelMessageInfo * * Returns: Whether the notifications are frozen. * * See: camel_message_info_freeze_notifications() * * Since: 3.24 **/ gboolean camel_message_info_get_notifications_frozen (const CamelMessageInfo *mi) { gboolean result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); camel_message_info_property_lock (mi); result = mi->priv->freeze_notifications > 0; camel_message_info_property_unlock (mi); return result; } /** * camel_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 * camel_message_info_get_uid (const CamelMessageInfo *mi) { const gchar *result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL); camel_message_info_property_lock (mi); result = mi->priv->uid; camel_message_info_property_unlock (mi); return result; } /** * camel_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 * camel_message_info_pooldup_uid (const CamelMessageInfo *mi) { const gchar *result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL); camel_message_info_property_lock (mi); result = camel_pstring_strdup (mi->priv->uid); camel_message_info_property_unlock (mi); return result; } /** * camel_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, unless the @mi is aborting notifications. This change * does not influence the 'folder-flagged' flag. * * Returns: Whether the UID changed. * * Since: 3.24 **/ gboolean camel_message_info_set_uid (CamelMessageInfo *mi, const gchar *uid) { gboolean changed, abort_notifications; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); camel_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); } abort_notifications = mi->priv->abort_notifications; camel_message_info_property_unlock (mi); if (changed && !abort_notifications) { g_object_notify (G_OBJECT (mi), "uid"); camel_message_info_set_dirty (mi, TRUE); } return changed; } /** * camel_message_info_get_flags: * @mi: a #CamelMessageInfo * * Returns: Bit-or of #CamelMessageFlags set on the @mi. * * Since: 3.24 **/ guint32 camel_message_info_get_flags (const CamelMessageInfo *mi) { CamelMessageInfoClass *klass; guint32 result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), 0); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, 0); g_return_val_if_fail (klass->get_flags != NULL, 0); camel_message_info_property_lock (mi); result = klass->get_flags (mi); camel_message_info_property_unlock (mi); return result; } /** * camel_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. Both @mask and @set are bit-or * of #CamelMessageFlags. * * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are * set automatically, unless the @mi is aborting notifications. There is also emitted * folder's "changed" signal for this @mi, if necessary. In case * the CAMEL_MESSAGE_FOLDER_FLAGGED flag would be set and the @mi is * not aborting notifications, the 'folder-flagged-stamp' changes too. * * Returns: Whether the flags changed. * * Since: 3.24 **/ gboolean camel_message_info_set_flags (CamelMessageInfo *mi, guint32 mask, guint32 set) { CamelMessageInfoClass *klass; gboolean changed, abort_notifications; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, FALSE); g_return_val_if_fail (klass->set_flags != NULL, FALSE); camel_message_info_property_lock (mi); changed = klass->set_flags (mi, mask, set); abort_notifications = mi->priv->abort_notifications; if (!abort_notifications && (mask & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0 && (set & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0) mi->priv->folder_flagged_stamp++; camel_message_info_property_unlock (mi); if (changed && !abort_notifications) { g_object_notify (G_OBJECT (mi), "flags"); camel_message_info_set_dirty (mi, TRUE); /* Only if the folder-flagged was not part of the change */ if (!(mask & CAMEL_MESSAGE_FOLDER_FLAGGED)) camel_message_info_set_folder_flagged (mi, TRUE); else g_object_notify (G_OBJECT (mi), "folder-flagged"); camel_message_info_update_summary_and_folder (mi, TRUE); } return changed; } /** * camel_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 camel_message_info_get_user_flag (const CamelMessageInfo *mi, const gchar *name) { CamelMessageInfoClass *klass; gboolean result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, FALSE); g_return_val_if_fail (klass->get_user_flag != NULL, FALSE); camel_message_info_property_lock (mi); result = klass->get_user_flag (mi, name); camel_message_info_property_unlock (mi); return result; } /** * camel_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, unless the @mi is aborting notifications. There is also emitted * folder's "changed" signal for this @mi, if necessary. * * Returns: Whether the message info changed. * * Since: 3.24 **/ gboolean camel_message_info_set_user_flag (CamelMessageInfo *mi, const gchar *name, gboolean state) { CamelMessageInfoClass *klass; gboolean changed, abort_notifications; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); g_return_val_if_fail (name != NULL, FALSE); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, FALSE); g_return_val_if_fail (klass->set_user_flag != NULL, FALSE); camel_message_info_property_lock (mi); changed = klass->set_user_flag (mi, name, state); abort_notifications = mi->priv->abort_notifications; camel_message_info_property_unlock (mi); if (changed && !abort_notifications) { g_object_notify (G_OBJECT (mi), "user-flags"); camel_message_info_set_dirty (mi, TRUE); camel_message_info_set_folder_flagged (mi, TRUE); camel_message_info_update_summary_and_folder (mi, FALSE); } return changed; } /** * camel_message_info_get_user_flags: * @mi: a #CamelMessageInfo * * Returns: (transfer none) (nullable): A #CamelNamedFlags with all the currently set * user flags on the @mi. Do not modify it. * * Since: 3.24 **/ const CamelNamedFlags * camel_message_info_get_user_flags (const CamelMessageInfo *mi) { CamelMessageInfoClass *klass; const CamelNamedFlags *result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, NULL); g_return_val_if_fail (klass->get_user_flags != NULL, NULL); camel_message_info_property_lock (mi); result = klass->get_user_flags (mi); camel_message_info_property_unlock (mi); return result; } /** * camel_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 * camel_message_info_dup_user_flags (const CamelMessageInfo *mi) { CamelMessageInfoClass *klass; CamelNamedFlags *result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, NULL); g_return_val_if_fail (klass->dup_user_flags != NULL, NULL); camel_message_info_property_lock (mi); result = klass->dup_user_flags (mi); camel_message_info_property_unlock (mi); return result; } /** * camel_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, unless the @mi is aborting notifications. There is also emitted * folder's "changed" signal for this @mi, if necessary. * * Note that it's not safe to use the @user_flags after the call to this function, * because it can be freed due to no change. * * Returns: Whether the message info changed. * * Since: 3.24 **/ gboolean camel_message_info_take_user_flags (CamelMessageInfo *mi, CamelNamedFlags *user_flags) { CamelMessageInfoClass *klass; gboolean changed, abort_notifications; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, FALSE); g_return_val_if_fail (klass->take_user_flags != NULL, FALSE); camel_message_info_property_lock (mi); changed = klass->take_user_flags (mi, user_flags); abort_notifications = mi->priv->abort_notifications; camel_message_info_property_unlock (mi); if (changed && !abort_notifications) { g_object_notify (G_OBJECT (mi), "user-flags"); camel_message_info_set_dirty (mi, TRUE); camel_message_info_set_folder_flagged (mi, TRUE); camel_message_info_update_summary_and_folder (mi, FALSE); } return changed; } /** * camel_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 * camel_message_info_get_user_tag (const CamelMessageInfo *mi, const gchar *name) { CamelMessageInfoClass *klass; const gchar *result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL); g_return_val_if_fail (name != NULL, NULL); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, NULL); g_return_val_if_fail (klass->get_user_tag != NULL, NULL); camel_message_info_property_lock (mi); result = klass->get_user_tag (mi, name); camel_message_info_property_unlock (mi); return result; } /** * camel_message_info_dup_user_tag: * @mi: a #CamelMessageInfo * @name: user tag name * * 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 * camel_message_info_dup_user_tag (const CamelMessageInfo *mi, const gchar *name) { gchar *result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL); g_return_val_if_fail (name != NULL, NULL); camel_message_info_property_lock (mi); result = g_strdup (camel_message_info_get_user_tag (mi, name)); camel_message_info_property_unlock (mi); return result; } /** * camel_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, unless the @mi is aborting notifications. There is also emitted * folder's "changed" signal for this @mi, if necessary. * * Returns: Whether the @mi changed. * * Since: 3.24 **/ gboolean camel_message_info_set_user_tag (CamelMessageInfo *mi, const gchar *name, const gchar *value) { CamelMessageInfoClass *klass; gboolean changed, abort_notifications; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); g_return_val_if_fail (name != NULL, FALSE); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, FALSE); g_return_val_if_fail (klass->set_user_tag != NULL, FALSE); camel_message_info_property_lock (mi); changed = klass->set_user_tag (mi, name, value); abort_notifications = mi->priv->abort_notifications; camel_message_info_property_unlock (mi); if (changed && !abort_notifications) { g_object_notify (G_OBJECT (mi), "user-tags"); camel_message_info_set_dirty (mi, TRUE); camel_message_info_set_folder_flagged (mi, TRUE); camel_message_info_update_summary_and_folder (mi, FALSE); } return changed; } /** * camel_message_info_get_user_tags: * @mi: a #CamelMessageInfo * * Returns: (transfer none) (nullable): a #CamelNameValueArray containing all set * user tags of the @mi. Do not modify it. * * Since: 3.24 **/ const CamelNameValueArray * camel_message_info_get_user_tags (const CamelMessageInfo *mi) { CamelMessageInfoClass *klass; const CamelNameValueArray *result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, NULL); g_return_val_if_fail (klass->get_user_tags != NULL, NULL); camel_message_info_property_lock (mi); result = klass->get_user_tags (mi); camel_message_info_property_unlock (mi); return result; } /** * camel_message_info_dup_user_tags: * @mi: a #CamelMessageInfo * * Returns: (transfer full) (nullable): 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 * camel_message_info_dup_user_tags (const CamelMessageInfo *mi) { CamelMessageInfoClass *klass; CamelNameValueArray *result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, NULL); g_return_val_if_fail (klass->dup_user_tags != NULL, NULL); camel_message_info_property_lock (mi); result = klass->dup_user_tags (mi); camel_message_info_property_unlock (mi); return result; } /** * camel_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, unless the @mi is aborting notifications. There is also emitted * folder's "changed" signal for this @mi, if necessary. * * Note that it's not safe to use the @user_tags after the call to this function, * because it can be freed due to no change. * * Returns: Whether the @mi changed. * * Since: 3.24 **/ gboolean camel_message_info_take_user_tags (CamelMessageInfo *mi, CamelNameValueArray *user_tags) { CamelMessageInfoClass *klass; gboolean changed, abort_notifications; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, FALSE); g_return_val_if_fail (klass->take_user_tags != NULL, FALSE); camel_message_info_property_lock (mi); changed = klass->take_user_tags (mi, user_tags); abort_notifications = mi->priv->abort_notifications; camel_message_info_property_unlock (mi); if (changed && !abort_notifications) { g_object_notify (G_OBJECT (mi), "user-tags"); camel_message_info_set_dirty (mi, TRUE); camel_message_info_set_folder_flagged (mi, TRUE); camel_message_info_update_summary_and_folder (mi, FALSE); } return changed; } /** * camel_message_info_get_subject: * @mi: a #CamelMessageInfo * * Returns: (transfer none): Subject of the #mi. * * Since: 3.24 **/ const gchar * camel_message_info_get_subject (const CamelMessageInfo *mi) { CamelMessageInfoClass *klass; const gchar *result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, NULL); g_return_val_if_fail (klass->get_subject != NULL, NULL); camel_message_info_property_lock (mi); result = klass->get_subject (mi); camel_message_info_property_unlock (mi); return result; } /** * camel_message_info_set_subject: * @mi: a #CamelMessageInfo * @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, unless the @mi is aborting notifications. There is not emitted * folder's "changed" signal for this @mi. * * Returns: Whether the value changed. * * Since: 3.24 **/ gboolean camel_message_info_set_subject (CamelMessageInfo *mi, const gchar *subject) { CamelMessageInfoClass *klass; gboolean changed, abort_notifications; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, FALSE); g_return_val_if_fail (klass->set_subject != NULL, FALSE); camel_message_info_property_lock (mi); changed = klass->set_subject (mi, subject); abort_notifications = mi->priv->abort_notifications; camel_message_info_property_unlock (mi); if (changed && !abort_notifications) { g_object_notify (G_OBJECT (mi), "subject"); camel_message_info_set_dirty (mi, TRUE); camel_message_info_set_folder_flagged (mi, TRUE); } return changed; } /** * camel_message_info_get_from: * @mi: a #CamelMessageInfo * * Returns: (transfer none): From address of the @mi. * * Since: 3.24 **/ const gchar * camel_message_info_get_from (const CamelMessageInfo *mi) { CamelMessageInfoClass *klass; const gchar *result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, NULL); g_return_val_if_fail (klass->get_from != NULL, NULL); camel_message_info_property_lock (mi); result = klass->get_from (mi); camel_message_info_property_unlock (mi); return result; } /** * camel_message_info_set_from: * @mi: a #CamelMessageInfo * @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, unless the @mi is aborting notifications. There is not emitted * folder's "changed" signal for this @mi. * * Returns: Whether the value changed. * * Since: 3.24 **/ gboolean camel_message_info_set_from (CamelMessageInfo *mi, const gchar *from) { CamelMessageInfoClass *klass; gboolean changed, abort_notifications; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, FALSE); g_return_val_if_fail (klass->set_from != NULL, FALSE); camel_message_info_property_lock (mi); changed = klass->set_from (mi, from); abort_notifications = mi->priv->abort_notifications; camel_message_info_property_unlock (mi); if (changed && !abort_notifications) { g_object_notify (G_OBJECT (mi), "from"); camel_message_info_set_dirty (mi, TRUE); camel_message_info_set_folder_flagged (mi, TRUE); } return changed; } /** * camel_message_info_get_to: * @mi: a #CamelMessageInfo * * Returns: (transfer none): To address of the @mi. * * Since: 3.24 **/ const gchar * camel_message_info_get_to (const CamelMessageInfo *mi) { CamelMessageInfoClass *klass; const gchar *result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, NULL); g_return_val_if_fail (klass->get_to != NULL, NULL); camel_message_info_property_lock (mi); result = klass->get_to (mi); camel_message_info_property_unlock (mi); return result; } /** * camel_message_info_set_to: * @mi: a #CamelMessageInfo * @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, unless the @mi is aborting notifications. There is not emitted * folder's "changed" signal for this @mi. * * Returns: Whether the value changed. * * Since: 3.24 **/ gboolean camel_message_info_set_to (CamelMessageInfo *mi, const gchar *to) { CamelMessageInfoClass *klass; gboolean changed, abort_notifications; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, FALSE); g_return_val_if_fail (klass->set_to != NULL, FALSE); camel_message_info_property_lock (mi); changed = klass->set_to (mi, to); abort_notifications = mi->priv->abort_notifications; camel_message_info_property_unlock (mi); if (changed && !abort_notifications) { g_object_notify (G_OBJECT (mi), "to"); camel_message_info_set_dirty (mi, TRUE); camel_message_info_set_folder_flagged (mi, TRUE); } return changed; } /** * camel_message_info_get_cc: * @mi: a #CamelMessageInfo * * Returns: (transfer none): CC address of the @mi. * * Since: 3.24 **/ const gchar * camel_message_info_get_cc (const CamelMessageInfo *mi) { CamelMessageInfoClass *klass; const gchar *result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, NULL); g_return_val_if_fail (klass->get_cc != NULL, NULL); camel_message_info_property_lock (mi); result = klass->get_cc (mi); camel_message_info_property_unlock (mi); return result; } /** * camel_message_info_set_cc: * @mi: a #CamelMessageInfo * @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, unless the @mi is aborting notifications. There is not emitted * folder's "changed" signal for this @mi. * * Returns: Whether the value changed. * * Since: 3.24 **/ gboolean camel_message_info_set_cc (CamelMessageInfo *mi, const gchar *cc) { CamelMessageInfoClass *klass; gboolean changed, abort_notifications; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, FALSE); g_return_val_if_fail (klass->set_cc != NULL, FALSE); camel_message_info_property_lock (mi); changed = klass->set_cc (mi, cc); abort_notifications = mi->priv->abort_notifications; camel_message_info_property_unlock (mi); if (changed && !abort_notifications) { g_object_notify (G_OBJECT (mi), "cc"); camel_message_info_set_dirty (mi, TRUE); camel_message_info_set_folder_flagged (mi, TRUE); } return changed; } /** * camel_message_info_get_mlist: * @mi: a #CamelMessageInfo * * Returns: (transfer none): Mailing list address of the @mi. * * Since: 3.24 **/ const gchar * camel_message_info_get_mlist (const CamelMessageInfo *mi) { CamelMessageInfoClass *klass; const gchar *result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, NULL); g_return_val_if_fail (klass->get_mlist != NULL, NULL); camel_message_info_property_lock (mi); result = klass->get_mlist (mi); camel_message_info_property_unlock (mi); return result; } /** * camel_message_info_set_mlist: * @mi: a #CamelMessageInfo * @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, unless the @mi is aborting notifications. There is not emitted * folder's "changed" signal for this @mi. * * Returns: Whether the value changed. * * Since: 3.24 **/ gboolean camel_message_info_set_mlist (CamelMessageInfo *mi, const gchar *mlist) { CamelMessageInfoClass *klass; gboolean changed, abort_notifications; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, FALSE); g_return_val_if_fail (klass->set_mlist != NULL, FALSE); camel_message_info_property_lock (mi); changed = klass->set_mlist (mi, mlist); abort_notifications = mi->priv->abort_notifications; camel_message_info_property_unlock (mi); if (changed && !abort_notifications) { g_object_notify (G_OBJECT (mi), "mlist"); camel_message_info_set_dirty (mi, TRUE); camel_message_info_set_folder_flagged (mi, TRUE); } return changed; } /** * camel_message_info_get_size: * @mi: a #CamelMessageInfo * * Returns: Size of the associated message. * * Since: 3.24 **/ guint32 camel_message_info_get_size (const CamelMessageInfo *mi) { CamelMessageInfoClass *klass; guint32 result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), 0); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, 0); g_return_val_if_fail (klass->get_size != NULL, 0); camel_message_info_property_lock (mi); result = klass->get_size (mi); camel_message_info_property_unlock (mi); return result; } /** * camel_message_info_set_size: * @mi: a #CamelMessageInfo * @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, unless the @mi is aborting notifications. There is not emitted * folder's "changed" signal for this @mi. * * Returns: Whether the value changed. * * Since: 3.24 **/ gboolean camel_message_info_set_size (CamelMessageInfo *mi, guint32 size) { CamelMessageInfoClass *klass; gboolean changed, abort_notifications; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, FALSE); g_return_val_if_fail (klass->set_size != NULL, FALSE); camel_message_info_property_lock (mi); changed = klass->set_size (mi, size); abort_notifications = mi->priv->abort_notifications; camel_message_info_property_unlock (mi); if (changed && !abort_notifications) { g_object_notify (G_OBJECT (mi), "size"); camel_message_info_set_dirty (mi, TRUE); camel_message_info_set_folder_flagged (mi, TRUE); } return changed; } /** * camel_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 camel_message_info_get_date_sent (const CamelMessageInfo *mi) { CamelMessageInfoClass *klass; gint64 result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), 0); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, 0); g_return_val_if_fail (klass->get_date_sent != NULL, 0); camel_message_info_property_lock (mi); result = klass->get_date_sent (mi); camel_message_info_property_unlock (mi); return result; } /** * camel_message_info_set_date_sent: * @mi: a #CamelMessageInfo * @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, unless the @mi is aborting notifications. There is not emitted * folder's "changed" signal for this @mi. * * Returns: Whether the value changed. * * Since: 3.24 **/ gboolean camel_message_info_set_date_sent (CamelMessageInfo *mi, gint64 date_sent) { CamelMessageInfoClass *klass; gboolean changed, abort_notifications; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, FALSE); g_return_val_if_fail (klass->set_date_sent != NULL, FALSE); camel_message_info_property_lock (mi); changed = klass->set_date_sent (mi, date_sent); abort_notifications = mi->priv->abort_notifications; camel_message_info_property_unlock (mi); if (changed && !abort_notifications) { g_object_notify (G_OBJECT (mi), "date-sent"); camel_message_info_set_dirty (mi, TRUE); camel_message_info_set_folder_flagged (mi, TRUE); } return changed; } /** * camel_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 camel_message_info_get_date_received (const CamelMessageInfo *mi) { CamelMessageInfoClass *klass; gint64 result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), 0); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, 0); g_return_val_if_fail (klass->get_date_received != NULL, 0); camel_message_info_property_lock (mi); result = klass->get_date_received (mi); camel_message_info_property_unlock (mi); return result; } /** * camel_message_info_set_date_received: * @mi: a #CamelMessageInfo * @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, unless the @mi is aborting notifications. There is not emitted * folder's "changed" signal for this @mi. * * Returns: Whether the value changed. * * Since: 3.24 **/ gboolean camel_message_info_set_date_received (CamelMessageInfo *mi, gint64 date_received) { CamelMessageInfoClass *klass; gboolean changed, abort_notifications; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, FALSE); g_return_val_if_fail (klass->set_date_received != NULL, FALSE); camel_message_info_property_lock (mi); changed = klass->set_date_received (mi, date_received); abort_notifications = mi->priv->abort_notifications; camel_message_info_property_unlock (mi); if (changed && !abort_notifications) { g_object_notify (G_OBJECT (mi), "date-received"); camel_message_info_set_dirty (mi, TRUE); camel_message_info_set_folder_flagged (mi, TRUE); } return changed; } /** * camel_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 camel_message_info_get_message_id (const CamelMessageInfo *mi) { CamelMessageInfoClass *klass; guint64 result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), 0); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, 0); g_return_val_if_fail (klass->get_message_id != NULL, 0); camel_message_info_property_lock (mi); result = klass->get_message_id (mi); camel_message_info_property_unlock (mi); return result; } /** * camel_message_info_set_message_id: * @mi: a #CamelMessageInfo * @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, unless the @mi is aborting notifications. There is not emitted * folder's "changed" signal for this @mi. * * Returns: Whether the value changed. * * Since: 3.24 **/ gboolean camel_message_info_set_message_id (CamelMessageInfo *mi, guint64 message_id) { CamelMessageInfoClass *klass; gboolean changed, abort_notifications; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, FALSE); g_return_val_if_fail (klass->set_message_id != NULL, FALSE); camel_message_info_property_lock (mi); changed = klass->set_message_id (mi, message_id); abort_notifications = mi->priv->abort_notifications; camel_message_info_property_unlock (mi); if (changed && !abort_notifications) { g_object_notify (G_OBJECT (mi), "message-id"); camel_message_info_set_dirty (mi, TRUE); camel_message_info_set_folder_flagged (mi, TRUE); } return changed; } /** * camel_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) (element-type guint64): A #GArray of * guint64 encoded Message-ID-s; or %NULL when none are available. * * Since: 3.24 **/ const GArray * camel_message_info_get_references (const CamelMessageInfo *mi) { CamelMessageInfoClass *klass; const GArray *result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, NULL); g_return_val_if_fail (klass->get_references != NULL, NULL); camel_message_info_property_lock (mi); result = klass->get_references (mi); camel_message_info_property_unlock (mi); return result; } /** * camel_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) (element-type guint64): 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 * camel_message_info_dup_references (const CamelMessageInfo *mi) { const GArray *arr; GArray *result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL); camel_message_info_property_lock (mi); arr = camel_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; } camel_message_info_property_unlock (mi); return result; } /** * camel_message_info_take_references: * @mi: a #CamelMessageInfo * @references: (element-type guint64) (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, unless the @mi is aborting notifications. There is not emitted * folder's "changed" signal for this @mi. * * Note that it's not safe to use the @references after the call to this function, * because it can be freed due to no change. * * Returns: Whether the value changed. * * Since: 3.24 **/ gboolean camel_message_info_take_references (CamelMessageInfo *mi, GArray *references) { CamelMessageInfoClass *klass; gboolean changed, abort_notifications; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, FALSE); g_return_val_if_fail (klass->take_references != NULL, FALSE); camel_message_info_property_lock (mi); changed = klass->take_references (mi, references); abort_notifications = mi->priv->abort_notifications; camel_message_info_property_unlock (mi); if (changed && !abort_notifications) { g_object_notify (G_OBJECT (mi), "references"); camel_message_info_set_dirty (mi, TRUE); camel_message_info_set_folder_flagged (mi, TRUE); } return changed; } /** * camel_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 * camel_message_info_get_headers (const CamelMessageInfo *mi) { CamelMessageInfoClass *klass; const CamelNameValueArray *result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, NULL); g_return_val_if_fail (klass->get_headers != NULL, NULL); camel_message_info_property_lock (mi); result = klass->get_headers (mi); camel_message_info_property_unlock (mi); return result; } /** * camel_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 * camel_message_info_dup_headers (const CamelMessageInfo *mi) { const CamelNameValueArray *arr; CamelNameValueArray *result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL); camel_message_info_property_lock (mi); arr = camel_message_info_get_headers (mi); if (arr) { result = camel_name_value_array_copy (arr); } else { result = NULL; } camel_message_info_property_unlock (mi); return result; } /** * camel_message_info_take_headers: * @mi: a #CamelMessageInfo * @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, unless the @mi is aborting notifications. There is not emitted * folder's "changed" signal for this @mi. * * Note that it's not safe to use the @headers after the call to this function, * because it can be freed due to no change. * * Returns: Whether the value changed. * * Since: 3.24 **/ gboolean camel_message_info_take_headers (CamelMessageInfo *mi, CamelNameValueArray *headers) { CamelMessageInfoClass *klass; gboolean changed, abort_notifications; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, FALSE); g_return_val_if_fail (klass->take_headers != NULL, FALSE); camel_message_info_property_lock (mi); changed = klass->take_headers (mi, headers); abort_notifications = mi->priv->abort_notifications; camel_message_info_property_unlock (mi); if (changed && !abort_notifications) { g_object_notify (G_OBJECT (mi), "headers"); camel_message_info_set_dirty (mi, TRUE); camel_message_info_set_folder_flagged (mi, TRUE); } return changed; } /** * camel_message_info_get_user_header: * @mi: a #CamelMessageInfo * @name: header name * * Returns: (transfer none) (nullable): Value of the header named @name from * the user-defined message headers of the associated message, or %NULL, * when not available. * * Since: 3.42 **/ const gchar * camel_message_info_get_user_header (const CamelMessageInfo *mi, const gchar *name) { CamelMessageInfoClass *klass; const gchar *result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL); g_return_val_if_fail (name != NULL, NULL); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, NULL); g_return_val_if_fail (klass->get_user_header != NULL, NULL); camel_message_info_property_lock (mi); result = klass->get_user_header (mi, name); camel_message_info_property_unlock (mi); return result; } /** * camel_message_info_dup_user_header: * @mi: a #CamelMessageInfo * @name: header name * * Returns: (transfer full) (nullable): Value of the header named @name from * the user-defined message headers of the associated message, or %NULL, * when not available. Free the returned string with g_free(), when no longer * needed. * * Since: 3.42 **/ gchar * camel_message_info_dup_user_header (const CamelMessageInfo *mi, const gchar *name) { gchar *result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL); camel_message_info_property_lock (mi); result = g_strdup (camel_message_info_get_user_header (mi, name)); camel_message_info_property_unlock (mi); return result; } /** * camel_message_info_set_user_header: * @mi: a #CamelMessageInfo * @name: header name * @value: (nullable): header value, or %NULL * * Set @value for a single user-defined message header of the associated message. * When the @value is %NULL, the header @name is removed from the user-defined * headers. * * If the @mi changed, the 'dirty' flag is set automatically, unless the @mi is * aborting notifications. There is not emitted folder's "changed" signal for this @mi. * * Returns: Whether the value changed. * * Since: 3.42 **/ gboolean camel_message_info_set_user_header (CamelMessageInfo *mi, const gchar *name, const gchar *value) { CamelMessageInfoClass *klass; gboolean changed, abort_notifications; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, FALSE); g_return_val_if_fail (klass->set_user_header != NULL, FALSE); camel_message_info_property_lock (mi); changed = klass->set_user_header (mi, name, value); abort_notifications = mi->priv->abort_notifications; camel_message_info_property_unlock (mi); if (changed && !abort_notifications) { g_object_notify (G_OBJECT (mi), "user-headers"); camel_message_info_set_dirty (mi, TRUE); } return changed; } /** * camel_message_info_get_user_headers: * @mi: a #CamelMessageInfo * * Returns: (transfer none) (nullable): All the user-defined message headers * of the associated message, or %NULL, when none are available. * * Since: 3.42 **/ const CamelNameValueArray * camel_message_info_get_user_headers (const CamelMessageInfo *mi) { CamelMessageInfoClass *klass; const CamelNameValueArray *result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, NULL); g_return_val_if_fail (klass->get_user_headers != NULL, NULL); camel_message_info_property_lock (mi); result = klass->get_user_headers (mi); camel_message_info_property_unlock (mi); return result; } /** * camel_message_info_dup_user_headers: * @mi: a #CamelMessageInfo * * Returns: (transfer full) (nullable): All the user-defined 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.42 **/ CamelNameValueArray * camel_message_info_dup_user_headers (const CamelMessageInfo *mi) { const CamelNameValueArray *arr; CamelNameValueArray *result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL); camel_message_info_property_lock (mi); arr = camel_message_info_get_user_headers (mi); if (arr) { result = camel_name_value_array_copy (arr); } else { result = NULL; } camel_message_info_property_unlock (mi); return result; } /** * camel_message_info_take_user_headers: * @mi: a #CamelMessageInfo * @headers: (transfer full) (nullable): headers to set, as #CamelNameValueArray, or %NULL * * Takes user-defined message headers of the associated message. * * If the @mi changed, the 'dirty' flag is set automatically, unless the @mi is * aborting notifications. There is not emitted folder's "changed" signal for this @mi. * * Note that it's not safe to use the @headers after the call to this function, * because it can be freed due to no change. * * Returns: Whether the value changed. * * Since: 3.42 **/ gboolean camel_message_info_take_user_headers (CamelMessageInfo *mi, CamelNameValueArray *headers) { CamelMessageInfoClass *klass; gboolean changed, abort_notifications; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, FALSE); g_return_val_if_fail (klass->take_user_headers != NULL, FALSE); camel_message_info_property_lock (mi); changed = klass->take_user_headers (mi, headers); abort_notifications = mi->priv->abort_notifications; camel_message_info_property_unlock (mi); if (changed && !abort_notifications) { g_object_notify (G_OBJECT (mi), "user-headers"); camel_message_info_set_dirty (mi, TRUE); } return changed; } /** * camel_message_info_get_preview: * @mi: a #CamelMessageInfo * * Returns: (transfer none) (nullable): Body preview of the associated * message, or %NULL, when not available. * * Since: 3.42 **/ const gchar * camel_message_info_get_preview (const CamelMessageInfo *mi) { CamelMessageInfoClass *klass; const gchar *result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, NULL); g_return_val_if_fail (klass->get_preview != NULL, NULL); camel_message_info_property_lock (mi); result = klass->get_preview (mi); camel_message_info_property_unlock (mi); return result; } /** * camel_message_info_dup_preview: * @mi: a #CamelMessageInfo * * Returns: (transfer none) (nullable): Body preview of the associated * message, or %NULL, when not available. Free the returned string * with g_free(), when no longer needed. * * Since: 3.42 **/ gchar * camel_message_info_dup_preview (const CamelMessageInfo *mi) { gchar *result; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL); camel_message_info_property_lock (mi); result = g_strdup (camel_message_info_get_preview (mi)); camel_message_info_property_unlock (mi); return result; } /** * camel_message_info_set_preview: * @mi: a #CamelMessageInfo * @preview: (nullable): message body preview, or %NULL * * Set @preview as the body preview of the associated message. Use %NULL or an empty * string to unset the value. * * If the @mi changed, the 'dirty' flag is set automatically, unless the @mi is * aborting notifications. There is not emitted folder's "changed" signal for this @mi. * * Returns: Whether the value changed. * * Since: 3.42 **/ gboolean camel_message_info_set_preview (CamelMessageInfo *mi, const gchar *preview) { CamelMessageInfoClass *klass; gboolean changed, abort_notifications; g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE); klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi); g_return_val_if_fail (klass != NULL, FALSE); g_return_val_if_fail (klass->set_preview != NULL, FALSE); camel_message_info_property_lock (mi); changed = klass->set_preview (mi, preview); abort_notifications = mi->priv->abort_notifications; camel_message_info_property_unlock (mi); if (changed && !abort_notifications) { g_object_notify (G_OBJECT (mi), "preview"); camel_message_info_set_dirty (mi, TRUE); } return changed; } /** * camel_message_info_dump: * @mi: a #CamelMessageInfo * * Dumps the mesasge info @mi to stdout. This is meand for debugging * purposes only. * * Since: 3.24 **/ void camel_message_info_dump (CamelMessageInfo *mi) { if (!mi) { printf ("No message info\n"); return; } camel_message_info_property_lock (mi); printf ("Message info %s:\n", G_OBJECT_TYPE_NAME (mi)); printf (" UID: %s\n", camel_message_info_get_uid (mi)); printf (" Flags: %04x\n", camel_message_info_get_flags (mi)); printf (" From: %s\n", camel_message_info_get_from (mi)); printf (" To: %s\n", camel_message_info_get_to (mi)); printf (" Cc: %s\n", camel_message_info_get_cc (mi)); printf (" Mailing list: %s\n", camel_message_info_get_mlist (mi)); printf (" Subject: %s\n", camel_message_info_get_subject (mi)); camel_message_info_property_unlock (mi); }