From 630241d74b1a6dede97380c8ed70c74641399e0f Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Wed, 9 May 2001 21:57:32 +0000 Subject: Set the disconnected status. (camel_disco_store_can_work_offline): Return * camel-disco-store.c (camel_disco_set_status): Set the disconnected status. (camel_disco_store_can_work_offline): Return whether or not a given CamelDiscoStore can work offline or not. * camel-disco-folder.c (camel_disco_folder_cache_message): Explicitly tell a folder to cache a message. (Better than using get_message, because for IMAP that doesn't guarantee you'll get all the message parts.) (camel_disco_folder_prepare_for_offline): Prepare a folder for offline use by caching all messages meeting given search criteria (and doing anything else the particular folder implementation needs). * camel-session.c (camel_session_set_online, camel_session_is_online): A session-wide online/offline toggle. (camel_session_init): Set online to TRUE. * providers/imap/camel-imap-store.c (can_work_offline): Implementation of CamelDiscoStore::can_work_offline. (Checks that the store has been used online at least once.) (imap_get_folder_online, imap_get_folder_offline): Deal with request for "inbox" properly. ("Don't you mean... 'INBOX'?"). * providers/imap/camel-imap-folder.c (imap_cache_message): Implementation of CamelDiscoFolder::cache_message. * camel.h: Add camel-disco-store.h and camel-disco-folder.h svn path=/trunk/; revision=9738 --- camel/ChangeLog | 31 +++++++++ camel/camel-disco-folder.c | 109 ++++++++++++++++++++++++++++--- camel/camel-disco-folder.h | 12 ++++ camel/camel-disco-store.c | 83 +++++++++++++++++++++++ camel/camel-disco-store.h | 11 +++- camel/camel-session.c | 27 ++++++++ camel/camel-session.h | 6 ++ camel/camel.h | 2 + camel/providers/imap/camel-imap-folder.c | 14 ++++ camel/providers/imap/camel-imap-store.c | 23 ++++++- 10 files changed, 308 insertions(+), 10 deletions(-) diff --git a/camel/ChangeLog b/camel/ChangeLog index 374811a26b..259f226100 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,3 +1,34 @@ +2001-05-09 Dan Winship + + * camel-disco-store.c (camel_disco_set_status): Set the + disconnected status. + (camel_disco_store_can_work_offline): Return whether or not a + given CamelDiscoStore can work offline or not. + + * camel-disco-folder.c (camel_disco_folder_cache_message): + Explicitly tell a folder to cache a message. (Better than using + get_message, because for IMAP that doesn't guarantee you'll get + all the message parts.) + (camel_disco_folder_prepare_for_offline): Prepare a folder for + offline use by caching all messages meeting given search criteria + (and doing anything else the particular folder implementation + needs). + + * camel-session.c (camel_session_set_online, + camel_session_is_online): A session-wide online/offline toggle. + (camel_session_init): Set online to TRUE. + + * providers/imap/camel-imap-store.c (can_work_offline): + Implementation of CamelDiscoStore::can_work_offline. (Checks that + the store has been used online at least once.) + (imap_get_folder_online, imap_get_folder_offline): Deal with + request for "inbox" properly. ("Don't you mean... 'INBOX'?"). + + * providers/imap/camel-imap-folder.c (imap_cache_message): + Implementation of CamelDiscoFolder::cache_message. + + * camel.h: Add camel-disco-store.h and camel-disco-folder.h + 2001-05-09 Jeffrey Stedfast * camel-mime-part.c (camel_mime_part_set_content_id): Wrap the diff --git a/camel/camel-disco-folder.c b/camel/camel-disco-folder.c index 91a12adece..b090bd6517 100644 --- a/camel/camel-disco-folder.c +++ b/camel/camel-disco-folder.c @@ -46,6 +46,11 @@ static void disco_copy_messages_to (CamelFolder *source, GPtrArray *uids, static void disco_move_messages_to (CamelFolder *source, GPtrArray *uids, CamelFolder *destination, CamelException *ex); +static void disco_cache_message (CamelDiscoFolder *disco_folder, + const char *uid, CamelException *ex); +static void disco_prepare_for_offline (CamelDiscoFolder *disco_folder, + const char *expression, + CamelException *ex); static void camel_disco_folder_class_init (CamelDiscoFolderClass *camel_disco_folder_class) @@ -54,6 +59,10 @@ camel_disco_folder_class_init (CamelDiscoFolderClass *camel_disco_folder_class) parent_class = CAMEL_FOLDER_CLASS (camel_type_get_global_classfuncs (camel_folder_get_type ())); + /* virtual method definition */ + camel_disco_folder_class->cache_message = disco_cache_message; + camel_disco_folder_class->prepare_for_offline = disco_prepare_for_offline; + /* virtual method overload */ camel_folder_class->refresh_info = disco_refresh_info; camel_folder_class->sync = disco_sync; @@ -126,8 +135,11 @@ disco_expunge_uids (CamelFolder *folder, GPtrArray *uids, CamelException *ex) case CAMEL_DISCO_STORE_OFFLINE: CDF_CLASS (folder)->expunge_uids_offline (folder, uids, ex); #ifdef NOTYET - if (!camel_exception_is_set (ex)) - camel_disco_diary_log (disco->diary, CAMEL_DISCO_DIARY_FOLDER_EXPUNGE, folder, uids); + if (!camel_exception_is_set (ex)) { + camel_disco_diary_log (disco->diary, + CAMEL_DISCO_DIARY_FOLDER_EXPUNGE, + folder, uids); + } #endif break; } @@ -171,8 +183,11 @@ disco_append_message (CamelFolder *folder, CamelMimeMessage *message, case CAMEL_DISCO_STORE_OFFLINE: uid = CDF_CLASS (folder)->append_offline (folder, message, info, ex); #ifdef NOTYET - if (uid) - camel_disco_diary_log (disco->diary, CAMEL_DISCO_DIARY_FOLDER_APPEND, folder, uid); + if (uid) { + camel_disco_diary_log (disco->diary, + CAMEL_DISCO_DIARY_FOLDER_APPEND, + folder, uid); + } #endif break; } @@ -193,8 +208,11 @@ disco_copy_messages_to (CamelFolder *source, GPtrArray *uids, case CAMEL_DISCO_STORE_OFFLINE: CDF_CLASS (source)->copy_offline (source, uids, destination, ex); #ifdef NOTYET - if (!camel_exception_is_set (ex)) - camel_disco_diary_log (disco->diary, CAMEL_DISCO_DIARY_FOLDER_COPY, source, destination, uids); + if (!camel_exception_is_set (ex)) { + camel_disco_diary_log (disco->diary, + CAMEL_DISCO_DIARY_FOLDER_COPY, + source, destination, uids); + } #endif break; } @@ -214,8 +232,11 @@ disco_move_messages_to (CamelFolder *source, GPtrArray *uids, case CAMEL_DISCO_STORE_OFFLINE: CDF_CLASS (source)->move_offline (source, uids, destination, ex); #ifdef NOTYET - if (!camel_exception_is_set (ex)) - camel_disco_diary_log (disco->diary, CAMEL_DISCO_DIARY_FOLDER_MOVE, source, destination, uids); + if (!camel_exception_is_set (ex)) { + camel_disco_diary_log (disco->diary, + CAMEL_DISCO_DIARY_FOLDER_MOVE, + source, destination, uids); + } #endif break; } @@ -240,3 +261,75 @@ camel_disco_folder_expunge_uids (CamelFolder *folder, GPtrArray *uids, { disco_expunge_uids (folder, uids, ex); } + + +static void +disco_cache_message (CamelDiscoFolder *disco_folder, const char *uid, + CamelException *ex) +{ + g_warning ("CamelDiscoFolder::cache_message not implemented for `%s'", + camel_type_to_name (CAMEL_OBJECT_GET_TYPE (disco_folder))); +} + +/** + * camel_disco_folder_cache_message: + * @disco_folder: the folder + * @uid: the UID of the message to cache + * @ex: a CamelException + * + * Requests that @disco_folder cache message @uid to disk. + **/ +void +camel_disco_folder_cache_message (CamelDiscoFolder *disco_folder, + const char *uid, CamelException *ex) +{ + CDF_CLASS (disco_folder)->cache_message (disco_folder, uid, ex); +} + + +static void +disco_prepare_for_offline (CamelDiscoFolder *disco_folder, + const char *expression, + CamelException *ex) +{ + CamelFolder *folder = CAMEL_FOLDER (disco_folder); + GPtrArray *uids; + int i; + + if (expression) + uids = camel_folder_search_by_expression (folder, expression, ex); + else + uids = camel_folder_get_uids (folder); + if (!uids) + return; + for (i = 0; i < uids->len; i++) { + camel_disco_folder_cache_message (disco_folder, uids->pdata[i], ex); + if (camel_exception_is_set (ex)) + break; + } + if (expression) + camel_folder_search_free (folder, uids); + else + camel_folder_free_uids (folder, uids); +} + +/** + * camel_disco_folder_prepare_for_offline: + * @disco_folder: the folder + * @expression: an expression describing messages to synchronize, or %NULL + * if all messages should be sync'ed. + * @ex: a CamelException + * + * This prepares @disco_folder for offline operation, by downloading + * the bodies of all messages described by @expression (using the + * same syntax as camel_folder_search_by_expression() ). + **/ +void +camel_disco_folder_prepare_for_offline (CamelDiscoFolder *disco_folder, + const char *expression, + CamelException *ex) +{ + g_return_if_fail (CAMEL_IS_DISCO_FOLDER (disco_folder)); + + CDF_CLASS (disco_folder)->prepare_for_offline (disco_folder, expression, ex); +} diff --git a/camel/camel-disco-folder.h b/camel/camel-disco-folder.h index 23e9d24923..cdca5a3b52 100644 --- a/camel/camel-disco-folder.h +++ b/camel/camel-disco-folder.h @@ -74,6 +74,12 @@ typedef struct { void (*move_offline) (CamelFolder *source, GPtrArray *uids, CamelFolder *destination, CamelException *ex); + void (*cache_message) (CamelDiscoFolder *disco_folder, + const char *uid, CamelException *ex); + void (*prepare_for_offline) (CamelDiscoFolder *disco_folder, + const char *expression, + CamelException *ex); + void (*update_uid) (CamelFolder *folder, const char *old_uid, const char *new_uid); } CamelDiscoFolderClass; @@ -83,6 +89,12 @@ typedef struct { void camel_disco_folder_expunge_uids (CamelFolder *folder, GPtrArray *uids, CamelException *ex); +void camel_disco_folder_cache_message (CamelDiscoFolder *disco_folder, + const char *uid, + CamelException *ex); +void camel_disco_folder_prepare_for_offline (CamelDiscoFolder *disco_folder, + const char *expression, + CamelException *ex); /* Standard Camel function */ CamelType camel_disco_folder_get_type (void); diff --git a/camel/camel-disco-store.c b/camel/camel-disco-store.c index 10d3ae78b3..ae51b54f0f 100644 --- a/camel/camel-disco-store.c +++ b/camel/camel-disco-store.c @@ -40,6 +40,10 @@ static CamelFolder *disco_get_folder (CamelStore *store, const char *name, static CamelFolderInfo *disco_get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex); +static void set_status (CamelDiscoStore *disco_store, + CamelDiscoStoreStatus status, + CamelException *ex); +static gboolean can_work_offline (CamelDiscoStore *disco_store); static void camel_disco_store_class_init (CamelDiscoStoreClass *camel_disco_store_class) @@ -51,6 +55,10 @@ camel_disco_store_class_init (CamelDiscoStoreClass *camel_disco_store_class) remote_store_class = CAMEL_REMOTE_STORE_CLASS (camel_type_get_global_classfuncs (camel_remote_store_get_type ())); + /* virtual method definition */ + camel_disco_store_class->set_status = set_status; + camel_disco_store_class->can_work_offline = can_work_offline; + /* virtual method overload */ camel_service_class->connect = disco_connect; camel_service_class->disconnect = disco_disconnect; @@ -172,6 +180,12 @@ disco_get_folder_info (CamelStore *store, const char *top, } +/** + * camel_disco_store_status: + * @store: a disconnectable store + * + * Return value: the current online/offline status of @store. + **/ CamelDiscoStoreStatus camel_disco_store_status (CamelDiscoStore *store) { @@ -180,6 +194,75 @@ camel_disco_store_status (CamelDiscoStore *store) return store->status; } + +static void +set_status (CamelDiscoStore *disco_store, CamelDiscoStoreStatus status, + CamelException *ex) +{ + if (disco_store->status == status) + return; + + camel_store_sync (CAMEL_STORE (disco_store), ex); + if (camel_exception_is_set (ex)) + return; + if (!camel_service_disconnect (CAMEL_SERVICE (disco_store), TRUE, ex)) + return; + + disco_store->status = status; + camel_service_connect (CAMEL_SERVICE (disco_store), ex); +} + +/** + * camel_disco_store_set_status: + * @store: a disconnectable store + * @status: the new status + * @ex: a CamelException + * + * Sets @store to @status. If an error occurrs and the status cannot + * be set to @status, @ex will be set. + **/ +void +camel_disco_store_set_status (CamelDiscoStore *store, + CamelDiscoStoreStatus status, + CamelException *ex) +{ + CDS_CLASS (store)->set_status (store, status, ex); +} + + +static gboolean +can_work_offline (CamelDiscoStore *disco_store) +{ + g_warning ("CamelDiscoStore::can_work_offline not implemented for `%s'", + camel_type_to_name (CAMEL_OBJECT_GET_TYPE (disco_store))); + return FALSE; +} + +/** + * camel_disco_store_can_work_offline: + * @store: a disconnectable store + * + * Return value: whether or not @store can be used offline. (Will be + * %FALSE if the store is not caching data to local disk, for example.) + **/ +gboolean +camel_disco_store_can_work_offline (CamelDiscoStore *store) +{ + return CDS_CLASS (store)->can_work_offline (store); +} + + +/** + * camel_disco_store_check_online: + * @store: a disconnectable store + * @ex: a CamelException + * + * This checks that @store is online, and sets @ex if it is not. This + * can be used as a simple way to set a generic error message in @ex + * for operations that won't work offline. + * + * Return value: whether or not @store is online. + **/ gboolean camel_disco_store_check_online (CamelDiscoStore *store, CamelException *ex) { diff --git a/camel/camel-disco-store.h b/camel/camel-disco-store.h index abd2693f80..cb40cf4590 100644 --- a/camel/camel-disco-store.h +++ b/camel/camel-disco-store.h @@ -57,6 +57,11 @@ struct _CamelDiscoStore { typedef struct { CamelRemoteStoreClass parent_class; + void (*set_status) (CamelDiscoStore *, + CamelDiscoStoreStatus, + CamelException *); + gboolean (*can_work_offline) (CamelDiscoStore *); + gboolean (*connect_online) (CamelService *, CamelException *); gboolean (*connect_offline) (CamelService *, @@ -92,7 +97,11 @@ typedef struct { CamelType camel_disco_store_get_type (void); /* Public methods */ -CamelDiscoStoreStatus camel_disco_store_status (CamelDiscoStore *store); +CamelDiscoStoreStatus camel_disco_store_status (CamelDiscoStore *); +void camel_disco_store_set_status (CamelDiscoStore *, + CamelDiscoStoreStatus, + CamelException *); +gboolean camel_disco_store_can_work_offline (CamelDiscoStore *); /* Convenience functions */ gboolean camel_disco_store_check_online (CamelDiscoStore *store, CamelException *ex); diff --git a/camel/camel-session.c b/camel/camel-session.c index a6e308693f..5dbd19d963 100644 --- a/camel/camel-session.c +++ b/camel/camel-session.c @@ -81,6 +81,7 @@ static CamelProvider vee_provider = { static void camel_session_init (CamelSession *session) { + session->online = TRUE; session->modules = camel_provider_init (); session->providers = g_hash_table_new (g_strcase_hash, g_strcase_equal); session->priv = g_malloc0(sizeof(*session->priv)); @@ -640,3 +641,29 @@ camel_session_remove_timeout (CamelSession *session, guint handle) return CS_CLASS (session)->remove_timeout (session, handle); } + + +/** + * camel_session_is_online: + * @session: the session. + * + * Return value: whether or not @session is online. + **/ +gboolean +camel_session_is_online (CamelSession *session) +{ + return session->online; +} + +/** + * camel_session_set_online: + * @session: the session + * @online: whether or not the session should be online + * + * Sets the online status of @session to @online. + **/ +void +camel_session_set_online (CamelSession *session, gboolean online) +{ + session->online = online; +} diff --git a/camel/camel-session.h b/camel/camel-session.h index e777bdcb6c..ba4a06490c 100644 --- a/camel/camel-session.h +++ b/camel/camel-session.h @@ -57,6 +57,7 @@ struct _CamelSession char *storage_path; GHashTable *providers, *modules; + gboolean online; }; typedef struct { @@ -162,6 +163,11 @@ guint camel_session_register_timeout (CamelSession *session, gboolean camel_session_remove_timeout (CamelSession *session, guint handle); + +gboolean camel_session_is_online (CamelSession *session); +void camel_session_set_online (CamelSession *session, + gboolean online); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/camel/camel.h b/camel/camel.h index e775f67812..e8708a70c9 100644 --- a/camel/camel.h +++ b/camel/camel.h @@ -37,6 +37,8 @@ extern "C" { #include #include #include +#include +#include #include #include #include diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c index d0828ccac9..852280127a 100644 --- a/camel/providers/imap/camel-imap-folder.c +++ b/camel/providers/imap/camel-imap-folder.c @@ -73,6 +73,7 @@ static void imap_sync_offline (CamelFolder *folder, CamelException *ex); static const char *imap_get_full_name (CamelFolder *folder); static void imap_expunge_uids_online (CamelFolder *folder, GPtrArray *uids, CamelException *ex); static void imap_expunge_uids_offline (CamelFolder *folder, GPtrArray *uids, CamelException *ex); +static void imap_cache_message (CamelDiscoFolder *disco_folder, const char *uid, CamelException *ex); /* message manipulation */ static CamelMimeMessage *imap_get_message (CamelFolder *folder, const gchar *uid, @@ -118,6 +119,7 @@ camel_imap_folder_class_init (CamelImapFolderClass *camel_imap_folder_class) camel_disco_folder_class->append_offline = imap_append_offline; camel_disco_folder_class->copy_online = imap_copy_online; camel_disco_folder_class->copy_offline = imap_copy_offline; + camel_disco_folder_class->cache_message = imap_cache_message; } static void @@ -1080,6 +1082,18 @@ imap_get_message (CamelFolder *folder, const char *uid, CamelException *ex) return msg; } +static void +imap_cache_message (CamelDiscoFolder *disco_folder, const char *uid, + CamelException *ex) +{ + CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (disco_folder); + CamelStream *stream; + + stream = camel_imap_folder_fetch_data (imap_folder, uid, "", FALSE, ex); + if (stream) + camel_object_unref (CAMEL_OBJECT (stream)); +} + static void imap_update_summary (CamelFolder *folder, CamelFolderChangeInfo *changes, diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c index 74f420fe41..bcdfc9f935 100644 --- a/camel/providers/imap/camel-imap-store.c +++ b/camel/providers/imap/camel-imap-store.c @@ -63,6 +63,7 @@ static char imap_tag_prefix = 'A'; static void construct (CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, CamelException *ex); +static gboolean can_work_offline (CamelDiscoStore *disco_store); static gboolean imap_connect_online (CamelService *service, CamelException *ex); static gboolean imap_connect_offline (CamelService *service, CamelException *ex); static gboolean imap_disconnect_online (CamelService *service, gboolean clean, CamelException *ex); @@ -117,6 +118,7 @@ camel_imap_store_class_init (CamelImapStoreClass *camel_imap_store_class) camel_remote_store_class->keepalive = imap_keepalive; + camel_disco_store_class->can_work_offline = can_work_offline; camel_disco_store_class->connect_online = imap_connect_online; camel_disco_store_class->connect_offline = imap_connect_offline; camel_disco_store_class->disconnect_online = imap_disconnect_online; @@ -538,6 +540,19 @@ imap_auth_loop (CamelService *service, CamelException *ex) #define IMAP_STOREINFO_VERSION 1 +static gboolean +can_work_offline (CamelDiscoStore *disco_store) +{ + CamelImapStore *store = CAMEL_IMAP_STORE (disco_store); + char *path; + gboolean can; + + path = g_strdup_printf ("%s/storeinfo", store->storage_path); + can = access (path, F_OK) == 0; + g_free (path); + return can; +} + static gboolean imap_connect_online (CamelService *service, CamelException *ex) { @@ -751,11 +766,11 @@ imap_disconnect_online (CamelService *service, gboolean clean, CamelException *e CamelImapStore *store = CAMEL_IMAP_STORE (service); CamelImapResponse *response; - imap_disconnect_offline (service, clean, ex); if (store->connected && clean) { response = camel_imap_command (store, NULL, ex, "LOGOUT"); camel_imap_response_free (store, response); } + imap_disconnect_offline (service, clean, ex); return TRUE; } @@ -801,6 +816,9 @@ get_folder_online (CamelStore *store, const char *folder_name, if (!camel_remote_store_connected (CAMEL_REMOTE_STORE (store), ex)) return NULL; + if (!g_strcasecmp (folder_name, "INBOX")) + folder_name = "INBOX"; + /* Lock around the whole lot to check/create atomically */ CAMEL_IMAP_STORE_LOCK (imap_store, command_lock); if (imap_store->current_folder) { @@ -858,6 +876,9 @@ get_folder_offline (CamelStore *store, const char *folder_name, !camel_service_connect (CAMEL_SERVICE (store), ex)) return NULL; + if (!g_strcasecmp (folder_name, "INBOX")) + folder_name = "INBOX"; + folder_dir = e_path_to_physical (imap_store->storage_path, folder_name); if (access (folder_dir, F_OK) != 0) return no_such_folder (folder_name, ex); -- cgit v1.2.3