From aad2d708c31bc7b238fc4f7027e5c48fcee5f062 Mon Sep 17 00:00:00 2001 From: Jeffrey Stedfast Date: Tue, 26 Oct 2004 21:22:17 +0000 Subject: New files implementing a folder-info cache for offline mode (and faster 2004-10-26 Jeffrey Stedfast * 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 * 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 --- camel/providers/imap4/Makefile.am | 2 + camel/providers/imap4/camel-imap4-engine.c | 30 +- camel/providers/imap4/camel-imap4-folder.c | 55 ++- camel/providers/imap4/camel-imap4-store-summary.c | 390 ++++++++++++++++++++++ camel/providers/imap4/camel-imap4-store-summary.h | 90 +++++ camel/providers/imap4/camel-imap4-store.c | 61 +++- camel/providers/imap4/camel-imap4-store.h | 1 + camel/providers/imap4/camel-imap4-utils.c | 71 +++- camel/providers/imap4/camel-imap4-utils.h | 13 +- 9 files changed, 664 insertions(+), 49 deletions(-) create mode 100644 camel/providers/imap4/camel-imap4-store-summary.c create mode 100644 camel/providers/imap4/camel-imap4-store-summary.h (limited to 'camel/providers/imap4') 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 @@ -114,22 +114,6 @@ camel_imap4_engine_init (CamelIMAP4Engine *engine, CamelIMAP4EngineClass *klass) e_dlist_init (&engine->queue); } -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) { @@ -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 + * + * 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 +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#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 + * + * 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 +#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 +#include + #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); -- cgit