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/camel-file-utils.h>
33 #include "camel-imapx-utils.h"
34 #include "camel-imapx-store-summary.h"
36 #define d(...) camel_imapx_debug(debug, '?', __VA_ARGS__)
38 #define CAMEL_IMAPX_STORE_SUMMARY_VERSION_0 (0)
40 #define CAMEL_IMAPX_STORE_SUMMARY_VERSION (0)
42 static gint summary_header_load (CamelStoreSummary *, FILE *);
43 static gint summary_header_save (CamelStoreSummary *, FILE *);
45 /*static CamelStoreInfo * store_info_new(CamelStoreSummary *, const gchar *);*/
46 static CamelStoreInfo * store_info_load (CamelStoreSummary *, FILE *);
47 static gint store_info_save (CamelStoreSummary *, FILE *, CamelStoreInfo *);
48 static void store_info_free (CamelStoreSummary *, CamelStoreInfo *);
50 static const gchar *store_info_string (CamelStoreSummary *, const CamelStoreInfo *, gint);
51 static void store_info_set_string (CamelStoreSummary *, CamelStoreInfo *, int, const gchar *);
53 G_DEFINE_TYPE (CamelIMAPXStoreSummary, camel_imapx_store_summary, CAMEL_TYPE_STORE_SUMMARY)
56 imapx_store_summary_finalize (GObject *object)
58 CamelIMAPXStoreSummary *summary;
60 summary = CAMEL_IMAPX_STORE_SUMMARY (object);
62 camel_imapx_namespace_list_clear (summary->namespaces);
64 /* Chain up to parent's finalize() method. */
65 G_OBJECT_CLASS (camel_imapx_store_summary_parent_class)->finalize (object);
69 camel_imapx_store_summary_class_init (CamelIMAPXStoreSummaryClass *class)
71 GObjectClass *object_class;
72 CamelStoreSummaryClass *store_summary_class;
74 object_class = G_OBJECT_CLASS (class);
75 object_class->finalize = imapx_store_summary_finalize;
77 store_summary_class = CAMEL_STORE_SUMMARY_CLASS (class);
78 store_summary_class->summary_header_load = summary_header_load;
79 store_summary_class->summary_header_save = summary_header_save;
80 store_summary_class->store_info_load = store_info_load;
81 store_summary_class->store_info_save = store_info_save;
82 store_summary_class->store_info_free = store_info_free;
83 store_summary_class->store_info_string = store_info_string;
84 store_summary_class->store_info_set_string = store_info_set_string;
88 camel_imapx_store_summary_init (CamelIMAPXStoreSummary *s)
90 ((CamelStoreSummary *) s)->store_info_size = sizeof (CamelIMAPXStoreInfo);
91 s->version = CAMEL_IMAPX_STORE_SUMMARY_VERSION;
95 * camel_imapx_store_summary_new:
97 * Create a new CamelIMAPXStoreSummary object.
99 * Returns: A new CamelIMAPXStoreSummary widget.
101 CamelIMAPXStoreSummary *
102 camel_imapx_store_summary_new (void)
104 return g_object_new (CAMEL_TYPE_IMAPX_STORE_SUMMARY, NULL);
108 * camel_imapx_store_summary_full_name:
112 * Retrieve a summary item by full name.
114 * A referenced to the summary item is returned, which may be
115 * ref'd or free'd as appropriate.
117 * Returns: The summary item, or NULL if the @full_name name
119 * It must be freed using camel_store_summary_info_free().
121 CamelIMAPXStoreInfo *
122 camel_imapx_store_summary_full_name (CamelIMAPXStoreSummary *s,
123 const gchar *full_name)
126 CamelIMAPXStoreInfo *info;
128 count = camel_store_summary_count ((CamelStoreSummary *) s);
129 for (i = 0; i < count; i++) {
130 info = (CamelIMAPXStoreInfo *) camel_store_summary_index ((CamelStoreSummary *) s, i);
132 if (strcmp (info->full_name, full_name) == 0)
134 camel_store_summary_info_free ((CamelStoreSummary *) s, (CamelStoreInfo *) info);
142 camel_imapx_store_summary_full_to_path (CamelIMAPXStoreSummary *s,
143 const gchar *full_name,
148 p = path = g_strdup (full_name);
150 if (dir_sep && dir_sep != '/') {
154 else if (*p == dir_sep)
163 camel_imapx_store_summary_path_to_full (CamelIMAPXStoreSummary *s,
169 gchar *subpath, *last = NULL;
171 CamelIMAPXStoreNamespace *ns;
173 /* check to see if we have a subpath of path already defined */
174 subpath = alloca (strlen (path) + 1);
175 strcpy (subpath, path);
177 si = camel_store_summary_path ((CamelStoreSummary *) s, subpath);
179 last = strrchr (subpath, '/');
183 } while (si == NULL && last);
185 /* path is already present, use the raw version we have */
186 if (si && strlen (subpath) == strlen (path)) {
187 f = g_strdup (camel_imapx_store_info_full_name (s, si));
188 camel_store_summary_info_free ((CamelStoreSummary *) s, si);
192 ns = camel_imapx_store_summary_namespace_find_path (s, path);
195 p = path + strlen (subpath);
197 p = path + strlen (ns->path);
201 f = full = g_strdup (p);
202 if (dir_sep != '/') {
206 else if (*f == dir_sep)
212 /* merge old path part if required */
215 full = g_strdup_printf("%s%s", camel_imapx_store_info_full_name(s, si), f);
217 camel_store_summary_info_free ((CamelStoreSummary *) s, si);
220 full = g_strdup_printf("%s%s", ns->full_name, f);
228 CamelIMAPXStoreInfo *
229 camel_imapx_store_summary_add_from_full (CamelIMAPXStoreSummary *s,
233 CamelIMAPXStoreInfo *info;
234 gchar *pathu8, *prefix;
237 CamelIMAPXStoreNamespace *ns;
239 d("adding full name '%s' '%c'\n", full, dir_sep);
242 full_name = alloca (len + 1);
243 strcpy (full_name, full);
244 if (full_name[len - 1] == dir_sep)
245 full_name[len - 1] = 0;
247 info = camel_imapx_store_summary_full_name (s, full_name);
249 camel_store_summary_info_free ((CamelStoreSummary *) s, (CamelStoreInfo *) info);
250 d(" already there\n");
254 ns = camel_imapx_store_summary_namespace_find_full (s, full_name);
256 d("(found namespace for '%s' ns '%s') ", full_name, ns->path);
257 len = strlen (ns->full_name);
258 if (len >= strlen (full_name)) {
259 pathu8 = g_strdup (ns->path);
261 if (full_name[len] == ns->sep)
264 prefix = camel_imapx_store_summary_full_to_path (s, full_name + len, ns->sep);
266 pathu8 = g_strdup_printf ("%s/%s", ns->path, prefix);
272 d(" (pathu8 = '%s')", pathu8);
274 d("(Cannot find namespace for '%s')\n", full_name);
275 pathu8 = camel_imapx_store_summary_full_to_path (s, full_name, dir_sep);
278 info = (CamelIMAPXStoreInfo *) camel_store_summary_add_from_path ((CamelStoreSummary *) s, pathu8);
280 d(" '%s' -> '%s'\n", pathu8, full_name);
281 camel_store_info_set_string ((CamelStoreSummary *) s, (CamelStoreInfo *) info, CAMEL_IMAPX_STORE_INFO_FULL_NAME, full_name);
283 if (!g_ascii_strcasecmp(full_name, "inbox"))
284 info->info.flags |= CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_TYPE_INBOX;
294 /* should this be const? */
295 /* TODO: deprecate/merge this function with path_to_full */
297 camel_imapx_store_summary_full_from_path (CamelIMAPXStoreSummary *s,
300 CamelIMAPXStoreNamespace *ns;
303 ns = camel_imapx_store_summary_namespace_find_path (s, path);
305 name = camel_imapx_store_summary_path_to_full (s, path, ns->sep);
307 d("looking up path %s -> %s\n", path, name?name:"not found");
312 /* TODO: this api needs some more work */
313 CamelIMAPXStoreNamespace *
314 camel_imapx_store_summary_namespace_new (CamelIMAPXStoreSummary *s,
315 const gchar *full_name,
318 CamelIMAPXStoreNamespace *ns;
322 ns = g_malloc0 (sizeof (*ns));
323 ns->full_name = g_strdup (full_name);
324 len = strlen (ns->full_name) - 1;
325 if (len >= 0 && ns->full_name[len] == dir_sep)
326 ns->full_name[len] = 0;
329 o = p = ns->path = camel_imapx_store_summary_full_to_path (s, ns->full_name, dir_sep);
342 void camel_imapx_store_summary_namespace_set (CamelIMAPXStoreSummary *s, CamelIMAPXStoreNamespace *ns)
344 d("Setting namesapce to '%s' '%c' -> '%s'\n", ns->full_name, ns->sep, ns->path);
346 /* CHEN not needed */
347 camel_store_summary_touch ((CamelStoreSummary *) s);
350 CamelIMAPXStoreNamespace *
351 camel_imapx_store_summary_namespace_find_path (CamelIMAPXStoreSummary *s,
355 CamelIMAPXStoreNamespace *ns;
357 /* NB: this currently only compares against 1 namespace, in future compare against others */
359 ns = s->namespaces->personal;
361 len = strlen (ns->path);
363 || (strncmp (ns->path, path, len) == 0
364 && (path[len] == '/' || path[len] == 0)))
369 /* have a default? */
373 CamelIMAPXStoreNamespace *
374 camel_imapx_store_summary_namespace_find_full (CamelIMAPXStoreSummary *s,
378 CamelIMAPXStoreNamespace *ns;
380 /* NB: this currently only compares against 1 namespace, in future compare against others */
382 ns = s->namespaces->personal;
385 len = strlen (ns->full_name);
386 d("find_full: comparing namespace '%s' to name '%s'\n", ns->full_name, full);
388 || (strncmp (ns->full_name, full, len) == 0
389 && (full[len] == ns->sep || full[len] == 0)))
394 /* have a default? */
398 static CamelIMAPXNamespaceList *
399 namespace_load (CamelStoreSummary *s,
402 CamelIMAPXStoreNamespace *ns, *tail;
403 CamelIMAPXNamespaceList *nsl;
407 nsl = g_malloc0 (sizeof (CamelIMAPXNamespaceList));
408 nsl->personal = NULL;
412 for (j = 0; j < 3; j++) {
415 tail = (CamelIMAPXStoreNamespace *) &nsl->personal;
418 tail = (CamelIMAPXStoreNamespace *) &nsl->shared;
421 tail = (CamelIMAPXStoreNamespace *) &nsl->other;
425 if (camel_file_util_decode_fixed_int32 (in, &n) == -1)
428 for (i = 0; i < n; i++) {
433 if (camel_file_util_decode_string (in, &path) == -1)
436 if (camel_file_util_decode_string (in, &full_name) == -1) {
441 if (camel_file_util_decode_uint32 (in, &sep) == -1) {
447 tail->next = ns = g_malloc (sizeof (CamelIMAPXStoreNamespace));
450 ns->full_name = full_name;
458 camel_imapx_namespace_list_clear (nsl);
464 namespace_save (CamelStoreSummary *s,
466 CamelIMAPXNamespaceList *nsl)
468 CamelIMAPXStoreNamespace *ns, *cur = NULL;
471 for (i = 0; i < 3; i++) {
484 for (ns = cur, n = 0; ns; n++)
487 if (camel_file_util_encode_fixed_int32 (out, n) == -1)
492 if (camel_file_util_encode_string (out, ns->path) == -1)
495 if (camel_file_util_encode_string (out, ns->full_name) == -1)
498 if (camel_file_util_encode_uint32 (out, ns->sep) == -1)
509 summary_header_load (CamelStoreSummary *s,
512 CamelIMAPXStoreSummary *is = (CamelIMAPXStoreSummary *) s;
513 CamelStoreSummaryClass *store_summary_class;
514 gint32 version, capabilities;
516 camel_imapx_namespace_list_clear (is->namespaces);
518 store_summary_class = CAMEL_STORE_SUMMARY_CLASS (camel_imapx_store_summary_parent_class);
519 if (store_summary_class->summary_header_load ((CamelStoreSummary *) s, in) == -1
520 || camel_file_util_decode_fixed_int32 (in, &version) == -1)
523 is->version = version;
525 if (version < CAMEL_IMAPX_STORE_SUMMARY_VERSION_0) {
526 g_warning("Store summary header version too low");
530 /* note file format can be expanded to contain more namespaces, but only 1 at the moment */
531 if (camel_file_util_decode_fixed_int32 (in, &capabilities) == -1)
534 is->capabilities = capabilities;
537 if ((is->namespaces = namespace_load (s, in)) == NULL)
544 summary_header_save (CamelStoreSummary *s,
547 CamelIMAPXStoreSummary *is = (CamelIMAPXStoreSummary *) s;
548 CamelStoreSummaryClass *store_summary_class;
550 /* always write as latest version */
551 store_summary_class = CAMEL_STORE_SUMMARY_CLASS (camel_imapx_store_summary_parent_class);
552 if (store_summary_class->summary_header_save ((CamelStoreSummary *) s, out) == -1
553 || camel_file_util_encode_fixed_int32 (out, CAMEL_IMAPX_STORE_SUMMARY_VERSION) == -1
554 || camel_file_util_encode_fixed_int32 (out, is->capabilities) == -1)
557 if (is->namespaces && namespace_save (s, out, is->namespaces) == -1)
563 static CamelStoreInfo *
564 store_info_load (CamelStoreSummary *s,
567 CamelIMAPXStoreInfo *mi;
568 CamelStoreSummaryClass *store_summary_class;
570 store_summary_class = CAMEL_STORE_SUMMARY_CLASS (camel_imapx_store_summary_parent_class);
571 mi = (CamelIMAPXStoreInfo *) store_summary_class->store_info_load (s, in);
573 if (camel_file_util_decode_string (in, &mi->full_name) == -1) {
574 camel_store_summary_info_free (s, (CamelStoreInfo *) mi);
577 /* NB: this is done again for compatability */
578 if (g_ascii_strcasecmp(mi->full_name, "inbox") == 0)
579 mi->info.flags |= CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_TYPE_INBOX;
583 return (CamelStoreInfo *) mi;
587 store_info_save (CamelStoreSummary *s,
591 CamelIMAPXStoreInfo *isi = (CamelIMAPXStoreInfo *) mi;
592 CamelStoreSummaryClass *store_summary_class;
594 store_summary_class = CAMEL_STORE_SUMMARY_CLASS (camel_imapx_store_summary_parent_class);
595 if (store_summary_class->store_info_save (s, out, mi) == -1
596 || camel_file_util_encode_string (out, isi->full_name) == -1)
603 store_info_free (CamelStoreSummary *s,
606 CamelIMAPXStoreInfo *isi = (CamelIMAPXStoreInfo *) mi;
607 CamelStoreSummaryClass *store_summary_class;
609 g_free (isi->full_name);
611 store_summary_class = CAMEL_STORE_SUMMARY_CLASS (camel_imapx_store_summary_parent_class);
612 store_summary_class->store_info_free (s, mi);
616 store_info_string (CamelStoreSummary *s,
617 const CamelStoreInfo *mi,
620 CamelIMAPXStoreInfo *isi = (CamelIMAPXStoreInfo *) mi;
621 CamelStoreSummaryClass *store_summary_class;
625 g_assert (mi != NULL);
627 store_summary_class = CAMEL_STORE_SUMMARY_CLASS (camel_imapx_store_summary_parent_class);
630 case CAMEL_IMAPX_STORE_INFO_FULL_NAME:
631 return isi->full_name;
633 return store_summary_class->store_info_string (s, mi, type);
638 store_info_set_string (CamelStoreSummary *s,
643 CamelIMAPXStoreInfo *isi = (CamelIMAPXStoreInfo *) mi;
644 CamelStoreSummaryClass *store_summary_class;
646 g_assert (mi != NULL);
648 store_summary_class = CAMEL_STORE_SUMMARY_CLASS (camel_imapx_store_summary_parent_class);
651 case CAMEL_IMAPX_STORE_INFO_FULL_NAME:
652 d("Set full name %s -> %s\n", isi->full_name, str);
653 camel_store_summary_lock (s, CAMEL_STORE_SUMMARY_SUMMARY_LOCK);
654 g_free (isi->full_name);
655 isi->full_name = g_strdup (str);
656 camel_store_summary_unlock (s, CAMEL_STORE_SUMMARY_SUMMARY_LOCK);
659 store_summary_class->store_info_set_string (s, mi, type, str);
665 camel_imapx_store_summary_set_namespaces (CamelIMAPXStoreSummary *summary,
666 const CamelIMAPXNamespaceList *nsl)
668 if (summary->namespaces)
669 camel_imapx_namespace_list_clear (summary->namespaces);
670 summary->namespaces = camel_imapx_namespace_list_copy (nsl);