Extending test-client-custom-summary to try e_book_client_get_contacts_uids()
[platform/upstream/evolution-data-server.git] / camel / camel-vee-data-cache.c
1 /*
2  *  Copyright (C) 2012 Red Hat, Inc. (www.redhat.com)
3  *
4  *  Authors: Milan Crha <mcrha@redhat.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of version 2 of the GNU Lesser General Public
8  * License as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include "camel-string-utils.h"
26 #include "camel-store.h"
27
28 #include "camel-vee-data-cache.h"
29
30 struct _CamelVeeSubfolderDataPrivate {
31         CamelFolder *folder;
32         const gchar *folder_id; /* stored in string pool */
33 };
34
35 G_DEFINE_TYPE (CamelVeeSubfolderData, camel_vee_subfolder_data, G_TYPE_OBJECT)
36
37 static void
38 camel_vee_subfolder_data_dispose (GObject *object)
39 {
40         CamelVeeSubfolderData *data;
41
42         data = CAMEL_VEE_SUBFOLDER_DATA (object);
43         if (data->priv) {
44                 if (data->priv->folder)
45                         g_object_unref (data->priv->folder);
46                 data->priv->folder = NULL;
47
48                 if (data->priv->folder_id)
49                         camel_pstring_free (data->priv->folder_id);
50                 data->priv->folder_id = NULL;
51         }
52
53         /* Chain up to parent's dispose () method. */
54         G_OBJECT_CLASS (camel_vee_subfolder_data_parent_class)->dispose (object);
55 }
56
57 static void
58 camel_vee_subfolder_data_class_init (CamelVeeSubfolderDataClass *class)
59 {
60         GObjectClass *object_class;
61
62         g_type_class_add_private (class, sizeof (CamelVeeSubfolderDataPrivate));
63
64         object_class = G_OBJECT_CLASS (class);
65         object_class->dispose = camel_vee_subfolder_data_dispose;
66 }
67
68 static void
69 camel_vee_subfolder_data_init (CamelVeeSubfolderData *data)
70 {
71         data->priv = G_TYPE_INSTANCE_GET_PRIVATE (data, CAMEL_TYPE_VEE_SUBFOLDER_DATA, CamelVeeSubfolderDataPrivate);
72 }
73
74 static void
75 vee_subfolder_data_hash_folder (CamelFolder *folder,
76                                 gchar buffer[8])
77 {
78         CamelStore *parent_store;
79         GChecksum *checksum;
80         guint8 *digest;
81         gsize length;
82         gint state = 0, save = 0;
83         gchar *ptr_string;
84         const gchar *uid;
85         gint i;
86
87         length = g_checksum_type_get_length (G_CHECKSUM_MD5);
88         digest = g_alloca (length);
89
90         checksum = g_checksum_new (G_CHECKSUM_MD5);
91         parent_store = camel_folder_get_parent_store (folder);
92         uid = camel_service_get_uid (CAMEL_SERVICE (parent_store));
93         g_checksum_update (checksum, (guchar *) uid, -1);
94
95         ptr_string = g_strdup_printf ("%p", folder);
96         g_checksum_update (checksum, (guchar *) ptr_string, -1);
97         g_free (ptr_string);
98
99         g_checksum_get_digest (checksum, digest, &length);
100         g_checksum_free (checksum);
101
102         g_base64_encode_step (digest, 6, FALSE, buffer, &state, &save);
103         g_base64_encode_close (FALSE, buffer, &state, &save);
104
105         for (i = 0; i < 8; i++) {
106                 if (buffer[i] == '+')
107                         buffer[i] = '.';
108                 if (buffer[i] == '/')
109                         buffer[i] = '_';
110         }
111 }
112
113 /**
114  * camel_vee_subfolder_data_new:
115  *
116  * FIXME Document me!
117  *
118  * Since: 3.6
119  **/
120 CamelVeeSubfolderData *
121 camel_vee_subfolder_data_new (CamelFolder *folder)
122 {
123         CamelVeeSubfolderData *data;
124         gchar buffer[8], *folder_id;
125
126         g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
127
128         data = g_object_new (CAMEL_TYPE_VEE_SUBFOLDER_DATA, NULL);
129         data->priv->folder = g_object_ref (folder);
130
131         vee_subfolder_data_hash_folder (folder, buffer);
132         folder_id = g_strndup (buffer, 8);
133
134         data->priv->folder_id = camel_pstring_add (folder_id, TRUE);
135
136         return data;
137 }
138
139 /**
140  * camel_vee_subfolder_data_get_folder:
141  *
142  * FIXME Document me!
143  *
144  * Since: 3.6
145  **/
146 CamelFolder *
147 camel_vee_subfolder_data_get_folder (CamelVeeSubfolderData *data)
148 {
149         g_return_val_if_fail (CAMEL_IS_VEE_SUBFOLDER_DATA (data), NULL);
150
151         return data->priv->folder;
152 }
153
154 /**
155  * camel_vee_subfolder_data_get_folder_id:
156  *
157  * FIXME Document me!
158  *
159  * Since: 3.6
160  **/
161 const gchar *
162 camel_vee_subfolder_data_get_folder_id (CamelVeeSubfolderData *data)
163 {
164         g_return_val_if_fail (CAMEL_IS_VEE_SUBFOLDER_DATA (data), NULL);
165
166         return data->priv->folder_id;
167 }
168
169 /* ----------------------------------------------------------------------- */
170
171 struct _CamelVeeMessageInfoDataPrivate {
172         CamelVeeSubfolderData *subfolder_data;
173         const gchar *orig_message_uid; /* stored in string pool */
174         const gchar *vee_message_uid; /* stored in string pool */
175 };
176
177 G_DEFINE_TYPE (CamelVeeMessageInfoData, camel_vee_message_info_data, G_TYPE_OBJECT)
178
179 static void
180 camel_vee_message_info_data_dispose (GObject *object)
181 {
182         CamelVeeMessageInfoData *data;
183
184         data = CAMEL_VEE_MESSAGE_INFO_DATA (object);
185         if (data->priv) {
186                 if (data->priv->subfolder_data)
187                         g_object_unref (data->priv->subfolder_data);
188                 data->priv->subfolder_data = NULL;
189
190                 if (data->priv->orig_message_uid)
191                         camel_pstring_free (data->priv->orig_message_uid);
192                 data->priv->orig_message_uid = NULL;
193
194                 if (data->priv->vee_message_uid)
195                         camel_pstring_free (data->priv->vee_message_uid);
196                 data->priv->vee_message_uid = NULL;
197         }
198
199         /* Chain up to parent's dispose () method. */
200         G_OBJECT_CLASS (camel_vee_message_info_data_parent_class)->dispose (object);
201 }
202
203 static void
204 camel_vee_message_info_data_class_init (CamelVeeMessageInfoDataClass *class)
205 {
206         GObjectClass *object_class;
207
208         g_type_class_add_private (class, sizeof (CamelVeeMessageInfoDataPrivate));
209
210         object_class = G_OBJECT_CLASS (class);
211         object_class->dispose = camel_vee_message_info_data_dispose;
212 }
213
214 static void
215 camel_vee_message_info_data_init (CamelVeeMessageInfoData *data)
216 {
217         data->priv = G_TYPE_INSTANCE_GET_PRIVATE (data, CAMEL_TYPE_VEE_MESSAGE_INFO_DATA, CamelVeeMessageInfoDataPrivate);
218 }
219
220 /**
221  * camel_vee_message_info_data_new:
222  *
223  * FIXME Document me!
224  *
225  * Since: 3.6
226  **/
227 CamelVeeMessageInfoData *
228 camel_vee_message_info_data_new (CamelVeeSubfolderData *subfolder_data,
229                                  const gchar *orig_message_uid)
230 {
231         CamelVeeMessageInfoData *data;
232         gchar *vee_message_uid;
233
234         g_return_val_if_fail (CAMEL_IS_VEE_SUBFOLDER_DATA (subfolder_data), NULL);
235         g_return_val_if_fail (orig_message_uid != NULL, NULL);
236
237         data = g_object_new (CAMEL_TYPE_VEE_MESSAGE_INFO_DATA, NULL);
238         data->priv->subfolder_data = g_object_ref (subfolder_data);
239
240         vee_message_uid = g_strconcat (camel_vee_subfolder_data_get_folder_id (subfolder_data), orig_message_uid, NULL);
241
242         data->priv->orig_message_uid = camel_pstring_strdup (orig_message_uid);
243         data->priv->vee_message_uid = camel_pstring_add (vee_message_uid, TRUE);
244
245         return data;
246 }
247
248 /**
249  * camel_vee_message_info_data_get_subfolder_data:
250  *
251  * FIXME Document me!
252  *
253  * Since: 3.6
254  **/
255 CamelVeeSubfolderData *
256 camel_vee_message_info_data_get_subfolder_data (CamelVeeMessageInfoData *data)
257 {
258         g_return_val_if_fail (CAMEL_IS_VEE_MESSAGE_INFO_DATA (data), NULL);
259
260         return data->priv->subfolder_data;
261 }
262
263 /**
264  * camel_vee_message_info_data_get_orig_message_uid:
265  *
266  * FIXME Document me!
267  *
268  * Since: 3.6
269  **/
270 const gchar *
271 camel_vee_message_info_data_get_orig_message_uid (CamelVeeMessageInfoData *data)
272 {
273         g_return_val_if_fail (CAMEL_IS_VEE_MESSAGE_INFO_DATA (data), NULL);
274
275         return data->priv->orig_message_uid;
276 }
277
278 /**
279  * camel_vee_message_info_data_get_vee_message_uid:
280  *
281  * FIXME Document me!
282  *
283  * Since: 3.6
284  **/
285 const gchar *
286 camel_vee_message_info_data_get_vee_message_uid (CamelVeeMessageInfoData *data)
287 {
288         g_return_val_if_fail (CAMEL_IS_VEE_MESSAGE_INFO_DATA (data), NULL);
289
290         return data->priv->vee_message_uid;
291 }
292
293 /* ----------------------------------------------------------------------- */
294
295 struct _CamelVeeDataCachePrivate {
296         GMutex sf_mutex; /* guards subfolder_hash */
297         GHashTable *subfolder_hash; /* CamelFolder * => CamelVeeSubfolderData * */
298
299         GMutex mi_mutex; /* guards message_info_hash */
300         GHashTable *orig_message_uid_hash; /* VeeData * => CamelVeeMessageInfoData * */
301         GHashTable *vee_message_uid_hash; /* const gchar *vee_uid => CamelVeeMessageInfoData * */
302 };
303
304 G_DEFINE_TYPE (CamelVeeDataCache, camel_vee_data_cache, G_TYPE_OBJECT)
305
306 typedef struct _VeeData {
307         CamelFolder *folder;
308         const gchar *orig_message_uid;
309 } VeeData;
310
311 static guint
312 vee_data_hash (gconstpointer ptr)
313 {
314         const VeeData *vee_data = ptr;
315
316         if (!vee_data)
317                 return 0;
318
319         return g_direct_hash (vee_data->folder)
320                 + g_str_hash (vee_data->orig_message_uid);
321 }
322
323 static gboolean
324 vee_data_equal (gconstpointer v1,
325                 gconstpointer v2)
326 {
327         const VeeData *vee_data1 = v1, *vee_data2 = v2;
328
329         if (!v1 || !v2)
330                 return v1 == v2;
331
332         /* can contain ponters directly, strings are always from the string pool */
333         return v1 == v2 ||
334                 (vee_data1->folder == vee_data2->folder &&
335                  vee_data1->orig_message_uid == vee_data2->orig_message_uid);
336 }
337
338 static void
339 camel_vee_data_cache_dispose (GObject *object)
340 {
341         CamelVeeDataCache *data_cache;
342
343         data_cache = CAMEL_VEE_DATA_CACHE (object);
344         if (data_cache->priv) {
345                 if (data_cache->priv->subfolder_hash)
346                         g_hash_table_destroy (data_cache->priv->subfolder_hash);
347                 data_cache->priv->subfolder_hash = NULL;
348
349                 if (data_cache->priv->orig_message_uid_hash)
350                         g_hash_table_destroy (data_cache->priv->orig_message_uid_hash);
351                 data_cache->priv->orig_message_uid_hash = NULL;
352
353                 if (data_cache->priv->vee_message_uid_hash)
354                         g_hash_table_destroy (data_cache->priv->vee_message_uid_hash);
355                 data_cache->priv->vee_message_uid_hash = NULL;
356         }
357
358         /* Chain up to parent's dispose () method. */
359         G_OBJECT_CLASS (camel_vee_data_cache_parent_class)->dispose (object);
360 }
361
362 static void
363 camel_vee_data_cache_finalize (GObject *object)
364 {
365         CamelVeeDataCache *data_cache;
366
367         data_cache = CAMEL_VEE_DATA_CACHE (object);
368         if (data_cache->priv) {
369                 g_mutex_clear (&data_cache->priv->sf_mutex);
370                 g_mutex_clear (&data_cache->priv->mi_mutex);
371         }
372
373         /* Chain up to parent's finalize () method. */
374         G_OBJECT_CLASS (camel_vee_data_cache_parent_class)->finalize (object);
375 }
376
377 static void
378 camel_vee_data_cache_class_init (CamelVeeDataCacheClass *class)
379 {
380         GObjectClass *object_class;
381
382         g_type_class_add_private (class, sizeof (CamelVeeDataCachePrivate));
383
384         object_class = G_OBJECT_CLASS (class);
385         object_class->dispose = camel_vee_data_cache_dispose;
386         object_class->finalize = camel_vee_data_cache_finalize;
387 }
388
389 static void
390 camel_vee_data_cache_init (CamelVeeDataCache *data_cache)
391 {
392         data_cache->priv = G_TYPE_INSTANCE_GET_PRIVATE (data_cache, CAMEL_TYPE_VEE_DATA_CACHE, CamelVeeDataCachePrivate);
393
394         g_mutex_init (&data_cache->priv->sf_mutex);
395         data_cache->priv->subfolder_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
396
397         g_mutex_init (&data_cache->priv->mi_mutex);
398         data_cache->priv->orig_message_uid_hash = g_hash_table_new_full (vee_data_hash, vee_data_equal, g_free, g_object_unref);
399         data_cache->priv->vee_message_uid_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
400 }
401
402 /**
403  * camel_vee_data_cache_new:
404  *
405  * FIXME Document me!
406  *
407  * Since: 3.6
408  **/
409 CamelVeeDataCache *
410 camel_vee_data_cache_new (void)
411 {
412         return g_object_new (CAMEL_TYPE_VEE_DATA_CACHE, NULL);
413 }
414
415 /**
416  * camel_vee_data_cache_add_subfolder:
417  *
418  * FIXME Document me!
419  *
420  * Since: 3.6
421  **/
422 void
423 camel_vee_data_cache_add_subfolder (CamelVeeDataCache *data_cache,
424                                     CamelFolder *subfolder)
425 {
426         CamelVeeSubfolderData *sf_data;
427
428         g_return_if_fail (CAMEL_IS_VEE_DATA_CACHE (data_cache));
429         g_return_if_fail (CAMEL_IS_FOLDER (subfolder));
430
431         g_mutex_lock (&data_cache->priv->mi_mutex);
432         g_mutex_lock (&data_cache->priv->sf_mutex);
433
434         sf_data = g_hash_table_lookup (data_cache->priv->subfolder_hash, subfolder);
435         if (!sf_data) {
436                 GPtrArray *uids;
437                 gint ii;
438
439                 sf_data = camel_vee_subfolder_data_new (subfolder);
440                 g_hash_table_insert (data_cache->priv->subfolder_hash, subfolder, sf_data);
441
442                 /* camel_vee_data_cache_get_message_info_data() caches uids on demand,
443                  * while here are cached all known uids in once - it is better when
444                  * the folder is used in Unmatched folder, where the uid/vuid will
445                  * be used in the vfolder or Unmatched folder anyway */
446                 uids = camel_folder_get_uids (subfolder);
447                 if (uids) {
448                         for (ii = 0; ii < uids->len; ii++) {
449                                 VeeData vdata;
450                                 CamelVeeMessageInfoData *mi_data;
451
452                                 /* make sure the orig_message_uid comes from the string pool */
453                                 vdata.folder = subfolder;
454                                 vdata.orig_message_uid = camel_pstring_strdup (uids->pdata[ii]);
455
456                                 mi_data = g_hash_table_lookup (data_cache->priv->orig_message_uid_hash, &vdata);
457                                 if (!mi_data) {
458                                         VeeData *hash_data;
459
460                                         mi_data = camel_vee_message_info_data_new (sf_data, vdata.orig_message_uid);
461
462                                         hash_data = g_new0 (VeeData, 1);
463                                         hash_data->folder = subfolder;
464                                         hash_data->orig_message_uid = camel_vee_message_info_data_get_orig_message_uid (mi_data);
465
466                                         g_hash_table_insert (data_cache->priv->orig_message_uid_hash, hash_data, mi_data);
467                                         g_hash_table_insert (
468                                                 data_cache->priv->vee_message_uid_hash,
469                                                 (gpointer) camel_vee_message_info_data_get_vee_message_uid (mi_data),
470                                                 mi_data);
471                                 }
472
473                                 camel_pstring_free (vdata.orig_message_uid);
474                         }
475
476                         camel_folder_free_uids (subfolder, uids);
477                 }
478         }
479
480         g_mutex_unlock (&data_cache->priv->sf_mutex);
481         g_mutex_unlock (&data_cache->priv->mi_mutex);
482 }
483
484 static gboolean
485 remove_vee_by_folder_cb (gpointer key,
486                          gpointer value,
487                          gpointer user_data)
488 {
489         CamelVeeMessageInfoData *mi_data = value;
490         CamelVeeSubfolderData *sf_data;
491         CamelFolder *folder = user_data;
492
493         if (!mi_data)
494                 return FALSE;
495
496         sf_data = camel_vee_message_info_data_get_subfolder_data (mi_data);
497         return sf_data && camel_vee_subfolder_data_get_folder (sf_data) == folder;
498 }
499
500 static gboolean
501 remove_orig_by_folder_cb (gpointer key,
502                           gpointer value,
503                           gpointer user_data)
504 {
505         VeeData *vee_data = key;
506         CamelFolder *folder = user_data;
507
508         return vee_data && vee_data->folder == folder;
509 }
510
511 /**
512  * camel_vee_data_cache_remove_subfolder:
513  *
514  * FIXME Document me!
515  *
516  * Since: 3.6
517  **/
518 void
519 camel_vee_data_cache_remove_subfolder (CamelVeeDataCache *data_cache,
520                                        CamelFolder *subfolder)
521 {
522         g_return_if_fail (CAMEL_IS_VEE_DATA_CACHE (data_cache));
523         g_return_if_fail (CAMEL_IS_FOLDER (subfolder));
524
525         g_mutex_lock (&data_cache->priv->mi_mutex);
526         g_mutex_lock (&data_cache->priv->sf_mutex);
527
528         g_hash_table_foreach_remove (data_cache->priv->vee_message_uid_hash, remove_vee_by_folder_cb, subfolder);
529         g_hash_table_foreach_remove (data_cache->priv->orig_message_uid_hash, remove_orig_by_folder_cb, subfolder);
530         g_hash_table_remove (data_cache->priv->subfolder_hash, subfolder);
531
532         g_mutex_unlock (&data_cache->priv->sf_mutex);
533         g_mutex_unlock (&data_cache->priv->mi_mutex);
534 }
535
536 /**
537  * camel_vee_data_cache_get_subfolder_data:
538  *
539  * FIXME Document me!
540  *
541  * Since: 3.6
542  **/
543 CamelVeeSubfolderData *
544 camel_vee_data_cache_get_subfolder_data (CamelVeeDataCache *data_cache,
545                                          CamelFolder *folder)
546 {
547         CamelVeeSubfolderData *res;
548
549         g_return_val_if_fail (CAMEL_IS_VEE_DATA_CACHE (data_cache), NULL);
550         g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
551
552         g_mutex_lock (&data_cache->priv->sf_mutex);
553
554         res = g_hash_table_lookup (data_cache->priv->subfolder_hash, folder);
555         if (!res) {
556                 res = camel_vee_subfolder_data_new (folder);
557                 g_hash_table_insert (data_cache->priv->subfolder_hash, folder, res);
558         }
559
560         g_object_ref (res);
561
562         g_mutex_unlock (&data_cache->priv->sf_mutex);
563
564         return res;
565 }
566
567 /**
568  * camel_vee_data_cache_contains_message_info_data:
569  *
570  * Returns whether data_cache contains certain UID for certain folder;
571  * instead of camel_vee_data_cache_get_message_info_data() only
572  * returns FALSE if not, while camel_vee_data_cache_get_message_info_data()
573  * auto-adds it to data_cache.
574  *
575  * Since: 3.6
576  */
577 gboolean
578 camel_vee_data_cache_contains_message_info_data (CamelVeeDataCache *data_cache,
579                                                  CamelFolder *folder,
580                                                  const gchar *orig_message_uid)
581 {
582         gboolean res;
583         VeeData vdata;
584
585         g_return_val_if_fail (CAMEL_IS_VEE_DATA_CACHE (data_cache), FALSE);
586         g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
587         g_return_val_if_fail (orig_message_uid != NULL, FALSE);
588
589         g_mutex_lock (&data_cache->priv->mi_mutex);
590
591         /* make sure the orig_message_uid comes from the string pool */
592         vdata.folder = folder;
593         vdata.orig_message_uid = camel_pstring_strdup (orig_message_uid);
594
595         res = g_hash_table_lookup (data_cache->priv->orig_message_uid_hash, &vdata) != NULL;
596
597         camel_pstring_free (vdata.orig_message_uid);
598
599         g_mutex_unlock (&data_cache->priv->mi_mutex);
600
601         return res;
602 }
603
604 /**
605  * camel_vee_data_cache_get_message_info_data:
606  *
607  * FIXME Document me!
608  *
609  * Since: 3.6
610  **/
611 CamelVeeMessageInfoData *
612 camel_vee_data_cache_get_message_info_data (CamelVeeDataCache *data_cache,
613                                             CamelFolder *folder,
614                                             const gchar *orig_message_uid)
615 {
616         CamelVeeMessageInfoData *res;
617         VeeData vdata;
618
619         g_return_val_if_fail (CAMEL_IS_VEE_DATA_CACHE (data_cache), NULL);
620         g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
621         g_return_val_if_fail (orig_message_uid != NULL, NULL);
622
623         g_mutex_lock (&data_cache->priv->mi_mutex);
624
625         /* make sure the orig_message_uid comes from the string pool */
626         vdata.folder = folder;
627         vdata.orig_message_uid = camel_pstring_strdup (orig_message_uid);
628
629         res = g_hash_table_lookup (data_cache->priv->orig_message_uid_hash, &vdata);
630         if (!res) {
631                 VeeData *hash_data;
632                 CamelVeeSubfolderData *sf_data;
633
634                 /* this locks also priv->sf_mutex */
635                 sf_data = camel_vee_data_cache_get_subfolder_data (data_cache, folder);
636                 if (!sf_data) {
637                         camel_pstring_free (vdata.orig_message_uid);
638                         g_mutex_unlock (&data_cache->priv->mi_mutex);
639                         g_return_val_if_fail (sf_data != NULL, NULL);
640                 }
641
642                 res = camel_vee_message_info_data_new (sf_data, orig_message_uid);
643
644                 /* res holds the reference now */
645                 g_object_unref (sf_data);
646
647                 hash_data = g_new0 (VeeData, 1);
648                 hash_data->folder = folder;
649                 hash_data->orig_message_uid = camel_vee_message_info_data_get_orig_message_uid (res);
650
651                 g_hash_table_insert (data_cache->priv->orig_message_uid_hash, hash_data, res);
652                 g_hash_table_insert (
653                         data_cache->priv->vee_message_uid_hash,
654                         (gpointer) camel_vee_message_info_data_get_vee_message_uid (res),
655                         res);
656         }
657
658         camel_pstring_free (vdata.orig_message_uid);
659         g_object_ref (res);
660
661         g_mutex_unlock (&data_cache->priv->mi_mutex);
662
663         return res;
664 }
665
666 /**
667  * camel_vee_data_cache_get_message_info_data_by_vuid:
668  *
669  * FIXME Document me!
670  *
671  * Since: 3.6
672  **/
673 CamelVeeMessageInfoData *
674 camel_vee_data_cache_get_message_info_data_by_vuid (CamelVeeDataCache *data_cache,
675                                                     const gchar *vee_message_uid)
676 {
677         CamelVeeMessageInfoData *res;
678         const gchar *vuid;
679
680         g_return_val_if_fail (CAMEL_IS_VEE_DATA_CACHE (data_cache), NULL);
681         g_return_val_if_fail (vee_message_uid != NULL, NULL);
682
683         g_mutex_lock (&data_cache->priv->mi_mutex);
684
685         /* make sure vee_message_uid comes from the string pool */
686         vuid = camel_pstring_strdup (vee_message_uid);
687
688         res = g_hash_table_lookup (data_cache->priv->vee_message_uid_hash, vuid);
689         if (res)
690                 g_object_ref (res);
691
692         g_mutex_unlock (&data_cache->priv->mi_mutex);
693
694         camel_pstring_free (vuid);
695
696         return res;
697 }
698
699 struct ForeachMiData {
700         CamelFolder *fromfolder;
701         void (* func) (CamelVeeMessageInfoData *mi_data,
702                         CamelFolder *subfolder,
703                         gpointer user_data);
704         gpointer user_data;
705 };
706
707 static void
708 cvdc_foreach_mi_data_cb (gpointer key,
709                          gpointer value,
710                          gpointer user_data)
711 {
712         VeeData *vdata = key;
713         CamelVeeMessageInfoData *mi_data = value;
714         struct ForeachMiData *fmd = user_data;
715
716         g_return_if_fail (key != NULL);
717         g_return_if_fail (value != NULL);
718         g_return_if_fail (user_data != NULL);
719
720         if (!fmd->fromfolder || fmd->fromfolder == vdata->folder)
721                 fmd->func (mi_data, vdata->folder, fmd->user_data);
722 }
723
724 /**
725  * camel_vee_data_cache_foreach_message_info_data:
726  *
727  * FIXME Document me!
728  *
729  * Since: 3.6
730  **/
731 void
732 camel_vee_data_cache_foreach_message_info_data (CamelVeeDataCache *data_cache,
733                                                 CamelFolder *fromfolder,
734                                                 void (* func) (CamelVeeMessageInfoData *mi_data,
735                                                                 CamelFolder *subfolder,
736                                                                 gpointer user_data),
737                                                 gpointer user_data)
738 {
739         struct ForeachMiData fmd;
740
741         g_return_if_fail (CAMEL_IS_VEE_DATA_CACHE (data_cache));
742         g_return_if_fail (func != NULL);
743
744         g_mutex_lock (&data_cache->priv->mi_mutex);
745
746         fmd.fromfolder = fromfolder;
747         fmd.func = func;
748         fmd.user_data = user_data;
749
750         g_hash_table_foreach (data_cache->priv->orig_message_uid_hash, cvdc_foreach_mi_data_cb, &fmd);
751
752         g_mutex_unlock (&data_cache->priv->mi_mutex);
753 }
754
755 /**
756  * camel_vee_data_cache_remove_message_info_data:
757  *
758  * FIXME Document me!
759  *
760  * Since: 3.6
761  **/
762 void
763 camel_vee_data_cache_remove_message_info_data (CamelVeeDataCache *data_cache,
764                                                CamelVeeMessageInfoData *mi_data)
765 {
766         VeeData vdata;
767         CamelVeeSubfolderData *sf_data;
768         const gchar *vuid;
769
770         g_return_if_fail (CAMEL_IS_VEE_DATA_CACHE (data_cache));
771         g_return_if_fail (CAMEL_IS_VEE_MESSAGE_INFO_DATA (mi_data));
772
773         g_mutex_lock (&data_cache->priv->mi_mutex);
774
775         g_object_ref (mi_data);
776
777         sf_data = camel_vee_message_info_data_get_subfolder_data (mi_data);
778
779         vdata.folder = camel_vee_subfolder_data_get_folder (sf_data);
780         vdata.orig_message_uid = camel_vee_message_info_data_get_orig_message_uid (mi_data);
781         vuid = camel_vee_message_info_data_get_vee_message_uid (mi_data);
782
783         g_hash_table_remove (data_cache->priv->vee_message_uid_hash, vuid);
784         g_hash_table_remove (data_cache->priv->orig_message_uid_hash, &vdata);
785
786         g_object_unref (mi_data);
787
788         g_mutex_unlock (&data_cache->priv->mi_mutex);
789 }