aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeffrey Stedfast <fejj@novell.com>2004-10-27 05:22:17 +0800
committerJeffrey Stedfast <fejj@src.gnome.org>2004-10-27 05:22:17 +0800
commitaad2d708c31bc7b238fc4f7027e5c48fcee5f062 (patch)
tree5b68028a7a5dc5a7f6c5106ea51f7287b9980644
parent99cbfb261554f038d9b709d2b3dab26a7f0e7bef (diff)
downloadgsoc2013-evolution-aad2d708c31bc7b238fc4f7027e5c48fcee5f062.tar
gsoc2013-evolution-aad2d708c31bc7b238fc4f7027e5c48fcee5f062.tar.gz
gsoc2013-evolution-aad2d708c31bc7b238fc4f7027e5c48fcee5f062.tar.bz2
gsoc2013-evolution-aad2d708c31bc7b238fc4f7027e5c48fcee5f062.tar.lz
gsoc2013-evolution-aad2d708c31bc7b238fc4f7027e5c48fcee5f062.tar.xz
gsoc2013-evolution-aad2d708c31bc7b238fc4f7027e5c48fcee5f062.tar.zst
gsoc2013-evolution-aad2d708c31bc7b238fc4f7027e5c48fcee5f062.zip
New files implementing a folder-info cache for offline mode (and faster
2004-10-26 Jeffrey Stedfast <fejj@novell.com> * providers/imap4/camel-imap4-store-summary.[c,h]: New files implementing a folder-info cache for offline mode (and faster startup I guess). * providers/imap4/camel-imap4-store.c (imap4_build_folder_info): Cache the folder-info for later use in offline mode. * providers/imap4/camel-imap4-utils.c (camel_imap4_get_path_delim): Instead of assigning top = "INBOX", do strcpy (top, "INBOX") so that we can later modify the string. Fixes bug #68814. 2004-10-25 Jeffrey Stedfast <fejj@novell.com> * providers/imap4/camel-imap4-engine.c (engine_parse_namespace): Updated to use the public function in camel-imap4-utils.c (camel_imap4_engine_finalize): Same. * providers/imap4/camel-imap4-store.c (imap4_construct): Setup and load the store summary. (camel_imap4_store_finalize): Unref the store summary. (imap4_get_folder): Implemented offline support. (imap4_folder_utf7_name): Pass the summary to get_delim rather than the engine. (imap4_create_folder): Same. (imap4_reconnect): Update the namespaces on the store summary. (connect_to_server): Update the store summary capabilities. * providers/imap4/camel-imap4-utils.c (camel_imap4_get_path_delim): Now takes a store-summary rather than an engine so that it will work in offline mode. (camel_imap4_namespace_clear): Moved here from camel-imap4-engine.c (camel_imap4_namespace_list_copy): New convenience function. (camel_imap4_namespace_list_free): New. * providers/imap4/camel-imap4-folder.c (camel_imap4_folder_new): Check the return value of summary loading in offline mode (if it fails, we can't get the folder). svn path=/trunk/; revision=27730
-rw-r--r--camel/ChangeLog42
-rw-r--r--camel/camel-store-summary.h2
-rw-r--r--camel/providers/imap4/Makefile.am2
-rw-r--r--camel/providers/imap4/camel-imap4-engine.c30
-rw-r--r--camel/providers/imap4/camel-imap4-folder.c55
-rw-r--r--camel/providers/imap4/camel-imap4-store-summary.c390
-rw-r--r--camel/providers/imap4/camel-imap4-store-summary.h90
-rw-r--r--camel/providers/imap4/camel-imap4-store.c61
-rw-r--r--camel/providers/imap4/camel-imap4-store.h1
-rw-r--r--camel/providers/imap4/camel-imap4-utils.c71
-rw-r--r--camel/providers/imap4/camel-imap4-utils.h13
11 files changed, 707 insertions, 50 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog
index 2a6dbf5c72..ff8ead8adb 100644
--- a/camel/ChangeLog
+++ b/camel/ChangeLog
@@ -1,3 +1,45 @@
+2004-10-26 Jeffrey Stedfast <fejj@novell.com>
+
+ * providers/imap4/camel-imap4-store-summary.[c,h]: New files
+ implementing a folder-info cache for offline mode (and faster
+ startup I guess).
+
+ * providers/imap4/camel-imap4-store.c (imap4_build_folder_info):
+ Cache the folder-info for later use in offline mode.
+
+ * providers/imap4/camel-imap4-utils.c
+ (camel_imap4_get_path_delim): Instead of assigning top = "INBOX",
+ do strcpy (top, "INBOX") so that we can later modify the
+ string. Fixes bug #68814.
+
+2004-10-25 Jeffrey Stedfast <fejj@novell.com>
+
+ * providers/imap4/camel-imap4-engine.c (engine_parse_namespace):
+ Updated to use the public function in camel-imap4-utils.c
+ (camel_imap4_engine_finalize): Same.
+
+ * providers/imap4/camel-imap4-store.c (imap4_construct): Setup and
+ load the store summary.
+ (camel_imap4_store_finalize): Unref the store summary.
+ (imap4_get_folder): Implemented offline support.
+ (imap4_folder_utf7_name): Pass the summary to get_delim rather
+ than the engine.
+ (imap4_create_folder): Same.
+ (imap4_reconnect): Update the namespaces on the store summary.
+ (connect_to_server): Update the store summary capabilities.
+
+ * providers/imap4/camel-imap4-utils.c
+ (camel_imap4_get_path_delim): Now takes a store-summary rather
+ than an engine so that it will work in offline mode.
+ (camel_imap4_namespace_clear): Moved here from
+ camel-imap4-engine.c
+ (camel_imap4_namespace_list_copy): New convenience function.
+ (camel_imap4_namespace_list_free): New.
+
+ * providers/imap4/camel-imap4-folder.c (camel_imap4_folder_new):
+ Check the return value of summary loading in offline mode (if it
+ fails, we can't get the folder).
+
2004-10-21 Jeffrey Stedfast <fejj@novell.com>
* camel-sasl-gssapi.c: #include "camel-i18n.h"
diff --git a/camel/camel-store-summary.h b/camel/camel-store-summary.h
index e512cc32ba..0d6672ad17 100644
--- a/camel/camel-store-summary.h
+++ b/camel/camel-store-summary.h
@@ -157,7 +157,7 @@ void camel_store_summary_clear(CamelStoreSummary *s);
/* lookup functions */
int camel_store_summary_count(CamelStoreSummary *);
CamelStoreInfo *camel_store_summary_index(CamelStoreSummary *, int);
-CamelStoreInfo *camel_store_summary_path(CamelStoreSummary *, const char *uid);
+CamelStoreInfo *camel_store_summary_path(CamelStoreSummary *, const char *path);
GPtrArray *camel_store_summary_array(CamelStoreSummary *s);
void camel_store_summary_array_free(CamelStoreSummary *s, GPtrArray *array);
diff --git a/camel/providers/imap4/Makefile.am b/camel/providers/imap4/Makefile.am
index aca5e7856b..259b71fe74 100644
--- a/camel/providers/imap4/Makefile.am
+++ b/camel/providers/imap4/Makefile.am
@@ -30,6 +30,8 @@ libcamelimap4_la_SOURCES = \
camel-imap4-specials.h \
camel-imap4-store.c \
camel-imap4-store.h \
+ camel-imap4-store-summary.c \
+ camel-imap4-store-summary.h \
camel-imap4-stream.c \
camel-imap4-stream.h \
camel-imap4-summary.c \
diff --git a/camel/providers/imap4/camel-imap4-engine.c b/camel/providers/imap4/camel-imap4-engine.c
index 33ec568a6b..7598b6f219 100644
--- a/camel/providers/imap4/camel-imap4-engine.c
+++ b/camel/providers/imap4/camel-imap4-engine.c
@@ -115,22 +115,6 @@ camel_imap4_engine_init (CamelIMAP4Engine *engine, CamelIMAP4EngineClass *klass)
}
static void
-imap4_namespace_clear (CamelIMAP4Namespace **namespace)
-{
- CamelIMAP4Namespace *node, *next;
-
- node = *namespace;
- while (node != NULL) {
- next = node->next;
- g_free (node->path);
- g_free (node);
- node = next;
- }
-
- *namespace = NULL;
-}
-
-static void
camel_imap4_engine_finalize (CamelObject *object)
{
CamelIMAP4Engine *engine = (CamelIMAP4Engine *) object;
@@ -145,9 +129,9 @@ camel_imap4_engine_finalize (CamelObject *object)
g_hash_table_foreach (engine->authtypes, (GHFunc) g_free, NULL);
g_hash_table_destroy (engine->authtypes);
- imap4_namespace_clear (&engine->namespaces.personal);
- imap4_namespace_clear (&engine->namespaces.other);
- imap4_namespace_clear (&engine->namespaces.shared);
+ camel_imap4_namespace_clear (&engine->namespaces.personal);
+ camel_imap4_namespace_clear (&engine->namespaces.other);
+ camel_imap4_namespace_clear (&engine->namespaces.shared);
if (engine->folder)
camel_object_unref (engine->folder);
@@ -565,9 +549,9 @@ engine_parse_namespace (CamelIMAP4Engine *engine, CamelException *ex)
camel_imap4_token_t token;
int i, n = 0;
- imap4_namespace_clear (&engine->namespaces.personal);
- imap4_namespace_clear (&engine->namespaces.other);
- imap4_namespace_clear (&engine->namespaces.shared);
+ camel_imap4_namespace_clear (&engine->namespaces.personal);
+ camel_imap4_namespace_clear (&engine->namespaces.other);
+ camel_imap4_namespace_clear (&engine->namespaces.shared);
if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
return -1;
@@ -674,7 +658,7 @@ engine_parse_namespace (CamelIMAP4Engine *engine, CamelException *ex)
exception:
for (i = 0; i <= n; i++)
- imap4_namespace_clear (&namespaces[i]);
+ camel_imap4_namespace_clear (&namespaces[i]);
return -1;
}
diff --git a/camel/providers/imap4/camel-imap4-folder.c b/camel/providers/imap4/camel-imap4-folder.c
index 58aebfd092..1eadc98904 100644
--- a/camel/providers/imap4/camel-imap4-folder.c
+++ b/camel/providers/imap4/camel-imap4-folder.c
@@ -217,7 +217,7 @@ camel_imap4_folder_new (CamelStore *store, const char *full_name, CamelException
utf7_name = g_alloca (strlen (full_name) + 1);
strcpy (utf7_name, full_name);
- sep = camel_imap4_get_path_delim (((CamelIMAP4Store *) store)->engine, full_name);
+ sep = camel_imap4_get_path_delim (((CamelIMAP4Store *) store)->summary, full_name);
if (sep != '/') {
p = utf7_name;
while (*p != '\0') {
@@ -229,7 +229,7 @@ camel_imap4_folder_new (CamelStore *store, const char *full_name, CamelException
utf7_name = camel_utf8_utf7 (utf7_name);
- folder = (CamelFolder *) (imap_folder = (CamelIMAP4Folder *)camel_object_new (CAMEL_TYPE_IMAP4_FOLDER));
+ folder = (CamelFolder *) (imap_folder = (CamelIMAP4Folder *) camel_object_new (CAMEL_TYPE_IMAP4_FOLDER));
camel_folder_construct (folder, store, full_name, name);
imap_folder->utf7_name = utf7_name;
@@ -241,24 +241,36 @@ camel_imap4_folder_new (CamelStore *store, const char *full_name, CamelException
camel_folder_summary_set_filename (folder->summary, path);
g_free (path);
- camel_folder_summary_load (folder->summary);
-
imap_folder->search = camel_imap4_search_new (((CamelIMAP4Store *) store)->engine, imap_folder->cachedir);
- if (camel_imap4_engine_select_folder (((CamelIMAP4Store *) store)->engine, folder, ex) == -1) {
- camel_object_unref (folder);
- folder = NULL;
- }
-
- if (folder && camel_imap4_summary_flush_updates (folder->summary, ex) == -1) {
- camel_object_unref (folder);
- folder = NULL;
+ if (camel_session_is_online (((CamelService *) store)->session)) {
+ /* we don't care if the summary loading fails here */
+ camel_folder_summary_load (folder->summary);
+
+ if (camel_imap4_engine_select_folder (((CamelIMAP4Store *) store)->engine, folder, ex) == -1) {
+ camel_object_unref (folder);
+ folder = NULL;
+ }
+
+ if (folder && camel_imap4_summary_flush_updates (folder->summary, ex) == -1) {
+ camel_object_unref (folder);
+ folder = NULL;
+ }
+ } else {
+ /* we *do* care if summary loading fails here though */
+ if (camel_folder_summary_load (folder->summary) == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID_PATH,
+ _("Cannot access folder `%s': %s"),
+ full_name, g_strerror (ENOENT));
+
+ camel_object_unref (folder);
+ folder = NULL;
+ }
}
return folder;
}
-
const char *
camel_imap4_folder_utf7_name (CamelIMAP4Folder *folder)
{
@@ -634,6 +646,23 @@ imap4_get_message (CamelFolder *folder, const char *uid, CamelException *ex)
* that fails and we are offline, we're done. else do the
* following code */
+ /* Note: While some hard-core IMAP extremists are probably
+ * going to flame me for fetching entire messages here, it's
+ * the *only* sure-fire way of working with all IMAP
+ * servers. There are numerous problems with fetching
+ * individual MIME parts from a good handful of IMAP servers
+ * which makes this a pain to do the Right Way (tm). For
+ * example: Courier-IMAP has "issues" parsing some multipart
+ * messages apparently, because BODY responses are often
+ * inaccurate. I'm also not very trusting of the free German
+ * IMAP hosting either (such as mail.gmx.net and imap.web.de)
+ * as they have proven themselves to be quite flakey wrt FETCH
+ * requests (they seem to be written exclusively for
+ * Outlook). Also, some IMAP servers such as GroupWise don't
+ * store mail in MIME format and so must re-construct the
+ * entire message in order to extract the requested part, so
+ * it is *mush* more efficient (generally) to just request the
+ * entire message anyway. */
ic = camel_imap4_engine_queue (engine, folder, "UID FETCH %s BODY.PEEK[]\r\n", uid);
camel_imap4_command_register_untagged (ic, "FETCH", untagged_fetch);
ic->user_data = stream = camel_stream_mem_new ();
diff --git a/camel/providers/imap4/camel-imap4-store-summary.c b/camel/providers/imap4/camel-imap4-store-summary.c
new file mode 100644
index 0000000000..7f9d211f4f
--- /dev/null
+++ b/camel/providers/imap4/camel-imap4-store-summary.c
@@ -0,0 +1,390 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@novell.com>
+ *
+ * Copyright 2004 Novell, Inc. (www.novell.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <camel/camel-store.h>
+#include <camel/camel-file-utils.h>
+
+#include "camel-imap4-utils.h"
+#include "camel-imap4-store-summary.h"
+
+
+#define CAMEL_IMAP4_STORE_SUMMARY_VERSION_0 (0)
+#define CAMEL_IMAP4_STORE_SUMMARY_VERSION (0)
+
+static void camel_imap4_store_summary_class_init (CamelIMAP4StoreSummaryClass *klass);
+static void camel_imap4_store_summary_init (CamelIMAP4StoreSummary *obj);
+static void camel_imap4_store_summary_finalize (CamelObject *obj);
+
+static int summary_header_load (CamelStoreSummary *s, FILE *in);
+static int summary_header_save (CamelStoreSummary *s, FILE *out);
+
+#if 0
+static CamelStoreInfo *store_info_load (CamelStoreSummary *s, FILE *in);
+static int store_info_save (CamelStoreSummary *s, FILE *out, CamelStoreInfo *info);
+static void store_info_free (CamelStoreSummary *s, CamelStoreInfo *info);
+#endif
+
+
+static CamelStoreSummaryClass *parent_class = NULL;
+
+
+CamelType
+camel_imap4_store_summary_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (camel_store_summary_get_type (),
+ "CamelIMAP4StoreSummary",
+ sizeof (CamelIMAP4StoreSummary),
+ sizeof (CamelIMAP4StoreSummaryClass),
+ (CamelObjectClassInitFunc) camel_imap4_store_summary_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_imap4_store_summary_init,
+ (CamelObjectFinalizeFunc) camel_imap4_store_summary_finalize);
+ }
+
+ return type;
+}
+
+
+static void
+camel_imap4_store_summary_class_init (CamelIMAP4StoreSummaryClass *klass)
+{
+ CamelStoreSummaryClass *ssklass = (CamelStoreSummaryClass *) klass;
+
+ parent_class = (CamelStoreSummaryClass *) camel_store_summary_get_type ();
+
+ ssklass->summary_header_load = summary_header_load;
+ ssklass->summary_header_save = summary_header_save;
+
+#if 0
+ ssklass->store_info_load = store_info_load;
+ ssklass->store_info_save = store_info_save;
+ ssklass->store_info_free = store_info_free;
+#endif
+}
+
+static void
+camel_imap4_store_summary_init (CamelIMAP4StoreSummary *s)
+{
+ ((CamelStoreSummary *) s)->store_info_size = sizeof (CamelIMAP4StoreInfo);
+ s->version = CAMEL_IMAP4_STORE_SUMMARY_VERSION;
+ s->namespaces = NULL;
+}
+
+static void
+camel_imap4_store_summary_finalize (CamelObject *obj)
+{
+ CamelIMAP4StoreSummary *s = (CamelIMAP4StoreSummary *) obj;
+
+ if (s->namespaces)
+ camel_imap4_namespace_list_free (s->namespaces);
+}
+
+
+static CamelIMAP4NamespaceList *
+load_namespaces (FILE *in)
+{
+ CamelIMAP4Namespace *ns, *tail;
+ CamelIMAP4NamespaceList *nsl;
+ guint32 i, j, n;
+
+ nsl = g_malloc (sizeof (CamelIMAP4NamespaceList));
+ nsl->personal = NULL;
+ nsl->shared = NULL;
+ nsl->other = NULL;
+
+ tail = (CamelIMAP4Namespace *) &nsl->personal;
+ if (camel_file_util_decode_fixed_int32 (in, &n) == -1)
+ goto exception;
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < n; i++) {
+ guint32 sep;
+ char *path;
+
+ if (camel_file_util_decode_string (in, &path) == -1)
+ goto exception;
+
+ if (camel_file_util_decode_uint32 (in, &sep) == -1) {
+ g_free (path);
+ goto exception;
+ }
+
+ tail->next = ns = g_malloc (sizeof (CamelIMAP4Namespace));
+ ns->sep = sep & 0xff;
+ ns->path = path;
+ ns->next = NULL;
+ tail = ns;
+ }
+
+ if (j == 0)
+ tail = (CamelIMAP4Namespace *) &nsl->shared;
+ else
+ tail = (CamelIMAP4Namespace *) &nsl->other;
+
+ if (camel_file_util_decode_fixed_int32 (in, &n) == -1)
+ goto exception;
+ }
+
+ return nsl;
+
+ exception:
+
+ camel_imap4_namespace_list_free (nsl);
+
+ return NULL;
+}
+
+static int
+summary_header_load (CamelStoreSummary *s, FILE *in)
+{
+ CamelIMAP4StoreSummary *is = (CamelIMAP4StoreSummary *) s;
+ guint32 version, capa;
+
+ if (parent_class->summary_header_load (s, in) == -1)
+ return -1;
+
+ if (camel_file_util_decode_fixed_int32 (in, &version) == -1)
+ return -1;
+
+ is->version = version;
+ if (version < CAMEL_IMAP4_STORE_SUMMARY_VERSION_0) {
+ g_warning ("Store summary header version too low");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (camel_file_util_decode_fixed_int32 (in, &capa) == -1)
+ return -1;
+
+ is->capa = capa;
+
+ if (!(is->namespaces = load_namespaces (in)))
+ return -1;
+
+ return 0;
+}
+
+static int
+save_namespaces (FILE *out, CamelIMAP4NamespaceList *nsl)
+{
+ CamelIMAP4Namespace *cur, *ns;
+ guint32 i, n;
+
+ cur = nsl->personal;
+ for (i = 0; i < 3; i++) {
+ for (ns = cur, n = 0; ns; n++)
+ ns = ns->next;
+
+ if (camel_file_util_encode_fixed_int32 (out, n) == -1)
+ return -1;
+
+ ns = cur;
+ while (ns != NULL) {
+ if (camel_file_util_encode_string (out, ns->path) == -1)
+ return -1;
+
+ if (camel_file_util_encode_uint32 (out, ns->sep) == -1)
+ return -1;
+
+ ns = ns->next;
+ }
+
+ if (i == 0)
+ cur = nsl->shared;
+ else
+ cur = nsl->other;
+ }
+
+ return 0;
+}
+
+static int
+summary_header_save (CamelStoreSummary *s, FILE *out)
+{
+ CamelIMAP4StoreSummary *is = (CamelIMAP4StoreSummary *) s;
+
+ if (parent_class->summary_header_save (s, out) == -1)
+ return -1;
+
+ if (camel_file_util_encode_fixed_int32 (out, is->version) == -1)
+ return -1;
+
+ if (camel_file_util_encode_fixed_int32 (out, is->capa) == -1)
+ return -1;
+
+ if (save_namespaces (out, is->namespaces) == -1)
+ return -1;
+
+ return 0;
+}
+
+#if 0
+static CamelStoreInfo *
+store_info_load (CamelStoreSummary *s, FILE *in)
+{
+ return NULL;
+}
+
+static int
+store_info_save (CamelStoreSummary *s, FILE *out, CamelStoreInfo *info)
+{
+ return 0;
+}
+
+static void
+store_info_free (CamelStoreSummary *s, CamelStoreInfo *info)
+{
+ ;
+}
+#endif
+
+/**
+ * camel_imap4_store_summary_new:
+ *
+ * Create a new CamelIMAP4StoreSummary object.
+ *
+ * Returns a new CamelIMAP4StoreSummary object.
+ **/
+CamelIMAP4StoreSummary *
+camel_imap4_store_summary_new (void)
+{
+ return (CamelIMAP4StoreSummary *) camel_object_new (camel_imap4_store_summary_get_type ());
+}
+
+
+void
+camel_imap4_store_summary_set_capabilities (CamelIMAP4StoreSummary *s, guint32 capa)
+{
+ s->capa = capa;
+}
+
+
+void
+camel_imap4_store_summary_set_namespaces (CamelIMAP4StoreSummary *s, const CamelIMAP4NamespaceList *ns)
+{
+ if (s->namespaces)
+ camel_imap4_namespace_list_free (s->namespaces);
+ s->namespaces = camel_imap4_namespace_list_copy (ns);
+}
+
+
+void
+camel_imap4_store_summary_note_info (CamelIMAP4StoreSummary *s, CamelFolderInfo *fi)
+{
+ CamelStoreSummary *ss = (CamelStoreSummary *) s;
+ CamelStoreInfo *si;
+
+ if ((si = camel_store_summary_path (ss, fi->full_name))) {
+ if (fi->unread != -1) {
+ si->unread = fi->unread;
+ ss->flags |= CAMEL_STORE_SUMMARY_DIRTY;
+ }
+
+ if (fi->total != -1) {
+ si->total = fi->total;
+ ss->flags |= CAMEL_STORE_SUMMARY_DIRTY;
+ }
+
+ camel_store_summary_info_free (ss, si);
+ return;
+ }
+
+ si = camel_store_summary_info_new (ss);
+ si->path = g_strdup (fi->full_name);
+ si->uri = g_strdup (fi->uri);
+ si->flags = fi->flags;
+ si->unread = fi->unread;
+ si->total = fi->total;
+
+ camel_store_summary_add (ss, si);
+}
+
+
+static CamelFolderInfo *
+store_info_to_folder_info (CamelStoreSummary *s, CamelStoreInfo *si)
+{
+ CamelFolderInfo *fi;
+
+ fi = g_malloc0 (sizeof (CamelFolderInfo));
+ fi->full_name = g_strdup (camel_store_info_path (s, si));
+ fi->name = g_strdup (camel_store_info_name (s, si));
+ fi->uri = g_strdup (camel_store_info_uri (s, si));
+ fi->flags = si->flags;
+ fi->unread = si->unread;
+ fi->total = si->total;
+
+ return fi;
+}
+
+CamelFolderInfo *
+camel_imap4_store_summary_get_folder_info (CamelIMAP4StoreSummary *s, const char *top, guint32 flags)
+{
+ CamelStoreSummary *ss = (CamelStoreSummary *) s;
+ CamelFolderInfo *fi;
+ GPtrArray *folders;
+ CamelStoreInfo *si;
+ size_t toplen, len;
+ int i;
+
+ if (top == NULL)
+ top = "";
+
+ toplen = strlen (top);
+ folders = g_ptr_array_new ();
+
+ for (i = 0; i < ss->folders->len; i++) {
+ si = ss->folders->pdata[i];
+ if (strncmp (si->path, top, toplen) != 0)
+ continue;
+
+ if ((len = strlen (si->path)) > toplen && si->path[toplen] != '/')
+ continue;
+
+ if (len == toplen) {
+ /* found toplevel folder */
+ g_ptr_array_add (folders, store_info_to_folder_info (ss, si));
+ continue;
+ }
+
+ if ((flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE) || !strchr (si->path + toplen + 1, '/'))
+ g_ptr_array_add (folders, store_info_to_folder_info (ss, si));
+ }
+
+ fi = camel_folder_info_build (folders, top, '/', TRUE);
+ g_ptr_array_free (folders, TRUE);
+
+ return fi;
+}
diff --git a/camel/providers/imap4/camel-imap4-store-summary.h b/camel/providers/imap4/camel-imap4-store-summary.h
new file mode 100644
index 0000000000..f9ddc54f19
--- /dev/null
+++ b/camel/providers/imap4/camel-imap4-store-summary.h
@@ -0,0 +1,90 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@novell.com>
+ *
+ * Copyright 2004 Novell, Inc. (www.novell.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifndef __CAMEL_IMAP_STORE_SUMMARY_H__
+#define __CAMEL_IMAP_STORE_SUMMARY_H__
+
+#include <camel/camel-store-summary.h>
+#include "camel-imap4-engine.h"
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+#define CAMEL_IMAP4_STORE_SUMMARY(obj) CAMEL_CHECK_CAST (obj, camel_imap4_store_summary_get_type (), CamelIMAP4StoreSummary)
+#define CAMEL_IMAP4_STORE_SUMMARY_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_imap4_store_summary_get_type (), CamelIMAP4StoreSummaryClass)
+#define CAMEL_IS_IMAP4_STORE_SUMMARY(obj) CAMEL_CHECK_TYPE (obj, camel_imap4_store_summary_get_type ())
+
+typedef struct _CamelIMAP4StoreSummary CamelIMAP4StoreSummary;
+typedef struct _CamelIMAP4StoreSummaryClass CamelIMAP4StoreSummaryClass;
+
+typedef struct _CamelIMAP4StoreInfo CamelIMAP4StoreInfo;
+
+enum {
+ CAMEL_IMAP4_STORE_INFO_FULL_NAME = CAMEL_STORE_INFO_LAST,
+ CAMEL_IMAP4_STORE_INFO_LAST,
+};
+
+
+struct _CamelFolderInfo;
+
+
+struct _CamelIMAP4StoreInfo {
+ CamelStoreInfo info;
+};
+
+struct _CamelIMAP4StoreSummary {
+ CamelStoreSummary summary;
+
+ struct _CamelIMAP4StoreSummaryPrivate *priv;
+
+ /* header info */
+ guint32 version;
+
+ CamelIMAP4NamespaceList *namespaces;
+ guint32 capa;
+};
+
+struct _CamelIMAP4StoreSummaryClass {
+ CamelStoreSummaryClass summary_class;
+};
+
+
+CamelType camel_imap4_store_summary_get_type (void);
+
+CamelIMAP4StoreSummary *camel_imap4_store_summary_new (void);
+
+void camel_imap4_store_summary_set_capabilities (CamelIMAP4StoreSummary *s, guint32 capa);
+void camel_imap4_store_summary_set_namespaces (CamelIMAP4StoreSummary *s, const CamelIMAP4NamespaceList *ns);
+
+/* add the info to the cache if we don't already have it, otherwise do nothing */
+void camel_imap4_store_summary_note_info (CamelIMAP4StoreSummary *s, struct _CamelFolderInfo *fi);
+
+struct _CamelFolderInfo *camel_imap4_store_summary_get_folder_info (CamelIMAP4StoreSummary *s, const char *top, guint32 flags);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __CAMEL_IMAP4_STORE_SUMMARY_H__ */
diff --git a/camel/providers/imap4/camel-imap4-store.c b/camel/providers/imap4/camel-imap4-store.c
index 02f38401fa..395804849c 100644
--- a/camel/providers/imap4/camel-imap4-store.c
+++ b/camel/providers/imap4/camel-imap4-store.c
@@ -43,6 +43,7 @@
#include "camel-imap4-command.h"
#include "camel-imap4-utils.h"
#include "camel-imap4-summary.h"
+#include "camel-imap4-store-summary.h"
static void camel_imap4_store_class_init (CamelIMAP4StoreClass *klass);
@@ -145,6 +146,7 @@ static void
camel_imap4_store_init (CamelIMAP4Store *store, CamelIMAP4StoreClass *klass)
{
store->engine = NULL;
+ store->summary = NULL;
}
static void
@@ -152,6 +154,11 @@ camel_imap4_store_finalize (CamelObject *object)
{
CamelIMAP4Store *store = (CamelIMAP4Store *) object;
+ if (store->summary) {
+ camel_store_summary_save ((CamelStoreSummary *) store->summary);
+ camel_object_unref (store->summary);
+ }
+
if (store->engine)
camel_object_unref (store->engine);
@@ -163,6 +170,7 @@ static void
imap4_construct (CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, CamelException *ex)
{
CamelIMAP4Store *store = (CamelIMAP4Store *) service;
+ char *buf;
CAMEL_SERVICE_CLASS (parent_class)->construct (service, session, provider, url, ex);
if (camel_exception_is_set (ex))
@@ -170,6 +178,20 @@ imap4_construct (CamelService *service, CamelSession *session, CamelProvider *pr
store->storage_path = camel_session_get_storage_path (session, service, ex);
store->engine = camel_imap4_engine_new (service, imap4_reconnect);
+
+ /* setup/load the summary */
+ buf = g_alloca (strlen (store->storage_path) + 32);
+ sprintf (buf, "%s/.summary", store->storage_path);
+ store->summary = camel_imap4_store_summary_new ();
+ camel_store_summary_set_filename ((CamelStoreSummary *) store->summary, buf);
+
+ buf = camel_url_to_string (service->url, CAMEL_URL_HIDE_ALL);
+ url = camel_url_new (buf, NULL);
+ g_free (buf);
+ camel_store_summary_set_uri_base ((CamelStoreSummary *) store->summary, url);
+ camel_url_free (url);
+
+ camel_store_summary_load ((CamelStoreSummary *) store->summary);
}
static char *
@@ -238,6 +260,8 @@ connect_to_server (CamelIMAP4Engine *engine, struct addrinfo *ai, int ssl_mode,
if (camel_imap4_engine_capability (engine, ex) == -1)
return FALSE;
+ camel_imap4_store_summary_set_capabilities (((CamelIMAP4Store *) service)->summary, engine->capa);
+
if (ssl_mode != MODE_TLS) {
/* we're done */
return TRUE;
@@ -481,6 +505,8 @@ imap4_reconnect (CamelIMAP4Engine *engine, CamelException *ex)
if (camel_imap4_engine_namespace (engine, ex) == -1)
return FALSE;
+ camel_imap4_store_summary_set_namespaces (((CamelIMAP4Store *) service)->summary, &engine->namespaces);
+
return TRUE;
}
@@ -562,7 +588,7 @@ imap4_folder_utf7_name (CamelStore *store, const char *folder_name, char wildcar
char sep;
int len;
- sep = camel_imap4_get_path_delim (((CamelIMAP4Store *) store)->engine, folder_name);
+ sep = camel_imap4_get_path_delim (((CamelIMAP4Store *) store)->summary, folder_name);
if (sep != '/') {
p = real_name = g_alloca (strlen (folder_name) + 1);
@@ -615,8 +641,7 @@ imap4_get_folder (CamelStore *store, const char *folder_name, guint32 flags, Cam
if ((flags & CAMEL_STORE_FOLDER_CREATE) != 0) {
camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create IMAP folders in offline mode."));
} else {
- /* FIXME: implement me */
- /*folder = camel_imap4_folder_new_offline (store, folder_name, ex);*/
+ folder = camel_imap4_folder_new (store, folder_name, ex);
}
CAMEL_SERVICE_UNLOCK (store, connect_lock);
@@ -711,7 +736,7 @@ imap4_create_folder (CamelStore *store, const char *parent_name, const char *fol
char sep;
int id;
- sep = camel_imap4_get_path_delim (engine, parent_name);
+ sep = camel_imap4_get_path_delim (((CamelIMAP4Store *) store)->summary, parent_name);
c = folder_name;
while (*c != '\0') {
@@ -1047,6 +1072,11 @@ imap4_build_folder_info (CamelStore *store, const char *top, guint32 flags, GPtr
url = camel_url_copy (engine->url);
+ if (!strcmp (top, "") && (flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE)) {
+ /* clear the folder-info cache */
+ camel_store_summary_clear ((CamelStoreSummary *) ((CamelIMAP4Store *) store)->summary);
+ }
+
for (i = 0; i < array->len; i++) {
list = array->pdata[i];
fi = g_malloc0 (sizeof (CamelFolderInfo));
@@ -1095,6 +1125,8 @@ imap4_build_folder_info (CamelStore *store, const char *top, guint32 flags, GPtr
g_free (list);
array->pdata[i] = fi;
+
+ camel_imap4_store_summary_note_info (((CamelIMAP4Store *) store)->summary, fi);
}
fi = camel_folder_info_build (array, top, '/', TRUE);
@@ -1103,6 +1135,8 @@ imap4_build_folder_info (CamelStore *store, const char *top, guint32 flags, GPtr
g_ptr_array_free (array, TRUE);
+ camel_store_summary_save ((CamelStoreSummary *) ((CamelIMAP4Store *) store)->summary);
+
return fi;
}
@@ -1122,10 +1156,23 @@ imap4_get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelE
CAMEL_SERVICE_LOCK (store, connect_lock);
- if (!camel_session_is_online (session) /* || engine->state == CAMEL_IMAP4_ENGINE_DISCONNECTED */) {
- /* FIXME: get cached folder-info's */
+ if (!camel_session_is_online (session) || engine->state == CAMEL_IMAP4_ENGINE_DISCONNECTED) {
+ fi = camel_imap4_store_summary_get_folder_info (((CamelIMAP4Store *) store)->summary, top, flags);
+ if (fi == NULL && camel_session_is_online (session)) {
+ /* folder info hasn't yet been cached and the store hasn't been
+ * connected yet, but the network is available so we can connect
+ * and query the server. */
+ goto check_online;
+ }
CAMEL_SERVICE_UNLOCK (store, connect_lock);
- return NULL;
+ return fi;
+ }
+
+ check_online:
+
+ if (engine->state == CAMEL_IMAP4_ENGINE_DISCONNECTED) {
+ if (!camel_service_connect ((CamelService *) store, ex))
+ return NULL;
}
if (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED)
diff --git a/camel/providers/imap4/camel-imap4-store.h b/camel/providers/imap4/camel-imap4-store.h
index ff6222ecae..aef3c6c6a4 100644
--- a/camel/providers/imap4/camel-imap4-store.h
+++ b/camel/providers/imap4/camel-imap4-store.h
@@ -43,6 +43,7 @@ struct _CamelIMAP4Engine;
struct _CamelIMAP4Store {
CamelStore parent_object;
+ struct _CamelIMAP4StoreSummary *summary;
struct _CamelIMAP4Engine *engine;
char *storage_path;
};
diff --git a/camel/providers/imap4/camel-imap4-utils.c b/camel/providers/imap4/camel-imap4-utils.c
index 1c8dc0c1ef..e8f0627ea2 100644
--- a/camel/providers/imap4/camel-imap4-utils.c
+++ b/camel/providers/imap4/camel-imap4-utils.c
@@ -33,6 +33,7 @@
#include "camel-imap4-engine.h"
#include "camel-imap4-stream.h"
#include "camel-imap4-command.h"
+#include "camel-imap4-store-summary.h"
#include "camel-imap4-utils.h"
@@ -75,8 +76,68 @@ camel_imap4_merge_flags (guint32 original, guint32 local, guint32 server)
}
+void
+camel_imap4_namespace_clear (CamelIMAP4Namespace **ns)
+{
+ CamelIMAP4Namespace *node, *next;
+
+ node = *ns;
+ while (node != NULL) {
+ next = node->next;
+ g_free (node->path);
+ g_free (node);
+ node = next;
+ }
+
+ *ns = NULL;
+}
+
+static CamelIMAP4Namespace *
+imap4_namespace_copy (const CamelIMAP4Namespace *ns)
+{
+ CamelIMAP4Namespace *list, *node, *tail;
+
+ list = NULL;
+ tail = (CamelIMAP4Namespace *) &list;
+
+ while (ns != NULL) {
+ tail->next = node = g_malloc (sizeof (CamelIMAP4Namespace));
+ node->path = g_strdup (ns->path);
+ node->sep = ns->sep;
+ ns = ns->next;
+ tail = node;
+ }
+
+ tail->next = NULL;
+
+ return list;
+}
+
+CamelIMAP4NamespaceList *
+camel_imap4_namespace_list_copy (const CamelIMAP4NamespaceList *nsl)
+{
+ CamelIMAP4NamespaceList *new;
+
+ new = g_malloc (sizeof (CamelIMAP4NamespaceList));
+ new->personal = imap4_namespace_copy (nsl->personal);
+ new->other = imap4_namespace_copy (nsl->other);
+ new->shared = imap4_namespace_copy (nsl->shared);
+
+ return new;
+}
+
+void
+camel_imap4_namespace_list_free (CamelIMAP4NamespaceList *nsl)
+{
+ camel_imap4_namespace_clear (&nsl->personal);
+ camel_imap4_namespace_clear (&nsl->shared);
+ camel_imap4_namespace_clear (&nsl->other);
+ g_free (nsl);
+}
+
+
char
-camel_imap4_get_path_delim (CamelIMAP4Engine *engine, const char *full_name)
+camel_imap4_get_path_delim (CamelIMAP4StoreSummary *s, const char *full_name)
{
CamelIMAP4Namespace *namespace;
const char *slash;
@@ -93,24 +154,24 @@ camel_imap4_get_path_delim (CamelIMAP4Engine *engine, const char *full_name)
top[len] = '\0';
if (!g_ascii_strcasecmp (top, "INBOX"))
- top = "INBOX";
+ strcpy (top, "INBOX");
retry:
- namespace = engine->namespaces.personal;
+ namespace = s->namespaces->personal;
while (namespace != NULL) {
if (!strcmp (namespace->path, top))
return namespace->sep;
namespace = namespace->next;
}
- namespace = engine->namespaces.other;
+ namespace = s->namespaces->other;
while (namespace != NULL) {
if (!strcmp (namespace->path, top))
return namespace->sep;
namespace = namespace->next;
}
- namespace = engine->namespaces.shared;
+ namespace = s->namespaces->shared;
while (namespace != NULL) {
if (!strcmp (namespace->path, top))
return namespace->sep;
diff --git a/camel/providers/imap4/camel-imap4-utils.h b/camel/providers/imap4/camel-imap4-utils.h
index c378165357..1bb8b00962 100644
--- a/camel/providers/imap4/camel-imap4-utils.h
+++ b/camel/providers/imap4/camel-imap4-utils.h
@@ -23,6 +23,8 @@
#include <glib.h>
+#include <camel/camel-exception.h>
+
#ifdef __cplusplus
extern "C" {
#pragma }
@@ -38,11 +40,20 @@ void camel_imap4_flags_diff (flags_diff_t *diff, guint32 old, guint32 new);
guint32 camel_imap4_flags_merge (flags_diff_t *diff, guint32 flags);
guint32 camel_imap4_merge_flags (guint32 original, guint32 local, guint32 server);
+
struct _CamelIMAP4Engine;
struct _CamelIMAP4Command;
+struct _CamelFolderSummary;
struct _camel_imap4_token_t;
+struct _CamelIMAP4StoreSummary;
+struct _CamelIMAP4NamespaceList;
+struct _CamelIMAP4Namespace;
+
+void camel_imap4_namespace_clear (struct _CamelIMAP4Namespace **ns);
+struct _CamelIMAP4NamespaceList *camel_imap4_namespace_list_copy (const struct _CamelIMAP4NamespaceList *nsl);
+void camel_imap4_namespace_list_free (struct _CamelIMAP4NamespaceList *nsl);
-char camel_imap4_get_path_delim (struct _CamelIMAP4Engine *engine, const char *full_name);
+char camel_imap4_get_path_delim (struct _CamelIMAP4StoreSummary *s, const char *full_name);
int camel_imap4_get_uid_set (struct _CamelIMAP4Engine *engine, struct _CamelFolderSummary *summary, GPtrArray *infos, int cur, size_t linelen, char **set);