1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
4  *
5  * This library is free software: you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation.
8  *
9  * This library is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
12  * for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this library. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "evolution-data-server-config.h"
19 
20 #include <stdio.h>
21 #include <string.h>
22 
23 #include "camel-db.h"
24 #include "camel-enumtypes.h"
25 #include "camel-folder.h"
26 #include "camel-folder-summary.h"
27 #include "camel-message-info-base.h"
28 #include "camel-string-utils.h"
29 #include "camel-weak-ref-group.h"
30 
31 #include "camel-message-info.h"
32 
33 struct _CamelMessageInfoPrivate {
34 	GRecMutex property_lock;
35 
36 	CamelWeakRefGroup *summary_wrg;	/* CamelFolderSummary * */
37 	gboolean dirty;			/* whether requires save to local disk/summary */
38 	const gchar *uid;		/* allocated in the string pool */
39 	gboolean abort_notifications;
40 	gboolean thaw_notify_folder;
41 	gboolean thaw_notify_folder_with_counts;
42 	guint freeze_notifications;
43 	guint folder_flagged_stamp;
44 };
45 
46 enum {
47 	PROP_0,
48 	PROP_SUMMARY,
49 	PROP_DIRTY,
50 	PROP_FOLDER_FLAGGED,
51 	PROP_FOLDER_FLAGGED_STAMP,
52 	PROP_ABORT_NOTIFICATIONS,
53 	PROP_UID,
54 	PROP_FLAGS,
55 	PROP_USER_FLAGS,
56 	PROP_USER_TAGS,
57 	PROP_SUBJECT,
58 	PROP_FROM,
59 	PROP_TO,
60 	PROP_CC,
61 	PROP_MLIST,
62 	PROP_SIZE,
63 	PROP_DATE_SENT,
64 	PROP_DATE_RECEIVED,
65 	PROP_MESSAGE_ID,
66 	PROP_REFERENCES,
67 	PROP_HEADERS,
68 	PROP_USER_HEADERS,
69 	PROP_PREVIEW
70 };
71 
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(CamelMessageInfo,camel_message_info,G_TYPE_OBJECT)72 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (CamelMessageInfo, camel_message_info, G_TYPE_OBJECT)
73 
74 static CamelMessageInfo *
75 message_info_clone (const CamelMessageInfo *mi,
76 		    CamelFolderSummary *assign_summary)
77 {
78 	CamelMessageInfo *result;
79 	const gchar *uid;
80 	const GArray *references;
81 	const CamelNameValueArray *headers;
82 
83 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
84 	if (assign_summary)
85 		g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (assign_summary), NULL);
86 
87 	/* Make sure the 'mi' doesn't change while copying the values. */
88 	camel_message_info_property_lock (mi);
89 
90 	if (!assign_summary) {
91 		CamelFolderSummary *mi_summary;
92 
93 		mi_summary = camel_message_info_ref_summary (mi);
94 		result = camel_message_info_new (mi_summary);
95 		g_clear_object (&mi_summary);
96 	} else {
97 		result = camel_message_info_new (assign_summary);
98 	}
99 
100 	g_object_freeze_notify (G_OBJECT (result));
101 	camel_message_info_set_abort_notifications (result, TRUE);
102 
103 	uid = camel_message_info_pooldup_uid (mi);
104 	camel_message_info_set_uid (result, uid);
105 	camel_pstring_free (uid);
106 
107 	camel_message_info_take_user_flags (result, camel_message_info_dup_user_flags (mi));
108 	camel_message_info_take_user_tags (result, camel_message_info_dup_user_tags (mi));
109 	camel_message_info_set_subject (result, camel_message_info_get_subject (mi));
110 	camel_message_info_set_from (result, camel_message_info_get_from (mi));
111 	camel_message_info_set_to (result, camel_message_info_get_to (mi));
112 	camel_message_info_set_cc (result, camel_message_info_get_cc (mi));
113 	camel_message_info_set_mlist (result, camel_message_info_get_mlist (mi));
114 	camel_message_info_set_preview (result, camel_message_info_get_preview (mi));
115 	camel_message_info_set_size (result, camel_message_info_get_size (mi));
116 	camel_message_info_set_date_sent (result, camel_message_info_get_date_sent (mi));
117 	camel_message_info_set_date_received (result, camel_message_info_get_date_received (mi));
118 	camel_message_info_set_message_id (result, camel_message_info_get_message_id (mi));
119 
120 	references = camel_message_info_get_references (mi);
121 	if (references && references->len) {
122 		GArray *copy;
123 		guint ii;
124 
125 		copy = g_array_sized_new (FALSE, FALSE, sizeof (guint64), references->len);
126 
127 		for (ii = 0; ii < references->len; ii++) {
128 			guint64 refr = g_array_index (references, guint64, ii);
129 
130 			g_array_append_val (copy, refr);
131 		}
132 
133 		camel_message_info_take_references (result, copy);
134 	}
135 
136 	headers = camel_message_info_get_headers (mi);
137 	if (headers) {
138 		camel_message_info_take_headers (result,
139 			camel_name_value_array_copy (headers));
140 	}
141 
142 	headers = camel_message_info_get_user_headers (mi);
143 	if (headers) {
144 		camel_message_info_take_user_headers (result,
145 			camel_name_value_array_copy (headers));
146 	}
147 
148 	/* Set flags as the last, to not overwrite 'folder-flagged' flag by
149 	   the "changes" when copying fields. */
150 	camel_message_info_set_flags (result, ~0, camel_message_info_get_flags (mi));
151 
152 	camel_message_info_property_unlock (mi);
153 
154 	/* Also ensure 'dirty' flag, thus it can be eventually saved. */
155 	camel_message_info_set_dirty (result, TRUE);
156 
157 	camel_message_info_set_abort_notifications (result, FALSE);
158 	g_object_thaw_notify (G_OBJECT (result));
159 
160 	return result;
161 }
162 
163 static gboolean
message_info_load(CamelMessageInfo * mi,const CamelMIRecord * record,gchar ** bdata_ptr)164 message_info_load (CamelMessageInfo *mi,
165 		   const CamelMIRecord *record,
166 		   /* const */ gchar **bdata_ptr)
167 {
168 	gint ii, count;
169 	gchar *part, *label;
170 
171 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
172 	g_return_val_if_fail (record != NULL, FALSE);
173 	g_return_val_if_fail (bdata_ptr != NULL, FALSE);
174 
175 	camel_message_info_set_uid (mi, record->uid);
176 	camel_message_info_set_flags (mi, ~0, record->flags);
177 	camel_message_info_set_size (mi, record->size);
178 	camel_message_info_set_date_sent (mi, record->dsent);
179 	camel_message_info_set_date_received (mi, record->dreceived);
180 
181 	camel_message_info_set_subject (mi, record->subject);
182 	camel_message_info_set_from (mi, record->from);
183 	camel_message_info_set_to (mi, record->to);
184 	camel_message_info_set_cc (mi, record->cc);
185 	camel_message_info_set_mlist (mi, record->mlist);
186 	camel_message_info_set_preview (mi, record->preview);
187 
188 	/* Extract Message id & References */
189 	part = record->part;
190 	if (part) {
191 		CamelSummaryMessageID message_id;
192 
193 		message_id.id.part.hi = camel_util_bdata_get_number (&part, 0);
194 		message_id.id.part.lo = camel_util_bdata_get_number (&part, 0);
195 
196 		camel_message_info_set_message_id (mi, message_id.id.id);
197 
198 		count = camel_util_bdata_get_number (&part, 0);
199 
200 		if (count > 0) {
201 			GArray *references = g_array_sized_new (FALSE, FALSE, sizeof (guint64), count);
202 
203 			for (ii = 0; ii < count; ii++) {
204 				message_id.id.part.hi = camel_util_bdata_get_number (&part, 0);
205 				message_id.id.part.lo = camel_util_bdata_get_number (&part, 0);
206 
207 				g_array_append_val (references, message_id.id.id);
208 			}
209 
210 			camel_message_info_take_references (mi, references);
211 		}
212 	}
213 
214 	/* Extract User flags/labels */
215 	part = record->labels;
216 	if (part) {
217 		CamelNamedFlags *user_flags;
218 
219 		user_flags = camel_named_flags_new ();
220 
221 		label = part;
222 		for (ii = 0; part[ii]; ii++) {
223 			if (part[ii] == ' ') {
224 				part[ii] = 0;
225 				if (label && *label)
226 					camel_named_flags_insert (user_flags, label);
227 				label = &(part[ii + 1]);
228 				part[ii] = ' ';
229 			}
230 		}
231 		if (label && *label)
232 			camel_named_flags_insert (user_flags, label);
233 
234 		if (camel_named_flags_get_length (user_flags) == 0) {
235 			camel_named_flags_free (user_flags);
236 			user_flags = NULL;
237 		}
238 
239 		camel_message_info_take_user_flags (mi, user_flags);
240 	}
241 
242 	/* Extract User tags */
243 	part = record->usertags;
244 	if (part) {
245 		CamelNameValueArray *user_tags;
246 
247 		count = camel_util_bdata_get_number (&part, 0);
248 
249 		user_tags = camel_name_value_array_new_sized (count);
250 
251 		for (ii = 0; ii < count; ii++) {
252 			gchar *name, *value;
253 
254 			name = camel_util_bdata_get_string (&part, NULL);
255 			value = camel_util_bdata_get_string (&part, NULL);
256 
257 			if (name)
258 				camel_name_value_array_set_named (user_tags, CAMEL_COMPARE_CASE_SENSITIVE, name, value ? value : "");
259 
260 			g_free (name);
261 			g_free (value);
262 		}
263 
264 		if (camel_name_value_array_get_length (user_tags) == 0) {
265 			camel_name_value_array_free (user_tags);
266 			user_tags = NULL;
267 		}
268 
269 		camel_message_info_take_user_tags (mi, user_tags);
270 	}
271 
272 	/* Extract User headers */
273 	part = record->userheaders;
274 	if (part) {
275 		CamelNameValueArray *user_headers;
276 
277 		count = camel_util_bdata_get_number (&part, 0);
278 
279 		user_headers = camel_name_value_array_new_sized (count);
280 
281 		for (ii = 0; ii < count; ii++) {
282 			gchar *name, *value;
283 
284 			name = camel_util_bdata_get_string (&part, NULL);
285 			value = camel_util_bdata_get_string (&part, NULL);
286 
287 			if (name)
288 				camel_name_value_array_set_named (user_headers, CAMEL_COMPARE_CASE_SENSITIVE, name, value ? value : "");
289 
290 			g_free (name);
291 			g_free (value);
292 		}
293 
294 		if (camel_name_value_array_get_length (user_headers) == 0) {
295 			camel_name_value_array_free (user_headers);
296 			user_headers = NULL;
297 		}
298 
299 		camel_message_info_take_user_headers (mi, user_headers);
300 	}
301 
302 	return TRUE;
303 }
304 
305 static gboolean
message_info_save(const CamelMessageInfo * mi,CamelMIRecord * record,GString * bdata_str)306 message_info_save (const CamelMessageInfo *mi,
307 		   CamelMIRecord *record,
308 		   GString *bdata_str)
309 {
310 	GString *tmp;
311 	CamelSummaryMessageID message_id;
312 	const CamelNamedFlags *user_flags;
313 	const CamelNameValueArray *user_tags;
314 	const GArray *references;
315 	guint32 read_or_flags = CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_JUNK;
316 
317 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
318 	g_return_val_if_fail (record != NULL, FALSE);
319 	g_return_val_if_fail (bdata_str != NULL, FALSE);
320 
321 	record->uid = camel_pstring_strdup (camel_message_info_get_uid (mi));
322 	record->flags = camel_message_info_get_flags (mi);
323 
324 	if ((record->flags & CAMEL_MESSAGE_JUNK) != 0) {
325 		CamelFolderSummary *folder_summary;
326 
327 		folder_summary = camel_message_info_ref_summary (mi);
328 		if (folder_summary) {
329 			CamelFolder *folder;
330 
331 			folder = camel_folder_summary_get_folder (folder_summary);
332 			if (folder) {
333 				guint32 folder_flags = camel_folder_get_flags (folder);
334 
335 				/* Do not consider Junk flag as message being read when it's a Junk folder */
336 				if ((folder_flags & CAMEL_FOLDER_IS_JUNK) != 0)
337 					read_or_flags = read_or_flags & (~CAMEL_MESSAGE_JUNK);
338 			}
339 
340 			g_object_unref (folder_summary);
341 		}
342 	}
343 
344 	record->read = ((record->flags & (CAMEL_MESSAGE_SEEN | read_or_flags))) ? 1 : 0;
345 	record->deleted = (record->flags & CAMEL_MESSAGE_DELETED) != 0 ? 1 : 0;
346 	record->replied = (record->flags & CAMEL_MESSAGE_ANSWERED) != 0 ? 1 : 0;
347 	record->important = (record->flags & CAMEL_MESSAGE_FLAGGED) != 0 ? 1 : 0;
348 	record->junk = (record->flags & CAMEL_MESSAGE_JUNK) != 0 ? 1 : 0;
349 	record->dirty = (record->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0 ? 1 : 0;
350 	record->attachment = (record->flags & CAMEL_MESSAGE_ATTACHMENTS) != 0 ? 1 : 0;
351 
352 	record->size = camel_message_info_get_size (mi);
353 	record->dsent = camel_message_info_get_date_sent (mi);
354 	record->dreceived = camel_message_info_get_date_received (mi);
355 
356 	record->subject = camel_pstring_strdup (camel_message_info_get_subject (mi));
357 	record->from = camel_pstring_strdup (camel_message_info_get_from (mi));
358 	record->to = camel_pstring_strdup (camel_message_info_get_to (mi));
359 	record->cc = camel_pstring_strdup (camel_message_info_get_cc (mi));
360 	record->mlist = camel_pstring_strdup (camel_message_info_get_mlist (mi));
361 	record->preview = g_strdup (camel_message_info_get_preview (mi));
362 
363 	record->followup_flag = g_strdup (camel_message_info_get_user_tag (mi, "follow-up"));
364 	record->followup_completed_on = g_strdup (camel_message_info_get_user_tag (mi, "completed-on"));
365 	record->followup_due_by = g_strdup (camel_message_info_get_user_tag (mi, "due-by"));
366 
367 	tmp = g_string_new (NULL);
368 	message_id.id.id = camel_message_info_get_message_id (mi);
369 	g_string_append_printf (tmp, "%lu %lu ", (gulong) message_id.id.part.hi, (gulong) message_id.id.part.lo);
370 	references = camel_message_info_get_references (mi);
371 	if (references) {
372 		guint ii;
373 
374 		g_string_append_printf (tmp, "%lu", (gulong) references->len);
375 		for (ii = 0; ii < references->len; ii++) {
376 			message_id.id.id = g_array_index (references, guint64, ii);
377 
378 			g_string_append_printf (tmp, " %lu %lu", (gulong) message_id.id.part.hi, (gulong) message_id.id.part.lo);
379 		}
380 	} else {
381 		g_string_append_c (tmp, '0');
382 	}
383 	record->part = g_string_free (tmp, FALSE);
384 
385 	tmp = g_string_new (NULL);
386 	user_flags = camel_message_info_get_user_flags (mi);
387 	if (user_flags) {
388 		guint ii, count;
389 
390 		count = camel_named_flags_get_length (user_flags);
391 		for (ii = 0; ii < count; ii++) {
392 			const gchar *name = camel_named_flags_get (user_flags, ii);
393 
394 			if (name && *name) {
395 				if (tmp->len)
396 					g_string_append_c (tmp, ' ');
397 				g_string_append (tmp, name);
398 			}
399 		}
400 	}
401 	record->labels = g_string_free (tmp, FALSE);
402 
403 	tmp = g_string_new (NULL);
404 	user_tags = camel_message_info_get_user_tags (mi);
405 	if (user_tags) {
406 		guint ii, count;
407 
408 		count = camel_name_value_array_get_length (user_tags);
409 		g_string_append_printf (tmp, "%lu", (gulong) count);
410 
411 		for (ii = 0; ii < count; ii++) {
412 			const gchar *name = NULL, *value = NULL;
413 
414 			if (camel_name_value_array_get (user_tags, ii, &name, &value)) {
415 				if (!name)
416 					name = "";
417 				if (!value)
418 					value = "";
419 
420 				g_string_append_printf (tmp, " %lu-%s %lu-%s", (gulong) strlen (name), name, (gulong) strlen (value), value);
421 			}
422 		}
423 	} else {
424 		g_string_append_c (tmp, '0');
425 	}
426 	record->usertags = g_string_free (tmp, FALSE);
427 
428 	tmp = g_string_new (NULL);
429 	user_tags = camel_message_info_get_user_headers (mi);
430 	if (user_tags) {
431 		guint32 ii, count;
432 
433 		count = camel_name_value_array_get_length (user_tags);
434 		g_string_append_printf (tmp, "%" G_GUINT32_FORMAT, count);
435 
436 		for (ii = 0; ii < count; ii++) {
437 			const gchar *name = NULL, *value = NULL;
438 
439 			if (camel_name_value_array_get (user_tags, ii, &name, &value) && name && value) {
440 				g_string_append_printf (tmp, " %" G_GUINT32_FORMAT "-%s %" G_GUINT32_FORMAT "-%s",
441 					(guint32) strlen (name), name,
442 					(guint32) strlen (value), value);
443 			}
444 		}
445 	} else {
446 		g_string_append_c (tmp, '0');
447 	}
448 	record->userheaders = g_string_free (tmp, FALSE);
449 
450 	return TRUE;
451 }
452 
453 static void
message_info_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)454 message_info_set_property (GObject *object,
455 			   guint property_id,
456 			   const GValue *value,
457 			   GParamSpec *pspec)
458 {
459 	CamelMessageInfo *mi = CAMEL_MESSAGE_INFO (object);
460 
461 	switch (property_id) {
462 	case PROP_SUMMARY:
463 		camel_weak_ref_group_set (mi->priv->summary_wrg, g_value_get_object (value));
464 		return;
465 
466 	case PROP_DIRTY:
467 		camel_message_info_set_dirty (mi, g_value_get_boolean (value));
468 		return;
469 
470 	case PROP_FOLDER_FLAGGED:
471 		camel_message_info_set_folder_flagged (mi, g_value_get_boolean (value));
472 		return;
473 
474 	case PROP_ABORT_NOTIFICATIONS:
475 		camel_message_info_set_abort_notifications (mi, g_value_get_boolean (value));
476 		return;
477 
478 	case PROP_UID:
479 		camel_message_info_set_uid (mi, g_value_get_string (value));
480 		return;
481 
482 	case PROP_FLAGS:
483 		camel_message_info_set_flags (mi, ~0, g_value_get_flags (value));
484 		return;
485 
486 	case PROP_USER_FLAGS:
487 		camel_message_info_take_user_flags (mi, g_value_dup_boxed (value));
488 		return;
489 
490 	case PROP_USER_TAGS:
491 		camel_message_info_take_user_tags (mi, g_value_dup_boxed (value));
492 		return;
493 
494 	case PROP_SUBJECT:
495 		camel_message_info_set_subject (mi, g_value_get_string (value));
496 		return;
497 
498 	case PROP_FROM:
499 		camel_message_info_set_from (mi, g_value_get_string (value));
500 		return;
501 
502 	case PROP_TO:
503 		camel_message_info_set_to (mi, g_value_get_string (value));
504 		return;
505 
506 	case PROP_CC:
507 		camel_message_info_set_cc (mi, g_value_get_string (value));
508 		return;
509 
510 	case PROP_MLIST:
511 		camel_message_info_set_mlist (mi, g_value_get_string (value));
512 		return;
513 
514 	case PROP_SIZE:
515 		camel_message_info_set_size (mi, g_value_get_uint (value));
516 		return;
517 
518 	case PROP_DATE_SENT:
519 		camel_message_info_set_date_sent (mi, g_value_get_int64 (value));
520 		return;
521 
522 	case PROP_DATE_RECEIVED:
523 		camel_message_info_set_date_received (mi, g_value_get_int64 (value));
524 		return;
525 
526 	case PROP_MESSAGE_ID:
527 		camel_message_info_set_message_id (mi, g_value_get_uint64 (value));
528 		return;
529 
530 	case PROP_REFERENCES:
531 		camel_message_info_take_references (mi, g_value_dup_boxed (value));
532 		return;
533 
534 	case PROP_HEADERS:
535 		camel_message_info_take_headers (mi, g_value_dup_boxed (value));
536 		return;
537 
538 	case PROP_USER_HEADERS:
539 		camel_message_info_take_user_headers (mi, g_value_dup_boxed (value));
540 		return;
541 
542 	case PROP_PREVIEW:
543 		camel_message_info_set_preview (mi, g_value_get_string (value));
544 		return;
545 	}
546 
547 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
548 }
549 
550 static void
message_info_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)551 message_info_get_property (GObject *object,
552 			   guint property_id,
553 			   GValue *value,
554 			   GParamSpec *pspec)
555 {
556 	CamelMessageInfo *mi = CAMEL_MESSAGE_INFO (object);
557 
558 	switch (property_id) {
559 	case PROP_SUMMARY:
560 		g_value_take_object (value, camel_message_info_ref_summary (mi));
561 		return;
562 
563 	case PROP_DIRTY:
564 		g_value_set_boolean (value, camel_message_info_get_dirty (mi));
565 		return;
566 
567 	case PROP_FOLDER_FLAGGED:
568 		g_value_set_boolean (value, camel_message_info_get_folder_flagged (mi));
569 		return;
570 
571 	case PROP_FOLDER_FLAGGED_STAMP:
572 		g_value_set_uint (value, camel_message_info_get_folder_flagged_stamp (mi));
573 		return;
574 
575 	case PROP_ABORT_NOTIFICATIONS:
576 		g_value_set_boolean (value, camel_message_info_get_abort_notifications (mi));
577 		return;
578 
579 	case PROP_UID:
580 		g_value_set_string (value, camel_message_info_get_uid (mi));
581 		return;
582 
583 	case PROP_FLAGS:
584 		g_value_set_flags (value, camel_message_info_get_flags (mi));
585 		return;
586 
587 	case PROP_USER_FLAGS:
588 		g_value_take_boxed (value, camel_message_info_dup_user_flags (mi));
589 		return;
590 
591 	case PROP_USER_TAGS:
592 		g_value_take_boxed (value, camel_message_info_dup_user_tags (mi));
593 		return;
594 
595 	case PROP_SUBJECT:
596 		g_value_set_string (value, camel_message_info_get_subject (mi));
597 		return;
598 
599 	case PROP_FROM:
600 		g_value_set_string (value, camel_message_info_get_from (mi));
601 		return;
602 
603 	case PROP_TO:
604 		g_value_set_string (value, camel_message_info_get_to (mi));
605 		return;
606 
607 	case PROP_CC:
608 		g_value_set_string (value, camel_message_info_get_cc (mi));
609 		return;
610 
611 	case PROP_MLIST:
612 		g_value_set_string (value, camel_message_info_get_mlist (mi));
613 		return;
614 
615 	case PROP_SIZE:
616 		g_value_set_uint (value, camel_message_info_get_size (mi));
617 		return;
618 
619 	case PROP_DATE_SENT:
620 		g_value_set_int64 (value, camel_message_info_get_date_sent (mi));
621 		return;
622 
623 	case PROP_DATE_RECEIVED:
624 		g_value_set_int64 (value, camel_message_info_get_date_received (mi));
625 		return;
626 
627 	case PROP_MESSAGE_ID:
628 		g_value_set_uint64 (value, camel_message_info_get_message_id (mi));
629 		return;
630 
631 	case PROP_REFERENCES:
632 		g_value_take_boxed (value, camel_message_info_dup_references (mi));
633 		return;
634 
635 	case PROP_HEADERS:
636 		g_value_take_boxed (value, camel_message_info_dup_headers (mi));
637 		return;
638 
639 	case PROP_USER_HEADERS:
640 		g_value_take_boxed (value, camel_message_info_dup_user_headers (mi));
641 		return;
642 
643 	case PROP_PREVIEW:
644 		g_value_take_string (value, camel_message_info_dup_preview (mi));
645 		return;
646 	}
647 
648 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
649 }
650 
651 static void
message_info_dispose(GObject * object)652 message_info_dispose (GObject *object)
653 {
654 	CamelMessageInfo *mi = CAMEL_MESSAGE_INFO (object);
655 
656 	camel_weak_ref_group_set (mi->priv->summary_wrg, NULL);
657 	camel_pstring_free (mi->priv->uid);
658 	mi->priv->uid = NULL;
659 
660 	/* Chain up to parent's method. */
661 	G_OBJECT_CLASS (camel_message_info_parent_class)->dispose (object);
662 }
663 
664 static void
message_info_finalize(GObject * object)665 message_info_finalize (GObject *object)
666 {
667 	CamelMessageInfo *mi = CAMEL_MESSAGE_INFO (object);
668 
669 	camel_weak_ref_group_unref (mi->priv->summary_wrg);
670 	g_rec_mutex_clear (&mi->priv->property_lock);
671 
672 	/* Chain up to parent's method. */
673 	G_OBJECT_CLASS (camel_message_info_parent_class)->finalize (object);
674 }
675 
676 static void
camel_message_info_class_init(CamelMessageInfoClass * class)677 camel_message_info_class_init (CamelMessageInfoClass *class)
678 {
679 	GObjectClass *object_class;
680 
681 	class->clone = message_info_clone;
682 	class->load = message_info_load;
683 	class->save = message_info_save;
684 
685 	object_class = G_OBJECT_CLASS (class);
686 	object_class->set_property = message_info_set_property;
687 	object_class->get_property = message_info_get_property;
688 	object_class->dispose = message_info_dispose;
689 	object_class->finalize = message_info_finalize;
690 
691 	/**
692 	 * CamelMessageInfo:summary
693 	 *
694 	 * The #CamelFolderSummary to which the message info belongs, or %NULL.
695 	 * It can be set only during construction of the object.
696 	 *
697 	 * Since: 3.24
698 	 **/
699 	g_object_class_install_property (
700 		object_class,
701 		PROP_SUMMARY,
702 		g_param_spec_object (
703 			"summary",
704 			"Summary",
705 			NULL,
706 			CAMEL_TYPE_FOLDER_SUMMARY,
707 			G_PARAM_READWRITE |
708 			G_PARAM_CONSTRUCT_ONLY |
709 			G_PARAM_STATIC_STRINGS));
710 
711 	/**
712 	 * CamelMessageInfo:uid
713 	 *
714 	 * A unique ID of the message in its folder.
715 	 *
716 	 * Since: 3.24
717 	 **/
718 	g_object_class_install_property (
719 		object_class,
720 		PROP_UID,
721 		g_param_spec_string (
722 			"uid",
723 			"UID",
724 			NULL,
725 			NULL,
726 			G_PARAM_READWRITE |
727 			G_PARAM_EXPLICIT_NOTIFY |
728 			G_PARAM_STATIC_STRINGS));
729 
730 	/**
731 	 * CamelMessageInfo:dirty
732 	 *
733 	 * Flag, whether the info is changed and requires save to disk.
734 	 * Compare with CamelMessageInfo:folder-flagged
735 	 *
736 	 * Since: 3.24
737 	 **/
738 	g_object_class_install_property (
739 		object_class,
740 		PROP_DIRTY,
741 		g_param_spec_boolean (
742 			"dirty",
743 			"Dirty",
744 			NULL,
745 			FALSE,
746 			G_PARAM_READWRITE |
747 			G_PARAM_EXPLICIT_NOTIFY |
748 			G_PARAM_STATIC_STRINGS));
749 
750 	/**
751 	 * CamelMessageInfo:folder-flagged
752 	 *
753 	 * Flag, whether the info is changed and requires save to
754 	 * the destination store/server. This is different from
755 	 * the CamelMessageInfo:dirty, which takes care of the local
756 	 * information only.
757 	 *
758 	 * Since: 3.24
759 	 **/
760 	g_object_class_install_property (
761 		object_class,
762 		PROP_FOLDER_FLAGGED,
763 		g_param_spec_boolean (
764 			"folder-flagged",
765 			"Folder Flagged",
766 			NULL,
767 			FALSE,
768 			G_PARAM_READWRITE |
769 			G_PARAM_EXPLICIT_NOTIFY |
770 			G_PARAM_STATIC_STRINGS));
771 
772 	/**
773 	 * CamelMessageInfo:folder-flagged-stamp
774 	 *
775 	 * The 'folder-flagged-stamp' is a stamp of the 'folder-flagged' flag. This stamp
776 	 * changes whenever anything would mark the @mi 'folder-flagged', regardless the @mi
777 	 * being already 'folder-flagged'. It can be used to recognize changes
778 	 * on the 'folder-flagged' flag during the time.
779 	 *
780 	 * Since: 3.24
781 	 **/
782 	g_object_class_install_property (
783 		object_class,
784 		PROP_FOLDER_FLAGGED_STAMP,
785 		g_param_spec_uint (
786 			"folder-flagged-stamp",
787 			"Folder Flagged Stamp",
788 			NULL,
789 			0, G_MAXUINT, 0,
790 			G_PARAM_READABLE |
791 			G_PARAM_STATIC_STRINGS));
792 
793 	/**
794 	 * CamelMessageInfo:abort-notifications
795 	 *
796 	 * Flag, whether the info is currently aborting notifications. It is used to avoid
797 	 * unnecessary 'folder-flagged' and 'dirty' flags changes and also to avoid
798 	 * associated folder's "changed" signal.
799 	 *f
800 	 * Since: 3.24
801 	 **/
802 	g_object_class_install_property (
803 		object_class,
804 		PROP_ABORT_NOTIFICATIONS,
805 		g_param_spec_boolean (
806 			"abort-notifications",
807 			"Abort Notifications",
808 			NULL,
809 			FALSE,
810 			G_PARAM_READWRITE |
811 			G_PARAM_EXPLICIT_NOTIFY |
812 			G_PARAM_STATIC_STRINGS));
813 
814 	/**
815 	 * CamelMessageInfo:flags
816 	 *
817 	 * Bit-or of #CamelMessageFlags.
818 	 *
819 	 * Since: 3.24
820 	 **/
821 	g_object_class_install_property (
822 		object_class,
823 		PROP_FLAGS,
824 		g_param_spec_flags (
825 			"flags",
826 			"Flags",
827 			NULL,
828 			CAMEL_TYPE_MESSAGE_FLAGS,
829 			0,
830 			G_PARAM_READWRITE |
831 			G_PARAM_EXPLICIT_NOTIFY |
832 			G_PARAM_STATIC_STRINGS));
833 
834 	/**
835 	 * CamelMessageInfo:user-flags
836 	 *
837 	 * User flags for the associated message. Can be %NULL.
838 	 * Unlike user-tags, which can contain various values, the user-flags
839 	 * can only be set or not.
840 	 *
841 	 * Since: 3.24
842 	 **/
843 	g_object_class_install_property (
844 		object_class,
845 		PROP_USER_FLAGS,
846 		g_param_spec_boxed (
847 			"user-flags",
848 			"User Flags",
849 			NULL,
850 			CAMEL_TYPE_NAMED_FLAGS,
851 			G_PARAM_READWRITE |
852 			G_PARAM_EXPLICIT_NOTIFY |
853 			G_PARAM_STATIC_STRINGS));
854 
855 	/**
856 	 * CamelMessageInfo:user-tags
857 	 *
858 	 * User tags for the associated message. Can be %NULL.
859 	 * Unlike user-flags, which can be set or not, the user-tags
860 	 * can contain various values.
861 	 *
862 	 * Since: 3.24
863 	 **/
864 	g_object_class_install_property (
865 		object_class,
866 		PROP_USER_TAGS,
867 		g_param_spec_boxed (
868 			"user-tags",
869 			"User tags",
870 			NULL,
871 			CAMEL_TYPE_NAME_VALUE_ARRAY,
872 			G_PARAM_READWRITE |
873 			G_PARAM_EXPLICIT_NOTIFY |
874 			G_PARAM_STATIC_STRINGS));
875 
876 	/**
877 	 * CamelMessageInfo:subject
878 	 *
879 	 * Subject of the associated message.
880 	 *
881 	 * Since: 3.24
882 	 **/
883 	g_object_class_install_property (
884 		object_class,
885 		PROP_SUBJECT,
886 		g_param_spec_string (
887 			"subject",
888 			"Subject",
889 			NULL,
890 			NULL,
891 			G_PARAM_READWRITE |
892 			G_PARAM_EXPLICIT_NOTIFY |
893 			G_PARAM_STATIC_STRINGS));
894 
895 	/**
896 	 * CamelMessageInfo:from
897 	 *
898 	 * From address of the associated message.
899 	 *
900 	 * Since: 3.24
901 	 **/
902 	g_object_class_install_property (
903 		object_class,
904 		PROP_FROM,
905 		g_param_spec_string (
906 			"from",
907 			"From",
908 			NULL,
909 			NULL,
910 			G_PARAM_READWRITE |
911 			G_PARAM_EXPLICIT_NOTIFY |
912 			G_PARAM_STATIC_STRINGS));
913 
914 	/**
915 	 * CamelMessageInfo:to
916 	 *
917 	 * To address of the associated message.
918 	 *
919 	 * Since: 3.24
920 	 **/
921 	g_object_class_install_property (
922 		object_class,
923 		PROP_TO,
924 		g_param_spec_string (
925 			"to",
926 			"To",
927 			NULL,
928 			NULL,
929 			G_PARAM_READWRITE |
930 			G_PARAM_EXPLICIT_NOTIFY |
931 			G_PARAM_STATIC_STRINGS));
932 
933 	/**
934 	 * CamelMessageInfo:cc
935 	 *
936 	 * CC address of the associated message.
937 	 *
938 	 * Since: 3.24
939 	 **/
940 	g_object_class_install_property (
941 		object_class,
942 		PROP_CC,
943 		g_param_spec_string (
944 			"cc",
945 			"CC",
946 			NULL,
947 			NULL,
948 			G_PARAM_READWRITE |
949 			G_PARAM_EXPLICIT_NOTIFY |
950 			G_PARAM_STATIC_STRINGS));
951 
952 	/**
953 	 * CamelMessageInfo:mlist
954 	 *
955 	 * Mailing list address of the associated message.
956 	 *
957 	 * Since: 3.24
958 	 **/
959 	g_object_class_install_property (
960 		object_class,
961 		PROP_MLIST,
962 		g_param_spec_string (
963 			"mlist",
964 			"mlist",
965 			NULL,
966 			NULL,
967 			G_PARAM_READWRITE |
968 			G_PARAM_EXPLICIT_NOTIFY |
969 			G_PARAM_STATIC_STRINGS));
970 
971 	/**
972 	 * CamelMessageInfo:size
973 	 *
974 	 * Size of the associated message.
975 	 *
976 	 * Since: 3.24
977 	 **/
978 	g_object_class_install_property (
979 		object_class,
980 		PROP_SIZE,
981 		g_param_spec_uint (
982 			"size",
983 			"Size",
984 			NULL,
985 			0, G_MAXUINT32, 0,
986 			G_PARAM_READWRITE |
987 			G_PARAM_EXPLICIT_NOTIFY |
988 			G_PARAM_STATIC_STRINGS));
989 
990 	/**
991 	 * CamelMessageInfo:date-sent
992 	 *
993 	 * Sent Date of the associated message.
994 	 *
995 	 * Since: 3.24
996 	 **/
997 	g_object_class_install_property (
998 		object_class,
999 		PROP_DATE_SENT,
1000 		g_param_spec_int64 (
1001 			"date-sent",
1002 			"Date Sent",
1003 			NULL,
1004 			G_MININT64, G_MAXINT64, 0,
1005 			G_PARAM_READWRITE |
1006 			G_PARAM_EXPLICIT_NOTIFY |
1007 			G_PARAM_STATIC_STRINGS));
1008 
1009 	/**
1010 	 * CamelMessageInfo:date-received
1011 	 *
1012 	 * Received date of the associated message.
1013 	 *
1014 	 * Since: 3.24
1015 	 **/
1016 	g_object_class_install_property (
1017 		object_class,
1018 		PROP_DATE_RECEIVED,
1019 		g_param_spec_int64 (
1020 			"date-received",
1021 			"Date Received",
1022 			NULL,
1023 			G_MININT64, G_MAXINT64, 0,
1024 			G_PARAM_READWRITE |
1025 			G_PARAM_EXPLICIT_NOTIFY |
1026 			G_PARAM_STATIC_STRINGS));
1027 
1028 	/**
1029 	 * CamelMessageInfo:message-id
1030 	 *
1031 	 * Encoded Message-ID of the associated message as a guint64 number,
1032 	 * partial MD5 sum. The value can be cast to #CamelSummaryMessageID.
1033 	 *
1034 	 * Since: 3.24
1035 	 **/
1036 	g_object_class_install_property (
1037 		object_class,
1038 		PROP_MESSAGE_ID,
1039 		g_param_spec_uint64 (
1040 			"message-id",
1041 			"Message ID",
1042 			NULL,
1043 			0, G_MAXUINT64, 0,
1044 			G_PARAM_READWRITE |
1045 			G_PARAM_EXPLICIT_NOTIFY |
1046 			G_PARAM_STATIC_STRINGS));
1047 
1048 	/**
1049 	 * CamelMessageInfo:references
1050 	 *
1051 	 * Encoded In-Reply-To and References headers of the associated message
1052 	 * as an array of guint64 numbers, partial MD5 sums. Each value can be
1053 	 * cast to #CamelSummaryMessageID.
1054 	 *
1055 	 * Since: 3.24
1056 	 **/
1057 	g_object_class_install_property (
1058 		object_class,
1059 		PROP_REFERENCES,
1060 		g_param_spec_boxed (
1061 			"references",
1062 			"References",
1063 			NULL,
1064 			G_TYPE_ARRAY,
1065 			G_PARAM_READWRITE |
1066 			G_PARAM_EXPLICIT_NOTIFY |
1067 			G_PARAM_STATIC_STRINGS));
1068 
1069 	/**
1070 	 * CamelMessageInfo:headers
1071 	 *
1072 	 * Headers of the associated message. Can be %NULL.
1073 	 *
1074 	 * Since: 3.24
1075 	 **/
1076 	g_object_class_install_property (
1077 		object_class,
1078 		PROP_HEADERS,
1079 		g_param_spec_boxed (
1080 			"headers",
1081 			"Headers",
1082 			NULL,
1083 			CAMEL_TYPE_NAME_VALUE_ARRAY,
1084 			G_PARAM_READWRITE |
1085 			G_PARAM_EXPLICIT_NOTIFY |
1086 			G_PARAM_STATIC_STRINGS));
1087 
1088 	/**
1089 	 * CamelMessageInfo:user-headers
1090 	 *
1091 	 * User-defined headers of the associated message. Can be %NULL.
1092 	 *
1093 	 * Since: 3.42
1094 	 **/
1095 	g_object_class_install_property (
1096 		object_class,
1097 		PROP_USER_HEADERS,
1098 		g_param_spec_boxed (
1099 			"user-headers",
1100 			"User Headers",
1101 			NULL,
1102 			CAMEL_TYPE_NAME_VALUE_ARRAY,
1103 			G_PARAM_READWRITE |
1104 			G_PARAM_EXPLICIT_NOTIFY |
1105 			G_PARAM_STATIC_STRINGS));
1106 
1107 	/**
1108 	 * CamelMessageInfo:preview
1109 	 *
1110 	 * Body preview of the associated message. Can be %NULL.
1111 	 *
1112 	 * Since: 3.42
1113 	 **/
1114 	g_object_class_install_property (
1115 		object_class,
1116 		PROP_PREVIEW,
1117 		g_param_spec_string (
1118 			"preview",
1119 			"Preview",
1120 			NULL,
1121 			NULL,
1122 			G_PARAM_READWRITE |
1123 			G_PARAM_EXPLICIT_NOTIFY |
1124 			G_PARAM_STATIC_STRINGS));
1125 }
1126 
1127 static void
camel_message_info_init(CamelMessageInfo * mi)1128 camel_message_info_init (CamelMessageInfo *mi)
1129 {
1130 	mi->priv = camel_message_info_get_instance_private (mi);
1131 	mi->priv->summary_wrg = camel_weak_ref_group_new ();
1132 
1133 	g_rec_mutex_init (&mi->priv->property_lock);
1134 }
1135 
1136 /* Private function */
1137 void _camel_message_info_unset_summary (CamelMessageInfo *mi);
1138 
1139 void
_camel_message_info_unset_summary(CamelMessageInfo * mi)1140 _camel_message_info_unset_summary (CamelMessageInfo *mi)
1141 {
1142 	g_return_if_fail (CAMEL_IS_MESSAGE_INFO (mi));
1143 
1144 	camel_weak_ref_group_set (mi->priv->summary_wrg, NULL);
1145 }
1146 
1147 /**
1148  * camel_message_info_new:
1149  * @summary: (nullable) (type CamelFolderSummary): parent #CamelFolderSummary object, or %NULL
1150  *
1151  * Create a new #CamelMessageInfo object, optionally for given @summary.
1152  *
1153  * Returns: (transfer full): a new #CamelMessageInfo object
1154  *
1155  * Since: 3.24
1156  **/
1157 CamelMessageInfo *
camel_message_info_new(CamelFolderSummary * summary)1158 camel_message_info_new (CamelFolderSummary *summary)
1159 {
1160 	GType type = CAMEL_TYPE_MESSAGE_INFO_BASE;
1161 
1162 	if (summary) {
1163 		CamelFolderSummaryClass *klass;
1164 
1165 		g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), NULL);
1166 
1167 		klass = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary);
1168 		g_return_val_if_fail (klass != NULL, NULL);
1169 
1170 		type = klass->message_info_type;
1171 	}
1172 
1173 	return g_object_new (type, "summary", summary, NULL);
1174 }
1175 
1176 /**
1177  * camel_message_info_clone:
1178  * @mi: a #CamelMessageInfo to clone
1179  * @assign_summary: (nullable) (type CamelFolderSummary): parent #CamelFolderSummary object, or %NULL, to set on the clone
1180  *
1181  * Clones the @mi as a new #CamelMessageInfo and eventually assigns
1182  * a new #CamelFolderSummary to it. If it's not set, then the same
1183  * summary as the one with @mi is used.
1184  *
1185  * Returns: (transfer full): a new #CamelMessageInfo object, clone of the @mi
1186  *
1187  * Since: 3.24
1188  **/
1189 CamelMessageInfo *
camel_message_info_clone(const CamelMessageInfo * mi,CamelFolderSummary * assign_summary)1190 camel_message_info_clone (const CamelMessageInfo *mi,
1191 			  CamelFolderSummary *assign_summary)
1192 {
1193 	CamelMessageInfoClass *klass;
1194 
1195 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
1196 	if (assign_summary)
1197 		g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (assign_summary), NULL);
1198 
1199 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
1200 	g_return_val_if_fail (klass != NULL, NULL);
1201 	g_return_val_if_fail (klass->clone != NULL, NULL);
1202 
1203 	return klass->clone (mi, assign_summary);
1204 }
1205 
1206 /**
1207  * camel_message_info_load:
1208  * @mi: a #CamelMessageInfo to load
1209  * @record: (type CamelMIRecord): a #CamelMIRecord to load the @mi from
1210  * @bdata_ptr: a backend specific data (bdata) pointer
1211  *
1212  * Load content of @mi from the data stored in @record. The @bdata_ptr points
1213  * to the current position of the record->bdata, where the read can continue.
1214  * Use helper functions camel_util_bdata_get_number() and camel_util_bdata_get_string()
1215  * to read data from it and also move forward the *bdata_ptr.
1216  *
1217  * After successful load of the @mi, the 'dirty' flag is unset.
1218  *
1219  * Returns: Whether the load was successful.
1220  *
1221  * Since: 3.24
1222  **/
1223 gboolean
camel_message_info_load(CamelMessageInfo * mi,const CamelMIRecord * record,gchar ** bdata_ptr)1224 camel_message_info_load (CamelMessageInfo *mi,
1225 			 const CamelMIRecord *record,
1226 			 /* const */ gchar **bdata_ptr)
1227 {
1228 	CamelMessageInfoClass *klass;
1229 	gboolean success;
1230 
1231 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
1232 	g_return_val_if_fail (record != NULL, FALSE);
1233 	g_return_val_if_fail (bdata_ptr != NULL, FALSE);
1234 
1235 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
1236 	g_return_val_if_fail (klass != NULL, FALSE);
1237 	g_return_val_if_fail (klass->load != NULL, FALSE);
1238 
1239 	g_object_freeze_notify (G_OBJECT (mi));
1240 	camel_message_info_property_lock (mi);
1241 	camel_message_info_set_abort_notifications (mi, TRUE);
1242 
1243 	success = klass->load (mi, record, bdata_ptr);
1244 
1245 	if (success)
1246 		camel_message_info_set_dirty (mi, FALSE);
1247 
1248 	camel_message_info_set_abort_notifications (mi, FALSE);
1249 	camel_message_info_property_unlock (mi);
1250 	g_object_thaw_notify (G_OBJECT (mi));
1251 
1252 	return success;
1253 }
1254 
1255 /**
1256  * camel_message_info_save:
1257  * @mi: a #CamelMessageInfo
1258  * @record: (type CamelMIRecord): a #CamelMIRecord to populate
1259  * @bdata_str: a #GString with a string to save as backend specific data (bdata)
1260  *
1261  * Save the @mi content to the message info record @record. It can populate all
1262  * but the record->bdata value, which is set fro mthe @bdata_str. Use helper functions
1263  * camel_util_bdata_put_number() and camel_util_bdata_put_string() to put data into the @bdata_str.
1264  *
1265  * Returns: Whether the save succeeded.
1266  *
1267  * Since: 3.24
1268  **/
1269 gboolean
camel_message_info_save(const CamelMessageInfo * mi,CamelMIRecord * record,GString * bdata_str)1270 camel_message_info_save (const CamelMessageInfo *mi,
1271 			 CamelMIRecord *record,
1272 			 GString *bdata_str)
1273 {
1274 	CamelMessageInfoClass *klass;
1275 	gboolean success;
1276 
1277 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
1278 	g_return_val_if_fail (record != NULL, FALSE);
1279 	g_return_val_if_fail (bdata_str != NULL, FALSE);
1280 
1281 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
1282 	g_return_val_if_fail (klass != NULL, FALSE);
1283 	g_return_val_if_fail (klass->save != NULL, FALSE);
1284 
1285 	camel_message_info_property_lock (mi);
1286 
1287 	success = klass->save (mi, record, bdata_str);
1288 
1289 	camel_message_info_property_unlock (mi);
1290 
1291 	return success;
1292 }
1293 
1294 /**
1295  * camel_message_info_ref_summary:
1296  * @mi: a #CamelMessageInfo
1297  *
1298  * Returns: (transfer full): Referenced #CamelFolderSummary to which the @mi belongs, or %NULL,
1299  * if there is none. Use g_object_unref() for non-NULL returned values when done with it.
1300  *
1301  * Since: 3.24
1302  **/
1303 CamelFolderSummary *
camel_message_info_ref_summary(const CamelMessageInfo * mi)1304 camel_message_info_ref_summary (const CamelMessageInfo *mi)
1305 {
1306 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
1307 
1308 	return camel_weak_ref_group_get (mi->priv->summary_wrg);
1309 }
1310 
1311 /**
1312  * camel_message_info_property_lock:
1313  * @mi: a #CamelMessageInfo
1314  *
1315  * Acquires a property lock, which is used to ensure thread safety
1316  * when properties are changing. Release the lock with
1317  * camel_message_info_property_unlock().
1318  *
1319  * Note: Make sure the CamelFolderSummary lock is held before this lock,
1320  * if there will be called any 'set' function on the @mi, to avoid deadlock
1321  * when the summary would be set as dirty while another thread might try
1322  * to read values from the @mi, waiting for the property lock and holding
1323  * the summary lock at the same time.
1324  *
1325  * Since: 3.24
1326  **/
1327 void
camel_message_info_property_lock(const CamelMessageInfo * mi)1328 camel_message_info_property_lock (const CamelMessageInfo *mi)
1329 {
1330 	g_return_if_fail (CAMEL_IS_MESSAGE_INFO (mi));
1331 
1332 	g_rec_mutex_lock (&mi->priv->property_lock);
1333 }
1334 
1335 /**
1336  * camel_message_info_property_unlock:
1337  * @mi: a #CamelMessageInfo
1338  *
1339  * Releases a property lock, previously acquired with
1340  * camel_message_info_property_lock().
1341  *
1342  * Since: 3.24
1343  **/
1344 void
camel_message_info_property_unlock(const CamelMessageInfo * mi)1345 camel_message_info_property_unlock (const CamelMessageInfo *mi)
1346 {
1347 	g_return_if_fail (CAMEL_IS_MESSAGE_INFO (mi));
1348 
1349 	g_rec_mutex_unlock (&mi->priv->property_lock);
1350 }
1351 
1352 static void
camel_message_info_update_summary_and_folder(CamelMessageInfo * mi,gboolean update_counts)1353 camel_message_info_update_summary_and_folder (CamelMessageInfo *mi,
1354 					      gboolean update_counts)
1355 {
1356 	CamelFolderSummary *summary;
1357 
1358 	g_return_if_fail (CAMEL_IS_MESSAGE_INFO (mi));
1359 
1360 	camel_message_info_property_lock (mi);
1361 	if (camel_message_info_get_notifications_frozen (mi)) {
1362 		mi->priv->thaw_notify_folder = TRUE;
1363 		mi->priv->thaw_notify_folder_with_counts |= update_counts;
1364 		camel_message_info_property_unlock (mi);
1365 
1366 		return;
1367 	}
1368 	camel_message_info_property_unlock (mi);
1369 
1370 	summary = camel_message_info_ref_summary (mi);
1371 	if (summary) {
1372 		CamelFolder *folder;
1373 		CamelMessageInfo *in_summary_mi = NULL;
1374 		const gchar *uid;
1375 
1376 		uid = camel_message_info_pooldup_uid (mi);
1377 
1378 		/* This is for cases when a new message info had been created,
1379 		   but not added into the summary yet. */
1380 		if (uid && camel_folder_summary_check_uid (summary, uid) &&
1381 		    (in_summary_mi = camel_folder_summary_peek_loaded (summary, uid)) == mi) {
1382 			if (update_counts) {
1383 				camel_folder_summary_lock (summary);
1384 				g_object_freeze_notify (G_OBJECT (summary));
1385 
1386 				camel_folder_summary_replace_flags (summary, mi);
1387 
1388 				g_object_thaw_notify (G_OBJECT (summary));
1389 				camel_folder_summary_unlock (summary);
1390 			}
1391 
1392 			folder = camel_folder_summary_get_folder (summary);
1393 			if (folder) {
1394 				CamelFolderChangeInfo *changes = camel_folder_change_info_new ();
1395 
1396 				camel_folder_change_info_change_uid (changes, uid);
1397 				camel_folder_changed (folder, changes);
1398 				camel_folder_change_info_free (changes);
1399 			}
1400 		}
1401 
1402 		g_clear_object (&in_summary_mi);
1403 		g_clear_object (&summary);
1404 		camel_pstring_free (uid);
1405 	}
1406 }
1407 
1408 /**
1409  * camel_message_info_get_dirty:
1410  * @mi: a #CamelMessageInfo
1411  *
1412  * Returns: Whether the @mi is dirty, which means that it had been
1413  *   changed and a save to the local summary is required.
1414  *
1415  * Since: 3.24
1416  **/
1417 gboolean
camel_message_info_get_dirty(const CamelMessageInfo * mi)1418 camel_message_info_get_dirty (const CamelMessageInfo *mi)
1419 {
1420 	gboolean result;
1421 
1422 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
1423 
1424 	camel_message_info_property_lock (mi);
1425 	result = mi->priv->dirty;
1426 	camel_message_info_property_unlock (mi);
1427 
1428 	return result;
1429 }
1430 
1431 /**
1432  * camel_message_info_set_dirty:
1433  * @mi: a #CamelMessageInfo
1434  * @dirty: a dirty state to set
1435  *
1436  * Marks the @mi as dirty, which means a save to the local summary
1437  * is required.
1438  *
1439  * Since: 3.24
1440  **/
1441 void
camel_message_info_set_dirty(CamelMessageInfo * mi,gboolean dirty)1442 camel_message_info_set_dirty (CamelMessageInfo *mi,
1443 			      gboolean dirty)
1444 {
1445 	gboolean changed, abort_notifications;
1446 
1447 	g_return_if_fail (CAMEL_IS_MESSAGE_INFO (mi));
1448 
1449 	camel_message_info_property_lock (mi);
1450 
1451 	changed = (!mi->priv->dirty) != (!dirty);
1452 	if (changed)
1453 		mi->priv->dirty = dirty;
1454 	abort_notifications = mi->priv->abort_notifications;
1455 
1456 	camel_message_info_property_unlock (mi);
1457 
1458 	if (changed && !abort_notifications) {
1459 		g_object_notify (G_OBJECT (mi), "dirty");
1460 
1461 		if (dirty) {
1462 			CamelFolderSummary *summary;
1463 
1464 			summary = camel_message_info_ref_summary (mi);
1465 			if (summary)
1466 				camel_folder_summary_touch (summary);
1467 
1468 			g_clear_object (&summary);
1469 		}
1470 	}
1471 }
1472 
1473 /**
1474  * camel_message_info_get_folder_flagged:
1475  * @mi: a #CamelMessageInfo
1476  *
1477  * The folder flagged flag is used to mark the message infor as being changed
1478  * and this change should be propagated to the remote store (server). This is
1479  * different from the 'dirty' flag, which is set for local changes only. It
1480  * can happen that the 'folder-flagged' flag is set, but the 'dirty' flag not.
1481  *
1482  * This is only a convenient wrapper around CAMEL_MESSAGE_FOLDER_FLAGGED flag,
1483  * for better readiness of the code.
1484  *
1485  * Returns: Whether requires save of the local changes into the remote store.
1486  *
1487  * Since: 3.24
1488  **/
1489 gboolean
camel_message_info_get_folder_flagged(const CamelMessageInfo * mi)1490 camel_message_info_get_folder_flagged (const CamelMessageInfo *mi)
1491 {
1492 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
1493 
1494 	return (camel_message_info_get_flags (mi) & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0;
1495 }
1496 
1497 /**
1498  * camel_message_info_set_folder_flagged:
1499  * @mi: a #CamelMessageInfo
1500  * @folder_flagged: a value to set to
1501  *
1502  * Changes the folder-flagged flag to the @folder_flagged value. See
1503  * camel_message_info_get_folder_flagged() for more information about
1504  * the use of this flag.
1505  *
1506  * This is only a convenient wrapper around CAMEL_MESSAGE_FOLDER_FLAGGED flag,
1507  * for better readiness of the code.
1508  *
1509  * Returns: Whether the flag had been changed.
1510  *
1511  * Since: 3.24
1512  **/
1513 gboolean
camel_message_info_set_folder_flagged(CamelMessageInfo * mi,gboolean folder_flagged)1514 camel_message_info_set_folder_flagged (CamelMessageInfo *mi,
1515 				       gboolean folder_flagged)
1516 {
1517 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
1518 
1519 	/* g_object_notify (G_OBJECT (mi), "folder-flagged");
1520 	   is called as part of the set_flags function */
1521 
1522 	return camel_message_info_set_flags (mi, CAMEL_MESSAGE_FOLDER_FLAGGED,
1523 		folder_flagged ? CAMEL_MESSAGE_FOLDER_FLAGGED : 0);
1524 }
1525 
1526 /**
1527  * camel_message_info_get_folder_flagged_stamp:
1528  * @mi: a #CamelMessageInfo
1529  *
1530  * The 'folder-flagged-stamp' is a stamp of the 'folder-flagged' flag. This stamp
1531  * changes whenever anything would mark the @mi as 'folder-flagged', regardless
1532  * the @mi being already 'folder-flagged'. It can be used to recognize changes
1533  * on the 'folder-flagged' flag during the time.
1534  *
1535  * Returns: Stamp of the 'folder-flagged' flag.
1536  *
1537  * Since: 3.24
1538  **/
1539 guint
camel_message_info_get_folder_flagged_stamp(const CamelMessageInfo * mi)1540 camel_message_info_get_folder_flagged_stamp (const CamelMessageInfo *mi)
1541 {
1542 	guint result;
1543 
1544 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), ~0);
1545 
1546 	camel_message_info_property_lock (mi);
1547 	result = mi->priv->folder_flagged_stamp;
1548 	camel_message_info_property_unlock (mi);
1549 
1550 	return result;
1551 }
1552 
1553 /**
1554  * camel_message_info_get_abort_notifications:
1555  * @mi: a #CamelMessageInfo
1556  *
1557  * Returns: Whether the @mi is aborting notifications, which means
1558  *   that it will not influence 'dirty' and 'folder-flagged' flags
1559  *   in the set/take functions, neither it will emit any GObject::notify
1560  *   signals on change, nor associated folder's "changed" signal.
1561  *
1562  * Since: 3.24
1563  **/
1564 gboolean
camel_message_info_get_abort_notifications(const CamelMessageInfo * mi)1565 camel_message_info_get_abort_notifications (const CamelMessageInfo *mi)
1566 {
1567 	gboolean result;
1568 
1569 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
1570 
1571 	camel_message_info_property_lock (mi);
1572 	result = mi->priv->abort_notifications;
1573 	camel_message_info_property_unlock (mi);
1574 
1575 	return result;
1576 }
1577 
1578 /**
1579  * camel_message_info_set_abort_notifications:
1580  * @mi: a #CamelMessageInfo
1581  * @abort_notifications: a state to set
1582  *
1583  * Marks the @mi to abort any notifications, which means that it
1584  * will not influence 'dirty' and 'folder-flagged' flags in
1585  * the set/take functions, neither it will emit any GObject::notify
1586  * signals on change, nor associated folder's "changed" signal.
1587  *
1588  * Since: 3.24
1589  **/
1590 void
camel_message_info_set_abort_notifications(CamelMessageInfo * mi,gboolean abort_notifications)1591 camel_message_info_set_abort_notifications (CamelMessageInfo *mi,
1592 					    gboolean abort_notifications)
1593 {
1594 	gboolean changed;
1595 	g_return_if_fail (CAMEL_IS_MESSAGE_INFO (mi));
1596 
1597 	camel_message_info_property_lock (mi);
1598 	changed = (!mi->priv->abort_notifications) != (!abort_notifications);
1599 	if (changed)
1600 		mi->priv->abort_notifications = abort_notifications;
1601 	camel_message_info_property_unlock (mi);
1602 
1603 	if (changed)
1604 		g_object_notify (G_OBJECT (mi), "abort-notifications");
1605 }
1606 
1607 /**
1608  * camel_message_info_freeze_notifications:
1609  * @mi: a #CamelMessageInfo
1610  *
1611  * Freezes all the notifications until the camel_message_info_thaw_notifications() is called.
1612  * This function can be called multiple times, where the last thaw will do the notifications.
1613  *
1614  * Since: 3.24
1615  **/
1616 void
camel_message_info_freeze_notifications(CamelMessageInfo * mi)1617 camel_message_info_freeze_notifications (CamelMessageInfo *mi)
1618 {
1619 	g_return_if_fail (CAMEL_IS_MESSAGE_INFO (mi));
1620 
1621 	camel_message_info_property_lock (mi);
1622 	mi->priv->freeze_notifications++;
1623 	if (mi->priv->freeze_notifications == 1) {
1624 		mi->priv->thaw_notify_folder = FALSE;
1625 		mi->priv->thaw_notify_folder_with_counts = FALSE;
1626 		g_object_freeze_notify (G_OBJECT (mi));
1627 	}
1628 	camel_message_info_property_unlock (mi);
1629 }
1630 
1631 /**
1632  * camel_message_info_thaw_notifications:
1633  * @mi: a #CamelMessageInfo
1634  *
1635  * Reverses the call of the camel_message_info_freeze_notifications().
1636  * If this is the last freeze, then the associated folder is also notified
1637  * about the change, if any happened during the freeze.
1638  *
1639  * Since: 3.24
1640  **/
1641 void
camel_message_info_thaw_notifications(CamelMessageInfo * mi)1642 camel_message_info_thaw_notifications (CamelMessageInfo *mi)
1643 {
1644 	g_return_if_fail (CAMEL_IS_MESSAGE_INFO (mi));
1645 
1646 	camel_message_info_property_lock (mi);
1647 	if (!mi->priv->freeze_notifications) {
1648 		camel_message_info_property_unlock (mi);
1649 
1650 		g_warn_if_reached ();
1651 		return;
1652 	}
1653 
1654 	mi->priv->freeze_notifications--;
1655 	if (!mi->priv->freeze_notifications) {
1656 		gboolean notify_folder, notify_folder_with_counts;
1657 
1658 		notify_folder = mi->priv->thaw_notify_folder;
1659 		notify_folder_with_counts = mi->priv->thaw_notify_folder_with_counts;
1660 
1661 		camel_message_info_property_unlock (mi);
1662 
1663 		g_object_thaw_notify (G_OBJECT (mi));
1664 
1665 		if (notify_folder)
1666 			camel_message_info_update_summary_and_folder (mi, notify_folder_with_counts);
1667 	} else {
1668 		camel_message_info_property_unlock (mi);
1669 	}
1670 }
1671 
1672 /**
1673  * camel_message_info_get_notifications_frozen:
1674  * @mi: a #CamelMessageInfo
1675  *
1676  * Returns: Whether the notifications are frozen.
1677  *
1678  * See: camel_message_info_freeze_notifications()
1679  *
1680  * Since: 3.24
1681  **/
1682 gboolean
camel_message_info_get_notifications_frozen(const CamelMessageInfo * mi)1683 camel_message_info_get_notifications_frozen (const CamelMessageInfo *mi)
1684 {
1685 	gboolean result;
1686 
1687 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
1688 
1689 	camel_message_info_property_lock (mi);
1690 	result = mi->priv->freeze_notifications > 0;
1691 	camel_message_info_property_unlock (mi);
1692 
1693 	return result;
1694 }
1695 
1696 /**
1697  * camel_message_info_get_uid:
1698  * @mi: a #CamelMessageInfo
1699  *
1700  * Get the UID of the #mi.
1701  *
1702  * Returns: (transfer none): The UID of the @mi.
1703  *
1704  * Since: 3.24
1705  **/
1706 const gchar *
camel_message_info_get_uid(const CamelMessageInfo * mi)1707 camel_message_info_get_uid (const CamelMessageInfo *mi)
1708 {
1709 	const gchar *result;
1710 
1711 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
1712 
1713 	camel_message_info_property_lock (mi);
1714 	result = mi->priv->uid;
1715 	camel_message_info_property_unlock (mi);
1716 
1717 	return result;
1718 }
1719 
1720 /**
1721  * camel_message_info_pooldup_uid:
1722  * @mi: a #CamelMessageInfo
1723  *
1724  * Get the UID of the #mi, duplicated on the Camel's string pool.
1725  * This is good for thread safety, though the UID should not change once set.
1726  *
1727  * Returns: A newly references string in the string pool, the #mi UID.
1728  *   Free it with camel_pstring_free() when no longer needed.
1729  *
1730  * Since: 3.24
1731  **/
1732 const gchar *
camel_message_info_pooldup_uid(const CamelMessageInfo * mi)1733 camel_message_info_pooldup_uid (const CamelMessageInfo *mi)
1734 {
1735 	const gchar *result;
1736 
1737 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
1738 
1739 	camel_message_info_property_lock (mi);
1740 	result = camel_pstring_strdup (mi->priv->uid);
1741 	camel_message_info_property_unlock (mi);
1742 
1743 	return result;
1744 }
1745 
1746 /**
1747  * camel_message_info_set_uid:
1748  * @mi: a #CamelMessageInfo
1749  * @uid: a UID to set
1750  *
1751  * Changes UID of the @mi to @uid. If it changes, the 'dirty' flag
1752  * of the @mi is set too, unless the @mi is aborting notifications. This change
1753  * does not influence the 'folder-flagged' flag.
1754  *
1755  * Returns: Whether the UID changed.
1756  *
1757  * Since: 3.24
1758  **/
1759 gboolean
camel_message_info_set_uid(CamelMessageInfo * mi,const gchar * uid)1760 camel_message_info_set_uid (CamelMessageInfo *mi,
1761 			    const gchar *uid)
1762 {
1763 	gboolean changed, abort_notifications;
1764 
1765 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
1766 
1767 	camel_message_info_property_lock (mi);
1768 	changed = mi->priv->uid != uid && g_strcmp0 (mi->priv->uid, uid) != 0;
1769 	if (changed) {
1770 		camel_pstring_free (mi->priv->uid);
1771 		mi->priv->uid = camel_pstring_strdup (uid);
1772 	}
1773 	abort_notifications = mi->priv->abort_notifications;
1774 	camel_message_info_property_unlock (mi);
1775 
1776 	if (changed && !abort_notifications) {
1777 		g_object_notify (G_OBJECT (mi), "uid");
1778 		camel_message_info_set_dirty (mi, TRUE);
1779 	}
1780 
1781 	return changed;
1782 }
1783 
1784 /**
1785  * camel_message_info_get_flags:
1786  * @mi: a #CamelMessageInfo
1787  *
1788  * Returns: Bit-or of #CamelMessageFlags set on the @mi.
1789  *
1790  * Since: 3.24
1791  **/
1792 guint32
camel_message_info_get_flags(const CamelMessageInfo * mi)1793 camel_message_info_get_flags (const CamelMessageInfo *mi)
1794 {
1795 	CamelMessageInfoClass *klass;
1796 	guint32 result;
1797 
1798 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), 0);
1799 
1800 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
1801 	g_return_val_if_fail (klass != NULL, 0);
1802 	g_return_val_if_fail (klass->get_flags != NULL, 0);
1803 
1804 	camel_message_info_property_lock (mi);
1805 	result = klass->get_flags (mi);
1806 	camel_message_info_property_unlock (mi);
1807 
1808 	return result;
1809 }
1810 
1811 /**
1812  * camel_message_info_set_flags:
1813  * @mi: a #CamelMessageInfo
1814  * @mask: mask of flags to change
1815  * @set: state the flags should be changed to
1816  *
1817  * Change the state of the flags on the @mi. Both @mask and @set are bit-or
1818  * of #CamelMessageFlags.
1819  *
1820  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
1821  * set automatically, unless the @mi is aborting notifications. There is also emitted
1822  * folder's "changed" signal for this @mi, if necessary. In case
1823  * the CAMEL_MESSAGE_FOLDER_FLAGGED flag would be set and the @mi is
1824  * not aborting notifications, the 'folder-flagged-stamp' changes too.
1825  *
1826  * Returns: Whether the flags changed.
1827  *
1828  * Since: 3.24
1829  **/
1830 gboolean
camel_message_info_set_flags(CamelMessageInfo * mi,guint32 mask,guint32 set)1831 camel_message_info_set_flags (CamelMessageInfo *mi,
1832 			      guint32 mask,
1833 			      guint32 set)
1834 {
1835 	CamelMessageInfoClass *klass;
1836 	gboolean changed, abort_notifications;
1837 
1838 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
1839 
1840 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
1841 	g_return_val_if_fail (klass != NULL, FALSE);
1842 	g_return_val_if_fail (klass->set_flags != NULL, FALSE);
1843 
1844 	camel_message_info_property_lock (mi);
1845 
1846 	changed = klass->set_flags (mi, mask, set);
1847 	abort_notifications = mi->priv->abort_notifications;
1848 
1849 	if (!abort_notifications &&
1850 	    (mask & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0 &&
1851 	    (set & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0)
1852 		mi->priv->folder_flagged_stamp++;
1853 
1854 	camel_message_info_property_unlock (mi);
1855 
1856 	if (changed && !abort_notifications) {
1857 		g_object_notify (G_OBJECT (mi), "flags");
1858 		camel_message_info_set_dirty (mi, TRUE);
1859 
1860 		/* Only if the folder-flagged was not part of the change */
1861 		if (!(mask & CAMEL_MESSAGE_FOLDER_FLAGGED))
1862 			camel_message_info_set_folder_flagged (mi, TRUE);
1863 		else
1864 			g_object_notify (G_OBJECT (mi), "folder-flagged");
1865 
1866 		camel_message_info_update_summary_and_folder (mi, TRUE);
1867 	}
1868 
1869 	return changed;
1870 }
1871 
1872 /**
1873  * camel_message_info_get_user_flag:
1874  * @mi: a #CamelMessageInfo
1875  * @name: user flag name
1876  *
1877  * Returns: Whther the user flag named @name is set.
1878  *
1879  * Since: 3.24
1880  **/
1881 gboolean
camel_message_info_get_user_flag(const CamelMessageInfo * mi,const gchar * name)1882 camel_message_info_get_user_flag (const CamelMessageInfo *mi,
1883 				  const gchar *name)
1884 {
1885 	CamelMessageInfoClass *klass;
1886 	gboolean result;
1887 
1888 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
1889 
1890 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
1891 	g_return_val_if_fail (klass != NULL, FALSE);
1892 	g_return_val_if_fail (klass->get_user_flag != NULL, FALSE);
1893 
1894 	camel_message_info_property_lock (mi);
1895 	result = klass->get_user_flag (mi, name);
1896 	camel_message_info_property_unlock (mi);
1897 
1898 	return result;
1899 }
1900 
1901 /**
1902  * camel_message_info_set_user_flag:
1903  * @mi: a #CamelMessageInfo
1904  * @name: user flag name
1905  * @state: state to set for the flag
1906  *
1907  * Change @state of the flag named @name. Unlike user tags, user flags
1908  * can only be set or unset, while the user tags can contain certain values.
1909  *
1910  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
1911  * set automatically, unless the @mi is aborting notifications. There is also emitted
1912  * folder's "changed" signal for this @mi, if necessary.
1913  *
1914  * Returns: Whether the message info changed.
1915  *
1916  * Since: 3.24
1917  **/
1918 gboolean
camel_message_info_set_user_flag(CamelMessageInfo * mi,const gchar * name,gboolean state)1919 camel_message_info_set_user_flag (CamelMessageInfo *mi,
1920 				  const gchar *name,
1921 				  gboolean state)
1922 {
1923 	CamelMessageInfoClass *klass;
1924 	gboolean changed, abort_notifications;
1925 
1926 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
1927 	g_return_val_if_fail (name != NULL, FALSE);
1928 
1929 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
1930 	g_return_val_if_fail (klass != NULL, FALSE);
1931 	g_return_val_if_fail (klass->set_user_flag != NULL, FALSE);
1932 
1933 	camel_message_info_property_lock (mi);
1934 	changed = klass->set_user_flag (mi, name, state);
1935 	abort_notifications = mi->priv->abort_notifications;
1936 	camel_message_info_property_unlock (mi);
1937 
1938 	if (changed && !abort_notifications) {
1939 		g_object_notify (G_OBJECT (mi), "user-flags");
1940 		camel_message_info_set_dirty (mi, TRUE);
1941 		camel_message_info_set_folder_flagged (mi, TRUE);
1942 
1943 		camel_message_info_update_summary_and_folder (mi, FALSE);
1944 	}
1945 
1946 	return changed;
1947 }
1948 
1949 /**
1950  * camel_message_info_get_user_flags:
1951  * @mi: a #CamelMessageInfo
1952  *
1953  * Returns: (transfer none) (nullable): A #CamelNamedFlags with all the currently set
1954  *   user flags on the @mi. Do not modify it.
1955  *
1956  * Since: 3.24
1957  **/
1958 const CamelNamedFlags *
camel_message_info_get_user_flags(const CamelMessageInfo * mi)1959 camel_message_info_get_user_flags (const CamelMessageInfo *mi)
1960 {
1961 	CamelMessageInfoClass *klass;
1962 	const CamelNamedFlags *result;
1963 
1964 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
1965 
1966 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
1967 	g_return_val_if_fail (klass != NULL, NULL);
1968 	g_return_val_if_fail (klass->get_user_flags != NULL, NULL);
1969 
1970 	camel_message_info_property_lock (mi);
1971 	result = klass->get_user_flags (mi);
1972 	camel_message_info_property_unlock (mi);
1973 
1974 	return result;
1975 }
1976 
1977 /**
1978  * camel_message_info_dup_user_flags:
1979  * @mi: a #CamelMessageInfo
1980  *
1981  * Returns: (transfer full): A newly allocated #CamelNamedFlags with all the currently set
1982  *   user flags on the @mi. Free the returned structure with camel_named_flags_free()
1983  *   when no londer needed.
1984  *
1985  * Since: 3.24
1986  **/
1987 CamelNamedFlags *
camel_message_info_dup_user_flags(const CamelMessageInfo * mi)1988 camel_message_info_dup_user_flags (const CamelMessageInfo *mi)
1989 {
1990 	CamelMessageInfoClass *klass;
1991 	CamelNamedFlags *result;
1992 
1993 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
1994 
1995 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
1996 	g_return_val_if_fail (klass != NULL, NULL);
1997 	g_return_val_if_fail (klass->dup_user_flags != NULL, NULL);
1998 
1999 	camel_message_info_property_lock (mi);
2000 	result = klass->dup_user_flags (mi);
2001 	camel_message_info_property_unlock (mi);
2002 
2003 	return result;
2004 }
2005 
2006 /**
2007  * camel_message_info_take_user_flags:
2008  * @mi: a #CamelMessageInfo
2009  * @user_flags: (transfer full) (nullable): user flags to set
2010  *
2011  * Takes all the @user_flags, which replaces any current user flags on the @mi.
2012  * The passed-in @user_flags is consumed by the @mi, which becomes an owner
2013  * of it. The caller should not change @user_flags afterwards.
2014  *
2015  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
2016  * set automatically, unless the @mi is aborting notifications. There is also emitted
2017  * folder's "changed" signal for this @mi, if necessary.
2018  *
2019  * Note that it's not safe to use the @user_flags after the call to this function,
2020  * because it can be freed due to no change.
2021  *
2022  * Returns: Whether the message info changed.
2023  *
2024  * Since: 3.24
2025  **/
2026 gboolean
camel_message_info_take_user_flags(CamelMessageInfo * mi,CamelNamedFlags * user_flags)2027 camel_message_info_take_user_flags (CamelMessageInfo *mi,
2028 				    CamelNamedFlags *user_flags)
2029 {
2030 	CamelMessageInfoClass *klass;
2031 	gboolean changed, abort_notifications;
2032 
2033 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
2034 
2035 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
2036 	g_return_val_if_fail (klass != NULL, FALSE);
2037 	g_return_val_if_fail (klass->take_user_flags != NULL, FALSE);
2038 
2039 	camel_message_info_property_lock (mi);
2040 	changed = klass->take_user_flags (mi, user_flags);
2041 	abort_notifications = mi->priv->abort_notifications;
2042 	camel_message_info_property_unlock (mi);
2043 
2044 	if (changed && !abort_notifications) {
2045 		g_object_notify (G_OBJECT (mi), "user-flags");
2046 		camel_message_info_set_dirty (mi, TRUE);
2047 		camel_message_info_set_folder_flagged (mi, TRUE);
2048 
2049 		camel_message_info_update_summary_and_folder (mi, FALSE);
2050 	}
2051 
2052 	return changed;
2053 }
2054 
2055 /**
2056  * camel_message_info_get_user_tag:
2057  * @mi: a #CamelMessageInfo
2058  * @name: user tag name
2059  *
2060  * Returns: (transfer none) (nullable): Value of the user tag, or %NULL when
2061  *   it is not set.
2062  *
2063  * Since: 3.24
2064  **/
2065 const gchar *
camel_message_info_get_user_tag(const CamelMessageInfo * mi,const gchar * name)2066 camel_message_info_get_user_tag (const CamelMessageInfo *mi,
2067 				 const gchar *name)
2068 {
2069 	CamelMessageInfoClass *klass;
2070 	const gchar *result;
2071 
2072 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
2073 	g_return_val_if_fail (name != NULL, NULL);
2074 
2075 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
2076 	g_return_val_if_fail (klass != NULL, NULL);
2077 	g_return_val_if_fail (klass->get_user_tag != NULL, NULL);
2078 
2079 	camel_message_info_property_lock (mi);
2080 	result = klass->get_user_tag (mi, name);
2081 	camel_message_info_property_unlock (mi);
2082 
2083 	return result;
2084 }
2085 
2086 /**
2087  * camel_message_info_dup_user_tag:
2088  * @mi: a #CamelMessageInfo
2089  * @name: user tag name
2090  *
2091  * Returns: (transfer full) (nullable): Value of the user tag as newly allocated
2092  *   string, or %NULL when it is not set. Free it with g_free() when no longer needed.
2093  *
2094  * Since: 3.24
2095  **/
2096 gchar *
camel_message_info_dup_user_tag(const CamelMessageInfo * mi,const gchar * name)2097 camel_message_info_dup_user_tag (const CamelMessageInfo *mi,
2098 				 const gchar *name)
2099 {
2100 	gchar *result;
2101 
2102 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
2103 	g_return_val_if_fail (name != NULL, NULL);
2104 
2105 	camel_message_info_property_lock (mi);
2106 	result = g_strdup (camel_message_info_get_user_tag (mi, name));
2107 	camel_message_info_property_unlock (mi);
2108 
2109 	return result;
2110 }
2111 
2112 /**
2113  * camel_message_info_set_user_tag:
2114  * @mi: a #CamelMessageInfo
2115  * @name: user tag name
2116  * @value: (nullable): user tag value, or %NULL to remove the user tag
2117  *
2118  * Set user tag @name to @value, or remove it, if @value is %NULL.
2119  *
2120  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
2121  * set automatically, unless the @mi is aborting notifications. There is also emitted
2122  * folder's "changed" signal for this @mi, if necessary.
2123  *
2124  * Returns: Whether the @mi changed.
2125  *
2126  * Since: 3.24
2127  **/
2128 gboolean
camel_message_info_set_user_tag(CamelMessageInfo * mi,const gchar * name,const gchar * value)2129 camel_message_info_set_user_tag (CamelMessageInfo *mi,
2130 				 const gchar *name,
2131 				 const gchar *value)
2132 {
2133 	CamelMessageInfoClass *klass;
2134 	gboolean changed, abort_notifications;
2135 
2136 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
2137 	g_return_val_if_fail (name != NULL, FALSE);
2138 
2139 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
2140 	g_return_val_if_fail (klass != NULL, FALSE);
2141 	g_return_val_if_fail (klass->set_user_tag != NULL, FALSE);
2142 
2143 	camel_message_info_property_lock (mi);
2144 	changed = klass->set_user_tag (mi, name, value);
2145 	abort_notifications = mi->priv->abort_notifications;
2146 	camel_message_info_property_unlock (mi);
2147 
2148 	if (changed && !abort_notifications) {
2149 		g_object_notify (G_OBJECT (mi), "user-tags");
2150 		camel_message_info_set_dirty (mi, TRUE);
2151 		camel_message_info_set_folder_flagged (mi, TRUE);
2152 
2153 		camel_message_info_update_summary_and_folder (mi, FALSE);
2154 	}
2155 
2156 	return changed;
2157 }
2158 
2159 /**
2160  * camel_message_info_get_user_tags:
2161  * @mi: a #CamelMessageInfo
2162  *
2163  * Returns: (transfer none) (nullable): a #CamelNameValueArray containing all set
2164  *   user tags of the @mi. Do not modify it.
2165  *
2166  * Since: 3.24
2167  **/
2168 const CamelNameValueArray *
camel_message_info_get_user_tags(const CamelMessageInfo * mi)2169 camel_message_info_get_user_tags (const CamelMessageInfo *mi)
2170 {
2171 	CamelMessageInfoClass *klass;
2172 	const CamelNameValueArray *result;
2173 
2174 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
2175 
2176 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
2177 	g_return_val_if_fail (klass != NULL, NULL);
2178 	g_return_val_if_fail (klass->get_user_tags != NULL, NULL);
2179 
2180 	camel_message_info_property_lock (mi);
2181 	result = klass->get_user_tags (mi);
2182 	camel_message_info_property_unlock (mi);
2183 
2184 	return result;
2185 }
2186 
2187 /**
2188  * camel_message_info_dup_user_tags:
2189  * @mi: a #CamelMessageInfo
2190  *
2191  * Returns: (transfer full) (nullable): a newly allocated #CamelNameValueArray containing all set
2192  *   user tags of the @mi. Free it with camel_name_value_array_free() when no longer needed.
2193  *
2194  * Since: 3.24
2195  **/
2196 CamelNameValueArray *
camel_message_info_dup_user_tags(const CamelMessageInfo * mi)2197 camel_message_info_dup_user_tags (const CamelMessageInfo *mi)
2198 {
2199 	CamelMessageInfoClass *klass;
2200 	CamelNameValueArray *result;
2201 
2202 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
2203 
2204 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
2205 	g_return_val_if_fail (klass != NULL, NULL);
2206 	g_return_val_if_fail (klass->dup_user_tags != NULL, NULL);
2207 
2208 	camel_message_info_property_lock (mi);
2209 	result = klass->dup_user_tags (mi);
2210 	camel_message_info_property_unlock (mi);
2211 
2212 	return result;
2213 }
2214 
2215 /**
2216  * camel_message_info_take_user_tags:
2217  * @mi: a #CamelMessageInfo
2218  * @user_tags: (transfer full) (nullable): user tags to set
2219  *
2220  * Takes all the @user_tags, which replaces any current user tags on the @mi.
2221  * The passed-in @user_tags is consumed by the @mi, which becomes an owner
2222  * of it. The caller should not change @user_tags afterwards.
2223  *
2224  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
2225  * set automatically, unless the @mi is aborting notifications. There is also emitted
2226  * folder's "changed" signal for this @mi, if necessary.
2227  *
2228  * Note that it's not safe to use the @user_tags after the call to this function,
2229  * because it can be freed due to no change.
2230  *
2231  * Returns: Whether the @mi changed.
2232  *
2233  * Since: 3.24
2234  **/
2235 gboolean
camel_message_info_take_user_tags(CamelMessageInfo * mi,CamelNameValueArray * user_tags)2236 camel_message_info_take_user_tags (CamelMessageInfo *mi,
2237 				   CamelNameValueArray *user_tags)
2238 {
2239 	CamelMessageInfoClass *klass;
2240 	gboolean changed, abort_notifications;
2241 
2242 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
2243 
2244 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
2245 	g_return_val_if_fail (klass != NULL, FALSE);
2246 	g_return_val_if_fail (klass->take_user_tags != NULL, FALSE);
2247 
2248 	camel_message_info_property_lock (mi);
2249 	changed = klass->take_user_tags (mi, user_tags);
2250 	abort_notifications = mi->priv->abort_notifications;
2251 	camel_message_info_property_unlock (mi);
2252 
2253 	if (changed && !abort_notifications) {
2254 		g_object_notify (G_OBJECT (mi), "user-tags");
2255 		camel_message_info_set_dirty (mi, TRUE);
2256 		camel_message_info_set_folder_flagged (mi, TRUE);
2257 
2258 		camel_message_info_update_summary_and_folder (mi, FALSE);
2259 	}
2260 
2261 	return changed;
2262 }
2263 
2264 /**
2265  * camel_message_info_get_subject:
2266  * @mi: a #CamelMessageInfo
2267  *
2268  * Returns: (transfer none): Subject of the #mi.
2269  *
2270  * Since: 3.24
2271  **/
2272 const gchar *
camel_message_info_get_subject(const CamelMessageInfo * mi)2273 camel_message_info_get_subject (const CamelMessageInfo *mi)
2274 {
2275 	CamelMessageInfoClass *klass;
2276 	const gchar *result;
2277 
2278 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
2279 
2280 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
2281 	g_return_val_if_fail (klass != NULL, NULL);
2282 	g_return_val_if_fail (klass->get_subject != NULL, NULL);
2283 
2284 	camel_message_info_property_lock (mi);
2285 	result = klass->get_subject (mi);
2286 	camel_message_info_property_unlock (mi);
2287 
2288 	return result;
2289 }
2290 
2291 /**
2292  * camel_message_info_set_subject:
2293  * @mi: a #CamelMessageInfo
2294  * @subject: (nullable): a Subject to set
2295  *
2296  * Sets Subject from the associated message.
2297  *
2298  * This property is considered static, in a meaning that it should
2299  * not change during the life-time of the @mi, the same as it doesn't
2300  * change in the associated message.
2301  *
2302  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
2303  * set automatically, unless the @mi is aborting notifications. There is not emitted
2304  * folder's "changed" signal for this @mi.
2305  *
2306  * Returns: Whether the value changed.
2307  *
2308  * Since: 3.24
2309  **/
2310 gboolean
camel_message_info_set_subject(CamelMessageInfo * mi,const gchar * subject)2311 camel_message_info_set_subject (CamelMessageInfo *mi,
2312 				const gchar *subject)
2313 {
2314 	CamelMessageInfoClass *klass;
2315 	gboolean changed, abort_notifications;
2316 
2317 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
2318 
2319 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
2320 	g_return_val_if_fail (klass != NULL, FALSE);
2321 	g_return_val_if_fail (klass->set_subject != NULL, FALSE);
2322 
2323 	camel_message_info_property_lock (mi);
2324 	changed = klass->set_subject (mi, subject);
2325 	abort_notifications = mi->priv->abort_notifications;
2326 	camel_message_info_property_unlock (mi);
2327 
2328 	if (changed && !abort_notifications) {
2329 		g_object_notify (G_OBJECT (mi), "subject");
2330 		camel_message_info_set_dirty (mi, TRUE);
2331 		camel_message_info_set_folder_flagged (mi, TRUE);
2332 	}
2333 
2334 	return changed;
2335 }
2336 
2337 /**
2338  * camel_message_info_get_from:
2339  * @mi: a #CamelMessageInfo
2340  *
2341  * Returns: (transfer none): From address of the @mi.
2342  *
2343  * Since: 3.24
2344  **/
2345 const gchar *
camel_message_info_get_from(const CamelMessageInfo * mi)2346 camel_message_info_get_from (const CamelMessageInfo *mi)
2347 {
2348 	CamelMessageInfoClass *klass;
2349 	const gchar *result;
2350 
2351 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
2352 
2353 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
2354 	g_return_val_if_fail (klass != NULL, NULL);
2355 	g_return_val_if_fail (klass->get_from != NULL, NULL);
2356 
2357 	camel_message_info_property_lock (mi);
2358 	result = klass->get_from (mi);
2359 	camel_message_info_property_unlock (mi);
2360 
2361 	return result;
2362 }
2363 
2364 /**
2365  * camel_message_info_set_from:
2366  * @mi: a #CamelMessageInfo
2367  * @from: (nullable): a From to set
2368  *
2369  * Sets From from the associated message.
2370  *
2371  * This property is considered static, in a meaning that it should
2372  * not change during the life-time of the @mi, the same as it doesn't
2373  * change in the associated message.
2374  *
2375  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
2376  * set automatically, unless the @mi is aborting notifications. There is not emitted
2377  * folder's "changed" signal for this @mi.
2378  *
2379  * Returns: Whether the value changed.
2380  *
2381  * Since: 3.24
2382  **/
2383 gboolean
camel_message_info_set_from(CamelMessageInfo * mi,const gchar * from)2384 camel_message_info_set_from (CamelMessageInfo *mi,
2385 			     const gchar *from)
2386 {
2387 	CamelMessageInfoClass *klass;
2388 	gboolean changed, abort_notifications;
2389 
2390 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
2391 
2392 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
2393 	g_return_val_if_fail (klass != NULL, FALSE);
2394 	g_return_val_if_fail (klass->set_from != NULL, FALSE);
2395 
2396 	camel_message_info_property_lock (mi);
2397 	changed = klass->set_from (mi, from);
2398 	abort_notifications = mi->priv->abort_notifications;
2399 	camel_message_info_property_unlock (mi);
2400 
2401 	if (changed && !abort_notifications) {
2402 		g_object_notify (G_OBJECT (mi), "from");
2403 		camel_message_info_set_dirty (mi, TRUE);
2404 		camel_message_info_set_folder_flagged (mi, TRUE);
2405 	}
2406 
2407 	return changed;
2408 }
2409 
2410 /**
2411  * camel_message_info_get_to:
2412  * @mi: a #CamelMessageInfo
2413  *
2414  * Returns: (transfer none): To address of the @mi.
2415  *
2416  * Since: 3.24
2417  **/
2418 const gchar *
camel_message_info_get_to(const CamelMessageInfo * mi)2419 camel_message_info_get_to (const CamelMessageInfo *mi)
2420 {
2421 	CamelMessageInfoClass *klass;
2422 	const gchar *result;
2423 
2424 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
2425 
2426 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
2427 	g_return_val_if_fail (klass != NULL, NULL);
2428 	g_return_val_if_fail (klass->get_to != NULL, NULL);
2429 
2430 	camel_message_info_property_lock (mi);
2431 	result = klass->get_to (mi);
2432 	camel_message_info_property_unlock (mi);
2433 
2434 	return result;
2435 }
2436 
2437 /**
2438  * camel_message_info_set_to:
2439  * @mi: a #CamelMessageInfo
2440  * @to: (nullable): a To to set
2441  *
2442  * Sets To from the associated message.
2443  *
2444  * This property is considered static, in a meaning that it should
2445  * not change during the life-time of the @mi, the same as it doesn't
2446  * change in the associated message.
2447  *
2448  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
2449  * set automatically, unless the @mi is aborting notifications. There is not emitted
2450  * folder's "changed" signal for this @mi.
2451  *
2452  * Returns: Whether the value changed.
2453  *
2454  * Since: 3.24
2455  **/
2456 gboolean
camel_message_info_set_to(CamelMessageInfo * mi,const gchar * to)2457 camel_message_info_set_to (CamelMessageInfo *mi,
2458 			   const gchar *to)
2459 {
2460 	CamelMessageInfoClass *klass;
2461 	gboolean changed, abort_notifications;
2462 
2463 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
2464 
2465 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
2466 	g_return_val_if_fail (klass != NULL, FALSE);
2467 	g_return_val_if_fail (klass->set_to != NULL, FALSE);
2468 
2469 	camel_message_info_property_lock (mi);
2470 	changed = klass->set_to (mi, to);
2471 	abort_notifications = mi->priv->abort_notifications;
2472 	camel_message_info_property_unlock (mi);
2473 
2474 	if (changed && !abort_notifications) {
2475 		g_object_notify (G_OBJECT (mi), "to");
2476 		camel_message_info_set_dirty (mi, TRUE);
2477 		camel_message_info_set_folder_flagged (mi, TRUE);
2478 	}
2479 
2480 	return changed;
2481 }
2482 
2483 /**
2484  * camel_message_info_get_cc:
2485  * @mi: a #CamelMessageInfo
2486  *
2487  * Returns: (transfer none): CC address of the @mi.
2488  *
2489  * Since: 3.24
2490  **/
2491 const gchar *
camel_message_info_get_cc(const CamelMessageInfo * mi)2492 camel_message_info_get_cc (const CamelMessageInfo *mi)
2493 {
2494 	CamelMessageInfoClass *klass;
2495 	const gchar *result;
2496 
2497 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
2498 
2499 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
2500 	g_return_val_if_fail (klass != NULL, NULL);
2501 	g_return_val_if_fail (klass->get_cc != NULL, NULL);
2502 
2503 	camel_message_info_property_lock (mi);
2504 	result = klass->get_cc (mi);
2505 	camel_message_info_property_unlock (mi);
2506 
2507 	return result;
2508 }
2509 
2510 /**
2511  * camel_message_info_set_cc:
2512  * @mi: a #CamelMessageInfo
2513  * @cc: (nullable): a CC to set
2514  *
2515  * Sets CC from the associated message.
2516  *
2517  * This property is considered static, in a meaning that it should
2518  * not change during the life-time of the @mi, the same as it doesn't
2519  * change in the associated message.
2520  *
2521  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
2522  * set automatically, unless the @mi is aborting notifications. There is not emitted
2523  * folder's "changed" signal for this @mi.
2524  *
2525  * Returns: Whether the value changed.
2526  *
2527  * Since: 3.24
2528  **/
2529 gboolean
camel_message_info_set_cc(CamelMessageInfo * mi,const gchar * cc)2530 camel_message_info_set_cc (CamelMessageInfo *mi,
2531 			   const gchar *cc)
2532 {
2533 	CamelMessageInfoClass *klass;
2534 	gboolean changed, abort_notifications;
2535 
2536 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
2537 
2538 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
2539 	g_return_val_if_fail (klass != NULL, FALSE);
2540 	g_return_val_if_fail (klass->set_cc != NULL, FALSE);
2541 
2542 	camel_message_info_property_lock (mi);
2543 	changed = klass->set_cc (mi, cc);
2544 	abort_notifications = mi->priv->abort_notifications;
2545 	camel_message_info_property_unlock (mi);
2546 
2547 	if (changed && !abort_notifications) {
2548 		g_object_notify (G_OBJECT (mi), "cc");
2549 		camel_message_info_set_dirty (mi, TRUE);
2550 		camel_message_info_set_folder_flagged (mi, TRUE);
2551 	}
2552 
2553 	return changed;
2554 }
2555 
2556 /**
2557  * camel_message_info_get_mlist:
2558  * @mi: a #CamelMessageInfo
2559  *
2560  * Returns: (transfer none): Mailing list address of the @mi.
2561  *
2562  * Since: 3.24
2563  **/
2564 const gchar *
camel_message_info_get_mlist(const CamelMessageInfo * mi)2565 camel_message_info_get_mlist (const CamelMessageInfo *mi)
2566 {
2567 	CamelMessageInfoClass *klass;
2568 	const gchar *result;
2569 
2570 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
2571 
2572 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
2573 	g_return_val_if_fail (klass != NULL, NULL);
2574 	g_return_val_if_fail (klass->get_mlist != NULL, NULL);
2575 
2576 	camel_message_info_property_lock (mi);
2577 	result = klass->get_mlist (mi);
2578 	camel_message_info_property_unlock (mi);
2579 
2580 	return result;
2581 }
2582 
2583 /**
2584  * camel_message_info_set_mlist:
2585  * @mi: a #CamelMessageInfo
2586  * @mlist: (nullable): a message list address to set
2587  *
2588  * Sets mesage list address from the associated message.
2589  *
2590  * This property is considered static, in a meaning that it should
2591  * not change during the life-time of the @mi, the same as it doesn't
2592  * change in the associated message.
2593  *
2594  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
2595  * set automatically, unless the @mi is aborting notifications. There is not emitted
2596  * folder's "changed" signal for this @mi.
2597  *
2598  * Returns: Whether the value changed.
2599  *
2600  * Since: 3.24
2601  **/
2602 gboolean
camel_message_info_set_mlist(CamelMessageInfo * mi,const gchar * mlist)2603 camel_message_info_set_mlist (CamelMessageInfo *mi,
2604 			      const gchar *mlist)
2605 {
2606 	CamelMessageInfoClass *klass;
2607 	gboolean changed, abort_notifications;
2608 
2609 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
2610 
2611 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
2612 	g_return_val_if_fail (klass != NULL, FALSE);
2613 	g_return_val_if_fail (klass->set_mlist != NULL, FALSE);
2614 
2615 	camel_message_info_property_lock (mi);
2616 	changed = klass->set_mlist (mi, mlist);
2617 	abort_notifications = mi->priv->abort_notifications;
2618 	camel_message_info_property_unlock (mi);
2619 
2620 	if (changed && !abort_notifications) {
2621 		g_object_notify (G_OBJECT (mi), "mlist");
2622 		camel_message_info_set_dirty (mi, TRUE);
2623 		camel_message_info_set_folder_flagged (mi, TRUE);
2624 	}
2625 
2626 	return changed;
2627 }
2628 
2629 /**
2630  * camel_message_info_get_size:
2631  * @mi: a #CamelMessageInfo
2632  *
2633  * Returns: Size of the associated message.
2634  *
2635  * Since: 3.24
2636  **/
2637 guint32
camel_message_info_get_size(const CamelMessageInfo * mi)2638 camel_message_info_get_size (const CamelMessageInfo *mi)
2639 {
2640 	CamelMessageInfoClass *klass;
2641 	guint32 result;
2642 
2643 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), 0);
2644 
2645 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
2646 	g_return_val_if_fail (klass != NULL, 0);
2647 	g_return_val_if_fail (klass->get_size != NULL, 0);
2648 
2649 	camel_message_info_property_lock (mi);
2650 	result = klass->get_size (mi);
2651 	camel_message_info_property_unlock (mi);
2652 
2653 	return result;
2654 }
2655 
2656 /**
2657  * camel_message_info_set_size:
2658  * @mi: a #CamelMessageInfo
2659  * @size: a size to set
2660  *
2661  * Sets size of the associated message.
2662  *
2663  * This property is considered static, in a meaning that it should
2664  * not change during the life-time of the @mi, the same as it doesn't
2665  * change in the associated message.
2666  *
2667  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
2668  * set automatically, unless the @mi is aborting notifications. There is not emitted
2669  * folder's "changed" signal for this @mi.
2670  *
2671  * Returns: Whether the value changed.
2672  *
2673  * Since: 3.24
2674  **/
2675 gboolean
camel_message_info_set_size(CamelMessageInfo * mi,guint32 size)2676 camel_message_info_set_size (CamelMessageInfo *mi,
2677 			     guint32 size)
2678 {
2679 	CamelMessageInfoClass *klass;
2680 	gboolean changed, abort_notifications;
2681 
2682 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
2683 
2684 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
2685 	g_return_val_if_fail (klass != NULL, FALSE);
2686 	g_return_val_if_fail (klass->set_size != NULL, FALSE);
2687 
2688 	camel_message_info_property_lock (mi);
2689 	changed = klass->set_size (mi, size);
2690 	abort_notifications = mi->priv->abort_notifications;
2691 	camel_message_info_property_unlock (mi);
2692 
2693 	if (changed && !abort_notifications) {
2694 		g_object_notify (G_OBJECT (mi), "size");
2695 		camel_message_info_set_dirty (mi, TRUE);
2696 		camel_message_info_set_folder_flagged (mi, TRUE);
2697 	}
2698 
2699 	return changed;
2700 }
2701 
2702 /**
2703  * camel_message_info_get_date_sent:
2704  * @mi: a #CamelMessageInfo
2705  *
2706  * Returns: time_t of the Date header of the message, encoded as gint64.
2707  *
2708  * Since: 3.24
2709  **/
2710 gint64
camel_message_info_get_date_sent(const CamelMessageInfo * mi)2711 camel_message_info_get_date_sent (const CamelMessageInfo *mi)
2712 {
2713 	CamelMessageInfoClass *klass;
2714 	gint64 result;
2715 
2716 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), 0);
2717 
2718 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
2719 	g_return_val_if_fail (klass != NULL, 0);
2720 	g_return_val_if_fail (klass->get_date_sent != NULL, 0);
2721 
2722 	camel_message_info_property_lock (mi);
2723 	result = klass->get_date_sent (mi);
2724 	camel_message_info_property_unlock (mi);
2725 
2726 	return result;
2727 }
2728 
2729 /**
2730  * camel_message_info_set_date_sent:
2731  * @mi: a #CamelMessageInfo
2732  * @date_sent: a sent date to set
2733  *
2734  * Sets sent date (the Date header) of the associated message.
2735  *
2736  * This property is considered static, in a meaning that it should
2737  * not change during the life-time of the @mi, the same as it doesn't
2738  * change in the associated message.
2739  *
2740  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
2741  * set automatically, unless the @mi is aborting notifications. There is not emitted
2742  * folder's "changed" signal for this @mi.
2743  *
2744  * Returns: Whether the value changed.
2745  *
2746  * Since: 3.24
2747  **/
2748 gboolean
camel_message_info_set_date_sent(CamelMessageInfo * mi,gint64 date_sent)2749 camel_message_info_set_date_sent (CamelMessageInfo *mi,
2750 				  gint64 date_sent)
2751 {
2752 	CamelMessageInfoClass *klass;
2753 	gboolean changed, abort_notifications;
2754 
2755 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
2756 
2757 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
2758 	g_return_val_if_fail (klass != NULL, FALSE);
2759 	g_return_val_if_fail (klass->set_date_sent != NULL, FALSE);
2760 
2761 	camel_message_info_property_lock (mi);
2762 	changed = klass->set_date_sent (mi, date_sent);
2763 	abort_notifications = mi->priv->abort_notifications;
2764 	camel_message_info_property_unlock (mi);
2765 
2766 	if (changed && !abort_notifications) {
2767 		g_object_notify (G_OBJECT (mi), "date-sent");
2768 		camel_message_info_set_dirty (mi, TRUE);
2769 		camel_message_info_set_folder_flagged (mi, TRUE);
2770 	}
2771 
2772 	return changed;
2773 }
2774 
2775 /**
2776  * camel_message_info_get_date_received:
2777  * @mi: a #CamelMessageInfo
2778  *
2779  * Returns: time_t of the Received header of the message, encoded as gint64.
2780  *
2781  * Since: 3.24
2782  **/
2783 gint64
camel_message_info_get_date_received(const CamelMessageInfo * mi)2784 camel_message_info_get_date_received (const CamelMessageInfo *mi)
2785 {
2786 	CamelMessageInfoClass *klass;
2787 	gint64 result;
2788 
2789 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), 0);
2790 
2791 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
2792 	g_return_val_if_fail (klass != NULL, 0);
2793 	g_return_val_if_fail (klass->get_date_received != NULL, 0);
2794 
2795 	camel_message_info_property_lock (mi);
2796 	result = klass->get_date_received (mi);
2797 	camel_message_info_property_unlock (mi);
2798 
2799 	return result;
2800 }
2801 
2802 /**
2803  * camel_message_info_set_date_received:
2804  * @mi: a #CamelMessageInfo
2805  * @date_received: a received date to set
2806  *
2807  * Sets received date (the Received header) of the associated message.
2808  *
2809  * This property is considered static, in a meaning that it should
2810  * not change during the life-time of the @mi, the same as it doesn't
2811  * change in the associated message.
2812  *
2813  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
2814  * set automatically, unless the @mi is aborting notifications. There is not emitted
2815  * folder's "changed" signal for this @mi.
2816  *
2817  * Returns: Whether the value changed.
2818  *
2819  * Since: 3.24
2820  **/
2821 gboolean
camel_message_info_set_date_received(CamelMessageInfo * mi,gint64 date_received)2822 camel_message_info_set_date_received (CamelMessageInfo *mi,
2823 				      gint64 date_received)
2824 {
2825 	CamelMessageInfoClass *klass;
2826 	gboolean changed, abort_notifications;
2827 
2828 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
2829 
2830 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
2831 	g_return_val_if_fail (klass != NULL, FALSE);
2832 	g_return_val_if_fail (klass->set_date_received != NULL, FALSE);
2833 
2834 	camel_message_info_property_lock (mi);
2835 	changed = klass->set_date_received (mi, date_received);
2836 	abort_notifications = mi->priv->abort_notifications;
2837 	camel_message_info_property_unlock (mi);
2838 
2839 	if (changed && !abort_notifications) {
2840 		g_object_notify (G_OBJECT (mi), "date-received");
2841 		camel_message_info_set_dirty (mi, TRUE);
2842 		camel_message_info_set_folder_flagged (mi, TRUE);
2843 	}
2844 
2845 	return changed;
2846 }
2847 
2848 /**
2849  * camel_message_info_get_message_id:
2850  * @mi: a #CamelMessageInfo
2851  *
2852  * Encoded Message-ID of the associated message as a guint64 number,
2853  * partial MD5 sum. The value can be cast to #CamelSummaryMessageID.
2854  *
2855  * Returns: Partial MD5 hash of the Message-ID header of the associated message.
2856  *
2857  * Since: 3.24
2858  **/
2859 guint64
camel_message_info_get_message_id(const CamelMessageInfo * mi)2860 camel_message_info_get_message_id (const CamelMessageInfo *mi)
2861 {
2862 	CamelMessageInfoClass *klass;
2863 	guint64 result;
2864 
2865 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), 0);
2866 
2867 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
2868 	g_return_val_if_fail (klass != NULL, 0);
2869 	g_return_val_if_fail (klass->get_message_id != NULL, 0);
2870 
2871 	camel_message_info_property_lock (mi);
2872 	result = klass->get_message_id (mi);
2873 	camel_message_info_property_unlock (mi);
2874 
2875 	return result;
2876 }
2877 
2878 /**
2879  * camel_message_info_set_message_id:
2880  * @mi: a #CamelMessageInfo
2881  * @message_id: a message id to set
2882  *
2883  * Sets encoded Message-ID of the associated message as a guint64 number,
2884  * partial MD5 sum. The value can be cast to #CamelSummaryMessageID.
2885  *
2886  * This property is considered static, in a meaning that it should
2887  * not change during the life-time of the @mi, the same as it doesn't
2888  * change in the associated message.
2889  *
2890  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
2891  * set automatically, unless the @mi is aborting notifications. There is not emitted
2892  * folder's "changed" signal for this @mi.
2893  *
2894  * Returns: Whether the value changed.
2895  *
2896  * Since: 3.24
2897  **/
2898 gboolean
camel_message_info_set_message_id(CamelMessageInfo * mi,guint64 message_id)2899 camel_message_info_set_message_id (CamelMessageInfo *mi,
2900 				   guint64 message_id)
2901 {
2902 	CamelMessageInfoClass *klass;
2903 	gboolean changed, abort_notifications;
2904 
2905 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
2906 
2907 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
2908 	g_return_val_if_fail (klass != NULL, FALSE);
2909 	g_return_val_if_fail (klass->set_message_id != NULL, FALSE);
2910 
2911 	camel_message_info_property_lock (mi);
2912 	changed = klass->set_message_id (mi, message_id);
2913 	abort_notifications = mi->priv->abort_notifications;
2914 	camel_message_info_property_unlock (mi);
2915 
2916 	if (changed && !abort_notifications) {
2917 		g_object_notify (G_OBJECT (mi), "message-id");
2918 		camel_message_info_set_dirty (mi, TRUE);
2919 		camel_message_info_set_folder_flagged (mi, TRUE);
2920 	}
2921 
2922 	return changed;
2923 }
2924 
2925 /**
2926  * camel_message_info_get_references:
2927  * @mi: a #CamelMessageInfo
2928  *
2929  * Gets encoded In-Reply-To and References headers of the associated
2930  * message as an array of guint64 numbers, partial MD5 sums. Each value
2931  * can be cast to #CamelSummaryMessageID.
2932  *
2933  * Returns: (transfer none) (nullable) (element-type guint64): A #GArray of
2934  *   guint64 encoded Message-ID-s; or %NULL when none are available.
2935  *
2936  * Since: 3.24
2937  **/
2938 const GArray *
camel_message_info_get_references(const CamelMessageInfo * mi)2939 camel_message_info_get_references (const CamelMessageInfo *mi)
2940 {
2941 	CamelMessageInfoClass *klass;
2942 	const GArray *result;
2943 
2944 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
2945 
2946 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
2947 	g_return_val_if_fail (klass != NULL, NULL);
2948 	g_return_val_if_fail (klass->get_references != NULL, NULL);
2949 
2950 	camel_message_info_property_lock (mi);
2951 	result = klass->get_references (mi);
2952 	camel_message_info_property_unlock (mi);
2953 
2954 	return result;
2955 }
2956 
2957 /**
2958  * camel_message_info_dup_references:
2959  * @mi: a #CamelMessageInfo
2960  *
2961  * Duplicates encoded In-Reply-To and References headers of the associated
2962  * message as an array of guint64 numbers, partial MD5 sums. Each value
2963  * can be cast to #CamelSummaryMessageID.
2964  *
2965  * Returns: (transfer full) (nullable) (element-type guint64): A #GArray of
2966  *   guint64 encoded Message-ID-s; or %NULL when none are available. Free returned
2967  *   array with g_array_unref() when no longer needed.
2968  *
2969  * Since: 3.24
2970  **/
2971 GArray *
camel_message_info_dup_references(const CamelMessageInfo * mi)2972 camel_message_info_dup_references (const CamelMessageInfo *mi)
2973 {
2974 	const GArray *arr;
2975 	GArray *result;
2976 
2977 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
2978 
2979 	camel_message_info_property_lock (mi);
2980 	arr = camel_message_info_get_references (mi);
2981 	if (arr) {
2982 		guint ii;
2983 
2984 		result = g_array_sized_new (FALSE, FALSE, sizeof (guint64), arr->len);
2985 		for (ii = 0; ii < arr->len; ii++) {
2986 			g_array_append_val (result, g_array_index (arr, guint64, ii));
2987 		}
2988 	} else {
2989 		result = NULL;
2990 	}
2991 	camel_message_info_property_unlock (mi);
2992 
2993 	return result;
2994 }
2995 
2996 /**
2997  * camel_message_info_take_references:
2998  * @mi: a #CamelMessageInfo
2999  * @references: (element-type guint64) (transfer full) (nullable): a references to set
3000  *
3001  * Takes encoded In-Reply-To and References headers of the associated message
3002  * as an array of guint64 numbers, partial MD5 sums. Each value can be
3003  * cast to #CamelSummaryMessageID.
3004  *
3005  * This property is considered static, in a meaning that it should
3006  * not change during the life-time of the @mi, the same as it doesn't
3007  * change in the associated message.
3008  *
3009  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
3010  * set automatically, unless the @mi is aborting notifications. There is not emitted
3011  * folder's "changed" signal for this @mi.
3012  *
3013  * Note that it's not safe to use the @references after the call to this function,
3014  * because it can be freed due to no change.
3015  *
3016  * Returns: Whether the value changed.
3017  *
3018  * Since: 3.24
3019  **/
3020 gboolean
camel_message_info_take_references(CamelMessageInfo * mi,GArray * references)3021 camel_message_info_take_references (CamelMessageInfo *mi,
3022 				    GArray *references)
3023 {
3024 	CamelMessageInfoClass *klass;
3025 	gboolean changed, abort_notifications;
3026 
3027 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
3028 
3029 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
3030 	g_return_val_if_fail (klass != NULL, FALSE);
3031 	g_return_val_if_fail (klass->take_references != NULL, FALSE);
3032 
3033 	camel_message_info_property_lock (mi);
3034 	changed = klass->take_references (mi, references);
3035 	abort_notifications = mi->priv->abort_notifications;
3036 	camel_message_info_property_unlock (mi);
3037 
3038 	if (changed && !abort_notifications) {
3039 		g_object_notify (G_OBJECT (mi), "references");
3040 		camel_message_info_set_dirty (mi, TRUE);
3041 		camel_message_info_set_folder_flagged (mi, TRUE);
3042 	}
3043 
3044 	return changed;
3045 }
3046 
3047 /**
3048  * camel_message_info_get_headers:
3049  * @mi: a #CamelMessageInfo
3050  *
3051  * Returns: (transfer none) (nullable): All the message headers of the associated
3052  *   message, or %NULL, when none are available.
3053  *
3054  * Since: 3.24
3055  **/
3056 const CamelNameValueArray *
camel_message_info_get_headers(const CamelMessageInfo * mi)3057 camel_message_info_get_headers (const CamelMessageInfo *mi)
3058 {
3059 	CamelMessageInfoClass *klass;
3060 	const CamelNameValueArray *result;
3061 
3062 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
3063 
3064 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
3065 	g_return_val_if_fail (klass != NULL, NULL);
3066 	g_return_val_if_fail (klass->get_headers != NULL, NULL);
3067 
3068 	camel_message_info_property_lock (mi);
3069 	result = klass->get_headers (mi);
3070 	camel_message_info_property_unlock (mi);
3071 
3072 	return result;
3073 }
3074 
3075 /**
3076  * camel_message_info_dup_headers:
3077  * @mi: a #CamelMessageInfo
3078  *
3079  * Duplicates array of headers for the @mi.
3080  *
3081  * Returns: (transfer full) (nullable): All the message headers of the associated
3082  *   message, or %NULL, when none are available. Free returned array with
3083  *   camel_name_value_array_free() when no longer needed.
3084  *
3085  * Since: 3.24
3086  **/
3087 CamelNameValueArray *
camel_message_info_dup_headers(const CamelMessageInfo * mi)3088 camel_message_info_dup_headers (const CamelMessageInfo *mi)
3089 {
3090 	const CamelNameValueArray *arr;
3091 	CamelNameValueArray *result;
3092 
3093 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
3094 
3095 	camel_message_info_property_lock (mi);
3096 	arr = camel_message_info_get_headers (mi);
3097 	if (arr) {
3098 		result = camel_name_value_array_copy (arr);
3099 	} else {
3100 		result = NULL;
3101 	}
3102 	camel_message_info_property_unlock (mi);
3103 
3104 	return result;
3105 }
3106 
3107 /**
3108  * camel_message_info_take_headers:
3109  * @mi: a #CamelMessageInfo
3110  * @headers: (transfer full) (nullable): headers to set, as #CamelNameValueArray, or %NULL
3111  *
3112  * Takes headers of the associated message.
3113  *
3114  * This property is considered static, in a meaning that it should
3115  * not change during the life-time of the @mi, the same as it doesn't
3116  * change in the associated message.
3117  *
3118  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
3119  * set automatically, unless the @mi is aborting notifications. There is not emitted
3120  * folder's "changed" signal for this @mi.
3121  *
3122  * Note that it's not safe to use the @headers after the call to this function,
3123  * because it can be freed due to no change.
3124  *
3125  * Returns: Whether the value changed.
3126  *
3127  * Since: 3.24
3128  **/
3129 gboolean
camel_message_info_take_headers(CamelMessageInfo * mi,CamelNameValueArray * headers)3130 camel_message_info_take_headers (CamelMessageInfo *mi,
3131 				 CamelNameValueArray *headers)
3132 {
3133 	CamelMessageInfoClass *klass;
3134 	gboolean changed, abort_notifications;
3135 
3136 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
3137 
3138 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
3139 	g_return_val_if_fail (klass != NULL, FALSE);
3140 	g_return_val_if_fail (klass->take_headers != NULL, FALSE);
3141 
3142 	camel_message_info_property_lock (mi);
3143 	changed = klass->take_headers (mi, headers);
3144 	abort_notifications = mi->priv->abort_notifications;
3145 	camel_message_info_property_unlock (mi);
3146 
3147 	if (changed && !abort_notifications) {
3148 		g_object_notify (G_OBJECT (mi), "headers");
3149 		camel_message_info_set_dirty (mi, TRUE);
3150 		camel_message_info_set_folder_flagged (mi, TRUE);
3151 	}
3152 
3153 	return changed;
3154 }
3155 
3156 /**
3157  * camel_message_info_get_user_header:
3158  * @mi: a #CamelMessageInfo
3159  * @name: header name
3160  *
3161  * Returns: (transfer none) (nullable): Value of the header named @name from
3162  *    the user-defined message headers of the associated message, or %NULL,
3163  *    when not available.
3164  *
3165  * Since: 3.42
3166  **/
3167 const gchar *
camel_message_info_get_user_header(const CamelMessageInfo * mi,const gchar * name)3168 camel_message_info_get_user_header (const CamelMessageInfo *mi,
3169 				    const gchar *name)
3170 {
3171 	CamelMessageInfoClass *klass;
3172 	const gchar *result;
3173 
3174 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
3175 	g_return_val_if_fail (name != NULL, NULL);
3176 
3177 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
3178 	g_return_val_if_fail (klass != NULL, NULL);
3179 	g_return_val_if_fail (klass->get_user_header != NULL, NULL);
3180 
3181 	camel_message_info_property_lock (mi);
3182 	result = klass->get_user_header (mi, name);
3183 	camel_message_info_property_unlock (mi);
3184 
3185 	return result;
3186 }
3187 
3188 /**
3189  * camel_message_info_dup_user_header:
3190  * @mi: a #CamelMessageInfo
3191  * @name: header name
3192  *
3193  * Returns: (transfer full) (nullable): Value of the header named @name from
3194  *    the user-defined message headers of the associated message, or %NULL,
3195  *    when not available. Free the returned string with g_free(), when no longer
3196  *    needed.
3197  *
3198  * Since: 3.42
3199  **/
3200 gchar *
camel_message_info_dup_user_header(const CamelMessageInfo * mi,const gchar * name)3201 camel_message_info_dup_user_header (const CamelMessageInfo *mi,
3202 				    const gchar *name)
3203 {
3204 	gchar *result;
3205 
3206 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
3207 
3208 	camel_message_info_property_lock (mi);
3209 	result = g_strdup (camel_message_info_get_user_header (mi, name));
3210 	camel_message_info_property_unlock (mi);
3211 
3212 	return result;
3213 }
3214 
3215 /**
3216  * camel_message_info_set_user_header:
3217  * @mi: a #CamelMessageInfo
3218  * @name: header name
3219  * @value: (nullable): header value, or %NULL
3220  *
3221  * Set @value for a single user-defined message header of the associated message.
3222  * When the @value is %NULL, the header @name is removed from the user-defined
3223  * headers.
3224  *
3225  * If the @mi changed, the 'dirty' flag is set automatically, unless the @mi is
3226  * aborting notifications. There is not emitted folder's "changed" signal for this @mi.
3227  *
3228  * Returns: Whether the value changed.
3229  *
3230  * Since: 3.42
3231  **/
3232 gboolean
camel_message_info_set_user_header(CamelMessageInfo * mi,const gchar * name,const gchar * value)3233 camel_message_info_set_user_header (CamelMessageInfo *mi,
3234 				    const gchar *name,
3235 				    const gchar *value)
3236 {
3237 	CamelMessageInfoClass *klass;
3238 	gboolean changed, abort_notifications;
3239 
3240 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
3241 
3242 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
3243 	g_return_val_if_fail (klass != NULL, FALSE);
3244 	g_return_val_if_fail (klass->set_user_header != NULL, FALSE);
3245 
3246 	camel_message_info_property_lock (mi);
3247 	changed = klass->set_user_header (mi, name, value);
3248 	abort_notifications = mi->priv->abort_notifications;
3249 	camel_message_info_property_unlock (mi);
3250 
3251 	if (changed && !abort_notifications) {
3252 		g_object_notify (G_OBJECT (mi), "user-headers");
3253 		camel_message_info_set_dirty (mi, TRUE);
3254 	}
3255 
3256 	return changed;
3257 }
3258 
3259 /**
3260  * camel_message_info_get_user_headers:
3261  * @mi: a #CamelMessageInfo
3262  *
3263  * Returns: (transfer none) (nullable): All the user-defined message headers
3264  *    of the associated message, or %NULL, when none are available.
3265  *
3266  * Since: 3.42
3267  **/
3268 const CamelNameValueArray *
camel_message_info_get_user_headers(const CamelMessageInfo * mi)3269 camel_message_info_get_user_headers (const CamelMessageInfo *mi)
3270 {
3271 	CamelMessageInfoClass *klass;
3272 	const CamelNameValueArray *result;
3273 
3274 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
3275 
3276 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
3277 	g_return_val_if_fail (klass != NULL, NULL);
3278 	g_return_val_if_fail (klass->get_user_headers != NULL, NULL);
3279 
3280 	camel_message_info_property_lock (mi);
3281 	result = klass->get_user_headers (mi);
3282 	camel_message_info_property_unlock (mi);
3283 
3284 	return result;
3285 }
3286 
3287 /**
3288  * camel_message_info_dup_user_headers:
3289  * @mi: a #CamelMessageInfo
3290  *
3291  * Returns: (transfer full) (nullable): All the user-defined message headers
3292  *    of the associated message, or %NULL, when none are available. Free returned
3293  *    array with camel_name_value_array_free() when no longer needed.
3294  *
3295  * Since: 3.42
3296  **/
3297 CamelNameValueArray *
camel_message_info_dup_user_headers(const CamelMessageInfo * mi)3298 camel_message_info_dup_user_headers (const CamelMessageInfo *mi)
3299 {
3300 	const CamelNameValueArray *arr;
3301 	CamelNameValueArray *result;
3302 
3303 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
3304 
3305 	camel_message_info_property_lock (mi);
3306 	arr = camel_message_info_get_user_headers (mi);
3307 	if (arr) {
3308 		result = camel_name_value_array_copy (arr);
3309 	} else {
3310 		result = NULL;
3311 	}
3312 	camel_message_info_property_unlock (mi);
3313 
3314 	return result;
3315 }
3316 
3317 /**
3318  * camel_message_info_take_user_headers:
3319  * @mi: a #CamelMessageInfo
3320  * @headers: (transfer full) (nullable): headers to set, as #CamelNameValueArray, or %NULL
3321  *
3322  * Takes user-defined message headers of the associated message.
3323  *
3324  * If the @mi changed, the 'dirty' flag is set automatically, unless the @mi is
3325  * aborting notifications. There is not emitted folder's "changed" signal for this @mi.
3326  *
3327  * Note that it's not safe to use the @headers after the call to this function,
3328  * because it can be freed due to no change.
3329  *
3330  * Returns: Whether the value changed.
3331  *
3332  * Since: 3.42
3333  **/
3334 gboolean
camel_message_info_take_user_headers(CamelMessageInfo * mi,CamelNameValueArray * headers)3335 camel_message_info_take_user_headers (CamelMessageInfo *mi,
3336 				      CamelNameValueArray *headers)
3337 {
3338 	CamelMessageInfoClass *klass;
3339 	gboolean changed, abort_notifications;
3340 
3341 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
3342 
3343 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
3344 	g_return_val_if_fail (klass != NULL, FALSE);
3345 	g_return_val_if_fail (klass->take_user_headers != NULL, FALSE);
3346 
3347 	camel_message_info_property_lock (mi);
3348 	changed = klass->take_user_headers (mi, headers);
3349 	abort_notifications = mi->priv->abort_notifications;
3350 	camel_message_info_property_unlock (mi);
3351 
3352 	if (changed && !abort_notifications) {
3353 		g_object_notify (G_OBJECT (mi), "user-headers");
3354 		camel_message_info_set_dirty (mi, TRUE);
3355 	}
3356 
3357 	return changed;
3358 }
3359 
3360 /**
3361  * camel_message_info_get_preview:
3362  * @mi: a #CamelMessageInfo
3363  *
3364  * Returns: (transfer none) (nullable): Body preview of the associated
3365  *    message, or %NULL, when not available.
3366  *
3367  * Since: 3.42
3368  **/
3369 const gchar *
camel_message_info_get_preview(const CamelMessageInfo * mi)3370 camel_message_info_get_preview (const CamelMessageInfo *mi)
3371 {
3372 	CamelMessageInfoClass *klass;
3373 	const gchar *result;
3374 
3375 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
3376 
3377 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
3378 	g_return_val_if_fail (klass != NULL, NULL);
3379 	g_return_val_if_fail (klass->get_preview != NULL, NULL);
3380 
3381 	camel_message_info_property_lock (mi);
3382 	result = klass->get_preview (mi);
3383 	camel_message_info_property_unlock (mi);
3384 
3385 	return result;
3386 }
3387 
3388 /**
3389  * camel_message_info_dup_preview:
3390  * @mi: a #CamelMessageInfo
3391  *
3392  * Returns: (transfer none) (nullable): Body preview of the associated
3393  *    message, or %NULL, when not available. Free the returned string
3394  *    with g_free(), when no longer needed.
3395  *
3396  * Since: 3.42
3397  **/
3398 gchar *
camel_message_info_dup_preview(const CamelMessageInfo * mi)3399 camel_message_info_dup_preview (const CamelMessageInfo *mi)
3400 {
3401 	gchar *result;
3402 
3403 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
3404 
3405 	camel_message_info_property_lock (mi);
3406 	result = g_strdup (camel_message_info_get_preview (mi));
3407 	camel_message_info_property_unlock (mi);
3408 
3409 	return result;
3410 }
3411 
3412 /**
3413  * camel_message_info_set_preview:
3414  * @mi: a #CamelMessageInfo
3415  * @preview: (nullable): message body preview, or %NULL
3416  *
3417  * Set @preview as the body preview of the associated message. Use %NULL or an empty
3418  * string to unset the value.
3419  *
3420  * If the @mi changed, the 'dirty' flag is set automatically, unless the @mi is
3421  * aborting notifications. There is not emitted folder's "changed" signal for this @mi.
3422  *
3423  * Returns: Whether the value changed.
3424  *
3425  * Since: 3.42
3426  **/
3427 gboolean
camel_message_info_set_preview(CamelMessageInfo * mi,const gchar * preview)3428 camel_message_info_set_preview (CamelMessageInfo *mi,
3429 				const gchar *preview)
3430 {
3431 	CamelMessageInfoClass *klass;
3432 	gboolean changed, abort_notifications;
3433 
3434 	g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
3435 
3436 	klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
3437 	g_return_val_if_fail (klass != NULL, FALSE);
3438 	g_return_val_if_fail (klass->set_preview != NULL, FALSE);
3439 
3440 	camel_message_info_property_lock (mi);
3441 	changed = klass->set_preview (mi, preview);
3442 	abort_notifications = mi->priv->abort_notifications;
3443 	camel_message_info_property_unlock (mi);
3444 
3445 	if (changed && !abort_notifications) {
3446 		g_object_notify (G_OBJECT (mi), "preview");
3447 		camel_message_info_set_dirty (mi, TRUE);
3448 	}
3449 
3450 	return changed;
3451 }
3452 
3453 /**
3454  * camel_message_info_dump:
3455  * @mi: a #CamelMessageInfo
3456  *
3457  * Dumps the mesasge info @mi to stdout. This is meand for debugging
3458  * purposes only.
3459  *
3460  * Since: 3.24
3461  **/
3462 void
camel_message_info_dump(CamelMessageInfo * mi)3463 camel_message_info_dump (CamelMessageInfo *mi)
3464 {
3465 	if (!mi) {
3466 		printf ("No message info\n");
3467 		return;
3468 	}
3469 
3470 	camel_message_info_property_lock (mi);
3471 
3472 	printf ("Message info %s:\n", G_OBJECT_TYPE_NAME (mi));
3473 	printf ("   UID: %s\n", camel_message_info_get_uid (mi));
3474 	printf ("   Flags: %04x\n", camel_message_info_get_flags (mi));
3475 	printf ("   From: %s\n", camel_message_info_get_from (mi));
3476 	printf ("   To: %s\n", camel_message_info_get_to (mi));
3477 	printf ("   Cc: %s\n", camel_message_info_get_cc (mi));
3478 	printf ("   Mailing list: %s\n", camel_message_info_get_mlist (mi));
3479 	printf ("   Subject: %s\n", camel_message_info_get_subject (mi));
3480 
3481 	camel_message_info_property_unlock (mi);
3482 }
3483