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;
127 gboolean is_inbox = g_ascii_strcasecmp (full_name, "INBOX") == 0;
129 count = camel_store_summary_count ((CamelStoreSummary *) s);
130 for (i = 0; i < count; i++) {
131 info = (CamelIMAPXStoreInfo *) camel_store_summary_index ((CamelStoreSummary *) s, i);
133 if (strcmp (info->full_name, full_name) == 0 ||
134 (is_inbox && g_ascii_strcasecmp (info->full_name, full_name) == 0))
136 camel_store_summary_info_free ((CamelStoreSummary *) s, (CamelStoreInfo *) info);
144 camel_imapx_store_summary_full_to_path (CamelIMAPXStoreSummary *s,
145 const gchar *full_name,
150 p = path = g_strdup (full_name);
152 if (dir_sep && dir_sep != '/') {
156 else if (*p == dir_sep)
165 camel_imapx_store_summary_path_to_full (CamelIMAPXStoreSummary *s,
171 gchar *subpath, *last = NULL;
173 CamelIMAPXStoreNamespace *ns;
175 /* check to see if we have a subpath of path already defined */
176 subpath = alloca (strlen (path) + 1);
177 strcpy (subpath, path);
179 si = camel_store_summary_path ((CamelStoreSummary *) s, subpath);
181 last = strrchr (subpath, '/');
185 } while (si == NULL && last);
187 /* path is already present, use the raw version we have */
188 if (si && strlen (subpath) == strlen (path)) {
189 f = g_strdup (camel_imapx_store_info_full_name (s, si));
190 camel_store_summary_info_free ((CamelStoreSummary *) s, si);
194 ns = camel_imapx_store_summary_namespace_find_path (s, path);
197 p = path + strlen (subpath);
199 p = path + strlen (ns->path);
203 f = full = g_strdup (p);
204 if (dir_sep != '/') {
208 else if (*f == dir_sep)
214 /* merge old path part if required */
217 full = g_strdup_printf ("%s%s", camel_imapx_store_info_full_name (s, si), f);
219 camel_store_summary_info_free ((CamelStoreSummary *) s, si);
222 full = g_strdup_printf ("%s%s", ns->full_name, f);
230 CamelIMAPXStoreInfo *
231 camel_imapx_store_summary_add_from_full (CamelIMAPXStoreSummary *s,
235 CamelIMAPXStoreInfo *info;
236 gchar *pathu8, *prefix;
239 CamelIMAPXStoreNamespace *ns;
241 d ("adding full name '%s' '%c'\n", full, dir_sep);
244 full_name = alloca (len + 1);
245 strcpy (full_name, full);
246 if (full_name[len - 1] == dir_sep)
247 full_name[len - 1] = 0;
249 info = camel_imapx_store_summary_full_name (s, full_name);
251 camel_store_summary_info_free ((CamelStoreSummary *) s, (CamelStoreInfo *) info);
252 d (" already there\n");
256 ns = camel_imapx_store_summary_namespace_find_full (s, full_name);
258 d ("(found namespace for '%s' ns '%s') ", full_name, ns->path);
259 len = strlen (ns->full_name);
260 if (len >= strlen (full_name)) {
261 pathu8 = g_strdup (ns->path);
263 if (full_name[len] == ns->sep)
266 prefix = camel_imapx_store_summary_full_to_path (s, full_name + len, ns->sep);
268 pathu8 = g_strdup_printf ("%s/%s", ns->path, prefix);
274 d (" (pathu8 = '%s')", pathu8);
276 d ("(Cannot find namespace for '%s')\n", full_name);
277 pathu8 = camel_imapx_store_summary_full_to_path (s, full_name, dir_sep);
280 info = (CamelIMAPXStoreInfo *) camel_store_summary_add_from_path ((CamelStoreSummary *) s, pathu8);
282 d (" '%s' -> '%s'\n", pathu8, full_name);
283 camel_store_info_set_string ((CamelStoreSummary *) s, (CamelStoreInfo *) info, CAMEL_IMAPX_STORE_INFO_FULL_NAME, full_name);
285 if (!g_ascii_strcasecmp (full_name, "inbox"))
286 info->info.flags |= CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_TYPE_INBOX;
296 /* should this be const? */
297 /* TODO: deprecate/merge this function with path_to_full */
299 camel_imapx_store_summary_full_from_path (CamelIMAPXStoreSummary *s,
302 CamelIMAPXStoreNamespace *ns;
305 ns = camel_imapx_store_summary_namespace_find_path (s, path);
307 name = camel_imapx_store_summary_path_to_full (s, path, ns->sep);
309 d ("looking up path %s -> %s\n", path, name ? name:"not found");
314 /* TODO: this api needs some more work */
315 CamelIMAPXStoreNamespace *
316 camel_imapx_store_summary_namespace_new (CamelIMAPXStoreSummary *s,
317 const gchar *full_name,
320 CamelIMAPXStoreNamespace *ns;
324 ns = g_malloc0 (sizeof (*ns));
325 ns->full_name = g_strdup (full_name);
326 len = strlen (ns->full_name) - 1;
327 if (len >= 0 && ns->full_name[len] == dir_sep)
328 ns->full_name[len] = 0;
331 o = p = ns->path = camel_imapx_store_summary_full_to_path (s, ns->full_name, dir_sep);
344 void camel_imapx_store_summary_namespace_set (CamelIMAPXStoreSummary *s, CamelIMAPXStoreNamespace *ns)
346 d ("Setting namesapce to '%s' '%c' -> '%s'\n", ns->full_name, ns->sep, ns->path);
348 /* CHEN not needed */
349 camel_store_summary_touch ((CamelStoreSummary *) s);
352 CamelIMAPXStoreNamespace *
353 camel_imapx_store_summary_namespace_find_path (CamelIMAPXStoreSummary *s,
357 CamelIMAPXStoreNamespace *ns;
359 /* NB: this currently only compares against 1 namespace, in future compare against others */
361 ns = s->namespaces->personal;
363 len = strlen (ns->path);
365 || (strncmp (ns->path, path, len) == 0
366 && (path[len] == '/' || path[len] == 0)))
371 /* have a default? */
375 CamelIMAPXStoreNamespace *
376 camel_imapx_store_summary_namespace_find_full (CamelIMAPXStoreSummary *s,
380 CamelIMAPXStoreNamespace *ns;
382 /* NB: this currently only compares against 1 namespace, in future compare against others */
384 ns = s->namespaces->personal;
387 len = strlen (ns->full_name);
388 d ("find_full: comparing namespace '%s' to name '%s'\n", ns->full_name, full);
390 || (strncmp (ns->full_name, full, len) == 0
391 && (full[len] == ns->sep || full[len] == 0)))
396 /* have a default? */
400 static CamelIMAPXNamespaceList *
401 namespace_load (CamelStoreSummary *s,
404 CamelIMAPXStoreNamespace *ns, *tail;
405 CamelIMAPXNamespaceList *nsl;
409 nsl = g_malloc0 (sizeof (CamelIMAPXNamespaceList));
410 nsl->personal = NULL;
414 for (j = 0; j < 3; j++) {
417 tail = (CamelIMAPXStoreNamespace *) &nsl->personal;
420 tail = (CamelIMAPXStoreNamespace *) &nsl->shared;
423 tail = (CamelIMAPXStoreNamespace *) &nsl->other;
427 if (camel_file_util_decode_fixed_int32 (in, &n) == -1)
430 for (i = 0; i < n; i++) {
435 if (camel_file_util_decode_string (in, &path) == -1)
438 if (camel_file_util_decode_string (in, &full_name) == -1) {
443 if (camel_file_util_decode_uint32 (in, &sep) == -1) {
449 tail->next = ns = g_malloc (sizeof (CamelIMAPXStoreNamespace));
452 ns->full_name = full_name;
460 camel_imapx_namespace_list_clear (nsl);
466 namespace_save (CamelStoreSummary *s,
468 CamelIMAPXNamespaceList *nsl)
470 CamelIMAPXStoreNamespace *ns, *cur = NULL;
473 for (i = 0; i < 3; i++) {
486 for (ns = cur, n = 0; ns; n++)
489 if (camel_file_util_encode_fixed_int32 (out, n) == -1)
494 if (camel_file_util_encode_string (out, ns->path) == -1)
497 if (camel_file_util_encode_string (out, ns->full_name) == -1)
500 if (camel_file_util_encode_uint32 (out, ns->sep) == -1)
511 summary_header_load (CamelStoreSummary *s,
514 CamelIMAPXStoreSummary *is = (CamelIMAPXStoreSummary *) s;
515 CamelStoreSummaryClass *store_summary_class;
516 gint32 version, capabilities;
518 camel_imapx_namespace_list_clear (is->namespaces);
520 store_summary_class = CAMEL_STORE_SUMMARY_CLASS (camel_imapx_store_summary_parent_class);
521 if (store_summary_class->summary_header_load ((CamelStoreSummary *) s, in) == -1
522 || camel_file_util_decode_fixed_int32 (in, &version) == -1)
525 is->version = version;
527 if (version < CAMEL_IMAPX_STORE_SUMMARY_VERSION_0) {
528 g_warning ("Store summary header version too low");
532 /* note file format can be expanded to contain more namespaces, but only 1 at the moment */
533 if (camel_file_util_decode_fixed_int32 (in, &capabilities) == -1)
536 is->capabilities = capabilities;
539 if ((is->namespaces = namespace_load (s, in)) == NULL)
546 summary_header_save (CamelStoreSummary *s,
549 CamelIMAPXStoreSummary *is = (CamelIMAPXStoreSummary *) s;
550 CamelStoreSummaryClass *store_summary_class;
552 /* always write as latest version */
553 store_summary_class = CAMEL_STORE_SUMMARY_CLASS (camel_imapx_store_summary_parent_class);
554 if (store_summary_class->summary_header_save ((CamelStoreSummary *) s, out) == -1
555 || camel_file_util_encode_fixed_int32 (out, CAMEL_IMAPX_STORE_SUMMARY_VERSION) == -1
556 || camel_file_util_encode_fixed_int32 (out, is->capabilities) == -1)
559 if (is->namespaces && namespace_save (s, out, is->namespaces) == -1)
565 static CamelStoreInfo *
566 store_info_load (CamelStoreSummary *s,
569 CamelIMAPXStoreInfo *mi;
570 CamelStoreSummaryClass *store_summary_class;
572 store_summary_class = CAMEL_STORE_SUMMARY_CLASS (camel_imapx_store_summary_parent_class);
573 mi = (CamelIMAPXStoreInfo *) store_summary_class->store_info_load (s, in);
575 if (camel_file_util_decode_string (in, &mi->full_name) == -1) {
576 camel_store_summary_info_free (s, (CamelStoreInfo *) mi);
579 /* NB: this is done again for compatability */
580 if (g_ascii_strcasecmp (mi->full_name, "inbox") == 0)
581 mi->info.flags |= CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_TYPE_INBOX;
585 return (CamelStoreInfo *) mi;
589 store_info_save (CamelStoreSummary *s,
593 CamelIMAPXStoreInfo *isi = (CamelIMAPXStoreInfo *) mi;
594 CamelStoreSummaryClass *store_summary_class;
596 store_summary_class = CAMEL_STORE_SUMMARY_CLASS (camel_imapx_store_summary_parent_class);
597 if (store_summary_class->store_info_save (s, out, mi) == -1
598 || camel_file_util_encode_string (out, isi->full_name) == -1)
605 store_info_free (CamelStoreSummary *s,
608 CamelIMAPXStoreInfo *isi = (CamelIMAPXStoreInfo *) mi;
609 CamelStoreSummaryClass *store_summary_class;
611 g_free (isi->full_name);
613 store_summary_class = CAMEL_STORE_SUMMARY_CLASS (camel_imapx_store_summary_parent_class);
614 store_summary_class->store_info_free (s, mi);
618 store_info_string (CamelStoreSummary *s,
619 const CamelStoreInfo *mi,
622 CamelIMAPXStoreInfo *isi = (CamelIMAPXStoreInfo *) mi;
623 CamelStoreSummaryClass *store_summary_class;
627 g_assert (mi != NULL);
629 store_summary_class = CAMEL_STORE_SUMMARY_CLASS (camel_imapx_store_summary_parent_class);
632 case CAMEL_IMAPX_STORE_INFO_FULL_NAME:
633 return isi->full_name;
635 return store_summary_class->store_info_string (s, mi, type);
640 store_info_set_string (CamelStoreSummary *s,
645 CamelIMAPXStoreInfo *isi = (CamelIMAPXStoreInfo *) mi;
646 CamelStoreSummaryClass *store_summary_class;
648 g_assert (mi != NULL);
650 store_summary_class = CAMEL_STORE_SUMMARY_CLASS (camel_imapx_store_summary_parent_class);
653 case CAMEL_IMAPX_STORE_INFO_FULL_NAME:
654 d ("Set full name %s -> %s\n", isi->full_name, str);
655 camel_store_summary_lock (s, CAMEL_STORE_SUMMARY_SUMMARY_LOCK);
656 g_free (isi->full_name);
657 isi->full_name = g_strdup (str);
658 camel_store_summary_unlock (s, CAMEL_STORE_SUMMARY_SUMMARY_LOCK);
661 store_summary_class->store_info_set_string (s, mi, type, str);
667 camel_imapx_store_summary_set_namespaces (CamelIMAPXStoreSummary *summary,
668 const CamelIMAPXNamespaceList *nsl)
670 if (summary->namespaces)
671 camel_imapx_namespace_list_clear (summary->namespaces);
672 summary->namespaces = camel_imapx_namespace_list_copy (nsl);