1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2002 Ximian Inc.
5 * Authors: Parthasarathi Susarla <sparthasarathi@novell.com>
7 * Description: Based on the imap implementaion of camelstoresummary
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of version 2 of the GNU Lesser General Public
11 * License as published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this program; if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
35 #include <libedataserver/e-memory.h>
36 #include <libedataserver/md5-utils.h>
38 #include "camel-file-utils.h"
39 #include "camel-private.h"
40 #include "camel-utf8.h"
42 #include "camel-groupwise-store-summary.h"
44 #define CAMEL_GW_STORE_SUMMARY_VERSION (0)
48 static void namespace_clear(CamelStoreSummary *s);
50 static int summary_header_load(CamelStoreSummary *, FILE *);
51 static int summary_header_save(CamelStoreSummary *, FILE *);
53 static CamelStoreInfo *store_info_load(CamelStoreSummary *s, FILE *in) ;
54 static int store_info_save(CamelStoreSummary *s, FILE *out, CamelStoreInfo *mi) ;
55 static void store_info_free(CamelStoreSummary *s, CamelStoreInfo *mi) ;
56 static void store_info_set_string(CamelStoreSummary *s, CamelStoreInfo *mi, int type, const char *str) ;
58 static const char *store_info_string(CamelStoreSummary *s, const CamelStoreInfo *mi, int type) ;
59 CamelGroupwiseStoreNamespace *camel_groupwise_store_summary_namespace_find_full(CamelGroupwiseStoreSummary *s, const char *full) ;
61 static void camel_groupwise_store_summary_class_init (CamelGroupwiseStoreSummaryClass *klass);
62 static void camel_groupwise_store_summary_init (CamelGroupwiseStoreSummary *obj);
63 static void camel_groupwise_store_summary_finalise (CamelObject *obj);
65 static CamelStoreSummaryClass *camel_groupwise_store_summary_parent;
69 camel_groupwise_store_summary_class_init (CamelGroupwiseStoreSummaryClass *klass)
71 CamelStoreSummaryClass *ssklass = (CamelStoreSummaryClass *)klass;
73 ssklass->summary_header_load = summary_header_load;
74 ssklass->summary_header_save = summary_header_save;
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;
87 camel_groupwise_store_summary_init (CamelGroupwiseStoreSummary *s)
90 ((CamelStoreSummary *)s)->store_info_size = sizeof(CamelGroupwiseStoreInfo);
91 s->version = CAMEL_GW_STORE_SUMMARY_VERSION;
96 camel_groupwise_store_summary_finalise (CamelObject *obj)
102 camel_groupwise_store_summary_get_type (void)
104 static CamelType type = CAMEL_INVALID_TYPE;
106 if (type == CAMEL_INVALID_TYPE) {
107 camel_groupwise_store_summary_parent = (CamelStoreSummaryClass *)camel_store_summary_get_type();
108 type = camel_type_register((CamelType)camel_groupwise_store_summary_parent, "CamelGroupwiseStoreSummary",
109 sizeof (CamelGroupwiseStoreSummary),
110 sizeof (CamelGroupwiseStoreSummaryClass),
111 (CamelObjectClassInitFunc) camel_groupwise_store_summary_class_init,
113 (CamelObjectInitFunc) camel_groupwise_store_summary_init,
114 (CamelObjectFinalizeFunc) camel_groupwise_store_summary_finalise);
121 CamelGroupwiseStoreSummary *
122 camel_groupwise_store_summary_new (void)
124 CamelGroupwiseStoreSummary *new = CAMEL_GW_STORE_SUMMARY ( camel_object_new (camel_groupwise_store_summary_get_type ()));
130 CamelGroupwiseStoreInfo *
131 camel_groupwise_store_summary_full_name(CamelGroupwiseStoreSummary *s, const char *full_name)
134 CamelGroupwiseStoreInfo *info;
136 count = camel_store_summary_count((CamelStoreSummary *)s);
137 for (i=0;i<count;i++) {
138 info = (CamelGroupwiseStoreInfo *)camel_store_summary_index((CamelStoreSummary *)s, i);
140 if (strcmp(info->full_name, full_name) == 0)
142 camel_store_summary_info_free((CamelStoreSummary *)s, (CamelStoreInfo *)info);
150 camel_groupwise_store_summary_full_to_path(CamelGroupwiseStoreSummary *s, const char *full_name, char dir_sep)
156 if (dir_sep != '/') {
157 p = path = alloca(strlen(full_name)*3+1);
159 while ( (c = *f++ & 0xff) ) {
162 else if (c == '/' || c == '%')
163 p += sprintf(p, "%%%02X", c);
169 path = (char *)full_name;
171 return g_strdup (path);
173 static guint32 hexnib(guint32 c)
175 if (c >= '0' && c <= '9')
177 else if (c>='A' && c <= 'Z')
184 namespace_save(CamelStoreSummary *s, FILE *in, CamelGroupwiseStoreNamespace *ns)
186 if (camel_file_util_encode_string(in, ns->path) == -1
187 || camel_file_util_encode_string(in, ns->full_name) == -1
188 || camel_file_util_encode_uint32(in, (guint32)ns->sep) == -1)
195 namespace_free(CamelStoreSummary *s, CamelGroupwiseStoreNamespace *ns)
198 g_free(ns->full_name);
203 namespace_clear(CamelStoreSummary *s)
205 CamelGroupwiseStoreSummary *is = (CamelGroupwiseStoreSummary *)s;
208 namespace_free(s, is->namespace);
209 is->namespace = NULL;
212 static CamelGroupwiseStoreNamespace *
213 namespace_load(CamelStoreSummary *s, FILE *in)
215 CamelGroupwiseStoreNamespace *ns;
218 ns = g_malloc0(sizeof(*ns));
219 if (camel_file_util_decode_string(in, &ns->path) == -1
220 || camel_file_util_decode_string(in, &ns->full_name) == -1
221 || camel_file_util_decode_uint32(in, &sep) == -1) {
222 namespace_free(s, ns);
232 camel_groupwise_store_summary_path_to_full(CamelGroupwiseStoreSummary *s, const char *path, char dir_sep)
234 unsigned char *full, *f;
238 char *subpath, *last = NULL;
240 CamelGroupwiseStoreNamespace *ns;
242 /* check to see if we have a subpath of path already defined */
243 subpath = alloca(strlen(path)+1);
244 strcpy(subpath, path);
246 si = camel_store_summary_path((CamelStoreSummary *)s, subpath);
248 last = strrchr(subpath, '/');
252 } while (si == NULL && last);
254 /* path is already present, use the raw version we have */
255 if (si && strlen(subpath) == strlen(path)) {
256 f = g_strdup(camel_groupwise_store_info_full_name(s, si));
257 camel_store_summary_info_free((CamelStoreSummary *)s, si);
261 ns = camel_groupwise_store_summary_namespace_find_path(s, path);
263 f = full = alloca(strlen(path)*2+1);
265 p = path + strlen(subpath);
267 p = path + strlen(ns->path);
271 while ( (c = camel_utf8_getc((const unsigned char **)&p)) ) {
279 camel_utf8_putc(&f, c);
289 camel_utf8_putc(&f, v);
293 camel_utf8_putc(&f, c);
295 /* merge old path part if required */
298 full = g_strdup_printf("%s%s", camel_groupwise_store_info_full_name(s, si), f);
300 camel_store_summary_info_free((CamelStoreSummary *)s, si);
303 full = g_strdup_printf("%s%s", ns->full_name, f);
310 CamelGroupwiseStoreNamespace *
311 camel_groupwise_store_summary_namespace_find_full(CamelGroupwiseStoreSummary *s, const char *full)
314 CamelGroupwiseStoreNamespace *ns;
316 /* NB: this currently only compares against 1 namespace, in future compare against others */
319 len = strlen(ns->full_name);
320 d(printf("find_full: comparing namespace '%s' to name '%s'\n", ns->full_name, full));
322 || (strncmp(ns->full_name, full, len) == 0
323 && (full[len] == ns->sep || full[len] == 0)))
328 /* have a default? */
332 CamelGroupwiseStoreInfo *
333 camel_groupwise_store_summary_add_from_full(CamelGroupwiseStoreSummary *s, const char *full, char dir_sep)
335 CamelGroupwiseStoreInfo *info;
336 char *pathu8, *prefix;
339 CamelGroupwiseStoreNamespace *ns;
341 d(printf("adding full name '%s' '%c'\n", full, dir_sep));
344 full_name = alloca(len+1);
345 strcpy(full_name, full);
346 if (full_name[len-1] == dir_sep)
347 full_name[len-1] = 0;
349 info = camel_groupwise_store_summary_full_name(s, full_name);
351 camel_store_summary_info_free((CamelStoreSummary *)s, (CamelStoreInfo *)info);
352 d(printf(" already there\n"));
356 ns = camel_groupwise_store_summary_namespace_find_full(s, full_name);
358 d(printf("(found namespace for '%s' ns '%s') ", full_name, ns->path));
359 len = strlen(ns->full_name);
360 if (len >= strlen(full_name)) {
361 pathu8 = g_strdup(ns->path);
363 if (full_name[len] == ns->sep)
366 prefix = camel_groupwise_store_summary_full_to_path(s, full_name+len, ns->sep);
368 pathu8 = g_strdup_printf ("%s/%s", ns->path, prefix);
374 d(printf(" (pathu8 = '%s')", pathu8));
376 d(printf("(Cannot find namespace for '%s')\n", full_name));
377 pathu8 = camel_groupwise_store_summary_full_to_path(s, full_name, dir_sep);
380 info = (CamelGroupwiseStoreInfo *)camel_store_summary_add_from_path((CamelStoreSummary *)s, pathu8);
382 d(printf(" '%s' -> '%s'\n", pathu8, full_name));
383 camel_store_info_set_string((CamelStoreSummary *)s, (CamelStoreInfo *)info, CAMEL_STORE_INFO_LAST, full_name);
385 d(printf(" failed\n"));
391 camel_groupwise_store_summary_full_from_path(CamelGroupwiseStoreSummary *s, const char *path)
393 CamelGroupwiseStoreNamespace *ns;
396 ns = camel_groupwise_store_summary_namespace_find_path(s, path);
398 name = camel_groupwise_store_summary_path_to_full(s, path, ns->sep);
400 d(printf("looking up path %s -> %s\n", path, name?name:"not found"));
405 CamelGroupwiseStoreNamespace *
406 camel_groupwise_store_summary_namespace_new(CamelGroupwiseStoreSummary *s, const char *full_name, char dir_sep)
408 CamelGroupwiseStoreNamespace *ns;
412 ns = g_malloc0(sizeof(*ns));
413 ns->full_name = g_strdup(full_name);
414 len = strlen(ns->full_name)-1;
415 if (len >= 0 && ns->full_name[len] == dir_sep)
416 ns->full_name[len] = 0;
419 o = p = ns->path = camel_groupwise_store_summary_full_to_path(s, ns->full_name, dir_sep);
433 camel_groupwise_store_summary_namespace_set(CamelGroupwiseStoreSummary *s, CamelGroupwiseStoreNamespace *ns)
435 d(printf("Setting namesapce to '%s' '%c' -> '%s'\n", ns->full_name, ns->sep, ns->path));
436 namespace_clear((CamelStoreSummary *)s);
438 camel_store_summary_touch((CamelStoreSummary *)s);
441 CamelGroupwiseStoreNamespace *
442 camel_groupwise_store_summary_namespace_find_path(CamelGroupwiseStoreSummary *s, const char *path)
445 CamelGroupwiseStoreNamespace *ns;
447 /* NB: this currently only compares against 1 namespace, in future compare against others */
450 len = strlen(ns->path);
452 || (strncmp(ns->path, path, len) == 0
453 && (path[len] == '/' || path[len] == 0)))
458 /* have a default? */
465 summary_header_load(CamelStoreSummary *s, FILE *in)
467 CamelGroupwiseStoreSummary *summary = (CamelGroupwiseStoreSummary *)s ;
468 gint32 version, capabilities, count ;
470 namespace_clear (s) ;
472 if (camel_groupwise_store_summary_parent->summary_header_load ((CamelStoreSummary *)s, in) == -1
473 || camel_file_util_decode_fixed_int32(in, &version) == -1)
476 summary->version = version ;
478 if (camel_file_util_decode_fixed_int32(in, &capabilities) == -1
479 || camel_file_util_decode_fixed_int32(in, &count) == -1
483 summary->capabilities = capabilities ;
485 if ((summary->namespace = namespace_load (s, in)) == NULL)
493 summary_header_save(CamelStoreSummary *s, FILE *out)
495 CamelGroupwiseStoreSummary *summary = (CamelGroupwiseStoreSummary *) s ;
498 count = summary->namespace?1:0 ;
499 if (camel_groupwise_store_summary_parent->summary_header_save((CamelStoreSummary *)s, out) == -1
500 || camel_file_util_encode_fixed_int32(out, 0) == -1
501 || camel_file_util_encode_fixed_int32(out, summary->capabilities) == -1
502 || camel_file_util_encode_fixed_int32(out, count) == -1)
505 if (summary->namespace && namespace_save(s, out, summary->namespace) == -1)
512 static CamelStoreInfo *
513 store_info_load(CamelStoreSummary *s, FILE *in)
515 CamelGroupwiseStoreInfo *si;
517 si = (CamelGroupwiseStoreInfo *)camel_groupwise_store_summary_parent->store_info_load(s, in);
519 if (camel_file_util_decode_string(in, &si->full_name) == -1) {
520 camel_store_summary_info_free(s, (CamelStoreInfo *)si);
525 return (CamelStoreInfo *)si;
529 store_info_save(CamelStoreSummary *s, FILE *out, CamelStoreInfo *mi)
531 CamelGroupwiseStoreInfo *summary = (CamelGroupwiseStoreInfo *)mi;
533 if (camel_groupwise_store_summary_parent->store_info_save(s, out, mi) == -1
534 || camel_file_util_encode_string(out, summary->full_name) == -1)
542 store_info_free(CamelStoreSummary *s, CamelStoreInfo *mi)
544 CamelGroupwiseStoreInfo *si = (CamelGroupwiseStoreInfo *)mi;
546 g_free(si->full_name);
547 camel_groupwise_store_summary_parent->store_info_free(s, mi);
555 store_info_string(CamelStoreSummary *s, const CamelStoreInfo *mi, int type)
557 CamelGroupwiseStoreInfo *isi = (CamelGroupwiseStoreInfo *)mi;
561 g_assert (mi != NULL);
564 case CAMEL_STORE_INFO_LAST:
565 return isi->full_name;
567 return camel_groupwise_store_summary_parent->store_info_string(s, mi, type);
572 store_info_set_string(CamelStoreSummary *s, CamelStoreInfo *mi, int type, const char *str)
574 CamelGroupwiseStoreInfo *isi = (CamelGroupwiseStoreInfo *)mi;
576 g_assert(mi != NULL);
579 case CAMEL_STORE_INFO_LAST:
580 d(printf("Set full name %s -> %s\n", isi->full_name, str));
581 CAMEL_STORE_SUMMARY_LOCK(s, summary_lock);
582 g_free(isi->full_name);
583 isi->full_name = g_strdup(str);
584 CAMEL_STORE_SUMMARY_UNLOCK(s, summary_lock);
587 camel_groupwise_store_summary_parent->store_info_set_string(s, mi, type, str);