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-file-utils.h"
33
#include "camel-private.h"
34
#include "camel-store.h"
35
#include "camel-utf8.h"
36
#include "camel-imapx-utils.h"
37
#include "camel-imapx-store-summary.h"
40
#define io(x) /* io debug */
42
#define CAMEL_IMAPX_STORE_SUMMARY_VERSION_0 (0)
44
#define CAMEL_IMAPX_STORE_SUMMARY_VERSION (0)
46
#define _PRIVATE(o) (((CamelIMAPXStoreSummary *)(o))->priv)
48
static gint summary_header_load(CamelStoreSummary *, FILE *);
49
static gint summary_header_save(CamelStoreSummary *, FILE *);
51
/*static CamelStoreInfo * store_info_new(CamelStoreSummary *, const gchar *);*/
52
static CamelStoreInfo * store_info_load(CamelStoreSummary *, FILE *);
53
static gint store_info_save(CamelStoreSummary *, FILE *, CamelStoreInfo *);
54
static void store_info_free(CamelStoreSummary *, CamelStoreInfo *);
56
static const gchar *store_info_string(CamelStoreSummary *, const CamelStoreInfo *, gint);
57
static void store_info_set_string(CamelStoreSummary *, CamelStoreInfo *, int, const gchar *);
59
static void camel_imapx_store_summary_class_init (CamelIMAPXStoreSummaryClass *klass);
60
static void camel_imapx_store_summary_init (CamelIMAPXStoreSummary *obj);
61
static void camel_imapx_store_summary_finalise (CamelObject *obj);
63
static CamelStoreSummaryClass *camel_imapx_store_summary_parent;
66
camel_imapx_store_summary_class_init (CamelIMAPXStoreSummaryClass *klass)
68
CamelStoreSummaryClass *ssklass = (CamelStoreSummaryClass *)klass;
70
ssklass->summary_header_load = summary_header_load;
71
ssklass->summary_header_save = summary_header_save;
73
/*ssklass->store_info_new = store_info_new;*/
74
ssklass->store_info_load = store_info_load;
75
ssklass->store_info_save = store_info_save;
76
ssklass->store_info_free = store_info_free;
78
ssklass->store_info_string = store_info_string;
79
ssklass->store_info_set_string = store_info_set_string;
83
camel_imapx_store_summary_init (CamelIMAPXStoreSummary *s)
85
/*struct _CamelImapStoreSummaryPrivate *p;
87
p = _PRIVATE(s) = g_malloc0(sizeof(*p));*/
89
((CamelStoreSummary *)s)->store_info_size = sizeof(CamelIMAPXStoreInfo);
90
s->version = CAMEL_IMAPX_STORE_SUMMARY_VERSION;
94
camel_imapx_store_summary_finalise (CamelObject *obj)
96
/*struct _CamelImapStoreSummaryPrivate *p;*/
97
/*CamelImapStoreSummary *s = (CamelImapStoreSummary *)obj;*/
104
camel_imapx_store_summary_get_type (void)
106
static CamelType type = CAMEL_INVALID_TYPE;
108
if (type == CAMEL_INVALID_TYPE) {
109
camel_imapx_store_summary_parent = (CamelStoreSummaryClass *)camel_store_summary_get_type();
110
type = camel_type_register((CamelType)camel_imapx_store_summary_parent, "CamelIMAPXStoreSummary",
111
sizeof (CamelIMAPXStoreSummary),
112
sizeof (CamelIMAPXStoreSummaryClass),
113
(CamelObjectClassInitFunc) camel_imapx_store_summary_class_init,
115
(CamelObjectInitFunc) camel_imapx_store_summary_init,
116
(CamelObjectFinalizeFunc) camel_imapx_store_summary_finalise);
123
* camel_imapx_store_summary_new:
125
* Create a new CamelIMAPXStoreSummary object.
127
* Returns: A new CamelIMAPXStoreSummary widget.
129
CamelIMAPXStoreSummary *
130
camel_imapx_store_summary_new (void)
132
CamelIMAPXStoreSummary *new = CAMEL_IMAPX_STORE_SUMMARY ( camel_object_new (camel_imapx_store_summary_get_type ()));
138
* camel_imapx_store_summary_full_name:
142
* Retrieve a summary item by full name.
144
* A referenced to the summary item is returned, which may be
145
* ref'd or free'd as appropriate.
147
* Returns: The summary item, or NULL if the @full_name name
149
* It must be freed using camel_store_summary_info_free().
151
CamelIMAPXStoreInfo *
152
camel_imapx_store_summary_full_name(CamelIMAPXStoreSummary *s, const gchar *full_name)
155
CamelIMAPXStoreInfo *info;
157
count = camel_store_summary_count((CamelStoreSummary *)s);
158
for (i=0;i<count;i++) {
159
info = (CamelIMAPXStoreInfo *)camel_store_summary_index((CamelStoreSummary *)s, i);
161
if (strcmp(info->full_name, full_name) == 0)
163
camel_store_summary_info_free((CamelStoreSummary *)s, (CamelStoreInfo *)info);
171
camel_imapx_store_summary_full_to_path(CamelIMAPXStoreSummary *s, const gchar *full_name, gchar dir_sep)
177
if (dir_sep != '/') {
178
p = path = alloca(strlen(full_name)*3+1);
180
while ((c = *f++ & 0xff)) {
183
else if (c == '/' || c == '%')
184
p += sprintf(p, "%%%02X", c);
190
path = (gchar *)full_name;
192
return g_strdup(path);
195
static guint32 hexnib(guint32 c)
197
if (c >= '0' && c <= '9')
199
else if (c>='A' && c <= 'Z')
206
camel_imapx_store_summary_path_to_full(CamelIMAPXStoreSummary *s, const gchar *path, gchar dir_sep)
212
gchar *subpath, *last = NULL;
214
CamelIMAPXStoreNamespace *ns;
216
/* check to see if we have a subpath of path already defined */
217
subpath = alloca(strlen(path)+1);
218
strcpy(subpath, path);
220
si = camel_store_summary_path((CamelStoreSummary *)s, subpath);
222
last = strrchr(subpath, '/');
226
} while (si == NULL && last);
228
/* path is already present, use the raw version we have */
229
if (si && strlen(subpath) == strlen(path)) {
230
f = g_strdup(camel_imapx_store_info_full_name(s, si));
231
camel_store_summary_info_free((CamelStoreSummary *)s, si);
235
ns = camel_imapx_store_summary_namespace_find_path(s, path);
237
f = full = alloca(strlen(path)*2+1);
239
p = path + strlen(subpath);
241
p = path + strlen(ns->path);
245
while ((c = camel_utf8_getc((const guchar **)&p))) {
253
camel_utf8_putc((guchar **) &f, c);
263
camel_utf8_putc((guchar **) &f, v);
267
camel_utf8_putc((guchar **) &f, c);
269
/* merge old path part if required */
272
full = g_strdup_printf("%s%s", camel_imapx_store_info_full_name(s, si), f);
274
camel_store_summary_info_free((CamelStoreSummary *)s, si);
277
full = g_strdup_printf("%s%s", ns->full_name, f);
285
CamelIMAPXStoreInfo *
286
camel_imapx_store_summary_add_from_full(CamelIMAPXStoreSummary *s, const gchar *full, gchar dir_sep)
288
CamelIMAPXStoreInfo *info;
289
gchar *pathu8, *prefix;
292
CamelIMAPXStoreNamespace *ns;
294
d(printf("adding full name '%s' '%c'\n", full, dir_sep));
297
full_name = alloca(len+1);
298
strcpy(full_name, full);
299
if (full_name[len-1] == dir_sep)
300
full_name[len-1] = 0;
302
info = camel_imapx_store_summary_full_name(s, full_name);
304
camel_store_summary_info_free((CamelStoreSummary *)s, (CamelStoreInfo *)info);
305
d(printf(" already there\n"));
309
ns = camel_imapx_store_summary_namespace_find_full(s, full_name);
311
d(printf("(found namespace for '%s' ns '%s') ", full_name, ns->path));
312
len = strlen(ns->full_name);
313
if (len >= strlen(full_name)) {
314
pathu8 = g_strdup(ns->path);
316
if (full_name[len] == ns->sep)
319
prefix = camel_imapx_store_summary_full_to_path(s, full_name+len, ns->sep);
321
pathu8 = g_strdup_printf ("%s/%s", ns->path, prefix);
327
d(printf(" (pathu8 = '%s')", pathu8));
329
d(printf("(Cannot find namespace for '%s')\n", full_name));
330
pathu8 = camel_imapx_store_summary_full_to_path(s, full_name, dir_sep);
333
info = (CamelIMAPXStoreInfo *)camel_store_summary_add_from_path((CamelStoreSummary *)s, pathu8);
335
d(printf(" '%s' -> '%s'\n", pathu8, full_name));
336
camel_store_info_set_string((CamelStoreSummary *)s, (CamelStoreInfo *)info, CAMEL_IMAPX_STORE_INFO_FULL_NAME, full_name);
338
if (!g_ascii_strcasecmp(full_name, "inbox"))
339
info->info.flags |= CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_TYPE_INBOX;
341
d(printf(" failed\n"));
347
/* should this be const? */
348
/* TODO: deprecate/merge this function with path_to_full */
350
camel_imapx_store_summary_full_from_path(CamelIMAPXStoreSummary *s, const gchar *path)
352
CamelIMAPXStoreNamespace *ns;
355
ns = camel_imapx_store_summary_namespace_find_path(s, path);
357
name = camel_imapx_store_summary_path_to_full(s, path, ns->sep);
359
d(printf("looking up path %s -> %s\n", path, name?name:"not found"));
364
/* TODO: this api needs some more work */
365
CamelIMAPXStoreNamespace *camel_imapx_store_summary_namespace_new(CamelIMAPXStoreSummary *s, const gchar *full_name, gchar dir_sep)
367
CamelIMAPXStoreNamespace *ns;
371
ns = g_malloc0(sizeof(*ns));
372
ns->full_name = g_strdup(full_name);
373
len = strlen(ns->full_name)-1;
374
if (len >= 0 && ns->full_name[len] == dir_sep)
375
ns->full_name[len] = 0;
378
o = p = ns->path = camel_imapx_store_summary_full_to_path(s, ns->full_name, dir_sep);
391
void camel_imapx_store_summary_namespace_set(CamelIMAPXStoreSummary *s, CamelIMAPXStoreNamespace *ns)
393
d(printf("Setting namesapce to '%s' '%c' -> '%s'\n", ns->full_name, ns->sep, ns->path));
395
/* CHEN not needed */
396
camel_store_summary_touch((CamelStoreSummary *)s);
399
CamelIMAPXStoreNamespace *
400
camel_imapx_store_summary_namespace_find_path(CamelIMAPXStoreSummary *s, const gchar *path)
403
CamelIMAPXStoreNamespace *ns;
405
/* NB: this currently only compares against 1 namespace, in future compare against others */
407
ns = s->namespaces->personal;
409
len = strlen(ns->path);
411
|| (strncmp(ns->path, path, len) == 0
412
&& (path[len] == '/' || path[len] == 0)))
417
/* have a default? */
421
CamelIMAPXStoreNamespace *
422
camel_imapx_store_summary_namespace_find_full(CamelIMAPXStoreSummary *s, const gchar *full)
425
CamelIMAPXStoreNamespace *ns;
427
/* NB: this currently only compares against 1 namespace, in future compare against others */
429
ns = s->namespaces->personal;
432
len = strlen(ns->full_name);
433
d(printf("find_full: comparing namespace '%s' to name '%s'\n", ns->full_name, full));
435
|| (strncmp(ns->full_name, full, len) == 0
436
&& (full[len] == ns->sep || full[len] == 0)))
441
/* have a default? */
445
static CamelIMAPXNamespaceList *
446
namespace_load(CamelStoreSummary *s, FILE *in)
448
CamelIMAPXStoreNamespace *ns, *tail;
449
CamelIMAPXNamespaceList *nsl;
453
nsl = g_malloc0(sizeof(CamelIMAPXNamespaceList));
454
nsl->personal = NULL;
458
for (j = 0; j < 3; j++) {
461
tail = (CamelIMAPXStoreNamespace *) &nsl->personal;
464
tail = (CamelIMAPXStoreNamespace *) &nsl->shared;
467
tail = (CamelIMAPXStoreNamespace *) &nsl->other;
471
if (camel_file_util_decode_fixed_int32 (in, &n) == -1)
474
for (i = 0; i < n; i++) {
479
if (camel_file_util_decode_string (in, &path) == -1)
482
if (camel_file_util_decode_string (in, &full_name) == -1) {
487
if (camel_file_util_decode_uint32 (in, &sep) == -1) {
493
tail->next = ns = g_malloc (sizeof (CamelIMAPXStoreNamespace));
496
ns->full_name = full_name;
504
camel_imapx_namespace_list_clear (nsl);
510
namespace_save(CamelStoreSummary *s, FILE *out, CamelIMAPXNamespaceList *nsl)
512
CamelIMAPXStoreNamespace *ns, *cur = NULL;
515
for (i = 0; i < 3; i++) {
528
for (ns = cur, n = 0; ns; n++)
531
if (camel_file_util_encode_fixed_int32 (out, n) == -1)
536
if (camel_file_util_encode_string (out, ns->path) == -1)
539
if (camel_file_util_encode_string (out, ns->full_name) == -1)
542
if (camel_file_util_encode_uint32 (out, ns->sep) == -1)
553
summary_header_load(CamelStoreSummary *s, FILE *in)
555
CamelIMAPXStoreSummary *is = (CamelIMAPXStoreSummary *)s;
556
gint32 version, capabilities;
558
camel_imapx_namespace_list_clear (is->namespaces);
560
if (camel_imapx_store_summary_parent->summary_header_load((CamelStoreSummary *)s, in) == -1
561
|| camel_file_util_decode_fixed_int32(in, &version) == -1)
564
is->version = version;
566
if (version < CAMEL_IMAPX_STORE_SUMMARY_VERSION_0) {
567
g_warning("Store summary header version too low");
571
/* note file format can be expanded to contain more namespaces, but only 1 at the moment */
572
if (camel_file_util_decode_fixed_int32(in, &capabilities) == -1)
575
is->capabilities = capabilities;
578
if ((is->namespaces = namespace_load(s, in)) == NULL)
585
summary_header_save(CamelStoreSummary *s, FILE *out)
587
CamelIMAPXStoreSummary *is = (CamelIMAPXStoreSummary *)s;
589
/* always write as latest version */
590
if (camel_imapx_store_summary_parent->summary_header_save((CamelStoreSummary *)s, out) == -1
591
|| camel_file_util_encode_fixed_int32(out, CAMEL_IMAPX_STORE_SUMMARY_VERSION) == -1
592
|| camel_file_util_encode_fixed_int32(out, is->capabilities) == -1)
595
if (is->namespaces && namespace_save(s, out, is->namespaces) == -1)
601
static CamelStoreInfo *
602
store_info_load(CamelStoreSummary *s, FILE *in)
604
CamelIMAPXStoreInfo *mi;
606
mi = (CamelIMAPXStoreInfo *)camel_imapx_store_summary_parent->store_info_load(s, in);
608
if (camel_file_util_decode_string(in, &mi->full_name) == -1) {
609
camel_store_summary_info_free(s, (CamelStoreInfo *)mi);
612
/* NB: this is done again for compatability */
613
if (g_ascii_strcasecmp(mi->full_name, "inbox") == 0)
614
mi->info.flags |= CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_TYPE_INBOX;
618
return (CamelStoreInfo *)mi;
622
store_info_save(CamelStoreSummary *s, FILE *out, CamelStoreInfo *mi)
624
CamelIMAPXStoreInfo *isi = (CamelIMAPXStoreInfo *)mi;
626
if (camel_imapx_store_summary_parent->store_info_save(s, out, mi) == -1
627
|| camel_file_util_encode_string(out, isi->full_name) == -1)
634
store_info_free(CamelStoreSummary *s, CamelStoreInfo *mi)
636
CamelIMAPXStoreInfo *isi = (CamelIMAPXStoreInfo *)mi;
638
g_free(isi->full_name);
639
camel_imapx_store_summary_parent->store_info_free(s, mi);
643
store_info_string(CamelStoreSummary *s, const CamelStoreInfo *mi, gint type)
645
CamelIMAPXStoreInfo *isi = (CamelIMAPXStoreInfo *)mi;
649
g_assert (mi != NULL);
652
case CAMEL_IMAPX_STORE_INFO_FULL_NAME:
653
return isi->full_name;
655
return camel_imapx_store_summary_parent->store_info_string(s, mi, type);
660
store_info_set_string(CamelStoreSummary *s, CamelStoreInfo *mi, gint type, const gchar *str)
662
CamelIMAPXStoreInfo *isi = (CamelIMAPXStoreInfo *)mi;
664
g_assert(mi != NULL);
667
case CAMEL_IMAPX_STORE_INFO_FULL_NAME:
668
d(printf("Set full name %s -> %s\n", isi->full_name, str));
669
CAMEL_STORE_SUMMARY_LOCK(s, summary_lock);
670
g_free(isi->full_name);
671
isi->full_name = g_strdup(str);
672
CAMEL_STORE_SUMMARY_UNLOCK(s, summary_lock);
675
camel_imapx_store_summary_parent->store_info_set_string(s, mi, type, str);
681
camel_imapx_store_summary_set_namespaces (CamelIMAPXStoreSummary *summary, const CamelIMAPXNamespaceList *nsl)
683
if (summary->namespaces)
684
camel_imapx_namespace_list_clear (summary->namespaces);
685
summary->namespaces = camel_imapx_namespace_list_copy (summary->namespaces);