1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
5 * Authors: Michael Zucchi <notzed@ximian.com>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of version 2 of the GNU Lesser General Public
9 * License as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
32 #include "camel-imapx-utils.h"
33 #include "camel-imapx-store-summary.h"
35 #define d(...) camel_imapx_debug(debug, '?', __VA_ARGS__)
37 #define CAMEL_IMAPX_STORE_SUMMARY_VERSION_0 (0)
39 #define CAMEL_IMAPX_STORE_SUMMARY_VERSION (0)
41 static gint summary_header_load (CamelStoreSummary *, FILE *);
42 static gint summary_header_save (CamelStoreSummary *, FILE *);
44 /*static CamelStoreInfo * store_info_new(CamelStoreSummary *, const gchar *);*/
45 static CamelStoreInfo * store_info_load (CamelStoreSummary *, FILE *);
46 static gint store_info_save (CamelStoreSummary *, FILE *, CamelStoreInfo *);
47 static void store_info_free (CamelStoreSummary *, CamelStoreInfo *);
49 static const gchar *store_info_string (CamelStoreSummary *, const CamelStoreInfo *, gint);
50 static void store_info_set_string (CamelStoreSummary *, CamelStoreInfo *, int, const gchar *);
52 G_DEFINE_TYPE (CamelIMAPXStoreSummary, camel_imapx_store_summary, CAMEL_TYPE_STORE_SUMMARY)
55 imapx_store_summary_finalize (GObject *object)
57 CamelIMAPXStoreSummary *summary;
59 summary = CAMEL_IMAPX_STORE_SUMMARY (object);
61 camel_imapx_namespace_list_clear (summary->namespaces);
63 /* Chain up to parent's finalize() method. */
64 G_OBJECT_CLASS (camel_imapx_store_summary_parent_class)->finalize (object);
68 camel_imapx_store_summary_class_init (CamelIMAPXStoreSummaryClass *class)
70 GObjectClass *object_class;
71 CamelStoreSummaryClass *store_summary_class;
73 object_class = G_OBJECT_CLASS (class);
74 object_class->finalize = imapx_store_summary_finalize;
76 store_summary_class = CAMEL_STORE_SUMMARY_CLASS (class);
77 store_summary_class->summary_header_load = summary_header_load;
78 store_summary_class->summary_header_save = summary_header_save;
79 store_summary_class->store_info_load = store_info_load;
80 store_summary_class->store_info_save = store_info_save;
81 store_summary_class->store_info_free = store_info_free;
82 store_summary_class->store_info_string = store_info_string;
83 store_summary_class->store_info_set_string = store_info_set_string;
87 camel_imapx_store_summary_init (CamelIMAPXStoreSummary *s)
89 ((CamelStoreSummary *) s)->store_info_size = sizeof (CamelIMAPXStoreInfo);
90 s->version = CAMEL_IMAPX_STORE_SUMMARY_VERSION;
94 * camel_imapx_store_summary_new:
96 * Create a new CamelIMAPXStoreSummary object.
98 * Returns: A new CamelIMAPXStoreSummary widget.
100 CamelIMAPXStoreSummary *
101 camel_imapx_store_summary_new (void)
103 return g_object_new (CAMEL_TYPE_IMAPX_STORE_SUMMARY, NULL);
107 * camel_imapx_store_summary_full_name:
111 * Retrieve a summary item by full name.
113 * A referenced to the summary item is returned, which may be
114 * ref'd or free'd as appropriate.
116 * Returns: The summary item, or NULL if the @full_name name
118 * It must be freed using camel_store_summary_info_free().
120 CamelIMAPXStoreInfo *
121 camel_imapx_store_summary_full_name (CamelIMAPXStoreSummary *s,
122 const gchar *full_name)
125 CamelIMAPXStoreInfo *info;
127 count = camel_store_summary_count ((CamelStoreSummary *) s);
128 for (i = 0; i < count; i++) {
129 info = (CamelIMAPXStoreInfo *) camel_store_summary_index ((CamelStoreSummary *) s, i);
131 if (strcmp (info->full_name, full_name) == 0)
133 camel_store_summary_info_free ((CamelStoreSummary *) s, (CamelStoreInfo *) info);
141 camel_imapx_store_summary_full_to_path (CamelIMAPXStoreSummary *s,
142 const gchar *full_name,
147 p = path = g_strdup (full_name);
149 if (dir_sep && dir_sep != '/') {
153 else if (*p == dir_sep)
162 camel_imapx_store_summary_path_to_full (CamelIMAPXStoreSummary *s,
168 gchar *subpath, *last = NULL;
170 CamelIMAPXStoreNamespace *ns;
172 /* check to see if we have a subpath of path already defined */
173 subpath = alloca (strlen (path) + 1);
174 strcpy (subpath, path);
176 si = camel_store_summary_path ((CamelStoreSummary *) s, subpath);
178 last = strrchr (subpath, '/');
182 } while (si == NULL && last);
184 /* path is already present, use the raw version we have */
185 if (si && strlen (subpath) == strlen (path)) {
186 f = g_strdup (camel_imapx_store_info_full_name (s, si));
187 camel_store_summary_info_free ((CamelStoreSummary *) s, si);
191 ns = camel_imapx_store_summary_namespace_find_path (s, path);
194 p = path + strlen (subpath);
196 p = path + strlen (ns->path);
200 f = full = g_strdup (p);
201 if (dir_sep != '/') {
205 else if (*f == dir_sep)
211 /* merge old path part if required */
214 full = g_strdup_printf("%s%s", camel_imapx_store_info_full_name(s, si), f);
216 camel_store_summary_info_free ((CamelStoreSummary *) s, si);
219 full = g_strdup_printf("%s%s", ns->full_name, f);
227 CamelIMAPXStoreInfo *
228 camel_imapx_store_summary_add_from_full (CamelIMAPXStoreSummary *s,
232 CamelIMAPXStoreInfo *info;
233 gchar *pathu8, *prefix;
236 CamelIMAPXStoreNamespace *ns;
238 d("adding full name '%s' '%c'\n", full, dir_sep);
241 full_name = alloca (len + 1);
242 strcpy (full_name, full);
243 if (full_name[len - 1] == dir_sep)
244 full_name[len - 1] = 0;
246 info = camel_imapx_store_summary_full_name (s, full_name);
248 camel_store_summary_info_free ((CamelStoreSummary *) s, (CamelStoreInfo *) info);
249 d(" already there\n");
253 ns = camel_imapx_store_summary_namespace_find_full (s, full_name);
255 d("(found namespace for '%s' ns '%s') ", full_name, ns->path);
256 len = strlen (ns->full_name);
257 if (len >= strlen (full_name)) {
258 pathu8 = g_strdup (ns->path);
260 if (full_name[len] == ns->sep)
263 prefix = camel_imapx_store_summary_full_to_path (s, full_name + len, ns->sep);
265 pathu8 = g_strdup_printf ("%s/%s", ns->path, prefix);
271 d(" (pathu8 = '%s')", pathu8);
273 d("(Cannot find namespace for '%s')\n", full_name);
274 pathu8 = camel_imapx_store_summary_full_to_path (s, full_name, dir_sep);
277 info = (CamelIMAPXStoreInfo *) camel_store_summary_add_from_path ((CamelStoreSummary *) s, pathu8);
279 d(" '%s' -> '%s'\n", pathu8, full_name);
280 camel_store_info_set_string ((CamelStoreSummary *) s, (CamelStoreInfo *) info, CAMEL_IMAPX_STORE_INFO_FULL_NAME, full_name);
282 if (!g_ascii_strcasecmp(full_name, "inbox"))
283 info->info.flags |= CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_TYPE_INBOX;
293 /* should this be const? */
294 /* TODO: deprecate/merge this function with path_to_full */
296 camel_imapx_store_summary_full_from_path (CamelIMAPXStoreSummary *s,
299 CamelIMAPXStoreNamespace *ns;
302 ns = camel_imapx_store_summary_namespace_find_path (s, path);
304 name = camel_imapx_store_summary_path_to_full (s, path, ns->sep);
306 d("looking up path %s -> %s\n", path, name?name:"not found");
311 /* TODO: this api needs some more work */
312 CamelIMAPXStoreNamespace *
313 camel_imapx_store_summary_namespace_new (CamelIMAPXStoreSummary *s,
314 const gchar *full_name,
317 CamelIMAPXStoreNamespace *ns;
321 ns = g_malloc0 (sizeof (*ns));
322 ns->full_name = g_strdup (full_name);
323 len = strlen (ns->full_name) - 1;
324 if (len >= 0 && ns->full_name[len] == dir_sep)
325 ns->full_name[len] = 0;
328 o = p = ns->path = camel_imapx_store_summary_full_to_path (s, ns->full_name, dir_sep);
341 void camel_imapx_store_summary_namespace_set (CamelIMAPXStoreSummary *s, CamelIMAPXStoreNamespace *ns)
343 d("Setting namesapce to '%s' '%c' -> '%s'\n", ns->full_name, ns->sep, ns->path);
345 /* CHEN not needed */
346 camel_store_summary_touch ((CamelStoreSummary *) s);
349 CamelIMAPXStoreNamespace *
350 camel_imapx_store_summary_namespace_find_path (CamelIMAPXStoreSummary *s,
354 CamelIMAPXStoreNamespace *ns;
356 /* NB: this currently only compares against 1 namespace, in future compare against others */
358 ns = s->namespaces->personal;
360 len = strlen (ns->path);
362 || (strncmp (ns->path, path, len) == 0
363 && (path[len] == '/' || path[len] == 0)))
368 /* have a default? */
372 CamelIMAPXStoreNamespace *
373 camel_imapx_store_summary_namespace_find_full (CamelIMAPXStoreSummary *s,
377 CamelIMAPXStoreNamespace *ns;
379 /* NB: this currently only compares against 1 namespace, in future compare against others */
381 ns = s->namespaces->personal;
384 len = strlen (ns->full_name);
385 d("find_full: comparing namespace '%s' to name '%s'\n", ns->full_name, full);
387 || (strncmp (ns->full_name, full, len) == 0
388 && (full[len] == ns->sep || full[len] == 0)))
393 /* have a default? */
397 static CamelIMAPXNamespaceList *
398 namespace_load (CamelStoreSummary *s,
401 CamelIMAPXStoreNamespace *ns, *tail;
402 CamelIMAPXNamespaceList *nsl;
406 nsl = g_malloc0 (sizeof (CamelIMAPXNamespaceList));
407 nsl->personal = NULL;
411 for (j = 0; j < 3; j++) {
414 tail = (CamelIMAPXStoreNamespace *) &nsl->personal;
417 tail = (CamelIMAPXStoreNamespace *) &nsl->shared;
420 tail = (CamelIMAPXStoreNamespace *) &nsl->other;
424 if (camel_file_util_decode_fixed_int32 (in, &n) == -1)
427 for (i = 0; i < n; i++) {
432 if (camel_file_util_decode_string (in, &path) == -1)
435 if (camel_file_util_decode_string (in, &full_name) == -1) {
440 if (camel_file_util_decode_uint32 (in, &sep) == -1) {
446 tail->next = ns = g_malloc (sizeof (CamelIMAPXStoreNamespace));
449 ns->full_name = full_name;
457 camel_imapx_namespace_list_clear (nsl);
463 namespace_save (CamelStoreSummary *s,
465 CamelIMAPXNamespaceList *nsl)
467 CamelIMAPXStoreNamespace *ns, *cur = NULL;
470 for (i = 0; i < 3; i++) {
483 for (ns = cur, n = 0; ns; n++)
486 if (camel_file_util_encode_fixed_int32 (out, n) == -1)
491 if (camel_file_util_encode_string (out, ns->path) == -1)
494 if (camel_file_util_encode_string (out, ns->full_name) == -1)
497 if (camel_file_util_encode_uint32 (out, ns->sep) == -1)
508 summary_header_load (CamelStoreSummary *s,
511 CamelIMAPXStoreSummary *is = (CamelIMAPXStoreSummary *) s;
512 CamelStoreSummaryClass *store_summary_class;
513 gint32 version, capabilities;
515 camel_imapx_namespace_list_clear (is->namespaces);
517 store_summary_class = CAMEL_STORE_SUMMARY_CLASS (camel_imapx_store_summary_parent_class);
518 if (store_summary_class->summary_header_load ((CamelStoreSummary *) s, in) == -1
519 || camel_file_util_decode_fixed_int32 (in, &version) == -1)
522 is->version = version;
524 if (version < CAMEL_IMAPX_STORE_SUMMARY_VERSION_0) {
525 g_warning("Store summary header version too low");
529 /* note file format can be expanded to contain more namespaces, but only 1 at the moment */
530 if (camel_file_util_decode_fixed_int32 (in, &capabilities) == -1)
533 is->capabilities = capabilities;
536 if ((is->namespaces = namespace_load (s, in)) == NULL)
543 summary_header_save (CamelStoreSummary *s,
546 CamelIMAPXStoreSummary *is = (CamelIMAPXStoreSummary *) s;
547 CamelStoreSummaryClass *store_summary_class;
549 /* always write as latest version */
550 store_summary_class = CAMEL_STORE_SUMMARY_CLASS (camel_imapx_store_summary_parent_class);
551 if (store_summary_class->summary_header_save ((CamelStoreSummary *) s, out) == -1
552 || camel_file_util_encode_fixed_int32 (out, CAMEL_IMAPX_STORE_SUMMARY_VERSION) == -1
553 || camel_file_util_encode_fixed_int32 (out, is->capabilities) == -1)
556 if (is->namespaces && namespace_save (s, out, is->namespaces) == -1)
562 static CamelStoreInfo *
563 store_info_load (CamelStoreSummary *s,
566 CamelIMAPXStoreInfo *mi;
567 CamelStoreSummaryClass *store_summary_class;
569 store_summary_class = CAMEL_STORE_SUMMARY_CLASS (camel_imapx_store_summary_parent_class);
570 mi = (CamelIMAPXStoreInfo *) store_summary_class->store_info_load (s, in);
572 if (camel_file_util_decode_string (in, &mi->full_name) == -1) {
573 camel_store_summary_info_free (s, (CamelStoreInfo *) mi);
576 /* NB: this is done again for compatability */
577 if (g_ascii_strcasecmp(mi->full_name, "inbox") == 0)
578 mi->info.flags |= CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_TYPE_INBOX;
582 return (CamelStoreInfo *) mi;
586 store_info_save (CamelStoreSummary *s,
590 CamelIMAPXStoreInfo *isi = (CamelIMAPXStoreInfo *) mi;
591 CamelStoreSummaryClass *store_summary_class;
593 store_summary_class = CAMEL_STORE_SUMMARY_CLASS (camel_imapx_store_summary_parent_class);
594 if (store_summary_class->store_info_save (s, out, mi) == -1
595 || camel_file_util_encode_string (out, isi->full_name) == -1)
602 store_info_free (CamelStoreSummary *s,
605 CamelIMAPXStoreInfo *isi = (CamelIMAPXStoreInfo *) mi;
606 CamelStoreSummaryClass *store_summary_class;
608 g_free (isi->full_name);
610 store_summary_class = CAMEL_STORE_SUMMARY_CLASS (camel_imapx_store_summary_parent_class);
611 store_summary_class->store_info_free (s, mi);
615 store_info_string (CamelStoreSummary *s,
616 const CamelStoreInfo *mi,
619 CamelIMAPXStoreInfo *isi = (CamelIMAPXStoreInfo *) mi;
620 CamelStoreSummaryClass *store_summary_class;
624 g_assert (mi != NULL);
626 store_summary_class = CAMEL_STORE_SUMMARY_CLASS (camel_imapx_store_summary_parent_class);
629 case CAMEL_IMAPX_STORE_INFO_FULL_NAME:
630 return isi->full_name;
632 return store_summary_class->store_info_string (s, mi, type);
637 store_info_set_string (CamelStoreSummary *s,
642 CamelIMAPXStoreInfo *isi = (CamelIMAPXStoreInfo *) mi;
643 CamelStoreSummaryClass *store_summary_class;
645 g_assert (mi != NULL);
647 store_summary_class = CAMEL_STORE_SUMMARY_CLASS (camel_imapx_store_summary_parent_class);
650 case CAMEL_IMAPX_STORE_INFO_FULL_NAME:
651 d("Set full name %s -> %s\n", isi->full_name, str);
652 camel_store_summary_lock (s, CAMEL_STORE_SUMMARY_SUMMARY_LOCK);
653 g_free (isi->full_name);
654 isi->full_name = g_strdup (str);
655 camel_store_summary_unlock (s, CAMEL_STORE_SUMMARY_SUMMARY_LOCK);
658 store_summary_class->store_info_set_string (s, mi, type, str);
664 camel_imapx_store_summary_set_namespaces (CamelIMAPXStoreSummary *summary,
665 const CamelIMAPXNamespaceList *nsl)
667 if (summary->namespaces)
668 camel_imapx_namespace_list_clear (summary->namespaces);
669 summary->namespaces = camel_imapx_namespace_list_copy (nsl);