1 /*
2 * camel-imapx-mailbox.c
3 *
4 * This library is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
7 *
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
11 * for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18 /**
19 * SECTION: camel-imapx-mailbox
20 * @include: camel/camel.h
21 * @short_description: Stores the state of an IMAP mailbox
22 *
23 * #CamelIMAPXMailbox models the current state of an IMAP mailbox as
24 * accumulated from untagged IMAP server responses in the current session.
25 *
26 * In particular, a #CamelIMAPXMailbox should <emphasis>not</emphasis> be
27 * populated with locally cached information from the previous session.
28 * This is why instantiation requires a #CamelIMAPXListResponse.
29 **/
30
31 #include "evolution-data-server-config.h"
32
33 #include "camel-imapx-mailbox.h"
34 #include "camel-imapx-utils.h"
35
36 struct _CamelIMAPXMailboxPrivate {
37 gchar *name;
38 gchar separator;
39 CamelIMAPXNamespace *namespace;
40
41 guint32 messages;
42 guint32 recent;
43 guint32 unseen;
44 guint32 uidnext;
45 guint32 uidvalidity;
46 guint64 highestmodseq;
47 guint32 permanentflags;
48
49 volatile gint change_stamp;
50
51 CamelIMAPXMailboxState state;
52
53 GMutex property_lock;
54 GMutex update_lock;
55 gint update_count;
56
57 /* Protected by the "property_lock". */
58 GHashTable *attributes;
59 GSequence *message_map;
60 gchar **quota_roots;
61 };
62
G_DEFINE_TYPE_WITH_PRIVATE(CamelIMAPXMailbox,camel_imapx_mailbox,G_TYPE_OBJECT)63 G_DEFINE_TYPE_WITH_PRIVATE (
64 CamelIMAPXMailbox,
65 camel_imapx_mailbox,
66 G_TYPE_OBJECT)
67
68 static gint
69 imapx_mailbox_message_map_compare (gconstpointer a,
70 gconstpointer b,
71 gpointer unused)
72 {
73 guint32 uid_a = GPOINTER_TO_UINT (a);
74 guint32 uid_b = GPOINTER_TO_UINT (b);
75
76 return (uid_a == uid_b) ? 0 : (uid_a < uid_b) ? -1 : 1;
77 }
78
79 static void
imapx_mailbox_dispose(GObject * object)80 imapx_mailbox_dispose (GObject *object)
81 {
82 CamelIMAPXMailboxPrivate *priv;
83
84 priv = CAMEL_IMAPX_MAILBOX (object)->priv;
85
86 g_clear_object (&priv->namespace);
87
88 /* Chain up to parent's dispose() method. */
89 G_OBJECT_CLASS (camel_imapx_mailbox_parent_class)->dispose (object);
90 }
91
92 static void
imapx_mailbox_finalize(GObject * object)93 imapx_mailbox_finalize (GObject *object)
94 {
95 CamelIMAPXMailboxPrivate *priv;
96
97 priv = CAMEL_IMAPX_MAILBOX (object)->priv;
98
99 g_free (priv->name);
100
101 g_mutex_clear (&priv->property_lock);
102 g_mutex_clear (&priv->update_lock);
103 g_hash_table_destroy (priv->attributes);
104 g_sequence_free (priv->message_map);
105 g_strfreev (priv->quota_roots);
106
107 /* Chain up to parent's finalize() method. */
108 G_OBJECT_CLASS (camel_imapx_mailbox_parent_class)->finalize (object);
109 }
110
111 static void
camel_imapx_mailbox_class_init(CamelIMAPXMailboxClass * class)112 camel_imapx_mailbox_class_init (CamelIMAPXMailboxClass *class)
113 {
114 GObjectClass *object_class;
115
116 object_class = G_OBJECT_CLASS (class);
117 object_class->dispose = imapx_mailbox_dispose;
118 object_class->finalize = imapx_mailbox_finalize;
119 }
120
121 static void
camel_imapx_mailbox_init(CamelIMAPXMailbox * mailbox)122 camel_imapx_mailbox_init (CamelIMAPXMailbox *mailbox)
123 {
124 mailbox->priv = camel_imapx_mailbox_get_instance_private (mailbox);
125
126 g_mutex_init (&mailbox->priv->property_lock);
127 g_mutex_init (&mailbox->priv->update_lock);
128 mailbox->priv->message_map = g_sequence_new (NULL);
129 mailbox->priv->permanentflags = ~0;
130 mailbox->priv->state = CAMEL_IMAPX_MAILBOX_STATE_CREATED;
131 mailbox->priv->update_count = 0;
132 mailbox->priv->change_stamp = 0;
133 }
134
135 /**
136 * camel_imapx_mailbox_new:
137 * @response: a #CamelIMAPXListResponse
138 * @namespace_: a #CamelIMAPXNamespace
139 *
140 * Creates a new #CamelIMAPXMailbox from @response and @namespace.
141 *
142 * The mailbox's name, path separator character, and attribute set are
143 * initialized from the #CamelIMAPXListResponse.
144 *
145 * Returns: a #CamelIMAPXMailbox
146 *
147 * Since: 3.12
148 **/
149 CamelIMAPXMailbox *
camel_imapx_mailbox_new(CamelIMAPXListResponse * response,CamelIMAPXNamespace * namespace)150 camel_imapx_mailbox_new (CamelIMAPXListResponse *response,
151 CamelIMAPXNamespace *namespace)
152 {
153 CamelIMAPXMailbox *mailbox;
154 GHashTable *attributes;
155 const gchar *name;
156 gchar separator;
157
158 g_return_val_if_fail (CAMEL_IS_IMAPX_LIST_RESPONSE (response), NULL);
159 g_return_val_if_fail (CAMEL_IS_IMAPX_NAMESPACE (namespace), NULL);
160
161 name = camel_imapx_list_response_get_mailbox_name (response);
162 separator = camel_imapx_list_response_get_separator (response);
163 attributes = camel_imapx_list_response_dup_attributes (response);
164
165 /* The INBOX mailbox is case-insensitive. */
166 if (g_ascii_strcasecmp (name, "INBOX") == 0)
167 name = "INBOX";
168
169 mailbox = g_object_new (CAMEL_TYPE_IMAPX_MAILBOX, NULL);
170 mailbox->priv->name = g_strdup (name);
171 mailbox->priv->separator = separator;
172 mailbox->priv->namespace = g_object_ref (namespace);
173 mailbox->priv->attributes = attributes; /* takes ownership */
174
175 return mailbox;
176 }
177
178 /**
179 * camel_imapx_mailbox_clone:
180 * @mailbox: a #CamelIMAPXMailbox
181 * @new_mailbox_name: new name for the cloned mailbox
182 *
183 * Creates an identical copy of @mailbox, except for the mailbox name.
184 * The copied #CamelIMAPXMailbox is given the name @new_mailbox_name.
185 *
186 * The @new_mailbox_name must be in the same IMAP namespace as @mailbox.
187 *
188 * This is primarily useful for handling mailbox renames. It is safer to
189 * create a new #CamelIMAPXMailbox instance with the new name than to try
190 * and rename an existing #CamelIMAPXMailbox, which could disrupt mailbox
191 * operations in progress as well as data structures that track mailboxes
192 * by name.
193 *
194 * Returns: a copy of @mailbox, named @new_mailbox_name
195 *
196 * Since: 3.12
197 **/
198 CamelIMAPXMailbox *
camel_imapx_mailbox_clone(CamelIMAPXMailbox * mailbox,const gchar * new_mailbox_name)199 camel_imapx_mailbox_clone (CamelIMAPXMailbox *mailbox,
200 const gchar *new_mailbox_name)
201 {
202 CamelIMAPXMailbox *clone;
203 GHashTableIter iter;
204 gpointer key;
205
206 g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), NULL);
207 g_return_val_if_fail (new_mailbox_name != NULL, NULL);
208
209 /* The INBOX mailbox is case-insensitive. */
210 if (g_ascii_strcasecmp (new_mailbox_name, "INBOX") == 0)
211 new_mailbox_name = "INBOX";
212
213 clone = g_object_new (CAMEL_TYPE_IMAPX_MAILBOX, NULL);
214 clone->priv->name = g_strdup (new_mailbox_name);
215 clone->priv->separator = mailbox->priv->separator;
216 clone->priv->namespace = g_object_ref (mailbox->priv->namespace);
217
218 clone->priv->messages = mailbox->priv->messages;
219 clone->priv->recent = mailbox->priv->recent;
220 clone->priv->unseen = mailbox->priv->unseen;
221 clone->priv->uidnext = mailbox->priv->uidnext;
222 clone->priv->uidvalidity = mailbox->priv->uidvalidity;
223 clone->priv->highestmodseq = mailbox->priv->highestmodseq;
224 clone->priv->state = mailbox->priv->state;
225
226 clone->priv->quota_roots = g_strdupv (mailbox->priv->quota_roots);
227
228 /* Use camel_imapx_list_response_dup_attributes()
229 * as a guide for cloning the mailbox attributes. */
230
231 clone->priv->attributes = g_hash_table_new (camel_strcase_hash, camel_strcase_equal);
232
233 g_mutex_lock (&mailbox->priv->property_lock);
234
235 g_hash_table_iter_init (&iter, mailbox->priv->attributes);
236
237 while (g_hash_table_iter_next (&iter, &key, NULL))
238 g_hash_table_add (clone->priv->attributes, key);
239
240 g_mutex_unlock (&mailbox->priv->property_lock);
241
242 return clone;
243 }
244
245 /**
246 * camel_imapx_mailbox_get_state:
247 * @mailbox: a #CamelIMAPXMailbox
248 *
249 * Returns current state of the mailbox. This is used for folder
250 * structure updates, to identify newly created, updated, renamed
251 * or removed mailboxes.
252 *
253 * Returns: Current (update) state of the mailbox.
254 *
255 * Since: 3.16
256 **/
257 CamelIMAPXMailboxState
camel_imapx_mailbox_get_state(CamelIMAPXMailbox * mailbox)258 camel_imapx_mailbox_get_state (CamelIMAPXMailbox *mailbox)
259 {
260 g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), CAMEL_IMAPX_MAILBOX_STATE_UNKNOWN);
261
262 return mailbox->priv->state;
263 }
264
265 /**
266 * camel_imapx_mailbox_set_state:
267 * @mailbox: a #CamelIMAPXMailbox
268 * @state: a new #CamelIMAPXMailboxState to set
269 *
270 * Sets current (update) state of the mailbox. This is used for folder
271 * structure updates, to identify newly created, updated, renamed
272 * or removed mailboxes.
273 *
274 * Since: 3.16
275 **/
276 void
camel_imapx_mailbox_set_state(CamelIMAPXMailbox * mailbox,CamelIMAPXMailboxState state)277 camel_imapx_mailbox_set_state (CamelIMAPXMailbox *mailbox,
278 CamelIMAPXMailboxState state)
279 {
280 g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
281
282 mailbox->priv->state = state;
283 }
284
285 /**
286 * camel_imapx_mailbox_exists:
287 * @mailbox: a #CamelIMAPXMailbox
288 *
289 * Convenience function returns whether @mailbox exists; that is, whether it
290 * <emphasis>lacks</emphasis> a #CAMEL_IMAPX_LIST_ATTR_NONEXISTENT attribute.
291 *
292 * Non-existent mailboxes should generally be disregarded.
293 *
294 * Returns: whether @mailbox exists
295 *
296 * Since: 3.12
297 **/
298 gboolean
camel_imapx_mailbox_exists(CamelIMAPXMailbox * mailbox)299 camel_imapx_mailbox_exists (CamelIMAPXMailbox *mailbox)
300 {
301 g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
302
303 return !camel_imapx_mailbox_has_attribute (
304 mailbox, CAMEL_IMAPX_LIST_ATTR_NONEXISTENT);
305 }
306
307 /**
308 * camel_imapx_mailbox_compare:
309 * @mailbox_a: the first #CamelIMAPXMailbox
310 * @mailbox_b: the second #CamelIMAPXMailbox
311 *
312 * Compares two #CamelIMAPXMailbox instances by their mailbox names.
313 *
314 * Returns: a negative value if @mailbox_a compares before @mailbox_b,
315 * zero if they compare equal, or a positive value if @mailbox_a
316 * compares after @mailbox_b
317 *
318 * Since: 3.12
319 **/
320 gint
camel_imapx_mailbox_compare(CamelIMAPXMailbox * mailbox_a,CamelIMAPXMailbox * mailbox_b)321 camel_imapx_mailbox_compare (CamelIMAPXMailbox *mailbox_a,
322 CamelIMAPXMailbox *mailbox_b)
323 {
324 const gchar *mailbox_name_a;
325 const gchar *mailbox_name_b;
326
327 mailbox_name_a = camel_imapx_mailbox_get_name (mailbox_a);
328 mailbox_name_b = camel_imapx_mailbox_get_name (mailbox_b);
329
330 return g_strcmp0 (mailbox_name_a, mailbox_name_b);
331 }
332
333 /**
334 * camel_imapx_mailbox_matches:
335 * @mailbox: a #CamelIMAPXMailbox
336 * @pattern: mailbox name with possible wildcards
337 *
338 * Returns %TRUE if @mailbox's name matches @pattern. The @pattern may
339 * contain wildcard characters '*' and '%', which are interpreted similar
340 * to the IMAP LIST command.
341 *
342 * Returns: %TRUE if @mailbox's name matches @pattern, %FALSE otherwise
343 *
344 * Since: 3.12
345 **/
346 gboolean
camel_imapx_mailbox_matches(CamelIMAPXMailbox * mailbox,const gchar * pattern)347 camel_imapx_mailbox_matches (CamelIMAPXMailbox *mailbox,
348 const gchar *pattern)
349 {
350 const gchar *name;
351 gchar separator;
352 gchar name_ch;
353 gchar patt_ch;
354
355 g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
356 g_return_val_if_fail (pattern != NULL, FALSE);
357
358 name = camel_imapx_mailbox_get_name (mailbox);
359 separator = camel_imapx_mailbox_get_separator (mailbox);
360
361 name_ch = *name++;
362 patt_ch = *pattern++;
363
364 while (name_ch != '\0' && patt_ch != '\0') {
365 if (name_ch == patt_ch) {
366 name_ch = *name++;
367 patt_ch = *pattern++;
368 } else if (patt_ch == '%') {
369 if (name_ch != separator)
370 name_ch = *name++;
371 else
372 patt_ch = *pattern++;
373 } else {
374 return (patt_ch == '*');
375 }
376 }
377
378 return (name_ch == '\0') &&
379 (patt_ch == '%' || patt_ch == '*' || patt_ch == '\0');
380 }
381
382 /**
383 * camel_imapx_mailbox_get_name:
384 * @mailbox: a #CamelIMAPXMailbox
385 *
386 * Returns the mailbox name for @mailbox.
387 *
388 * Returns: the mailbox name
389 *
390 * Since: 3.12
391 **/
392 const gchar *
camel_imapx_mailbox_get_name(CamelIMAPXMailbox * mailbox)393 camel_imapx_mailbox_get_name (CamelIMAPXMailbox *mailbox)
394 {
395 g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), NULL);
396
397 return mailbox->priv->name;
398 }
399
400 /**
401 * camel_imapx_mailbox_get_separator:
402 * @mailbox: a #CamelIMAPXMailbox
403 *
404 * Returns the path separator character for @mailbox.
405 *
406 * Returns: the mailbox path separator character
407 *
408 * Since: 3.12
409 **/
410 gchar
camel_imapx_mailbox_get_separator(CamelIMAPXMailbox * mailbox)411 camel_imapx_mailbox_get_separator (CamelIMAPXMailbox *mailbox)
412 {
413 g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), '\0');
414
415 return mailbox->priv->separator;
416 }
417
418 /**
419 * camel_imapx_mailbox_dup_folder_path:
420 * @mailbox: a #CamelIMAPXMailbox
421 *
422 * Returns the mailbox name as folder path.
423 *
424 * Returns: the mailbox name as folder path.
425 *
426 * Since: 3.16
427 **/
428 gchar *
camel_imapx_mailbox_dup_folder_path(CamelIMAPXMailbox * mailbox)429 camel_imapx_mailbox_dup_folder_path (CamelIMAPXMailbox *mailbox)
430 {
431 g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), NULL);
432
433 return camel_imapx_mailbox_to_folder_path (
434 camel_imapx_mailbox_get_name (mailbox),
435 camel_imapx_mailbox_get_separator (mailbox));
436 }
437
438 /**
439 * camel_imapx_mailbox_get_namespace:
440 * @mailbox: a #CamelIMAPXMailbox
441 *
442 * Returns the #CamelIMAPXNamespace representing the IMAP server namespace
443 * to which @mailbox belongs.
444 *
445 * Returns: a #CamelIMAPXNamespace
446 *
447 * Since: 3.12
448 **/
449 CamelIMAPXNamespace *
camel_imapx_mailbox_get_namespace(CamelIMAPXMailbox * mailbox)450 camel_imapx_mailbox_get_namespace (CamelIMAPXMailbox *mailbox)
451 {
452 g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), NULL);
453
454 return mailbox->priv->namespace;
455 }
456
457 /**
458 * camel_imapx_mailbox_get_messages:
459 * @mailbox: a #CamelIMAPXMailbox
460 *
461 * Returns the last known number of messages in the mailbox.
462 *
463 * This value should reflect the present state of the IMAP server as
464 * reported through untagged server responses in the current session.
465 *
466 * Returns: the last known "MESSAGES" value
467 *
468 * Since: 3.12
469 **/
470 guint32
camel_imapx_mailbox_get_messages(CamelIMAPXMailbox * mailbox)471 camel_imapx_mailbox_get_messages (CamelIMAPXMailbox *mailbox)
472 {
473 g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), 0);
474
475 return mailbox->priv->messages;
476 }
477
478 /**
479 * camel_imapx_mailbox_set_messages:
480 * @mailbox: a #CamelIMAPXMailbox
481 * @messages: a newly-reported "MESSAGES" value
482 *
483 * Updates the last known number of messages in the mailbox.
484 *
485 * This value should reflect the present state of the IMAP server as
486 * reported through untagged server responses in the current session.
487 *
488 * Since: 3.12
489 **/
490 void
camel_imapx_mailbox_set_messages(CamelIMAPXMailbox * mailbox,guint32 messages)491 camel_imapx_mailbox_set_messages (CamelIMAPXMailbox *mailbox,
492 guint32 messages)
493 {
494 g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
495
496 if (mailbox->priv->messages == messages)
497 return;
498
499 mailbox->priv->messages = messages;
500
501 g_atomic_int_add (&mailbox->priv->change_stamp, 1);
502 }
503
504 /**
505 * camel_imapx_mailbox_get_recent:
506 * @mailbox: a #CamelIMAPXMailbox
507 *
508 * Returns the last known number of messages with the \Recent flag set.
509 *
510 * This value should reflect the present state of the IMAP server as
511 * reported through untagged server responses in the current session.
512 *
513 * Returns: the last known "RECENT" value
514 *
515 * Since: 3.12
516 **/
517 guint32
camel_imapx_mailbox_get_recent(CamelIMAPXMailbox * mailbox)518 camel_imapx_mailbox_get_recent (CamelIMAPXMailbox *mailbox)
519 {
520 g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), 0);
521
522 return mailbox->priv->recent;
523 }
524
525 /**
526 * camel_imapx_mailbox_set_recent:
527 * @mailbox: a #CamelIMAPXMailbox
528 * @recent: a newly-reported "RECENT" value
529 *
530 * Updates the last known number of messages with the \Recent flag set.
531 *
532 * This value should reflect the present state of the IMAP server as
533 * reported through untagged server responses in the current session.
534 *
535 * Since: 3.12
536 **/
537 void
camel_imapx_mailbox_set_recent(CamelIMAPXMailbox * mailbox,guint32 recent)538 camel_imapx_mailbox_set_recent (CamelIMAPXMailbox *mailbox,
539 guint32 recent)
540 {
541 g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
542
543 if (mailbox->priv->recent == recent)
544 return;
545
546 mailbox->priv->recent = recent;
547
548 g_atomic_int_add (&mailbox->priv->change_stamp, 1);
549 }
550
551 /**
552 * camel_imapx_mailbox_get_unseen:
553 * @mailbox: a #CamelIMAPXMailbox
554 *
555 * Returns the last known number of messages which do not have the \Seen
556 * flag set.
557 *
558 * This value should reflect the present state of the IMAP server as
559 * reported through untagged server responses in the current session.
560 *
561 * Returns: the last known "UNSEEN" value
562 *
563 * Since: 3.12
564 **/
565 guint32
camel_imapx_mailbox_get_unseen(CamelIMAPXMailbox * mailbox)566 camel_imapx_mailbox_get_unseen (CamelIMAPXMailbox *mailbox)
567 {
568 g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), 0);
569
570 return mailbox->priv->unseen;
571 }
572
573 /**
574 * camel_imapx_mailbox_set_unseen:
575 * @mailbox: a #CamelIMAPXMailbox
576 * @unseen: a newly-reported "UNSEEN" value
577 *
578 * Updates the last known number of messages which do not have the \Seen
579 * flag set.
580 *
581 * This value should reflect the present state of the IMAP server as
582 * reported through untagged server responses in the current session.
583 *
584 * Since: 3.12
585 **/
586 void
camel_imapx_mailbox_set_unseen(CamelIMAPXMailbox * mailbox,guint32 unseen)587 camel_imapx_mailbox_set_unseen (CamelIMAPXMailbox *mailbox,
588 guint32 unseen)
589 {
590 g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
591
592 if (mailbox->priv->unseen == unseen)
593 return;
594
595 mailbox->priv->unseen = unseen;
596
597 g_atomic_int_add (&mailbox->priv->change_stamp, 1);
598 }
599
600 /**
601 * camel_imapx_mailbox_get_uidnext:
602 * @mailbox: a #CamelIMAPXMailbox
603 *
604 * Returns the last known next unique identifier value of the mailbox.
605 *
606 * This value should reflect the present state of the IMAP server as
607 * reported through untagged server responses in the current session.
608 *
609 * Returns: the last known "UIDNEXT" value
610 *
611 * Since: 3.12
612 **/
613 guint32
camel_imapx_mailbox_get_uidnext(CamelIMAPXMailbox * mailbox)614 camel_imapx_mailbox_get_uidnext (CamelIMAPXMailbox *mailbox)
615 {
616 g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), 0);
617
618 return mailbox->priv->uidnext;
619 }
620
621 /**
622 * camel_imapx_mailbox_set_uidnext:
623 * @mailbox: a #CamelIMAPXMailbox
624 * @uidnext: a newly-reported "UIDNEXT" value
625 *
626 * Updates the last known next unique identifier value of the mailbox.
627 *
628 * This value should reflect the present state of the IMAP server as
629 * reported through untagged server responses in the current session.
630 *
631 * Since: 3.12
632 **/
633 void
camel_imapx_mailbox_set_uidnext(CamelIMAPXMailbox * mailbox,guint32 uidnext)634 camel_imapx_mailbox_set_uidnext (CamelIMAPXMailbox *mailbox,
635 guint32 uidnext)
636 {
637 g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
638
639 if (mailbox->priv->uidnext == uidnext)
640 return;
641
642 mailbox->priv->uidnext = uidnext;
643
644 g_atomic_int_add (&mailbox->priv->change_stamp, 1);
645 }
646
647 /**
648 * camel_imapx_mailbox_get_uidvalidity:
649 * @mailbox: a #CamelIMAPXMailbox
650 *
651 * Returns the last known unique identifier validity value of the mailbox.
652 *
653 * This valud should reflect the present state of the IMAP server as
654 * reported through untagged server responses in the current session.
655 *
656 * Returns: the last known "UIDVALIDITY" value
657 *
658 * Since: 3.12
659 **/
660 guint32
camel_imapx_mailbox_get_uidvalidity(CamelIMAPXMailbox * mailbox)661 camel_imapx_mailbox_get_uidvalidity (CamelIMAPXMailbox *mailbox)
662 {
663 g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), 0);
664
665 return mailbox->priv->uidvalidity;
666 }
667
668 /**
669 * camel_imapx_mailbox_set_uidvalidity:
670 * @mailbox: a #CamelIMAPXMailbox
671 * @uidvalidity: a newly-reported "UIDVALIDITY" value
672 *
673 * Updates the last known unique identifier validity value of the mailbox.
674 *
675 * This value should reflect the present state of the IMAP server as
676 * reported through untagged server responses in the current session.
677 *
678 * Since: 3.12
679 **/
680 void
camel_imapx_mailbox_set_uidvalidity(CamelIMAPXMailbox * mailbox,guint32 uidvalidity)681 camel_imapx_mailbox_set_uidvalidity (CamelIMAPXMailbox *mailbox,
682 guint32 uidvalidity)
683 {
684 g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
685
686 if (mailbox->priv->uidvalidity == uidvalidity)
687 return;
688
689 mailbox->priv->uidvalidity = uidvalidity;
690
691 g_atomic_int_add (&mailbox->priv->change_stamp, 1);
692 }
693
694 /**
695 * camel_imapx_mailbox_get_highestmodseq:
696 * @mailbox: a #CamelIMAPXMailbox
697 *
698 * Returns the last known highest mod-sequence value of all messages in the
699 * mailbox, or zero if the server does not support the persistent storage of
700 * mod-sequences for the mailbox.
701 *
702 * This value should reflect the present state of the IMAP server as
703 * reported through untagged server responses in the current session.
704 *
705 * Returns: the last known "HIGHESTMODSEQ" value
706 *
707 * Since: 3.12
708 **/
709 guint64
camel_imapx_mailbox_get_highestmodseq(CamelIMAPXMailbox * mailbox)710 camel_imapx_mailbox_get_highestmodseq (CamelIMAPXMailbox *mailbox)
711 {
712 g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), 0);
713
714 return mailbox->priv->highestmodseq;
715 }
716
717 /**
718 * camel_imapx_mailbox_set_highestmodseq:
719 * @mailbox: a #CamelIMAPXMailbox
720 * @highestmodseq: a newly-reported "HIGHESTMODSEQ" value
721 *
722 * Updates the last known highest mod-sequence value of all messages in
723 * the mailbox. If the server does not support the persistent storage of
724 * mod-sequences for the mailbox then the value should remain zero.
725 *
726 * This value should reflect the present state of the IMAP server as
727 * reported through untagged server responses in the current session.
728 *
729 * Since: 3.12
730 **/
731 void
camel_imapx_mailbox_set_highestmodseq(CamelIMAPXMailbox * mailbox,guint64 highestmodseq)732 camel_imapx_mailbox_set_highestmodseq (CamelIMAPXMailbox *mailbox,
733 guint64 highestmodseq)
734 {
735 g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
736
737 if (mailbox->priv->highestmodseq == highestmodseq)
738 return;
739
740 mailbox->priv->highestmodseq = highestmodseq;
741
742 g_atomic_int_add (&mailbox->priv->change_stamp, 1);
743 }
744
745 /**
746 * camel_imapx_mailbox_get_permanentflags:
747 * @mailbox: a #CamelIMAPXMailbox
748 *
749 * Returns: PERMANENTFLAGS response for the mailbox, or ~0, if the mailbox
750 * was not selected yet.
751 *
752 * Since: 3.16
753 **/
754 guint32
camel_imapx_mailbox_get_permanentflags(CamelIMAPXMailbox * mailbox)755 camel_imapx_mailbox_get_permanentflags (CamelIMAPXMailbox *mailbox)
756 {
757 g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), ~0);
758
759 return mailbox->priv->permanentflags;
760 }
761
762 /**
763 * camel_imapx_mailbox_set_permanentflags:
764 * @mailbox: a #CamelIMAPXMailbox
765 * @permanentflags: a newly-reported "PERMANENTFLAGS" value
766 *
767 * Updates the last know value for PERMANENTFLAGS for this mailbox.
768 *
769 * Since: 3.16
770 **/
771 void
camel_imapx_mailbox_set_permanentflags(CamelIMAPXMailbox * mailbox,guint32 permanentflags)772 camel_imapx_mailbox_set_permanentflags (CamelIMAPXMailbox *mailbox,
773 guint32 permanentflags)
774 {
775 g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
776
777 if ((permanentflags & CAMEL_MESSAGE_USER) != 0) {
778 permanentflags |= CAMEL_MESSAGE_JUNK;
779 permanentflags |= CAMEL_MESSAGE_NOTJUNK;
780 }
781
782 mailbox->priv->permanentflags = permanentflags;
783 }
784
785 /**
786 * camel_imapx_mailbox_dup_quota_roots:
787 * @mailbox: a #CamelIMAPXMailbox
788 *
789 * Returns the last known list of quota roots for @mailbox as described
790 * in <ulink url="http://tools.ietf.org/html/rfc2087">RFC 2087</ulink>,
791 * or %NULL if no quota information for @mailbox is available.
792 *
793 * This value should reflect the present state of the IMAP server as
794 * reported through untagged server responses in the current session.
795 *
796 * The returned newly-allocated, %NULL-terminated string array should
797 * be freed with g_strfreev() when finished with it.
798 *
799 * Returns: the last known "QUOTAROOT" value
800 *
801 * Since: 3.12
802 **/
803 gchar **
camel_imapx_mailbox_dup_quota_roots(CamelIMAPXMailbox * mailbox)804 camel_imapx_mailbox_dup_quota_roots (CamelIMAPXMailbox *mailbox)
805 {
806 gchar **quota_roots;
807
808 g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), NULL);
809
810 g_mutex_lock (&mailbox->priv->property_lock);
811
812 quota_roots = g_strdupv (mailbox->priv->quota_roots);
813
814 g_mutex_unlock (&mailbox->priv->property_lock);
815
816 return quota_roots;
817 }
818
819 /**
820 * camel_imapx_mailbox_set_quota_roots:
821 * @mailbox: a #CamelIMAPXMailbox
822 * @quota_roots: a newly-reported "QUOTAROOT" value
823 *
824 * Updates the last known list of quota roots for @mailbox as described
825 * in <ulink url="http://tools.ietf.org/html/rfc2087">RFC 2087</ulink>.
826 *
827 * This value should reflect the present state of the IMAP server as
828 * reported through untagged server responses in the current session.
829 *
830 * Since: 3.12
831 **/
832 void
camel_imapx_mailbox_set_quota_roots(CamelIMAPXMailbox * mailbox,const gchar ** quota_roots)833 camel_imapx_mailbox_set_quota_roots (CamelIMAPXMailbox *mailbox,
834 const gchar **quota_roots)
835 {
836 g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
837
838 g_mutex_lock (&mailbox->priv->property_lock);
839
840 g_strfreev (mailbox->priv->quota_roots);
841 mailbox->priv->quota_roots = g_strdupv ((gchar **) quota_roots);
842
843 g_mutex_unlock (&mailbox->priv->property_lock);
844 }
845
846 /**
847 * camel_imapx_mailbox_copy_message_map:
848 * @mailbox: a #CamelIMAPXMailbox
849 *
850 * Creates a copy of @mailbox's message map: a #GSequence of 32-bit integers
851 * which map message sequence numbers (MSNs) to unique identifiers (UIDs).
852 *
853 * Free the returned #GSequence with g_sequence_free() when finished with it.
854 *
855 * Returns: a #GSequence mapping MSNs to UIDs
856 *
857 * Since: 3.12
858 **/
859 GSequence *
camel_imapx_mailbox_copy_message_map(CamelIMAPXMailbox * mailbox)860 camel_imapx_mailbox_copy_message_map (CamelIMAPXMailbox *mailbox)
861 {
862 GSequence *copy;
863 GSequenceIter *iter;
864
865 g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), NULL);
866
867 copy = g_sequence_new (NULL);
868
869 g_mutex_lock (&mailbox->priv->property_lock);
870
871 iter = g_sequence_get_begin_iter (mailbox->priv->message_map);
872
873 while (!g_sequence_iter_is_end (iter)) {
874 gpointer data;
875
876 data = g_sequence_get (iter);
877 g_sequence_append (copy, data);
878
879 iter = g_sequence_iter_next (iter);
880 }
881
882 g_mutex_unlock (&mailbox->priv->property_lock);
883
884 return copy;
885 }
886
887 /**
888 * camel_imapx_mailbox_take_message_map:
889 * @mailbox: a #CamelIMAPXMailbox
890 * @message_map: a #GSequence mapping MSNs to UIDs
891 *
892 * Takes ownership of a #GSequence of 32-bit integers which map message
893 * sequence numbers (MSNs) to unique identifiers (UIDs) for @mailbox.
894 *
895 * The @message_map is expected to be assembled from a local cache of
896 * previously fetched UIDs. The @mailbox will update it as untagged
897 * server responses are processed.
898 *
899 * Since: 3.12
900 **/
901 void
camel_imapx_mailbox_take_message_map(CamelIMAPXMailbox * mailbox,GSequence * message_map)902 camel_imapx_mailbox_take_message_map (CamelIMAPXMailbox *mailbox,
903 GSequence *message_map)
904 {
905 g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
906 g_return_if_fail (message_map != NULL);
907
908 g_mutex_lock (&mailbox->priv->property_lock);
909
910 /* XXX GSequence is not reference counted. */
911 if (message_map != mailbox->priv->message_map) {
912 g_sequence_free (mailbox->priv->message_map);
913 mailbox->priv->message_map = message_map;
914 }
915
916 g_mutex_unlock (&mailbox->priv->property_lock);
917 }
918
919 /**
920 * camel_imapx_mailbox_get_msn_for_uid:
921 * @mailbox: a #CamelIMAPXMailbox
922 * @uid: a message's unique identifier
923 * @out_msn: return location for the message's sequence number, or %NULL
924 *
925 * Given a message's unique identifier (@uid), write the message's sequence
926 * number to @out_msn and return %TRUE. If the unique identifier is unknown
927 * (as far as @mailbox has been informed), the function returns %FALSE.
928 *
929 * Returns: whether @out_msn was set
930 *
931 * Since: 3.12
932 **/
933 gboolean
camel_imapx_mailbox_get_msn_for_uid(CamelIMAPXMailbox * mailbox,guint32 uid,guint32 * out_msn)934 camel_imapx_mailbox_get_msn_for_uid (CamelIMAPXMailbox *mailbox,
935 guint32 uid,
936 guint32 *out_msn)
937 {
938 GSequence *message_map;
939 GSequenceIter *iter;
940 gboolean success = FALSE;
941
942 g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
943
944 /* Remember: Message sequence numbers start at 1.
945 * GSequence position numbers start at 0. */
946
947 g_mutex_lock (&mailbox->priv->property_lock);
948
949 message_map = mailbox->priv->message_map;
950 iter = g_sequence_lookup (
951 message_map, GUINT_TO_POINTER (uid),
952 imapx_mailbox_message_map_compare, NULL);
953
954 if (iter != NULL) {
955 if (out_msn != NULL)
956 *out_msn = g_sequence_iter_get_position (iter) + 1;
957 success = TRUE;
958 }
959
960 g_mutex_unlock (&mailbox->priv->property_lock);
961
962 return success;
963 }
964
965 /**
966 * camel_imapx_mailbox_get_uid_for_msn:
967 * @mailbox: a #CamelIMAPXMailbox
968 * @msn: a message's sequence number (1..n)
969 * @out_uid: return location for the message's unique identifier, or %NULL
970 *
971 * Given a message's sequence number (@msn), write the message's unique
972 * identifier to @out_uid and return %TRUE. If the sequence number is out of
973 * range (as far as @mailbox has been informed), the function returns %FALSE.
974 *
975 * Returns: whether @out_uid was set
976 *
977 * Since: 3.12
978 **/
979 gboolean
camel_imapx_mailbox_get_uid_for_msn(CamelIMAPXMailbox * mailbox,guint32 msn,guint32 * out_uid)980 camel_imapx_mailbox_get_uid_for_msn (CamelIMAPXMailbox *mailbox,
981 guint32 msn,
982 guint32 *out_uid)
983 {
984 GSequence *message_map;
985 GSequenceIter *iter;
986 gboolean success = FALSE;
987
988 g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
989
990 /* Remember: Message sequence numbers start at 1.
991 * GSequence position numbers start at 0. */
992
993 if (msn == 0)
994 return FALSE;
995
996 g_mutex_lock (&mailbox->priv->property_lock);
997
998 message_map = mailbox->priv->message_map;
999 iter = g_sequence_get_iter_at_pos (message_map, msn - 1);
1000
1001 if (!g_sequence_iter_is_end (iter)) {
1002 if (out_uid != NULL) {
1003 gpointer data = g_sequence_get (iter);
1004 *out_uid = GPOINTER_TO_UINT (data);
1005 }
1006 success = TRUE;
1007 }
1008
1009 g_mutex_unlock (&mailbox->priv->property_lock);
1010
1011 return success;
1012 }
1013
1014 /**
1015 * camel_imapx_mailbox_deleted:
1016 * @mailbox: a #CamelIMAPXMailbox
1017 *
1018 * Adds the #CAMEL_IMAPX_LIST_ATTR_NONEXISTENT attribute to @mailbox.
1019 *
1020 * Call this function after successfully completing a DELETE command.
1021 *
1022 * Since: 3.12
1023 **/
1024 void
camel_imapx_mailbox_deleted(CamelIMAPXMailbox * mailbox)1025 camel_imapx_mailbox_deleted (CamelIMAPXMailbox *mailbox)
1026 {
1027 const gchar *attribute;
1028
1029 g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
1030
1031 attribute = CAMEL_IMAPX_LIST_ATTR_NONEXISTENT;
1032
1033 g_mutex_lock (&mailbox->priv->property_lock);
1034
1035 g_hash_table_add (
1036 mailbox->priv->attributes,
1037 (gpointer) g_intern_string (attribute));
1038
1039 g_mutex_unlock (&mailbox->priv->property_lock);
1040 }
1041
1042 /**
1043 * camel_imapx_mailbox_subscribed:
1044 * @mailbox: a #CamelIMAPXMailbox
1045 *
1046 * Add the #CAMEL_IMAPX_LIST_ATTR_SUBSCRIBED attribute to @mailbox.
1047 *
1048 * Call this function after successfully completing a SUBSCRIBE command.
1049 *
1050 * Since: 3.12
1051 **/
1052 void
camel_imapx_mailbox_subscribed(CamelIMAPXMailbox * mailbox)1053 camel_imapx_mailbox_subscribed (CamelIMAPXMailbox *mailbox)
1054 {
1055 const gchar *attribute;
1056
1057 g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
1058
1059 attribute = CAMEL_IMAPX_LIST_ATTR_SUBSCRIBED;
1060
1061 g_mutex_lock (&mailbox->priv->property_lock);
1062
1063 g_hash_table_add (
1064 mailbox->priv->attributes,
1065 (gpointer) g_intern_string (attribute));
1066
1067 g_mutex_unlock (&mailbox->priv->property_lock);
1068 }
1069
1070 /**
1071 * camel_imapx_mailbox_unsubscribed:
1072 * @mailbox: a #CamelIMAPXMailbox
1073 *
1074 * Removes the #CAMEL_IMAPX_LIST_ATTR_SUBSCRIBED attribute from @mailbox.
1075 *
1076 * Call this function after successfully completing an UNSUBSCRIBE command.
1077 *
1078 * Since: 3.12
1079 **/
1080 void
camel_imapx_mailbox_unsubscribed(CamelIMAPXMailbox * mailbox)1081 camel_imapx_mailbox_unsubscribed (CamelIMAPXMailbox *mailbox)
1082 {
1083 const gchar *attribute;
1084
1085 g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
1086
1087 attribute = CAMEL_IMAPX_LIST_ATTR_SUBSCRIBED;
1088
1089 g_mutex_lock (&mailbox->priv->property_lock);
1090
1091 g_hash_table_remove (mailbox->priv->attributes, attribute);
1092
1093 g_mutex_unlock (&mailbox->priv->property_lock);
1094 }
1095
1096 /**
1097 * camel_imapx_mailbox_has_attribute:
1098 * @mailbox: a #CamelIMAPXMailbox
1099 * @attribute: a mailbox attribute
1100 *
1101 * Returns whether @mailbox includes the given mailbox attribute.
1102 * The @attribute should be one of the LIST attribute macros defined
1103 * for #CamelIMAPXListResponse.
1104 *
1105 * Returns: %TRUE if @mailbox has @attribute, or else %FALSE
1106 *
1107 * Since: 3.12
1108 **/
1109 gboolean
camel_imapx_mailbox_has_attribute(CamelIMAPXMailbox * mailbox,const gchar * attribute)1110 camel_imapx_mailbox_has_attribute (CamelIMAPXMailbox *mailbox,
1111 const gchar *attribute)
1112 {
1113 gboolean has_it;
1114
1115 g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
1116 g_return_val_if_fail (attribute != NULL, FALSE);
1117
1118 g_mutex_lock (&mailbox->priv->property_lock);
1119
1120 has_it = g_hash_table_contains (mailbox->priv->attributes, attribute);
1121
1122 g_mutex_unlock (&mailbox->priv->property_lock);
1123
1124 return has_it;
1125 }
1126
1127 /**
1128 * camel_imapx_mailbox_handle_list_response:
1129 * @mailbox: a #CamelIMAPXMailbox
1130 * @response: a #CamelIMAPXListResponse
1131 *
1132 * Updates the internal state of @mailbox from the data in @response.
1133 *
1134 * Since: 3.12
1135 **/
1136 void
camel_imapx_mailbox_handle_list_response(CamelIMAPXMailbox * mailbox,CamelIMAPXListResponse * response)1137 camel_imapx_mailbox_handle_list_response (CamelIMAPXMailbox *mailbox,
1138 CamelIMAPXListResponse *response)
1139 {
1140 GHashTable *attributes;
1141
1142 g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
1143 g_return_if_fail (CAMEL_IS_IMAPX_LIST_RESPONSE (response));
1144
1145 attributes = camel_imapx_list_response_dup_attributes (response);
1146
1147 g_mutex_lock (&mailbox->priv->property_lock);
1148
1149 g_hash_table_destroy (mailbox->priv->attributes);
1150 mailbox->priv->attributes = attributes; /* takes ownership */
1151
1152 g_mutex_unlock (&mailbox->priv->property_lock);
1153 }
1154
1155 /**
1156 * camel_imapx_mailbox_handle_lsub_response:
1157 * @mailbox: a #CamelIMAPXMailbox
1158 * @response: a #CamelIMAPXListResponse
1159 *
1160 * Updates the internal state of @mailbox from the data in @response.
1161 *
1162 * Since: 3.12
1163 **/
1164 void
camel_imapx_mailbox_handle_lsub_response(CamelIMAPXMailbox * mailbox,CamelIMAPXListResponse * response)1165 camel_imapx_mailbox_handle_lsub_response (CamelIMAPXMailbox *mailbox,
1166 CamelIMAPXListResponse *response)
1167 {
1168 GHashTable *attributes;
1169 GHashTableIter iter;
1170 gpointer key;
1171
1172 g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
1173 g_return_if_fail (CAMEL_IS_IMAPX_LIST_RESPONSE (response));
1174
1175 /* LIST responses are more authoritative than LSUB responses,
1176 * so instead of replacing the old attribute set as we would
1177 * for a LIST response, we'll merge the LSUB attributes. */
1178
1179 attributes = camel_imapx_list_response_dup_attributes (response);
1180
1181 g_hash_table_iter_init (&iter, attributes);
1182
1183 g_mutex_lock (&mailbox->priv->property_lock);
1184
1185 while (g_hash_table_iter_next (&iter, &key, NULL))
1186 g_hash_table_add (mailbox->priv->attributes, key);
1187
1188 g_mutex_unlock (&mailbox->priv->property_lock);
1189
1190 g_hash_table_destroy (attributes);
1191 }
1192
1193 /**
1194 * camel_imapx_mailbox_handle_status_response:
1195 * @mailbox: a #CamelIMAPXMailbox
1196 * @response: a #CamelIMAPXStatusResponse
1197 *
1198 * Updates the internal state of @mailbox from the data in @response.
1199 *
1200 * Since: 3.12
1201 **/
1202 void
camel_imapx_mailbox_handle_status_response(CamelIMAPXMailbox * mailbox,CamelIMAPXStatusResponse * response)1203 camel_imapx_mailbox_handle_status_response (CamelIMAPXMailbox *mailbox,
1204 CamelIMAPXStatusResponse *response)
1205 {
1206 guint32 value32;
1207 guint64 value64;
1208
1209 g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
1210 g_return_if_fail (CAMEL_IS_IMAPX_STATUS_RESPONSE (response));
1211
1212 if (camel_imapx_status_response_get_messages (response, &value32))
1213 camel_imapx_mailbox_set_messages (mailbox, value32);
1214
1215 if (camel_imapx_status_response_get_recent (response, &value32))
1216 camel_imapx_mailbox_set_recent (mailbox, value32);
1217
1218 if (camel_imapx_status_response_get_unseen (response, &value32))
1219 camel_imapx_mailbox_set_unseen (mailbox, value32);
1220
1221 if (camel_imapx_status_response_get_uidnext (response, &value32))
1222 camel_imapx_mailbox_set_uidnext (mailbox, value32);
1223
1224 if (camel_imapx_status_response_get_uidvalidity (response, &value32))
1225 camel_imapx_mailbox_set_uidvalidity (mailbox, value32);
1226
1227 if (camel_imapx_status_response_get_highestmodseq (response, &value64))
1228 camel_imapx_mailbox_set_highestmodseq (mailbox, value64);
1229 }
1230
1231 gint
camel_imapx_mailbox_get_update_count(CamelIMAPXMailbox * mailbox)1232 camel_imapx_mailbox_get_update_count (CamelIMAPXMailbox *mailbox)
1233 {
1234 gint res;
1235
1236 g_mutex_lock (&mailbox->priv->update_lock);
1237 res = mailbox->priv->update_count;
1238 g_mutex_unlock (&mailbox->priv->update_lock);
1239
1240 return res;
1241 }
1242
1243 void
camel_imapx_mailbox_inc_update_count(CamelIMAPXMailbox * mailbox,gint inc)1244 camel_imapx_mailbox_inc_update_count (CamelIMAPXMailbox *mailbox,
1245 gint inc)
1246 {
1247 g_mutex_lock (&mailbox->priv->update_lock);
1248 mailbox->priv->update_count += inc;
1249 g_mutex_unlock (&mailbox->priv->update_lock);
1250 }
1251
1252 gint
camel_imapx_mailbox_get_change_stamp(CamelIMAPXMailbox * mailbox)1253 camel_imapx_mailbox_get_change_stamp (CamelIMAPXMailbox *mailbox)
1254 {
1255 g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), 0);
1256
1257 return mailbox->priv->change_stamp;
1258 }
1259