2 * Copyright (C) 2002 Ximian Inc.
4 * Authors: Michael Zucchi <notzed@ximian.com>
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.
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.
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.
31 #include <libedataserver/md5-utils.h>
32 #include <libedataserver/e-memory.h>
34 #include "camel-file-utils.h"
35 #include "camel-private.h"
36 #include "camel-string-utils.h"
37 #include "camel-utf8.h"
39 #include "camel-imapp-store-summary.h"
42 #define io(x) /* io debug */
44 #define CAMEL_IMAPP_STORE_SUMMARY_VERSION_0 (0)
46 #define CAMEL_IMAPP_STORE_SUMMARY_VERSION (0)
48 #define _PRIVATE(o) (((CamelIMAPPStoreSummary *)(o))->priv)
50 static int summary_header_load(CamelStoreSummary *, FILE *);
51 static int summary_header_save(CamelStoreSummary *, FILE *);
53 /*static CamelStoreInfo * store_info_new(CamelStoreSummary *, const char *);*/
54 static CamelStoreInfo * store_info_load(CamelStoreSummary *, FILE *);
55 static int store_info_save(CamelStoreSummary *, FILE *, CamelStoreInfo *);
56 static void store_info_free(CamelStoreSummary *, CamelStoreInfo *);
58 static const char *store_info_string(CamelStoreSummary *, const CamelStoreInfo *, int);
59 static void store_info_set_string(CamelStoreSummary *, CamelStoreInfo *, int, const char *);
61 static void camel_imapp_store_summary_class_init (CamelIMAPPStoreSummaryClass *klass);
62 static void camel_imapp_store_summary_init (CamelIMAPPStoreSummary *obj);
63 static void camel_imapp_store_summary_finalise (CamelObject *obj);
65 static CamelStoreSummaryClass *camel_imapp_store_summary_parent;
68 camel_imapp_store_summary_class_init (CamelIMAPPStoreSummaryClass *klass)
70 CamelStoreSummaryClass *ssklass = (CamelStoreSummaryClass *)klass;
72 ssklass->summary_header_load = summary_header_load;
73 ssklass->summary_header_save = summary_header_save;
75 /*ssklass->store_info_new = store_info_new;*/
76 ssklass->store_info_load = store_info_load;
77 ssklass->store_info_save = store_info_save;
78 ssklass->store_info_free = store_info_free;
80 ssklass->store_info_string = store_info_string;
81 ssklass->store_info_set_string = store_info_set_string;
85 camel_imapp_store_summary_init (CamelIMAPPStoreSummary *s)
87 /*struct _CamelIMAPPStoreSummaryPrivate *p;
89 p = _PRIVATE(s) = g_malloc0(sizeof(*p));*/
91 ((CamelStoreSummary *)s)->store_info_size = sizeof(CamelIMAPPStoreInfo);
92 s->version = CAMEL_IMAPP_STORE_SUMMARY_VERSION;
96 camel_imapp_store_summary_finalise (CamelObject *obj)
98 /*struct _CamelIMAPPStoreSummaryPrivate *p;*/
99 /*CamelIMAPPStoreSummary *s = (CamelIMAPPStoreSummary *)obj;*/
106 camel_imapp_store_summary_get_type (void)
108 static CamelType type = CAMEL_INVALID_TYPE;
110 if (type == CAMEL_INVALID_TYPE) {
111 camel_imapp_store_summary_parent = (CamelStoreSummaryClass *)camel_store_summary_get_type();
112 type = camel_type_register((CamelType)camel_imapp_store_summary_parent, "CamelIMAPPStoreSummary",
113 sizeof (CamelIMAPPStoreSummary),
114 sizeof (CamelIMAPPStoreSummaryClass),
115 (CamelObjectClassInitFunc) camel_imapp_store_summary_class_init,
117 (CamelObjectInitFunc) camel_imapp_store_summary_init,
118 (CamelObjectFinalizeFunc) camel_imapp_store_summary_finalise);
125 * camel_imapp_store_summary_new:
127 * Create a new CamelIMAPPStoreSummary object.
129 * Return value: A new CamelIMAPPStoreSummary widget.
131 CamelIMAPPStoreSummary *
132 camel_imapp_store_summary_new (void)
134 CamelIMAPPStoreSummary *new = CAMEL_IMAPP_STORE_SUMMARY ( camel_object_new (camel_imapp_store_summary_get_type ()));
140 * camel_imapp_store_summary_full_name:
144 * Retrieve a summary item by full name.
146 * A referenced to the summary item is returned, which may be
147 * ref'd or free'd as appropriate.
149 * Return value: The summary item, or NULL if the @full_name name
151 * It must be freed using camel_store_summary_info_free().
153 CamelIMAPPStoreInfo *
154 camel_imapp_store_summary_full_name(CamelIMAPPStoreSummary *s, const char *full_name)
157 CamelIMAPPStoreInfo *info;
159 count = camel_store_summary_count((CamelStoreSummary *)s);
160 for (i=0;i<count;i++) {
161 info = (CamelIMAPPStoreInfo *)camel_store_summary_index((CamelStoreSummary *)s, i);
163 if (strcmp(info->full_name, full_name) == 0)
165 camel_store_summary_info_free((CamelStoreSummary *)s, (CamelStoreInfo *)info);
173 camel_imapp_store_summary_full_to_path(CamelIMAPPStoreSummary *s, const char *full_name, char dir_sep)
179 if (dir_sep != '/') {
180 p = path = alloca(strlen(full_name)*3+1);
182 while ( (c = *f++ & 0xff) ) {
185 else if (c == '/' || c == '%')
186 p += sprintf(p, "%%%02X", c);
192 path = (char *)full_name;
194 return camel_utf7_utf8(path);
197 static guint32 hexnib(guint32 c)
199 if (c >= '0' && c <= '9')
201 else if (c>='A' && c <= 'Z')
208 camel_imapp_store_summary_path_to_full(CamelIMAPPStoreSummary *s, const char *path, char dir_sep)
210 unsigned char *full, *f;
214 char *subpath, *last = NULL;
216 CamelIMAPPStoreNamespace *ns;
218 /* check to see if we have a subpath of path already defined */
219 subpath = alloca(strlen(path)+1);
220 strcpy(subpath, path);
222 si = camel_store_summary_path((CamelStoreSummary *)s, subpath);
224 last = strrchr(subpath, '/');
228 } while (si == NULL && last);
230 /* path is already present, use the raw version we have */
231 if (si && strlen(subpath) == strlen(path)) {
232 f = g_strdup(camel_imapp_store_info_full_name(s, si));
233 camel_store_summary_info_free((CamelStoreSummary *)s, si);
237 ns = camel_imapp_store_summary_namespace_find_path(s, path);
239 f = full = alloca(strlen(path)*2+1);
241 p = path + strlen(subpath);
243 p = path + strlen(ns->path);
247 while ( (c = camel_utf8_getc((const unsigned char **)&p)) ) {
255 camel_utf8_putc(&f, c);
265 camel_utf8_putc(&f, v);
269 camel_utf8_putc(&f, c);
271 /* merge old path part if required */
272 f = camel_utf8_utf7(full);
274 full = g_strdup_printf("%s%s", camel_imapp_store_info_full_name(s, si), f);
276 camel_store_summary_info_free((CamelStoreSummary *)s, si);
279 full = g_strdup_printf("%s%s", ns->full_name, f);
287 CamelIMAPPStoreInfo *
288 camel_imapp_store_summary_add_from_full(CamelIMAPPStoreSummary *s, const char *full, char dir_sep)
290 CamelIMAPPStoreInfo *info;
291 char *pathu8, *prefix;
294 CamelIMAPPStoreNamespace *ns;
296 d(printf("adding full name '%s' '%c'\n", full, dir_sep));
299 full_name = alloca(len+1);
300 strcpy(full_name, full);
301 if (full_name[len-1] == dir_sep)
302 full_name[len-1] = 0;
304 info = camel_imapp_store_summary_full_name(s, full_name);
306 camel_store_summary_info_free((CamelStoreSummary *)s, (CamelStoreInfo *)info);
307 d(printf(" already there\n"));
311 ns = camel_imapp_store_summary_namespace_find_full(s, full_name);
313 d(printf("(found namespace for '%s' ns '%s') ", full_name, ns->path));
314 len = strlen(ns->full_name);
315 if (len >= strlen(full_name)) {
316 pathu8 = g_strdup(ns->path);
318 if (full_name[len] == ns->sep)
321 prefix = camel_imapp_store_summary_full_to_path(s, full_name+len, ns->sep);
323 pathu8 = g_strdup_printf ("%s/%s", ns->path, prefix);
329 d(printf(" (pathu8 = '%s')", pathu8));
331 d(printf("(Cannot find namespace for '%s')\n", full_name));
332 pathu8 = camel_imapp_store_summary_full_to_path(s, full_name, dir_sep);
335 info = (CamelIMAPPStoreInfo *)camel_store_summary_add_from_path((CamelStoreSummary *)s, pathu8);
337 d(printf(" '%s' -> '%s'\n", pathu8, full_name));
338 camel_store_info_set_string((CamelStoreSummary *)s, (CamelStoreInfo *)info, CAMEL_IMAPP_STORE_INFO_FULL_NAME, full_name);
340 d(printf(" failed\n"));
345 /* should this be const? */
346 /* TODO: deprecate/merge this function with path_to_full */
348 camel_imapp_store_summary_full_from_path(CamelIMAPPStoreSummary *s, const char *path)
350 CamelIMAPPStoreNamespace *ns;
353 ns = camel_imapp_store_summary_namespace_find_path(s, path);
355 name = camel_imapp_store_summary_path_to_full(s, path, ns->sep);
357 d(printf("looking up path %s -> %s\n", path, name?name:"not found"));
362 /* TODO: this api needs some more work */
363 CamelIMAPPStoreNamespace *camel_imapp_store_summary_namespace_new(CamelIMAPPStoreSummary *s, const char *full_name, char dir_sep)
365 CamelIMAPPStoreNamespace *ns;
369 ns = g_malloc0(sizeof(*ns));
370 ns->full_name = g_strdup(full_name);
371 len = strlen(ns->full_name)-1;
372 if (len >= 0 && ns->full_name[len] == dir_sep)
373 ns->full_name[len] = 0;
376 p = ns->path = camel_imapp_store_summary_full_to_path(s, ns->full_name, dir_sep);
386 void camel_imapp_store_summary_namespace_set(CamelIMAPPStoreSummary *s, CamelIMAPPStoreNamespace *ns)
388 static void namespace_clear(CamelStoreSummary *s);
390 d(printf("Setting namesapce to '%s' '%c' -> '%s'\n", ns->full_name, ns->sep, ns->path));
391 namespace_clear((CamelStoreSummary *)s);
393 camel_store_summary_touch((CamelStoreSummary *)s);
396 CamelIMAPPStoreNamespace *
397 camel_imapp_store_summary_namespace_find_path(CamelIMAPPStoreSummary *s, const char *path)
400 CamelIMAPPStoreNamespace *ns;
402 /* NB: this currently only compares against 1 namespace, in future compare against others */
405 len = strlen(ns->path);
407 || (strncmp(ns->path, path, len) == 0
408 && (path[len] == '/' || path[len] == 0)))
413 /* have a default? */
417 CamelIMAPPStoreNamespace *
418 camel_imapp_store_summary_namespace_find_full(CamelIMAPPStoreSummary *s, const char *full)
421 CamelIMAPPStoreNamespace *ns;
423 /* NB: this currently only compares against 1 namespace, in future compare against others */
426 len = strlen(ns->full_name);
427 d(printf("find_full: comparing namespace '%s' to name '%s'\n", ns->full_name, full));
429 || (strncmp(ns->full_name, full, len) == 0
430 && (full[len] == ns->sep || full[len] == 0)))
435 /* have a default? */
440 namespace_free(CamelStoreSummary *s, CamelIMAPPStoreNamespace *ns)
443 g_free(ns->full_name);
448 namespace_clear(CamelStoreSummary *s)
450 CamelIMAPPStoreSummary *is = (CamelIMAPPStoreSummary *)s;
453 namespace_free(s, is->namespace);
454 is->namespace = NULL;
457 static CamelIMAPPStoreNamespace *
458 namespace_load(CamelStoreSummary *s, FILE *in)
460 CamelIMAPPStoreNamespace *ns;
463 ns = g_malloc0(sizeof(*ns));
464 if (camel_file_util_decode_string(in, &ns->path) == -1
465 || camel_file_util_decode_string(in, &ns->full_name) == -1
466 || camel_file_util_decode_uint32(in, &sep) == -1) {
467 namespace_free(s, ns);
477 namespace_save(CamelStoreSummary *s, FILE *in, CamelIMAPPStoreNamespace *ns)
479 if (camel_file_util_encode_string(in, ns->path) == -1
480 || camel_file_util_encode_string(in, ns->full_name) == -1
481 || camel_file_util_encode_uint32(in, (guint32)ns->sep) == -1)
488 summary_header_load(CamelStoreSummary *s, FILE *in)
490 CamelIMAPPStoreSummary *is = (CamelIMAPPStoreSummary *)s;
491 gint32 version, capabilities, count;
495 if (camel_imapp_store_summary_parent->summary_header_load((CamelStoreSummary *)s, in) == -1
496 || camel_file_util_decode_fixed_int32(in, &version) == -1)
499 is->version = version;
501 if (version < CAMEL_IMAPP_STORE_SUMMARY_VERSION_0) {
502 g_warning("Store summary header version too low");
506 /* note file format can be expanded to contain more namespaces, but only 1 at the moment */
507 if (camel_file_util_decode_fixed_int32(in, &capabilities) == -1
508 || camel_file_util_decode_fixed_int32(in, &count) == -1
512 is->capabilities = capabilities;
514 if ((is->namespace = namespace_load(s, in)) == NULL)
522 summary_header_save(CamelStoreSummary *s, FILE *out)
524 CamelIMAPPStoreSummary *is = (CamelIMAPPStoreSummary *)s;
527 count = is->namespace?1:0;
529 /* always write as latest version */
530 if (camel_imapp_store_summary_parent->summary_header_save((CamelStoreSummary *)s, out) == -1
531 || camel_file_util_encode_fixed_int32(out, CAMEL_IMAPP_STORE_SUMMARY_VERSION) == -1
532 || camel_file_util_encode_fixed_int32(out, is->capabilities) == -1
533 || camel_file_util_encode_fixed_int32(out, count) == -1)
536 if (is->namespace && namespace_save(s, out, is->namespace) == -1)
542 static CamelStoreInfo *
543 store_info_load(CamelStoreSummary *s, FILE *in)
545 CamelIMAPPStoreInfo *mi;
547 mi = (CamelIMAPPStoreInfo *)camel_imapp_store_summary_parent->store_info_load(s, in);
549 if (camel_file_util_decode_string(in, &mi->full_name) == -1) {
550 camel_store_summary_info_free(s, (CamelStoreInfo *)mi);
555 return (CamelStoreInfo *)mi;
559 store_info_save(CamelStoreSummary *s, FILE *out, CamelStoreInfo *mi)
561 CamelIMAPPStoreInfo *isi = (CamelIMAPPStoreInfo *)mi;
563 if (camel_imapp_store_summary_parent->store_info_save(s, out, mi) == -1
564 || camel_file_util_encode_string(out, isi->full_name) == -1)
571 store_info_free(CamelStoreSummary *s, CamelStoreInfo *mi)
573 CamelIMAPPStoreInfo *isi = (CamelIMAPPStoreInfo *)mi;
575 g_free(isi->full_name);
576 camel_imapp_store_summary_parent->store_info_free(s, mi);
580 store_info_string(CamelStoreSummary *s, const CamelStoreInfo *mi, int type)
582 CamelIMAPPStoreInfo *isi = (CamelIMAPPStoreInfo *)mi;
586 g_assert (mi != NULL);
589 case CAMEL_IMAPP_STORE_INFO_FULL_NAME:
590 return isi->full_name;
592 return camel_imapp_store_summary_parent->store_info_string(s, mi, type);
597 store_info_set_string(CamelStoreSummary *s, CamelStoreInfo *mi, int type, const char *str)
599 CamelIMAPPStoreInfo *isi = (CamelIMAPPStoreInfo *)mi;
601 g_assert(mi != NULL);
604 case CAMEL_IMAPP_STORE_INFO_FULL_NAME:
605 d(printf("Set full name %s -> %s\n", isi->full_name, str));
606 CAMEL_STORE_SUMMARY_LOCK(s, summary_lock);
607 g_free(isi->full_name);
608 isi->full_name = g_strdup(str);
609 CAMEL_STORE_SUMMARY_UNLOCK(s, summary_lock);
612 camel_imapp_store_summary_parent->store_info_set_string(s, mi, type, str);