aboutsummaryrefslogtreecommitdiffstats
path: root/camel/providers/imap
diff options
context:
space:
mode:
authorDan Winship <danw@src.gnome.org>2001-03-21 01:38:46 +0800
committerDan Winship <danw@src.gnome.org>2001-03-21 01:38:46 +0800
commitfbb7448b5e10f89471432478789605cfe36ccff3 (patch)
tree0a32a790063326be8ef8a34b1da13db401a07251 /camel/providers/imap
parent8047141a5085c7eb096f940b757880ca249b19a0 (diff)
downloadgsoc2013-evolution-fbb7448b5e10f89471432478789605cfe36ccff3.tar.gz
gsoc2013-evolution-fbb7448b5e10f89471432478789605cfe36ccff3.tar.zst
gsoc2013-evolution-fbb7448b5e10f89471432478789605cfe36ccff3.zip
Function to check if the store is online and set an exception if not.
* providers/imap/camel-imap-store.c (camel_imap_store_check_online): Function to check if the store is online and set an exception if not. Currently controlled by an environment variable, but eventually there will be both a global (session-level) setting and a per-store setting. (construct): Set up storage_path and base_url here rather than at connect-time. (imap_auth_loop): Split out from imap_connect. (imap_setup_online): Split out from imap_connect. Do the post-authentication connection setup, and cache the results to disk. (imap_setup_offline): Set up a CamelImapStore with information saved from a previous imap_setup_online. (imap_connect): If online, do connect_to_server(), imap_auth_loop(), and imap_setup_online(). Otherwise, do imap_setup_offline(). (get_folder, get_folder_info): Add offline support. (create_folder, subscribe_folder, unsubscribe_folder): Disable these when offline (for now). * providers/imap/camel-imap-folder.c (camel_imap_folder_new): Remove the sync'ing-with-server stuff... it's done by camel_imap_folder_selected now, which only gets called if the store is online. (camel_imap_folder_selected): add the code removed from camel_imap_folder_new. Besides simplifying the folder_new and summary_new code, this also means now that we'll DTRT if a folder's UIDVALIDITY changes while we're connected. Also, when that happens, clear the message cache explicitly. (imap_refresh_info, imap_sync): These are no-ops when offline. (imap_expunge, imap_append_message, imap_copy_message_to, imap_search_by_expression): These don't yet work offline. (imap_get_message, camel_imap_folder_fetch_data): Return an error when trying to fetch a non-cached body part when we're offline. * providers/imap/camel-imap-summary.c (camel_imap_summary_new): Rewrite to not check the validity here. (We'll do it from camel_imap_folder_selected instead.) * providers/imap/camel-imap-command.c (camel_imap_command): Call camel_imap_folder_selected even when the selection is all we're doing, to match the changes in camel-imap-folder.c. * providers/imap/camel-imap-message-cache.c (camel_imap_message_cache_clear): New function to clear out a message cache. svn path=/trunk/; revision=8851
Diffstat (limited to 'camel/providers/imap')
-rw-r--r--camel/providers/imap/camel-imap-command.c2
-rw-r--r--camel/providers/imap/camel-imap-folder.c115
-rw-r--r--camel/providers/imap/camel-imap-message-cache.c13
-rw-r--r--camel/providers/imap/camel-imap-message-cache.h1
-rw-r--r--camel/providers/imap/camel-imap-store.c435
-rw-r--r--camel/providers/imap/camel-imap-store.h2
-rw-r--r--camel/providers/imap/camel-imap-summary.c21
-rw-r--r--camel/providers/imap/camel-imap-summary.h3
8 files changed, 402 insertions, 190 deletions
diff --git a/camel/providers/imap/camel-imap-command.c b/camel/providers/imap/camel-imap-command.c
index 8a713cde8b..7215168dc7 100644
--- a/camel/providers/imap/camel-imap-command.c
+++ b/camel/providers/imap/camel-imap-command.c
@@ -94,10 +94,10 @@ camel_imap_command (CamelImapStore *store, CamelFolder *folder,
return NULL;
store->current_folder = folder;
+ camel_imap_folder_selected (folder, response, ex);
if (!fmt)
return response;
- camel_imap_folder_selected (folder, response, ex);
camel_imap_response_free (response);
}
diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c
index 6d944747c9..5181b19ed8 100644
--- a/camel/providers/imap/camel-imap-folder.c
+++ b/camel/providers/imap/camel-imap-folder.c
@@ -46,6 +46,7 @@
#include "camel-imap-utils.h"
#include "camel-imap-wrapper.h"
#include "string-utils.h"
+#include "camel-session.h"
#include "camel-stream.h"
#include "camel-stream-mem.h"
#include "camel-stream-buffer.h"
@@ -162,42 +163,12 @@ camel_imap_folder_new (CamelStore *parent, const char *folder_name,
CamelFolder *folder = CAMEL_FOLDER (camel_object_new (camel_imap_folder_get_type ()));
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
CamelImapResponse *response;
- char *resp, *summary_file;
- guint32 validity = 0;
- int i, exists = 0;
+ char *summary_file;
camel_folder_construct (folder, parent, folder_name, short_name);
- CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
- response = camel_imap_command (imap_store, folder, ex, NULL);
- CAMEL_IMAP_STORE_UNLOCK(imap_store, command_lock);
-
- if (!response) {
- camel_object_unref ((CamelObject *)folder);
- return NULL;
- }
-
- for (i = 0; i < response->untagged->len; i++) {
- resp = response->untagged->pdata[i] + 2;
- if (!g_strncasecmp (resp, "FLAGS ", 6)) {
- resp += 6;
- folder->permanent_flags = imap_parse_flag_list (&resp);
- } else if (!g_strncasecmp (resp, "OK [PERMANENTFLAGS ", 19)) {
- resp += 19;
- folder->permanent_flags = imap_parse_flag_list (&resp);
- } else if (!g_strncasecmp (resp, "OK [UIDVALIDITY ", 16)) {
- validity = strtoul (resp + 16, NULL, 10);
- } else if (isdigit ((unsigned char)*resp)) {
- unsigned long num = strtoul (resp, &resp, 10);
-
- if (!g_strncasecmp (resp, " EXISTS", 7))
- exists = num;
- }
- }
- camel_imap_response_free (response);
-
summary_file = g_strdup_printf ("%s/summary", folder_dir);
- folder->summary = camel_imap_summary_new (summary_file, validity);
+ folder->summary = camel_imap_summary_new (summary_file);
g_free (summary_file);
if (!folder->summary) {
camel_object_unref (CAMEL_OBJECT (folder));
@@ -213,12 +184,16 @@ camel_imap_folder_new (CamelStore *parent, const char *folder_name,
return NULL;
}
- CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
- imap_rescan (folder, exists, ex);
- CAMEL_IMAP_STORE_UNLOCK(imap_store, command_lock);
- if (camel_exception_is_set (ex)) {
- camel_object_unref (CAMEL_OBJECT (folder));
- return NULL;
+ if (camel_imap_store_check_online (imap_store, NULL)) {
+ CAMEL_IMAP_STORE_LOCK (imap_store, command_lock);
+ response = camel_imap_command (imap_store, folder, ex, NULL);
+ CAMEL_IMAP_STORE_UNLOCK (imap_store, command_lock);
+
+ if (!response) {
+ camel_object_unref (CAMEL_OBJECT (folder));
+ return NULL;
+ }
+ camel_imap_response_free (response);
}
return folder;
@@ -230,26 +205,44 @@ camel_imap_folder_selected (CamelFolder *folder, CamelImapResponse *response,
CamelException *ex)
{
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
- unsigned long exists = 0, val, uid;
+ CamelImapSummary *imap_summary = CAMEL_IMAP_SUMMARY (folder->summary);
+ unsigned long exists = 0, validity = 0, val, uid;
CamelMessageInfo *info;
GData *fetch_data;
int i, count;
char *resp;
+ count = camel_folder_summary_count (folder->summary);
+
for (i = 0; i < response->untagged->len; i++) {
resp = response->untagged->pdata[i] + 2;
+ if (!g_strncasecmp (resp, "FLAGS ", 6) &&
+ !folder->permanent_flags) {
+ resp += 6;
+ folder->permanent_flags = imap_parse_flag_list (&resp);
+ } else if (!g_strncasecmp (resp, "OK [PERMANENTFLAGS ", 19)) {
+ resp += 19;
+ folder->permanent_flags = imap_parse_flag_list (&resp);
+ } else if (!g_strncasecmp (resp, "OK [UIDVALIDITY ", 16)) {
+ validity = strtoul (resp + 16, NULL, 10);
+ } else if (isdigit ((unsigned char)*resp)) {
+ unsigned long num = strtoul (resp, &resp, 10);
- exists = strtoul (resp, &resp, 10);
- if (!g_strncasecmp (resp, " EXISTS", 7))
- break;
+ if (!g_strncasecmp (resp, " EXISTS", 7))
+ exists = num;
+ }
}
- if (i == response->untagged->len) {
- g_warning ("Server response did not include EXISTS info");
+
+ if (!imap_summary->validity)
+ imap_summary->validity = validity;
+ else if (validity != imap_summary->validity) {
+ imap_summary->validity = validity;
+ camel_folder_summary_clear (folder->summary);
+ camel_imap_message_cache_clear (imap_folder->cache);
+ camel_imap_folder_changed (folder, exists, NULL, ex);
return;
}
- count = camel_folder_summary_count (folder->summary);
-
/* If we've lost messages, we have to rescan everything */
if (exists < count) {
imap_rescan (folder, exists, ex);
@@ -323,6 +316,9 @@ imap_finalize (CamelObject *object)
static void
imap_refresh_info (CamelFolder *folder, CamelException *ex)
{
+ if (!camel_imap_store_check_online (CAMEL_IMAP_STORE (folder->parent_store), NULL))
+ return;
+
CAMEL_IMAP_STORE_LOCK (folder->parent_store, command_lock);
imap_rescan (folder, camel_folder_summary_count (folder->summary), ex);
CAMEL_IMAP_STORE_UNLOCK (folder->parent_store, command_lock);
@@ -505,6 +501,9 @@ imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
char *set, *flaglist;
int i, j, max;
+ if (!camel_imap_store_check_online (store, NULL))
+ return;
+
max = camel_folder_summary_count (folder->summary);
/* If we're expunging then we don't need to be precise about the
@@ -594,6 +593,9 @@ imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
static void
imap_expunge (CamelFolder *folder, CamelException *ex)
{
+ if (!camel_imap_store_check_online (CAMEL_IMAP_STORE (folder->parent_store), ex))
+ return;
+
imap_sync (folder, TRUE, ex);
}
@@ -624,6 +626,9 @@ imap_append_message (CamelFolder *folder, CamelMimeMessage *message,
GByteArray *ba;
char *flagstr, *result;
+ if (!camel_imap_store_check_online (store, ex))
+ return;
+
/* create flag string param */
if (info && info->flags)
flagstr = imap_create_flag_list (info->flags);
@@ -683,6 +688,9 @@ imap_copy_message_to (CamelFolder *source, const char *uid,
CamelImapResponse *response;
CamelMessageInfo *mi;
+ if (!camel_imap_store_check_online (store, ex))
+ return;
+
mi = camel_folder_summary_uid (source->summary, uid);
g_return_if_fail (mi != NULL);
@@ -746,6 +754,9 @@ imap_search_by_expression (CamelFolder *folder, const char *expression, CamelExc
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
GPtrArray *matches, *summary;
+ if (!camel_imap_store_check_online (CAMEL_IMAP_STORE (folder->parent_store), ex))
+ return NULL;
+
/* we could get around this by creating a new search object each time,
but i doubt its worth it since any long operation would lock the
command channel too */
@@ -930,6 +941,12 @@ imap_get_message (CamelFolder *folder, const char *uid, CamelException *ex)
char *body, *found_uid;
int i;
+ if (!camel_imap_store_check_online (store, NULL)) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("This message is not currently available"));
+ return NULL;
+ }
+
CAMEL_IMAP_STORE_LOCK (store, command_lock);
response = camel_imap_command (store, folder, ex,
"UID FETCH %s BODY", uid);
@@ -1121,6 +1138,12 @@ camel_imap_folder_fetch_data (CamelImapFolder *imap_folder, const char *uid,
return stream;
}
+ if (!camel_imap_store_check_online (store, NULL)) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("This message is not currently available"));
+ return NULL;
+ }
+
CAMEL_IMAP_STORE_LOCK (store, command_lock);
if (store->server_level < IMAP_LEVEL_IMAP4REV1 && !*section_text) {
response = camel_imap_command (store, folder, ex,
diff --git a/camel/providers/imap/camel-imap-message-cache.c b/camel/providers/imap/camel-imap-message-cache.c
index 0ac90f7062..a45c039242 100644
--- a/camel/providers/imap/camel-imap-message-cache.c
+++ b/camel/providers/imap/camel-imap-message-cache.c
@@ -275,3 +275,16 @@ camel_imap_message_cache_remove (CamelImapMessageCache *cache, const char *uid)
g_ptr_array_free (subparts, TRUE);
}
+static gboolean
+clear_part (gpointer key, gpointer value, gpointer data)
+{
+ if (!strchr (key, '.'))
+ camel_imap_message_cache_remove (data, key);
+ return TRUE;
+}
+
+void
+camel_imap_message_cache_clear (CamelImapMessageCache *cache)
+{
+ g_hash_table_foreach_remove (cache->parts, clear_part, cache);
+}
diff --git a/camel/providers/imap/camel-imap-message-cache.h b/camel/providers/imap/camel-imap-message-cache.h
index 1ac48086ae..66e3adbaaa 100644
--- a/camel/providers/imap/camel-imap-message-cache.h
+++ b/camel/providers/imap/camel-imap-message-cache.h
@@ -74,6 +74,7 @@ CamelStream *camel_imap_message_cache_get (CamelImapMessageCache *cache,
void camel_imap_message_cache_remove (CamelImapMessageCache *cache,
const char *uid);
+void camel_imap_message_cache_clear (CamelImapMessageCache *cache);
/* Standard Camel function */
CamelType camel_imap_message_cache_get_type (void);
diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c
index 44ebea5ebe..21eb673945 100644
--- a/camel/providers/imap/camel-imap-store.c
+++ b/camel/providers/imap/camel-imap-store.c
@@ -58,6 +58,9 @@
static CamelRemoteStoreClass *remote_store_class = NULL;
+static void construct (CamelService *service, CamelSession *session,
+ CamelProvider *provider, CamelURL *url,
+ CamelException *ex);
static gboolean imap_connect (CamelService *service, CamelException *ex);
static gboolean imap_disconnect (CamelService *service, gboolean clean, CamelException *ex);
static GList *query_auth_types (CamelService *service, gboolean connect, CamelException *ex);
@@ -76,6 +79,12 @@ static void unsubscribe_folder (CamelStore *store, const char *folder_name,
CamelException *ex);
static void imap_keepalive (CamelRemoteStore *store);
+static gboolean imap_store_setup_online (CamelImapStore *store,
+ CamelException *ex);
+static gboolean imap_store_setup_offline (CamelImapStore *store,
+ CamelException *ex);
+
+
static void
camel_imap_store_class_init (CamelImapStoreClass *camel_imap_store_class)
{
@@ -91,6 +100,7 @@ camel_imap_store_class_init (CamelImapStoreClass *camel_imap_store_class)
(camel_remote_store_get_type ()));
/* virtual method overload */
+ camel_service_class->construct = construct;
camel_service_class->query_auth_types = query_auth_types;
camel_service_class->connect = imap_connect;
camel_service_class->disconnect = imap_disconnect;
@@ -182,6 +192,40 @@ camel_imap_store_get_type (void)
return camel_imap_store_type;
}
+static void
+construct (CamelService *service, CamelSession *session,
+ CamelProvider *provider, CamelURL *url,
+ CamelException *ex)
+{
+ CamelImapStore *store = CAMEL_IMAP_STORE (service);
+ int len;
+
+ CAMEL_SERVICE_CLASS (remote_store_class)->construct (service, session, provider, url, ex);
+ if (camel_exception_is_set (ex))
+ return;
+
+ if (!g_strcasecmp (service->url->protocol, "simap")) {
+ CamelRemoteStore *rstore = CAMEL_REMOTE_STORE (service);
+
+ rstore->default_port = 993;
+ rstore->use_ssl = TRUE;
+ }
+
+ store->storage_path = camel_session_get_storage_path (session, service, ex);
+ if (camel_exception_is_set (ex))
+ return;
+
+ store->base_url = camel_url_to_string (service->url, FALSE);
+ len = strlen (store->base_url);
+ if (service->url->path)
+ store->base_url[len - strlen (service->url->path) + 1] = '\0';
+ else {
+ store->base_url = g_realloc (store->base_url, len + 2);
+ store->base_url[len] = '/';
+ store->base_url[len + 1] = '\0';
+ }
+}
+
static struct {
const char *name;
guint32 flag;
@@ -223,13 +267,12 @@ connect_to_server (CamelService *service, CamelException *ex)
response = camel_imap_command (store, NULL, ex, "CAPABILITY");
if (!response)
return FALSE;
- result = camel_imap_response_extract (response, "CAPABILITY", ex);
+ result = camel_imap_response_extract (response, "CAPABILITY ", ex);
if (!result)
return FALSE;
- /* Skip over "* CAPABILITY". */
- capa = imap_next_word (result + 2);
-
+ /* Skip over "* CAPABILITY ". */
+ capa = result + 13;
for (capa = strtok_r (capa, " ", &lasts); capa;
capa = strtok_r (NULL, " ", &lasts)) {
if (!strncmp (capa, "AUTH=", 5)) {
@@ -390,26 +433,15 @@ try_auth (CamelImapStore *store, const char *mech, CamelException *ex)
}
static gboolean
-imap_connect (CamelService *service, CamelException *ex)
+imap_auth_loop (CamelService *service, CamelException *ex)
{
CamelImapStore *store = CAMEL_IMAP_STORE (service);
CamelSession *session = camel_service_get_session (service);
CamelServiceAuthType *authtype = NULL;
- char *result, *errbuf = NULL, *name;
- gboolean authenticated = FALSE;
CamelImapResponse *response;
- int len, i, flags;
-
- if (!g_strcasecmp (service->url->protocol, "simap")) {
- CamelRemoteStore *rstore = CAMEL_REMOTE_STORE (service);
-
- rstore->default_port = 993;
- rstore->use_ssl = TRUE;
- }
-
- if (connect_to_server (service, ex) == 0)
- return FALSE;
-
+ char *errbuf = NULL;
+ gboolean authenticated = FALSE;
+
if (service->url->authmech) {
if (!g_hash_table_lookup (store->authtypes, service->url->authmech)) {
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
@@ -417,7 +449,6 @@ imap_connect (CamelService *service, CamelException *ex)
"authentication type %s"),
service->url->host,
service->url->authmech);
- camel_service_disconnect (service, TRUE, NULL);
return FALSE;
}
@@ -426,16 +457,13 @@ imap_connect (CamelService *service, CamelException *ex)
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
_("No support for authentication type %s"),
service->url->authmech);
- camel_service_disconnect (service, TRUE, NULL);
return FALSE;
}
if (!authtype->need_password) {
authenticated = try_auth (store, authtype->authproto, ex);
- if (!authenticated) {
- camel_service_disconnect (service, TRUE, NULL);
+ if (!authenticated)
return FALSE;
- }
}
}
@@ -468,7 +496,6 @@ imap_connect (CamelService *service, CamelException *ex)
if (!service->url->passwd) {
camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
_("You didn't enter a password."));
- camel_service_disconnect (service, TRUE, NULL);
return FALSE;
}
}
@@ -484,12 +511,12 @@ imap_connect (CamelService *service, CamelException *ex)
if (authtype)
authenticated = try_auth (store, authtype->authproto, ex);
else {
- CAMEL_IMAP_STORE_LOCK(store, command_lock);
+ CAMEL_IMAP_STORE_LOCK (store, command_lock);
response = camel_imap_command (store, NULL, ex,
"LOGIN %S %S",
service->url->user,
service->url->passwd);
- CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
+ CAMEL_IMAP_STORE_UNLOCK (store, command_lock);
if (response) {
camel_imap_response_free (response);
authenticated = TRUE;
@@ -503,29 +530,55 @@ imap_connect (CamelService *service, CamelException *ex)
}
}
- /* Get subscribed folders */
- CAMEL_IMAP_STORE_LOCK (store, command_lock);
- response = camel_imap_command (store, NULL, ex, "LSUB \"\" \"*\"");
- CAMEL_IMAP_STORE_UNLOCK (store, command_lock);
- if (!response)
- return FALSE;
- store->subscribed_folders = g_hash_table_new (g_str_hash, g_str_equal);
- for (i = 0; i < response->untagged->len; i++) {
- result = response->untagged->pdata[i];
- if (!imap_parse_list_response (result, &flags, NULL, &name))
- continue;
- if (flags & (IMAP_LIST_FLAG_MARKED | IMAP_LIST_FLAG_UNMARKED))
- store->useful_lsub = TRUE;
- if (flags & IMAP_LIST_FLAG_NOSELECT) {
- g_free (name);
- continue;
+ return TRUE;
+}
+
+static gboolean
+imap_connect (CamelService *service, CamelException *ex)
+{
+ CamelImapStore *store = CAMEL_IMAP_STORE (service);
+
+ if (camel_imap_store_check_online (store, NULL)) {
+ if (!connect_to_server (service, ex))
+ return FALSE;
+ if (!imap_auth_loop (service, ex)) {
+ camel_service_disconnect (service, TRUE, NULL);
+ return FALSE;
}
- g_hash_table_insert (store->subscribed_folders, name,
- GINT_TO_POINTER (1));
- }
- camel_imap_response_free (response);
+ if (!imap_store_setup_online (store, ex)) {
+ camel_service_disconnect (service, TRUE, NULL);
+ return FALSE;
+ }
+ } else
+ imap_store_setup_offline (store, ex);
+
+ imap_store_refresh_folders (CAMEL_REMOTE_STORE (store), ex);
+ return !camel_exception_is_set (ex);
+}
+
+#define IMAP_STOREINFO_VERSION 1
+
+static gboolean
+imap_store_setup_online (CamelImapStore *store, CamelException *ex)
+{
+ CamelService *service;
+ CamelImapResponse *response;
+ int i, flags, len;
+ char *result, *name, *path;
+ FILE *storeinfo;
+
+ path = g_strdup_printf ("%s/storeinfo", store->storage_path);
+ storeinfo = fopen (path, "w");
+ if (!storeinfo)
+ g_warning ("Could not open storeinfo %s", path);
+ g_free (path);
+
+ /* Write header and capabilities */
+ camel_folder_summary_encode_uint32 (storeinfo, IMAP_STOREINFO_VERSION);
+ camel_folder_summary_encode_uint32 (storeinfo, store->capabilities);
/* Get namespace and hierarchy separator */
+ service = CAMEL_SERVICE (store);
if (service->url->path && strlen (service->url->path) > 1)
store->namespace = g_strdup (service->url->path + 1);
else if (store->capabilities & IMAP_CAPABILITY_NAMESPACE) {
@@ -559,7 +612,7 @@ imap_connect (CamelService *service, CamelException *ex)
store->namespace = g_strdup ("");
if (!store->dir_sep) {
- CAMEL_IMAP_STORE_LOCK(store, command_lock);
+ CAMEL_IMAP_STORE_LOCK (store, command_lock);
if (store->server_level >= IMAP_LEVEL_IMAP4REV1) {
/* This idiom means "tell me the hierarchy separator
* for the given path, even if that path doesn't exist.
@@ -590,30 +643,78 @@ imap_connect (CamelService *service, CamelException *ex)
store->dir_sep = '/'; /* Guess */
}
- /* Generate base URL */
- store->base_url = camel_url_to_string (service->url, FALSE);
- len = strlen (store->base_url);
- if (service->url->path)
- store->base_url[len - strlen (service->url->path) + 1] = '\0';
- else {
- store->base_url = g_realloc (store->base_url, len + 2);
- store->base_url[len] = '/';
- store->base_url[len + 1] = '\0';
+ /* Write namespace/separator out */
+ camel_folder_summary_encode_string (storeinfo, store->namespace);
+ camel_folder_summary_encode_uint32 (storeinfo, store->dir_sep);
+
+ /* Get subscribed folders */
+ CAMEL_IMAP_STORE_LOCK (store, command_lock);
+ response = camel_imap_command (store, NULL, ex, "LSUB \"\" \"*\"");
+ CAMEL_IMAP_STORE_UNLOCK (store, command_lock);
+ if (!response)
+ return FALSE;
+ store->subscribed_folders = g_hash_table_new (g_str_hash, g_str_equal);
+ for (i = 0; i < response->untagged->len; i++) {
+ result = response->untagged->pdata[i];
+ if (!imap_parse_list_response (result, &flags, NULL, &name))
+ continue;
+ if (flags & (IMAP_LIST_FLAG_MARKED | IMAP_LIST_FLAG_UNMARKED))
+ store->useful_lsub = TRUE;
+ if (flags & IMAP_LIST_FLAG_NOSELECT) {
+ g_free (name);
+ continue;
+ }
+ g_hash_table_insert (store->subscribed_folders, name,
+ GINT_TO_POINTER (1));
+ camel_folder_summary_encode_string (storeinfo, result);
}
+ camel_imap_response_free (response);
+ fclose (storeinfo);
- /* Find our storage path. */
- if (!store->storage_path) {
- store->storage_path =
- camel_session_get_storage_path (session, service, ex);
- if (camel_exception_is_set (ex))
- return FALSE;
+ return TRUE;
+}
+
+static gboolean
+imap_store_setup_offline (CamelImapStore *store, CamelException *ex)
+{
+ char *buf, *name, *path;
+ FILE *storeinfo;
+ guint32 tmp;
+
+ path = g_strdup_printf ("%s/storeinfo", store->storage_path);
+ storeinfo = fopen (path, "r");
+ g_free (path);
+ tmp = 0;
+ if (storeinfo)
+ camel_folder_summary_decode_uint32 (storeinfo, &tmp);
+ if (tmp != IMAP_STOREINFO_VERSION) {
+ /* This must set ex and return FALSE if we're here... */
+ return camel_imap_store_check_online (store, ex);
}
- imap_store_refresh_folders (CAMEL_REMOTE_STORE (store), ex);
+ camel_folder_summary_decode_uint32 (storeinfo, &store->capabilities);
+ camel_folder_summary_decode_string (storeinfo, &store->namespace);
+ camel_folder_summary_decode_uint32 (storeinfo, &tmp);
+ store->dir_sep = tmp;
- return !camel_exception_is_set (ex);
+ /* Get subscribed folders */
+ store->subscribed_folders = g_hash_table_new (g_str_hash, g_str_equal);
+ while (camel_folder_summary_decode_string (storeinfo, &buf) == 0) {
+ if (!imap_parse_list_response (buf, NULL, NULL, &name)) {
+ g_free (buf);
+ continue;
+ }
+ g_hash_table_insert (store->subscribed_folders, name,
+ GINT_TO_POINTER (1));
+ g_free (buf);
+ }
+
+ fclose (storeinfo);
+ return TRUE;
}
+
+
static gboolean
imap_disconnect (CamelService *service, gboolean clean, CamelException *ex)
{
@@ -733,22 +834,30 @@ get_folder (CamelStore *store, const char *folder_name, guint32 flags,
char *short_name, *folder_dir;
gboolean selectable;
- if (!camel_remote_store_connected (CAMEL_REMOTE_STORE (store), ex))
- return NULL;
+ if (camel_imap_store_check_online (imap_store, NULL)) {
+ if (!camel_remote_store_connected (CAMEL_REMOTE_STORE (store), ex))
+ return NULL;
- /* lock around the whole lot to check/create atomically */
- CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
- if (!imap_folder_exists (imap_store, folder_name,
- &selectable, &short_name, ex)) {
- if ((flags & CAMEL_STORE_FOLDER_CREATE) == 0
- || (!imap_create (imap_store, folder_name, ex))
- || (!imap_folder_exists (imap_store, folder_name,
- &selectable, &short_name, ex))) {
+ /* lock around the whole lot to check/create atomically */
+ CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
+ if (!imap_folder_exists (imap_store, folder_name,
+ &selectable, &short_name, ex) &&
+ ((flags & CAMEL_STORE_FOLDER_CREATE) == 0
+ || (!imap_create (imap_store, folder_name, ex))
+ || (!imap_folder_exists (imap_store, folder_name,
+ &selectable, &short_name, ex)))) {
CAMEL_IMAP_STORE_UNLOCK(imap_store, command_lock);
return NULL;
}
+ CAMEL_IMAP_STORE_UNLOCK(imap_store, command_lock);
+ } else {
+ selectable = g_hash_table_lookup (imap_store->subscribed_folders, folder_name) != NULL;
+ short_name = strrchr (folder_name, imap_store->dir_sep);
+ if (short_name)
+ short_name = g_strdup (short_name + 1);
+ else
+ short_name = g_strdup (folder_name);
}
- CAMEL_IMAP_STORE_UNLOCK(imap_store, command_lock);
if (!selectable) {
camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
@@ -798,6 +907,8 @@ create_folder (CamelStore *store, const char *parent_name,
CamelFolderInfo *fi;
char *full_name;
+ if (!camel_imap_store_check_online (imap_store, ex))
+ return NULL;
if (!parent_name)
parent_name = imap_store->namespace;
full_name = imap_concat (imap_store, parent_name, folder_name);
@@ -902,14 +1013,17 @@ get_subscribed_folders_by_hand (CamelImapStore *imap_store, const char *top,
}
static void
-get_folders (CamelImapStore *imap_store, const char *pattern,
- GPtrArray *folders, gboolean lsub, CamelException *ex)
+get_folders_online (CamelImapStore *imap_store, const char *pattern,
+ GPtrArray *folders, gboolean lsub, CamelException *ex)
{
CamelImapResponse *response;
CamelFolderInfo *fi;
char *list;
int i;
+ if (!camel_remote_store_connected (CAMEL_REMOTE_STORE (imap_store), ex))
+ return;
+
CAMEL_IMAP_STORE_LOCK (imap_store, command_lock);
response = camel_imap_command (imap_store, NULL, ex,
"%s \"\" %S", lsub ? "LSUB" : "LIST",
@@ -921,35 +1035,91 @@ get_folders (CamelImapStore *imap_store, const char *pattern,
for (i = 0; i < response->untagged->len; i++) {
list = response->untagged->pdata[i];
fi = parse_list_response_as_folder_info (imap_store, list);
- if (!fi)
- continue;
- g_ptr_array_add (folders, fi);
+ if (fi)
+ g_ptr_array_add (folders, fi);
}
camel_imap_response_free (response);
}
+static void
+get_unread_online (CamelImapStore *imap_store, CamelFolderInfo *fi)
+{
+ CamelImapResponse *response;
+ char *status, *p;
+
+ CAMEL_IMAP_STORE_LOCK (imap_store, command_lock);
+ response = camel_imap_command (imap_store, NULL, NULL,
+ "STATUS %S (UNSEEN)", fi->full_name);
+ CAMEL_IMAP_STORE_UNLOCK (imap_store, command_lock);
+ if (!response)
+ return;
+ status = camel_imap_response_extract (response, "STATUS", NULL);
+ if (!status)
+ return;
+
+ p = e_strstrcase (status, "UNSEEN");
+ if (p)
+ fi->unread_message_count = strtoul (p + 6, NULL, 10);
+ g_free (status);
+}
+
+static void
+add_folder (gpointer key, gpointer value, gpointer data)
+{
+ g_ptr_array_add (data, key);
+}
+
+static void
+get_folders_offline (CamelImapStore *imap_store, GPtrArray *folders,
+ CamelException *ex)
+{
+ CamelFolderInfo *fi;
+ int i;
+
+ i = folders->len;
+ g_hash_table_foreach (imap_store->subscribed_folders,
+ add_folder, folders);
+ while (i < folders->len) {
+ fi = g_new0 (CamelFolderInfo, 1);
+ fi->full_name = g_strdup (folders->pdata[i]);
+ fi->name = strchr (fi->full_name, imap_store->dir_sep);
+ if (fi->name)
+ fi->name = g_strdup (fi->name + 1);
+ else
+ fi->name = g_strdup (fi->full_name);
+ fi->url = g_strdup_printf ("%s%s", imap_store->base_url,
+ fi->full_name);
+ fi->unread_message_count = -1;
+ folders->pdata[i++] = fi;
+ }
+}
+
+static void
+get_unread_offline (CamelImapStore *imap_store, CamelFolderInfo *fi)
+{
+ /* FIXME */
+}
+
static CamelFolderInfo *
get_folder_info (CamelStore *store, const char *top, gboolean fast,
gboolean recursive, gboolean subscribed_only,
CamelException *ex)
{
CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
- gboolean need_inbox = FALSE;
- CamelImapResponse *response;
+ gboolean need_inbox = FALSE, online;
GPtrArray *folders;
- const char *name, *p;
- char *pattern, *status;
+ const char *name;
+ char *pattern;
CamelFolderInfo *fi;
int i;
- if (!camel_remote_store_connected (CAMEL_REMOTE_STORE (store), ex))
- return NULL;
+ if (!subscribed_only || !recursive || top) {
+ if (!camel_imap_store_check_online (imap_store, ex))
+ return NULL;
+ } else
+ online = camel_imap_store_check_online (imap_store, NULL);
- /* Sync flag changes to the server so it has the same ideas about
- * read/unread as we do.
- */
- camel_store_sync (store, ex);
- if (camel_exception_is_set (ex))
+ if (!camel_remote_store_connected (CAMEL_REMOTE_STORE (store), ex))
return NULL;
name = top;
@@ -960,22 +1130,30 @@ get_folder_info (CamelStore *store, const char *top, gboolean fast,
folders = g_ptr_array_new ();
- get_folders (imap_store, name, folders, FALSE, ex);
- if (camel_exception_is_set (ex))
- return NULL;
- if (folders->len) {
- fi = folders->pdata[0];
- if (!fi->url)
- g_ptr_array_remove_index (folders, 0);
- }
+ if (online) {
+ /* Get top-level */
+ get_folders_online (imap_store, name, folders, FALSE, ex);
+ if (camel_exception_is_set (ex))
+ return NULL;
+ if (folders->len) {
+ fi = folders->pdata[0];
+ if (!fi->url)
+ g_ptr_array_remove_index (folders, 0);
+ }
+
+ if (subscribed_only && !imap_store->useful_lsub)
+ get_subscribed_folders_by_hand (imap_store, name,
+ folders, ex);
+ else {
+ pattern = imap_concat (imap_store, name,
+ recursive ? "*" : "%");
+ get_folders_online (imap_store, pattern, folders,
+ subscribed_only, ex);
+ g_free (pattern);
+ }
+ } else
+ get_folders_offline (imap_store, folders, ex);
- if (subscribed_only && !imap_store->useful_lsub)
- get_subscribed_folders_by_hand (imap_store, name, folders, ex);
- else {
- pattern = imap_concat (imap_store, name, recursive ? "*" : "%");
- get_folders (imap_store, pattern, folders, subscribed_only, ex);
- g_free (pattern);
- }
if (camel_exception_is_set (ex)) {
for (i = 0; i < folders->len; i++)
camel_folder_info_free (folders->pdata[i]);
@@ -1004,7 +1182,11 @@ get_folder_info (CamelStore *store, const char *top, gboolean fast,
}
if (!fast) {
- /* Get unread counts */
+ /* Get unread counts. Sync flag changes to the server
+ * first so it has the same ideas about read/unread as
+ * we do.
+ */
+ camel_store_sync (store, NULL);
for (i = 0; i < folders->len; i++) {
fi = folders->pdata[i];
if (!fi->url || fi->unread_message_count != -1)
@@ -1021,21 +1203,10 @@ get_folder_info (CamelStore *store, const char *top, gboolean fast,
continue;
}
- CAMEL_IMAP_STORE_LOCK (imap_store, command_lock);
- response = camel_imap_command (imap_store, NULL, NULL,
- "STATUS %S (UNSEEN)",
- fi->full_name);
- CAMEL_IMAP_STORE_UNLOCK (imap_store, command_lock);
- if (!response)
- continue;
- status = camel_imap_response_extract (response, "STATUS", NULL);
- if (!status)
- continue;
-
- p = e_strstrcase (status, "UNSEEN");
- if (p)
- fi->unread_message_count = strtoul (p + 6, NULL, 10);
- g_free (status);
+ if (online)
+ get_unread_online (imap_store, fi);
+ else
+ get_unread_offline (imap_store, fi);
}
}
@@ -1063,6 +1234,8 @@ subscribe_folder (CamelStore *store, const char *folder_name,
CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
CamelImapResponse *response;
+ if (!camel_imap_store_check_online (imap_store, ex))
+ return;
if (!camel_remote_store_connected (CAMEL_REMOTE_STORE (store), ex))
return;
@@ -1104,6 +1277,8 @@ unsubscribe_folder (CamelStore *store, const char *folder_name,
CamelImapResponse *response;
gpointer key, value;
+ if (!camel_imap_store_check_online (imap_store, ex))
+ return;
if (!camel_remote_store_connected (CAMEL_REMOTE_STORE (store), ex))
return;
@@ -1150,3 +1325,17 @@ imap_keepalive (CamelRemoteStore *store)
CAMEL_IMAP_STORE_UNLOCK(imap_store, command_lock);
camel_imap_response_free (response);
}
+
+gboolean
+camel_imap_store_check_online (CamelImapStore *store, CamelException *ex)
+{
+ /* Hack */
+ if (getenv ("CAMEL_OFFLINE")) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("You must be working online to "
+ "complete this operation"));
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/camel/providers/imap/camel-imap-store.h b/camel/providers/imap/camel-imap-store.h
index 3792e92872..8cc186655c 100644
--- a/camel/providers/imap/camel-imap-store.h
+++ b/camel/providers/imap/camel-imap-store.h
@@ -83,6 +83,8 @@ typedef struct {
/* Standard Camel function */
CamelType camel_imap_store_get_type (void);
+gboolean camel_imap_store_check_online (CamelImapStore *store, CamelException *ex);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/camel/providers/imap/camel-imap-summary.c b/camel/providers/imap/camel-imap-summary.c
index 66228649bc..34597cfe31 100644
--- a/camel/providers/imap/camel-imap-summary.c
+++ b/camel/providers/imap/camel-imap-summary.c
@@ -99,16 +99,14 @@ camel_imap_summary_init (CamelImapSummary *obj)
/**
* camel_imap_summary_new:
* @filename: the file to store the summary in.
- * @validity: the current UIDVALIDITY value of the folder
*
* This will create a new CamelImapSummary object and read in the
- * summary data from disk, if it exists and has the right UIDVALIDITY
- * value.
+ * summary data from disk, if it exists.
*
* Return value: A new CamelImapSummary object.
**/
CamelFolderSummary *
-camel_imap_summary_new (const char *filename, guint32 validity)
+camel_imap_summary_new (const char *filename)
{
CamelFolderSummary *summary = CAMEL_FOLDER_SUMMARY (
camel_object_new (camel_imap_summary_get_type ()));
@@ -118,21 +116,8 @@ camel_imap_summary_new (const char *filename, guint32 validity)
camel_folder_summary_set_filename (summary, filename);
if (camel_folder_summary_load (summary) == -1) {
- if (errno == ENOENT) {
- imap_summary->validity = validity;
- return summary;
- } else {
- /* FIXME: are there error conditions where this won't work? */
- camel_folder_summary_clear (summary);
- camel_folder_summary_touch (summary);
-
- return summary;
- }
- }
-
- if (imap_summary->validity != validity) {
camel_folder_summary_clear (summary);
- imap_summary->validity = validity;
+ camel_folder_summary_touch (summary);
}
return summary;
diff --git a/camel/providers/imap/camel-imap-summary.h b/camel/providers/imap/camel-imap-summary.h
index 7ad1e3f4e8..e3e51c5b7d 100644
--- a/camel/providers/imap/camel-imap-summary.h
+++ b/camel/providers/imap/camel-imap-summary.h
@@ -63,8 +63,7 @@ struct _CamelImapSummaryClass {
};
guint camel_imap_summary_get_type (void);
-CamelFolderSummary *camel_imap_summary_new (const char *filename,
- guint32 validity);
+CamelFolderSummary *camel_imap_summary_new (const char *filename);
#endif /* ! _CAMEL_IMAP_SUMMARY_H */