diff options
author | Peter Williams <peterw@src.gnome.org> | 2000-08-30 05:28:46 +0800 |
---|---|---|
committer | Peter Williams <peterw@src.gnome.org> | 2000-08-30 05:28:46 +0800 |
commit | da570c66609a9baea34d4899c4ca7e1f8329d471 (patch) | |
tree | 78f82074f39463fc8db0cfb92728d57fe9c2ac84 /camel/providers/imap | |
parent | ba2eaa68b17882b0fec2eac160f674d29598795f (diff) | |
download | gsoc2013-evolution-da570c66609a9baea34d4899c4ca7e1f8329d471.tar gsoc2013-evolution-da570c66609a9baea34d4899c4ca7e1f8329d471.tar.gz gsoc2013-evolution-da570c66609a9baea34d4899c4ca7e1f8329d471.tar.bz2 gsoc2013-evolution-da570c66609a9baea34d4899c4ca7e1f8329d471.tar.lz gsoc2013-evolution-da570c66609a9baea34d4899c4ca7e1f8329d471.tar.xz gsoc2013-evolution-da570c66609a9baea34d4899c4ca7e1f8329d471.tar.zst gsoc2013-evolution-da570c66609a9baea34d4899c4ca7e1f8329d471.zip |
CamelRemoteStore: a new generic store for stores that connect to servers. Prepare for the ability to cancel operations (much better exception handling). Clean up IMAP like nobody's business
svn path=/trunk/; revision=5103
Diffstat (limited to 'camel/providers/imap')
-rw-r--r-- | camel/providers/imap/camel-imap-folder.c | 197 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-store.c | 1018 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-store.h | 16 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-stream.c | 9 |
4 files changed, 402 insertions, 838 deletions
diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c index e3ce219b89..b0dbad53a4 100644 --- a/camel/providers/imap/camel-imap-folder.c +++ b/camel/providers/imap/camel-imap-folder.c @@ -63,7 +63,7 @@ static void imap_init (CamelFolder *folder, CamelStore *parent_store, CamelFolder *parent_folder, const gchar *name, gchar *separator, gboolean path_begns_with_sep, CamelException *ex); - +static void imap_refresh_info (CamelFolder *folder, CamelException *ex); static void imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex); static void imap_expunge (CamelFolder *folder, CamelException *ex); @@ -108,6 +108,7 @@ camel_imap_folder_class_init (CamelImapFolderClass *camel_imap_folder_class) /* virtual method overload */ camel_folder_class->init = imap_init; + camel_folder_class->refresh_info = imap_refresh_info; camel_folder_class->sync = imap_sync; camel_folder_class->expunge = imap_expunge; @@ -185,11 +186,8 @@ camel_imap_folder_new (CamelStore *parent, char *folder_name, CamelException *ex if (!strcmp (folder_name, url->path + 1)) folder->can_hold_messages = FALSE; - imap_get_subfolder_names_internal (folder, ex); - - if (folder->can_hold_messages) - imap_get_summary_internal (folder, ex); - + CF_CLASS (folder)->refresh_info (folder, ex); + return folder; } @@ -286,6 +284,15 @@ imap_init (CamelFolder *folder, CamelStore *parent_store, CamelFolder *parent_fo } static void +imap_refresh_info (CamelFolder *folder, CamelException *ex) +{ + imap_get_subfolder_names_internal (folder, ex); + + if (folder->can_hold_messages) + imap_get_summary_internal (folder, ex); +} + +static void imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex) { CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder); @@ -317,21 +324,12 @@ imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex) *(flags + strlen (flags) - 1) = '\0'; s = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), - folder, &result, + folder, &result, ex, "UID STORE %s FLAGS.SILENT (%s)", info->uid, flags); - if (s != CAMEL_IMAP_OK) { - CamelService *service = CAMEL_SERVICE (folder->parent_store); - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - "Could not set flags on message %s on IMAP " - "server %s: %s.", info->uid, - service->url->host, - s != CAMEL_IMAP_FAIL && result ? result : - "Unknown error"); - g_free (result); + if (s != CAMEL_IMAP_OK) return; - } g_free (result); } @@ -352,19 +350,11 @@ imap_expunge (CamelFolder *folder, CamelException *ex) imap_sync (folder, FALSE, ex); - status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder, - &result, "EXPUNGE"); + status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder, + &result, ex, "EXPUNGE"); - if (status != CAMEL_IMAP_OK) { - CamelService *service = CAMEL_SERVICE (folder->parent_store); - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - "Could not EXPUNGE from IMAP server %s: %s.", - service->url->host, - status != CAMEL_IMAP_FAIL && result ? result : - "Unknown error"); - g_free (result); + if (status != CAMEL_IMAP_OK) return; - } /* determine which messages were successfully expunged */ node = result; @@ -381,7 +371,7 @@ imap_expunge (CamelFolder *folder, CamelException *ex) word = imap_next_word (word); for (ep = word; *ep && *ep != '\n'; ep++); - reason = g_strndup (word, (gint)(ep - word) + 1); + reason = g_strndup (word, (gint)(ep - word)); camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, "Could not EXPUNGE from IMAP server %s: %s.", @@ -462,23 +452,15 @@ imap_get_message_count_internal (CamelFolder *folder, CamelException *ex) if (CAMEL_IMAP_STORE (store)->has_status_capability) status = camel_imap_command_extended (CAMEL_IMAP_STORE (store), folder, - &result, "STATUS %s (MESSAGES)", folder_path); + &result, ex, "STATUS %s (MESSAGES)", folder_path); else status = camel_imap_command_extended (CAMEL_IMAP_STORE (store), folder, - &result, "EXAMINE %s", folder_path); + &result, ex, "EXAMINE %s", folder_path); + + g_free (folder_path); - if (status != CAMEL_IMAP_OK) { - CamelService *service = CAMEL_SERVICE (folder->parent_store); - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - "Could not get message count for %s from IMAP " - "server %s: %s.", folder_path, service->url->host, - status != CAMEL_IMAP_FAIL && result ? result : - "Unknown error"); - g_free (result); - g_free (folder_path); + if (status != CAMEL_IMAP_OK) return 0; - } - g_free (folder_path); /* parse out the message count */ if (result && *result == '*') { @@ -582,45 +564,27 @@ imap_append_message (CamelFolder *folder, CamelMimeMessage *message, const Camel camel_stream_reset (memstream); status = camel_imap_command_preliminary (CAMEL_IMAP_STORE (folder->parent_store), - &result, &cmdid, "APPEND %s%s {%d}", + &cmdid, ex, "APPEND %s%s {%d}", folder_path, flagstr ? flagstr : "", ba->len - 2); + g_free (folder_path); if (status != CAMEL_IMAP_PLUS) { - CamelService *service = CAMEL_SERVICE (folder->parent_store); - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - "Could not APPEND message to IMAP server %s: %s.", - service->url->host, result ? result : "Unknown error"); - - g_free (result); g_free (cmdid); - g_free (folder_path); return; } - g_free (result); - g_free (folder_path); - /* send the rest of our data - the mime message */ status = camel_imap_command_continuation_with_stream (CAMEL_IMAP_STORE (folder->parent_store), - &result, cmdid, memstream); + &result, cmdid, memstream, ex); + g_free (cmdid); - if (status != CAMEL_IMAP_OK) { - CamelService *service = CAMEL_SERVICE (folder->parent_store); - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - "Could not APPEND message to IMAP server %s: %s.", - service->url->host, result ? result : "Unknown error"); - - camel_object_unref (CAMEL_OBJECT (memstream)); - g_free (result); - g_free (cmdid); + if (status != CAMEL_IMAP_OK) return; - } - - camel_object_unref (CAMEL_OBJECT (memstream)); - g_free (cmdid); + g_free (result); - camel_imap_folder_changed (folder, 1, NULL, ex); + camel_object_unref (CAMEL_OBJECT (memstream)); + camel_imap_folder_changed (folder, 1, NULL, ex); } static void @@ -638,23 +602,14 @@ imap_copy_message_to (CamelFolder *source, const char *uid, CamelFolder *destina else folder_path = g_strdup (destination->full_name); - status = camel_imap_command_extended (CAMEL_IMAP_STORE (store), source, &result, + status = camel_imap_command_extended (CAMEL_IMAP_STORE (store), source, &result, ex, "UID COPY %s %s", uid, folder_path); + g_free (folder_path); - if (status != CAMEL_IMAP_OK) { - CamelService *service = CAMEL_SERVICE (store); - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - "Could not COPY message %s to %s on IMAP server %s: %s.", - uid, folder_path, service->url->host, - status != CAMEL_IMAP_FAIL && result ? result : - "Unknown error"); - g_free (result); - g_free (folder_path); + if (status != CAMEL_IMAP_OK) return; - } g_free (result); - g_free (folder_path); camel_imap_folder_changed (destination, 1, NULL, ex); } @@ -676,23 +631,14 @@ imap_move_message_to (CamelFolder *source, const char *uid, CamelFolder *destina else folder_path = g_strdup (destination->full_name); - status = camel_imap_command_extended (CAMEL_IMAP_STORE (store), source, &result, + status = camel_imap_command_extended (CAMEL_IMAP_STORE (store), source, &result, ex, "UID COPY %s %s", uid, folder_path); + g_free (folder_path); - if (status != CAMEL_IMAP_OK) { - CamelService *service = CAMEL_SERVICE (store); - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - "Could not COPY message %s to %s on IMAP server %s: %s.", - uid, folder_path, service->url->host, - status != CAMEL_IMAP_FAIL && result ? result : - "Unknown error"); - g_free (result); - g_free (folder_path); + if (status != CAMEL_IMAP_OK) return; - } - + g_free (result); - g_free (folder_path); if (!(info = (CamelMessageInfo *)imap_get_message_info (source, uid))) { CamelService *service = CAMEL_SERVICE (store); @@ -779,17 +725,10 @@ imap_get_subfolder_names_internal (CamelFolder *folder, CamelException *ex) } status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), NULL, - &result, "LIST \"\" \"%s%s*\"", namespace, + &result, ex, "LIST \"\" \"%s%s*\"", namespace, *namespace ? dir_sep : ""); if (status != CAMEL_IMAP_OK) { - CamelService *service = CAMEL_SERVICE (folder->parent_store); - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - "Could not get subfolder listing from IMAP " - "server %s: %s.", service->url->host, - status != CAMEL_IMAP_FAIL && result ? result : - "Unknown error"); - g_free (result); g_free (namespace); imap_folder->lsub = g_ptr_array_new (); @@ -871,20 +810,11 @@ imap_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex) data_item = "RFC822.HEADER"; status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder, - &result, "UID FETCH %s %s", uid, + &result, ex, "UID FETCH %s %s", uid, data_item); - if (!result || status != CAMEL_IMAP_OK) { - CamelService *service = CAMEL_SERVICE (folder->parent_store); - - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - "Could not fetch message %s on IMAP server %s: %s", - uid, service->url->host, - status != CAMEL_IMAP_FAIL && result ? result : - "Unknown error"); - g_free (result); + if (!result || status != CAMEL_IMAP_OK) return NULL; - } /* parse out the message part */ for (p = result; *p && *p != '{' && *p != '"' && *p != '\n'; p++); @@ -933,18 +863,10 @@ imap_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex) data_item = "RFC822.TEXT"; status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder, - &result, "UID FETCH %s %s", uid, + &result, ex, "UID FETCH %s %s", uid, data_item); if (!result || status != CAMEL_IMAP_OK) { - CamelService *service = CAMEL_SERVICE (folder->parent_store); - - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - "Could not fetch message %s on IMAP server %s: %s", - uid, service->url->host, - status != CAMEL_IMAP_FAIL && result ? result : - "Unknown error"); - g_free (result); g_free (header); return NULL; } @@ -1111,23 +1033,14 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex) if (num == 1) { status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder, - &result, "FETCH 1 (%s)", summary_specifier); + &result, ex, "FETCH 1 (%s)", summary_specifier); } else { status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder, - &result, "FETCH 1:%d (%s)", num, summary_specifier); + &result, ex, "FETCH 1:%d (%s)", num, summary_specifier); } g_free (summary_specifier); if (status != CAMEL_IMAP_OK) { - CamelService *service = CAMEL_SERVICE (folder->parent_store); - - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - "Could not get summary for %s on IMAP server %s: %s", - folder->full_name, service->url->host, - status != CAMEL_IMAP_FAIL && result ? result : - "Unknown error"); - g_free (result); - if (!imap_folder->summary) { imap_folder->summary = g_ptr_array_new (); imap_folder->summary_hash = g_hash_table_new (g_str_hash, g_str_equal); @@ -1293,7 +1206,7 @@ imap_get_summary (CamelFolder *folder) /* get a single message info from the server */ static CamelMessageInfo * -imap_get_message_info_internal (CamelFolder *folder, guint id) +imap_get_message_info_internal (CamelFolder *folder, guint id, CamelException *ex) { CamelMessageInfo *info = NULL; struct _header_raw *h, *tail = NULL; @@ -1306,14 +1219,12 @@ imap_get_message_info_internal (CamelFolder *folder, guint id) summary_specifier = imap_protocol_get_summary_specifier (folder); status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder, - &result, "FETCH %d (%s)", id, summary_specifier); + &result, ex, "FETCH %d (%s)", id, summary_specifier); g_free (summary_specifier); - if (status != CAMEL_IMAP_OK) { - g_free (result); + if (status != CAMEL_IMAP_OK) return NULL; - } /* lets grab the UID... */ if (!(uid = (char *) e_strstrcase (result, "UID "))) { @@ -1456,17 +1367,9 @@ imap_search_by_expression (CamelFolder *folder, const char *expression, CamelExc } status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder, - &result, "UID SEARCH %s", sexp); + &result, ex, "UID SEARCH %s", sexp); if (status != CAMEL_IMAP_OK) { - CamelService *service = CAMEL_SERVICE (folder->parent_store); - - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - "Could not get summary for %s on IMAP server %s: %s", - folder->full_name, service->url->host, - status != CAMEL_IMAP_FAIL && result ? result : - "Unknown error"); - g_free (result); g_free (sexp); return uids; } @@ -1594,7 +1497,7 @@ camel_imap_folder_changed (CamelFolder *folder, gint recent, GPtrArray *expunged last = imap_folder->summary->len + 1; for (i = last, j = 0; j < recent; i++, j++) { - info = imap_get_message_info_internal (folder, i); + info = imap_get_message_info_internal (folder, i, ex); if (info) { g_ptr_array_add (imap_folder->summary, info); g_hash_table_insert (imap_folder->summary_hash, info->uid, info); diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c index 9e57dc03d7..3830e37104 100644 --- a/camel/providers/imap/camel-imap-store.c +++ b/camel/providers/imap/camel-imap-store.c @@ -25,15 +25,10 @@ #include <config.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> -#include <errno.h> #include <e-util/e-util.h> @@ -54,20 +49,16 @@ /* Specified in RFC 2060 */ #define IMAP_PORT 143 -static CamelServiceClass *service_class = NULL; +static CamelRemoteStoreClass *remote_store_class = NULL; -static void finalize (CamelObject *object); static gboolean imap_create (CamelFolder *folder, CamelException *ex); -static gboolean imap_connect (CamelService *service, CamelException *ex); -static gboolean imap_disconnect (CamelService *service, CamelException *ex); +static void imap_post_connect (CamelRemoteStore *remote_store, CamelException *ex); +static void imap_pre_disconnect (CamelRemoteStore *remote_store, CamelException *ex); static GList *query_auth_types_generic (CamelService *service, CamelException *ex); static GList *query_auth_types_connected (CamelService *service, CamelException *ex); -static void free_auth_types (CamelService *service, GList *authtypes); -static char *get_name (CamelService *service, gboolean brief); static CamelFolder *get_folder (CamelStore *store, const char *folder_name, gboolean create, CamelException *ex); -static char *get_folder_name (CamelStore *store, const char *folder_name, CamelException *ex); -static gboolean imap_noop (gpointer data); +static void imap_keepalive (CamelRemoteStore *store); /*static gboolean stream_is_alive (CamelStream *istream);*/ static int camel_imap_status (char *cmdid, char *respbuf); @@ -79,35 +70,35 @@ camel_imap_store_class_init (CamelImapStoreClass *camel_imap_store_class) CAMEL_SERVICE_CLASS (camel_imap_store_class); CamelStoreClass *camel_store_class = CAMEL_STORE_CLASS (camel_imap_store_class); + CamelRemoteStoreClass *camel_remote_store_class = + CAMEL_REMOTE_STORE_CLASS (camel_imap_store_class); - service_class = CAMEL_SERVICE_CLASS(camel_type_get_global_classfuncs (camel_service_get_type ())); + remote_store_class = CAMEL_REMOTE_STORE_CLASS(camel_type_get_global_classfuncs + (camel_remote_store_get_type ())); /* virtual method overload */ - camel_service_class->connect = imap_connect; - camel_service_class->disconnect = imap_disconnect; camel_service_class->query_auth_types_generic = query_auth_types_generic; camel_service_class->query_auth_types_connected = query_auth_types_connected; - camel_service_class->free_auth_types = free_auth_types; - camel_service_class->get_name = get_name; camel_store_class->get_folder = get_folder; - camel_store_class->get_folder_name = get_folder_name; + + camel_remote_store_class->post_connect = imap_post_connect; + camel_remote_store_class->pre_disconnect = imap_pre_disconnect; + camel_remote_store_class->keepalive = imap_keepalive; } static void camel_imap_store_init (gpointer object, gpointer klass) { CamelService *service = CAMEL_SERVICE (object); - CamelStore *store = CAMEL_STORE (object); + CamelImapStore *imap_store = CAMEL_IMAP_STORE (object); - service->url_flags = (CAMEL_SERVICE_URL_NEED_USER | - CAMEL_SERVICE_URL_NEED_HOST | - CAMEL_SERVICE_URL_ALLOW_PATH); + service->url_flags |= (CAMEL_SERVICE_URL_NEED_USER | + CAMEL_SERVICE_URL_NEED_HOST | + CAMEL_SERVICE_URL_ALLOW_PATH); - store->folders = g_hash_table_new (g_str_hash, g_str_equal); - CAMEL_IMAP_STORE (store)->dir_sep = g_strdup ("/"); /*default*/ - CAMEL_IMAP_STORE (store)->current_folder = NULL; - CAMEL_IMAP_STORE (store)->timeout_id = 0; + imap_store->dir_sep = g_strdup ("/"); /*default*/ + imap_store->current_folder = NULL; } CamelType @@ -116,31 +107,18 @@ camel_imap_store_get_type (void) static CamelType camel_imap_store_type = CAMEL_INVALID_TYPE; if (camel_imap_store_type == CAMEL_INVALID_TYPE) { - camel_imap_store_type = camel_type_register (CAMEL_STORE_TYPE, "CamelImapStore", + camel_imap_store_type = camel_type_register (CAMEL_REMOTE_STORE_TYPE, "CamelImapStore", sizeof (CamelImapStore), sizeof (CamelImapStoreClass), (CamelObjectClassInitFunc) camel_imap_store_class_init, NULL, (CamelObjectInitFunc) camel_imap_store_init, - (CamelObjectFinalizeFunc) finalize); + (CamelObjectFinalizeFunc) NULL); } return camel_imap_store_type; } -static void -finalize (CamelObject *object) -{ - /* Done for us now */ - /* - *CamelException ex; - * - *camel_exception_init (&ex); - *imap_disconnect (CAMEL_SERVICE (object), &ex); - *camel_exception_clear (&ex); - */ -} - static CamelServiceAuthType password_authtype = { "Password", @@ -208,6 +186,7 @@ query_auth_types_connected (CamelService *service, CamelException *ex) return ret; #else g_warning ("imap::query_auth_types_connected: not implemented. Defaulting."); + /* FIXME: use the classfunc instead of the local? */ return query_auth_types_generic (service, ex); #endif } @@ -215,90 +194,30 @@ query_auth_types_connected (CamelService *service, CamelException *ex) static GList * query_auth_types_generic (CamelService *service, CamelException *ex) { - return g_list_append (NULL, &password_authtype); -} + GList *prev; -static void -free_auth_types (CamelService *service, GList *authtypes) -{ - g_list_free (authtypes); + prev = CAMEL_SERVICE_CLASS (remote_store_class)->query_auth_types_generic (service, ex); + return g_list_prepend (prev, &password_authtype); } -static char * -get_name (CamelService *service, gboolean brief) +static void +imap_post_connect (CamelRemoteStore *remote_store, CamelException *ex) { - if (brief) - return g_strdup_printf ("IMAP server %s", service->url->host); - else { - return g_strdup_printf ("IMAP service for %s on %s", - service->url->user, - service->url->host); - } -} + CamelService *service = CAMEL_SERVICE (remote_store); + CamelImapStore *store = CAMEL_IMAP_STORE (remote_store); + CamelSession *session = camel_service_get_session (CAMEL_SERVICE (store)); -static gboolean -imap_connect (CamelService *service, CamelException *ex) -{ - CamelImapStore *store = CAMEL_IMAP_STORE (service); - struct hostent *h; - struct sockaddr_in sin; - gint fd, status; - gchar *buf, *msg, *result, *errbuf = NULL; + gint status; + gchar *buf, *result, *errbuf = NULL; gboolean authenticated = FALSE; - /* FIXME: do we really need this here? */ - /* - *if (store->timeout_id) { - * gtk_timeout_remove (store->timeout_id); - * store->timeout_id = 0; - *} - */ - - h = camel_service_gethost (service, ex); - if (!h) - return FALSE; - - /* connect to the IMAP server */ - sin.sin_family = h->h_addrtype; - if (service->url->port) - sin.sin_port = htons(service->url->port); - else - sin.sin_port = htons(IMAP_PORT); - - memcpy (&sin.sin_addr, h->h_addr, sizeof (sin.sin_addr)); - - fd = socket (h->h_addrtype, SOCK_STREAM, 0); - if (fd == -1 || connect (fd, (struct sockaddr *)&sin, sizeof(sin)) == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - "Could not connect to %s (port %d): %s", - service->url->host ? service->url->host : "(unknown host)", - service->url->port ? service->url->port : IMAP_PORT, - strerror(errno)); - if (fd > -1) - close (fd); - - return FALSE; - } - - /* parent class conect initialization */ - service_class->connect (service, ex); - - store->ostream = camel_stream_fs_new_with_fd (fd); - store->istream = camel_stream_buffer_new (store->ostream, CAMEL_STREAM_BUFFER_READ); store->command = 0; g_free (store->dir_sep); store->dir_sep = g_strdup ("/"); /* default dir sep */ /* Read the greeting, if any. */ - buf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (store->istream)); - if (!buf) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - "Could not read greeting from IMAP " - "server: %s", - camel_exception_get_description (ex)); - - imap_disconnect (service, ex); - return FALSE; + if (camel_remote_store_recv_line (remote_store, &buf, ex) < 0) { + return; } g_free (buf); @@ -306,7 +225,7 @@ imap_connect (CamelService *service, CamelException *ex) while (!authenticated) { if (errbuf) { /* We need to un-cache the password before prompting again */ - camel_session_query_authenticator (camel_service_get_session (service), + camel_session_query_authenticator (session, CAMEL_AUTHENTICATOR_TELL, NULL, TRUE, service, "password", ex); g_free (service->url->passwd); @@ -317,9 +236,9 @@ imap_connect (CamelService *service, CamelException *ex) gchar *prompt; prompt = g_strdup_printf ("%sPlease enter the IMAP password for %s@%s", - errbuf ? errbuf : "", service->url->user, h->h_name); + errbuf ? errbuf : "", service->url->user, service->url->host); service->url->passwd = - camel_session_query_authenticator (camel_service_get_session (service), + camel_session_query_authenticator (session, CAMEL_AUTHENTICATOR_ASK, prompt, TRUE, service, "password", ex); g_free (prompt); @@ -327,19 +246,19 @@ imap_connect (CamelService *service, CamelException *ex) errbuf = NULL; if (!service->url->passwd) { - imap_disconnect (service, ex); - return FALSE; + camel_service_disconnect (service, ex); + return; } } - status = camel_imap_command (store, NULL, &msg, "LOGIN \"%s\" \"%s\"", + status = camel_imap_command (store, NULL, ex, "LOGIN \"%s\" \"%s\"", service->url->user, service->url->passwd); if (status != CAMEL_IMAP_OK) { errbuf = g_strdup_printf ("Unable to authenticate to IMAP server.\n" - "Error sending password: %s\n\n", - msg ? msg : "(Unknown)"); + "%s\n\n", + camel_exception_get_description (ex)); } else { g_message ("IMAP Service sucessfully authenticated user %s", service->url->user); authenticated = TRUE; @@ -347,17 +266,10 @@ imap_connect (CamelService *service, CamelException *ex) } /* Now lets find out the IMAP capabilities */ - status = camel_imap_command_extended (store, NULL, &result, "CAPABILITY"); + status = camel_imap_command_extended (store, NULL, &result, ex, "CAPABILITY"); if (status != CAMEL_IMAP_OK) { - /* Non-fatal error, but we should still warn the user... */ - CamelService *service = CAMEL_SERVICE (store); - - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - "Could not get capabilities on IMAP server %s: %s.", - service->url->host, - status != CAMEL_IMAP_FAIL && result ? result : - "Unknown error"); + /* Non-fatal error... (ex is set) */ } /* parse for capabilities here. */ @@ -376,17 +288,10 @@ imap_connect (CamelService *service, CamelException *ex) g_free (result); /* We now need to find out which directory separator this daemon uses */ - status = camel_imap_command_extended (store, NULL, &result, "LIST \"\" \"\""); + status = camel_imap_command_extended (store, NULL, &result, ex, "LIST \"\" \"\""); if (status != CAMEL_IMAP_OK) { /* Again, this is non-fatal */ - CamelService *service = CAMEL_SERVICE (store); - - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - "Could not get directory separator on IMAP server %s: %s.", - service->url->host, - status != CAMEL_IMAP_FAIL && result ? result : - "Unknown error"); } else { char *flags, *sep, *folder; @@ -402,65 +307,31 @@ imap_connect (CamelService *service, CamelException *ex) g_free (folder); } - /* default directory separator */ - if (!store->dir_sep) - store->dir_sep = g_strdup ("/"); - g_free (result); - /* Lets add a timeout so that we can hopefully prevent getting disconnected */ - /* FIXME fast timeout */ - store->timeout_id = camel_session_register_timeout (camel_service_get_session (service), - 10 * 60 * 1000, imap_noop, service); - /*store->timeout_id = gtk_timeout_add (600000, imap_noop, store);*/ - - return TRUE; + CAMEL_REMOTE_STORE_CLASS (remote_store_class)->post_connect (remote_store, ex); } -static gboolean -imap_disconnect (CamelService *service, CamelException *ex) +static void +imap_pre_disconnect (CamelRemoteStore *remote_store, CamelException *ex) { - CamelImapStore *store = CAMEL_IMAP_STORE (service); + CamelImapStore *store = CAMEL_IMAP_STORE (remote_store); char *result; int status; - - /*if (!service->connected) - * return TRUE; - */ - /* send the logout command */ - status = camel_imap_command_extended (CAMEL_IMAP_STORE (service), NULL, &result, "LOGOUT"); + status = camel_imap_command_extended (store, NULL, &result, ex, "LOGOUT"); if (status != CAMEL_IMAP_OK) { /* Oh fuck it, we're disconnecting anyway... */ } g_free (result); - if (!service_class->disconnect (service, ex)) - return FALSE; - - if (store->istream) { - camel_object_unref (CAMEL_OBJECT (store->istream)); - store->istream = NULL; - } - - if (store->ostream) { - camel_object_unref (CAMEL_OBJECT (store->ostream)); - store->ostream = NULL; - } - g_free (store->dir_sep); store->dir_sep = NULL; store->current_folder = NULL; - if (store->timeout_id) { - camel_session_remove_timeout (camel_service_get_session (CAMEL_SERVICE (store)), - store->timeout_id); - store->timeout_id = 0; - } - - return TRUE; + CAMEL_REMOTE_STORE_CLASS (remote_store_class)->pre_disconnect (remote_store, ex); } const gchar * @@ -473,7 +344,7 @@ camel_imap_store_get_toplevel_dir (CamelImapStore *store) } static gboolean -imap_folder_exists (CamelFolder *folder) +imap_folder_exists (CamelFolder *folder, CamelException *ex) { CamelStore *store = CAMEL_STORE (folder->parent_store); CamelURL *url = CAMEL_SERVICE (store)->url; @@ -490,7 +361,7 @@ imap_folder_exists (CamelFolder *folder) folder_path = g_strdup (folder->full_name); status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), NULL, - &result, "EXAMINE %s", folder_path); + &result, ex, "EXAMINE %s", folder_path); if (status != CAMEL_IMAP_OK) { g_free (result); @@ -522,7 +393,7 @@ imap_create (CamelFolder *folder, CamelException *ex) if (!strcmp (folder->full_name, "INBOX")) return TRUE; - if (imap_folder_exists (folder)) + if (imap_folder_exists (folder, ex)) return TRUE; /* create the directory for the subfolder */ @@ -536,27 +407,17 @@ imap_create (CamelFolder *folder, CamelException *ex) folder_path = g_strdup (folder->full_name); status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), NULL, - &result, "CREATE %s", folder_path); + &result, ex, "CREATE %s", folder_path); + g_free (folder_path); - if (status != CAMEL_IMAP_OK) { - CamelService *service = CAMEL_SERVICE (folder->parent_store); - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - "Could not CREATE %s on IMAP server %s: %s.", - folder_path, service->url->host, - status != CAMEL_IMAP_FAIL && result ? result : - "Unknown error"); - g_free (result); - g_free (folder_path); + if (status != CAMEL_IMAP_OK) return FALSE; - } - g_free (folder_path); - g_free (result); return TRUE; } static gboolean -folder_is_selectable (CamelStore *store, const char *folder_path) +folder_is_selectable (CamelStore *store, const char *folder_path, CamelException *ex) { char *result, *flags, *sep, *folder; int status; @@ -565,11 +426,9 @@ folder_is_selectable (CamelStore *store, const char *folder_path) return TRUE; status = camel_imap_command_extended (CAMEL_IMAP_STORE (store), NULL, - &result, "LIST \"\" %s", folder_path); - if (status != CAMEL_IMAP_OK) { - g_free (result); + &result, ex, "LIST \"\" %s", folder_path); + if (status != CAMEL_IMAP_OK) return FALSE; - } if (imap_parse_list_response (result, "", &flags, &sep, &folder)) { gboolean retval; @@ -613,7 +472,7 @@ get_folder (CamelStore *store, const char *folder_name, gboolean create, CamelEx return new_folder; if (create && !imap_create (new_folder, ex)) { - if (!folder_is_selectable (store, folder_path)) { + if (!folder_is_selectable (store, folder_path, ex)) { camel_exception_clear (ex); new_folder->can_hold_messages = FALSE; return new_folder; @@ -627,24 +486,20 @@ get_folder (CamelStore *store, const char *folder_name, gboolean create, CamelEx return new_folder; } -static gchar * -get_folder_name (CamelStore *store, const char *folder_name, CamelException *ex) -{ - return g_strdup (folder_name); -} - -static gboolean -imap_noop (gpointer data) +static void +imap_keepalive (CamelRemoteStore *store) { - CamelImapStore *store = CAMEL_IMAP_STORE (data); + CamelImapStore *imap_store = CAMEL_IMAP_STORE (store); char *result; int status; + CamelException ex; - status = camel_imap_command_extended (store, store->current_folder, &result, "NOOP"); - - g_free (result); - - return TRUE; + camel_exception_init (&ex); + status = camel_imap_command_extended (imap_store, imap_store->current_folder, + &result, &ex, "NOOP"); + camel_exception_clear (&ex); + if (result) + g_free (result); } #if 0 @@ -687,11 +542,223 @@ camel_imap_status (char *cmdid, char *respbuf) return CAMEL_IMAP_FAIL; } +static gint +check_current_folder (CamelImapStore *store, CamelFolder *folder, char *fmt, CamelException *ex) +{ + CamelURL *url = CAMEL_SERVICE (store)->url; + char *r, *folder_path, *dir_sep; + int s; + + if (!folder) + return CAMEL_IMAP_OK; + if (store->current_folder == folder) + return CAMEL_IMAP_OK; + if (strncmp (fmt, "CREATE", 5) == 0) + return CAMEL_IMAP_OK; + + dir_sep = store->dir_sep; + + if (url && url->path && *(url->path + 1) && strcmp (folder->full_name, "INBOX")) + folder_path = g_strdup_printf ("%s%s%s", url->path + 1, dir_sep, folder->full_name); + else + folder_path = g_strdup (folder->full_name); + + s = camel_imap_command_extended (store, NULL, &r, ex, "SELECT %s", folder_path); + g_free (folder_path); + + if (!r || s != CAMEL_IMAP_OK) { + store->current_folder = NULL; + return s; + } + + g_free (r); + store->current_folder = folder; + return CAMEL_IMAP_OK; +} + +static gint +send_command (CamelImapStore *store, char **cmdid, char *fmt, va_list ap, CamelException *ex) +{ + gchar *cmdbuf; + + (*cmdid) = g_strdup_printf ("A%.5d", store->command++); + + cmdbuf = g_strdup_vprintf (fmt, ap); + + if (camel_remote_store_send_string (CAMEL_REMOTE_STORE (store), ex, "%s %s\r\n", (*cmdid), cmdbuf) < 0) { + g_free (cmdbuf); + g_free ((*cmdid)); + (*cmdid) = NULL; + return CAMEL_IMAP_FAIL; + } + + g_free (cmdbuf); + return CAMEL_IMAP_OK; +} + +static gint +slurp_response (CamelImapStore *store, CamelFolder *folder, char *cmdid, char **ret, gboolean stop_on_plus, CamelException *ex) +{ + gint status = CAMEL_IMAP_OK; + GPtrArray *data, *expunged; + gchar *respbuf; + guint32 len = 0; + gint recent = 0; + gint i; + + data = g_ptr_array_new(); + expunged = g_ptr_array_new(); + + while (1) { + if (camel_remote_store_recv_line (CAMEL_REMOTE_STORE (store), &respbuf, ex) < 0) + return CAMEL_IMAP_FAIL; + + g_ptr_array_add (data, respbuf); + len += strlen (respbuf) + 1; + + /* IMAP's last response starts with our command id or, sometimes, a plus */ + + if (stop_on_plus && *respbuf == '+') { + status = CAMEL_IMAP_PLUS; + break; + } + + if (!strncmp (respbuf, cmdid, strlen (cmdid))) { + status = camel_imap_status (cmdid, respbuf); + break; + } + + /* If recent was somehow set and this response doesn't begin with a '*' + then recent must have been misdetected */ + if (recent && *respbuf != '*') + recent = 0; + + /* Check for a RECENT in the untagged response */ + if (*respbuf == '*') { + if (strstr (respbuf, "RECENT")) { + char *rcnt; + + d(fprintf (stderr, "*** We may have found a 'RECENT' flag: %s\n", respbuf)); + /* Make sure it's in the form: "* %d RECENT" */ + rcnt = imap_next_word (respbuf); + if (*rcnt >= '0' && *rcnt <= '9' && !strncmp ("RECENT", imap_next_word (rcnt), 6)) + recent = atoi (rcnt); + } else if (strstr (respbuf, "EXPUNGE")) { + char *id_str; + int id; + + d(fprintf (stderr, "*** We may have found an 'EXPUNGE' flag: %s\n", respbuf)); + /* Make sure it's in the form: "* %d EXPUNGE" */ + id_str = imap_next_word (respbuf); + if (*id_str >= '0' && *id_str <= '9' && !strncmp ("EXPUNGE", imap_next_word (id_str), 7)) { + id = atoi (id_str); + g_ptr_array_add (expunged, g_strdup_printf ("%d", id)); + } + } + } + } + + /* Apply the 'recent' changes */ + if (folder && recent > 0) + camel_imap_folder_changed (folder, recent, expunged, ex); + + if (status == CAMEL_IMAP_OK || status == CAMEL_IMAP_PLUS) { + gchar *p; + + /* Command succeeded! Put the output into one big + * string of love. */ + + (*ret) = g_new (char, len + 1); + p = (*ret); + + for (i = 0; i < data->len; i++) { + char *datap; + + datap = (char *) data->pdata[i]; + if (*datap == '.') + datap++; + len = strlen (datap); + memcpy (p, datap, len); + p += len; + *p++ = '\n'; + } + + *p = '\0'; + } else { + /* Bummer. Try to grab what the server said. */ + if (respbuf) { + char *word; + + word = imap_next_word (respbuf); + + if (*respbuf != '-') + word = imap_next_word (word); + + camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, + "IMAP command failed: %s", + word); + } + + *ret = NULL; + } + + /* Can this be put into the 'if succeeded' bit? + * Or can a failed command generate untagged responses? */ + + for (i = 0; i < data->len; i++) + g_free (data->pdata[i]); + g_ptr_array_free (data, TRUE); + + for (i = 0; i < expunged->len; i++) + g_free (expunged->pdata[i]); + g_ptr_array_free (expunged, TRUE); + + return status; +} + +/* frees cmdid! */ +static gint +parse_single_line (CamelImapStore *store, char *cmdid, CamelException *ex) +{ + char *respbuf; + gint status; + char *word; + + if (camel_remote_store_recv_line (CAMEL_REMOTE_STORE (store), &respbuf, ex) < 0) + return CAMEL_IMAP_FAIL; + + /* Assume that buf indeed starts with cmdid; then + * it can only start with a plus when the slurper + * found a valid plus. So no need to check for + * stop_on_plus. + */ + + if (*respbuf == '+') { + g_free (cmdid); + return CAMEL_IMAP_PLUS; + } + + status = camel_imap_status (cmdid, respbuf); + g_free (cmdid); + + if (status == CAMEL_IMAP_OK) + return status; + + word = imap_next_word (respbuf); + if (*respbuf != '-') + word = imap_next_word (word); + + camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, + "IMAP command failed: %s", word); + return status; +} + /** * camel_imap_command: Send a command to a IMAP server. * @store: the IMAP store * @folder: The folder to perform the operation in * @ret: a pointer to return the full server response in + * @ex: a CamelException. * @fmt: a printf-style format string, followed by arguments * * This camel method sends the command specified by @fmt and the following @@ -709,84 +776,26 @@ camel_imap_status (char *cmdid, char *respbuf) * occurred, and Camel is uncertain of the result of the command.) **/ gint -camel_imap_command (CamelImapStore *store, CamelFolder *folder, char **ret, char *fmt, ...) +camel_imap_command (CamelImapStore *store, CamelFolder *folder, CamelException *ex, char *fmt, ...) { - CamelURL *url = CAMEL_SERVICE (store)->url; - gchar *cmdbuf, *respbuf; gchar *cmdid; va_list ap; gint status = CAMEL_IMAP_OK; - - if (folder && store->current_folder != folder && strncmp (fmt, "CREATE", 5)) { - /* We need to select the correct mailbox first */ - char *r, *folder_path, *dir_sep; - int s; - - dir_sep = store->dir_sep; - if (url && url->path && *(url->path + 1) && strcmp (folder->full_name, "INBOX")) - folder_path = g_strdup_printf ("%s%s%s", url->path + 1, dir_sep, folder->full_name); - else - folder_path = g_strdup (folder->full_name); - - s = camel_imap_command_extended (store, NULL, &r, "SELECT %s", folder_path); - g_free (folder_path); - if (!r || s != CAMEL_IMAP_OK) { - *ret = r; - store->current_folder = NULL; - - return s; - } - - g_free (r); - - store->current_folder = folder; - } - - /* create the command */ - cmdid = g_strdup_printf ("A%.5d", store->command++); + + /* check for current folder */ + status = check_current_folder (store, folder, fmt, ex); + if (status != CAMEL_IMAP_OK) + return status; + + /* send the command */ va_start (ap, fmt); - cmdbuf = g_strdup_vprintf (fmt, ap); + status = send_command (store, &cmdid, fmt, ap, ex); va_end (ap); - - d(fprintf (stderr, "sending : %s %s\r\n", cmdid, cmdbuf)); - - if (camel_stream_printf (store->ostream, "%s %s\r\n", cmdid, cmdbuf) == -1) { - g_free (cmdbuf); - g_free (cmdid); - if (*ret) - *ret = g_strdup (strerror (errno)); - return CAMEL_IMAP_FAIL; - } - g_free (cmdbuf); - - /* Read the response */ - respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (store->istream)); - if (respbuf == NULL) { - if (*ret) - *ret = g_strdup (strerror (errno)); - return CAMEL_IMAP_FAIL; - } - - d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)")); - - status = camel_imap_status (cmdid, respbuf); - g_free (cmdid); + if (status != CAMEL_IMAP_OK) + return status; - if (ret) { - if (status != CAMEL_IMAP_FAIL && respbuf) { - char *word; - - word = imap_next_word (respbuf); /* word should now point to NO or BAD */ - - *ret = g_strdup (imap_next_word (word)); - } else { - *ret = NULL; - } - } - - g_free (respbuf); - - return status; + /* Read the response */ + return parse_single_line (store, cmdid, ex); } /** @@ -817,202 +826,32 @@ camel_imap_command (CamelImapStore *store, CamelFolder *folder, char **ret, char * message from the server), or CAMEL_IMAP_FAIL (a protocol-level error * occurred, and Camel is uncertain of the result of the command.) **/ + gint -camel_imap_command_extended (CamelImapStore *store, CamelFolder *folder, char **ret, char *fmt, ...) +camel_imap_command_extended (CamelImapStore *store, CamelFolder *folder, char **ret, CamelException *ex, char *fmt, ...) { - CamelService *service = CAMEL_SERVICE (store); - CamelURL *url = service->url; - gint len = 0, recent = 0, status = CAMEL_IMAP_OK; - gchar *cmdid, *cmdbuf, *respbuf; - GPtrArray *data, *expunged = NULL; - va_list app; - int i; - -#if 0 - /* First make sure we're connected... */ - if (!service->connected || !stream_is_alive (store->istream)) { - CamelException *ex; - - ex = camel_exception_new (); - - if (!imap_disconnect (service, ex) || !imap_connect (service, ex)) { - camel_exception_free (ex); - - *ret = NULL; - - return CAMEL_IMAP_FAIL; - } - service->connected = TRUE; - - camel_exception_free (ex); - } -#endif - - if (folder && store->current_folder != folder && strncmp (fmt, "CREATE", 6)) { - /* We need to select the correct mailbox first */ - char *r, *folder_path, *dir_sep; - int s; - - dir_sep = store->dir_sep; - - if (url && url->path && *(url->path + 1) && strcmp (folder->full_name, "INBOX")) - folder_path = g_strdup_printf ("%s%s%s", url->path + 1, dir_sep, folder->full_name); - else - folder_path = g_strdup (folder->full_name); - - s = camel_imap_command_extended (store, NULL, &r, "SELECT %s", folder_path); - g_free (folder_path); - if (!r || s != CAMEL_IMAP_OK) { - *ret = r; - store->current_folder = NULL; - - return s; - } - - g_free (r); - - store->current_folder = folder; - } - - /* Create the command */ - cmdid = g_strdup_printf ("A%.5d", store->command++); - va_start (app, fmt); - cmdbuf = g_strdup_vprintf (fmt, app); - va_end (app); - - d(fprintf (stderr, "sending : %s %s\r\n", cmdid, cmdbuf)); - - if (camel_stream_printf (store->ostream, "%s %s\r\n", cmdid, cmdbuf) == -1) { - g_free (cmdbuf); - g_free (cmdid); - - *ret = g_strdup (strerror (errno)); - - return CAMEL_IMAP_FAIL; - } - g_free (cmdbuf); - - data = g_ptr_array_new (); - expunged = g_ptr_array_new (); - - while (1) { - CamelStreamBuffer *stream = CAMEL_STREAM_BUFFER (store->istream); - char *ptr; - - respbuf = camel_stream_buffer_read_line (stream); - if (!respbuf || !strncmp (respbuf, cmdid, strlen (cmdid))) { - /* IMAP's last response starts with our command id */ - d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)")); -#if 0 - if (!respbuf && strcmp (fmt, "LOGOUT")) { - /* we need to force a disconnect here? */ - CamelException *ex; - - ex = camel_exception_new (); - imap_disconnect (service, ex); - camel_exception_free (ex); - } -#endif - break; - } - - d(fprintf (stderr, "received: %s\n", respbuf)); - - g_ptr_array_add (data, respbuf); - len += strlen (respbuf) + 1; - - /* If recent was somehow set and this response doesn't begin with a '*' - then recent must have been misdetected */ - if (recent && *respbuf != '*') - recent = 0; - - if (*respbuf == '*') { - if ((ptr = strstr (respbuf, "RECENT"))) { - char *rcnt; - - d(fprintf (stderr, "*** We may have found a 'RECENT' flag: %s\n", respbuf)); - /* Make sure it's in the form: "* %d RECENT" */ - rcnt = imap_next_word (respbuf); - if (*rcnt >= '0' && *rcnt <= '9' && !strncmp ("RECENT", imap_next_word (rcnt), 6)) - recent = atoi (rcnt); - } else if ((ptr = strstr (respbuf, "EXPUNGE"))) { - char *id_str; - int id; - - d(fprintf (stderr, "*** We may have found an 'EXPUNGE' flag: %s\n", respbuf)); - /* Make sure it's in the form: "* %d EXPUNGE" */ - id_str = imap_next_word (respbuf); - if (*id_str >= '0' && *id_str <= '9' && !strncmp ("EXPUNGE", imap_next_word (id_str), 7)) { - id = atoi (id_str); - g_ptr_array_add (expunged, g_strdup_printf ("%d", id)); - } - } - } - } - - if (respbuf) { - g_ptr_array_add (data, respbuf); - len += strlen (respbuf) + 1; - - status = camel_imap_status (cmdid, respbuf); - } else { - status = CAMEL_IMAP_FAIL; - } - g_free (cmdid); - - if (status == CAMEL_IMAP_OK) { - char *p; - - *ret = g_malloc0 (len + 1); - - for (i = 0, p = *ret; i < data->len; i++) { - char *ptr, *datap; - - datap = (char *) data->pdata[i]; - ptr = (*datap == '.') ? datap + 1 : datap; - len = strlen (ptr); - memcpy (p, ptr, len); - p += len; - *p++ = '\n'; - } - *p = '\0'; - } else { - if (status != CAMEL_IMAP_FAIL && respbuf) { - char *word; - - word = imap_next_word (respbuf); /* word should now point to NO or BAD */ - - *ret = g_strdup (imap_next_word (word)); - } else { - *ret = NULL; - } - } - - for (i = 0; i < data->len; i++) - g_free (data->pdata[i]); - g_ptr_array_free (data, TRUE); - - if (folder && recent > 0) { - CamelException *ex; - - ex = camel_exception_new (); - camel_imap_folder_changed (folder, recent, expunged, ex); - - for (i = 0; i < expunged->len; i++) - g_free (expunged->pdata[i]); - g_ptr_array_free (expunged, TRUE); - - camel_exception_free (ex); - } - - return status; + gint status = CAMEL_IMAP_OK; + gchar *cmdid; + va_list ap; + + status = check_current_folder (store, folder, fmt, ex); + if (status != CAMEL_IMAP_OK) + return status; + + /* send the command */ + va_start (ap, fmt); + status = send_command (store, &cmdid, fmt, ap, ex); + va_end (ap); + if (status != CAMEL_IMAP_OK) + return status; + + return slurp_response (store, folder, cmdid, ret, FALSE, ex); } /** * camel_imap_command_preliminary: Send a preliminary command to the * IMAP server. * @store: the IMAP store - * @ret: a pointer to return the full server response in * @cmdid: a pointer to return the command identifier (for use in * camel_imap_command_continuation) * @fmt: a printf-style format string, followed by arguments @@ -1027,57 +866,26 @@ camel_imap_command_extended (CamelImapStore *store, CamelFolder *folder, char ** * containing the rest of the response from the IMAP server. The * caller function is responsible for freeing @ret. * - * Return value: one of CAMEL_IMAP_PLUS or CAMEL_IMAP_FAIL + * Return value: one of CAMEL_IMAP_PLUS, CAMEL_IMAP_OK, or CAMEL_IMAP_FAIL * * Note: on success (CAMEL_IMAP_PLUS), you will need to follow up with * a camel_imap_command_continuation call. **/ gint -camel_imap_command_preliminary (CamelImapStore *store, char **ret, char **cmdid, char *fmt, ...) +camel_imap_command_preliminary (CamelImapStore *store, char **cmdid, CamelException *ex, char *fmt, ...) { - gchar *cmdbuf, *respbuf; gint status = CAMEL_IMAP_OK; - va_list app; - - /* Create the command */ - *cmdid = g_strdup_printf ("A%.5d", store->command++); - va_start (app, fmt); - cmdbuf = g_strdup_vprintf (fmt, app); - va_end (app); - - d(fprintf (stderr, "sending : %s %s\r\n", *cmdid, cmdbuf)); - - if (camel_stream_printf (store->ostream, "%s %s\r\n", *cmdid, cmdbuf) == -1) { - g_free (cmdbuf); - - if (ret) - *ret = g_strdup (strerror (errno)); - - return CAMEL_IMAP_FAIL; - } - g_free (cmdbuf); - - respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (store->istream)); - - if (respbuf) { - switch (*respbuf) { - case '+': - /* continuation request */ - status = CAMEL_IMAP_PLUS; - break; - default: - status = camel_imap_status (*cmdid, respbuf); - } - - if (ret) - *ret = g_strdup (imap_next_word (respbuf)); - } else { - status = CAMEL_IMAP_FAIL; - if (ret) - *ret = NULL; - } - - return status; + va_list ap; + + /* send the command */ + va_start (ap, fmt); + status = send_command (store, cmdid, fmt, ap, ex); + va_end (ap); + if (status != CAMEL_IMAP_OK) + return status; + + /* Read the response */ + return parse_single_line (store, g_strdup (*cmdid), ex); } /** @@ -1102,91 +910,15 @@ camel_imap_command_preliminary (CamelImapStore *store, char **ret, char **cmdid, * of the result of the command.) **/ gint -camel_imap_command_continuation (CamelImapStore *store, char **ret, char *cmdid, char *cmdbuf) +camel_imap_command_continuation (CamelImapStore *store, char **ret, char *cmdid, char *cmdbuf, CamelException *ex) { - gint len = 0, status = CAMEL_IMAP_OK; - gchar *respbuf; - GPtrArray *data; - int i; - - d(fprintf (stderr, "sending : %s\r\n", cmdbuf)); - - if (camel_stream_printf (store->ostream, "%s\r\n", cmdbuf) == -1) { - *ret = g_strdup (strerror (errno)); - - return CAMEL_IMAP_FAIL; - } - - data = g_ptr_array_new (); - - while (1) { - CamelStreamBuffer *stream = CAMEL_STREAM_BUFFER (store->istream); - - respbuf = camel_stream_buffer_read_line (stream); - if (!respbuf || *respbuf == '+' || !strncmp (respbuf, cmdid, strlen (cmdid))) { - /* IMAP's last response starts with our command id or a continuation request */ - d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)")); - - break; - } - - d(fprintf (stderr, "received: %s\n", respbuf)); - - g_ptr_array_add (data, respbuf); - len += strlen (respbuf) + 1; - } - - if (respbuf) { - g_ptr_array_add (data, respbuf); - len += strlen (respbuf) + 1; - - switch (*respbuf) { - case '+': - status = CAMEL_IMAP_PLUS; - break; - default: - status = camel_imap_status (cmdid, respbuf); - } - } else { - status = CAMEL_IMAP_FAIL; - } - - if (status == CAMEL_IMAP_OK || status == CAMEL_IMAP_PLUS) { - char *p; - - *ret = g_malloc0 (len + 1); - - for (i = 0, p = *ret; i < data->len; i++) { - char *ptr, *datap; - - datap = (char *) data->pdata[i]; - ptr = (*datap == '.') ? datap + 1 : datap; - len = strlen (ptr); - memcpy (p, ptr, len); - p += len; - *p++ = '\n'; - } - *p = '\0'; - } else { - if (status != CAMEL_IMAP_FAIL && respbuf) { - char *word; - - word = imap_next_word (respbuf); - - if (*respbuf == '-') - *ret = g_strdup (word); - else - *ret = g_strdup (imap_next_word (word)); - } else { + if (camel_remote_store_send_string (CAMEL_REMOTE_STORE (store), ex, "%s\r\n", cmdbuf) < 0) { + if (ret) *ret = NULL; - } + return CAMEL_IMAP_FAIL; } - for (i = 0; i < data->len; i++) - g_free (data->pdata[i]); - g_ptr_array_free (data, TRUE); - - return status; + return slurp_response (store, NULL, cmdid, ret, TRUE, ex); } /** @@ -1211,89 +943,13 @@ camel_imap_command_continuation (CamelImapStore *store, char **ret, char *cmdid, * of the result of the command.) **/ gint -camel_imap_command_continuation_with_stream (CamelImapStore *store, char **ret, char *cmdid, CamelStream *cstream) +camel_imap_command_continuation_with_stream (CamelImapStore *store, char **ret, char *cmdid, CamelStream *cstream, CamelException *ex) { - gint len = 0, status = CAMEL_IMAP_OK; - gchar *respbuf; - GPtrArray *data; - int i; - - d(fprintf (stderr, "sending continuation stream\r\n")); - - if (camel_stream_write_to_stream (cstream, store->ostream) == -1) { - *ret = g_strdup (strerror (errno)); - - return CAMEL_IMAP_FAIL; - } - - data = g_ptr_array_new (); - - while (1) { - CamelStreamBuffer *stream = CAMEL_STREAM_BUFFER (store->istream); - - respbuf = camel_stream_buffer_read_line (stream); - if (!respbuf || *respbuf == '+' || !strncmp (respbuf, cmdid, strlen (cmdid))) { - /* IMAP's last response starts with our command id or a continuation request */ - d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)")); - - break; - } - - d(fprintf (stderr, "received: %s\n", respbuf)); - - g_ptr_array_add (data, respbuf); - len += strlen (respbuf) + 1; - } - - if (respbuf) { - g_ptr_array_add (data, respbuf); - len += strlen (respbuf) + 1; - - switch (*respbuf) { - case '+': - status = CAMEL_IMAP_PLUS; - break; - default: - status = camel_imap_status (cmdid, respbuf); - } - } else { - status = CAMEL_IMAP_FAIL; - } - - if (status == CAMEL_IMAP_OK || status == CAMEL_IMAP_PLUS) { - char *p; - - *ret = g_malloc0 (len + 1); - - for (i = 0, p = *ret; i < data->len; i++) { - char *ptr, *datap; - - datap = (char *) data->pdata[i]; - ptr = (*datap == '.') ? datap + 1 : datap; - len = strlen (ptr); - memcpy (p, ptr, len); - p += len; - *p++ = '\n'; - } - *p = '\0'; - } else { - if (status != CAMEL_IMAP_FAIL && respbuf) { - char *word; - - word = imap_next_word (respbuf); - - if (*respbuf == '-') - *ret = g_strdup (word); - else - *ret = g_strdup (imap_next_word (word)); - } else { + if (camel_remote_store_send_stream (CAMEL_REMOTE_STORE (store), cstream, ex) < 0) { + if (ret) *ret = NULL; - } + return CAMEL_IMAP_FAIL; } - - for (i = 0; i < data->len; i++) - g_free (data->pdata[i]); - g_ptr_array_free (data, TRUE); - - return status; + + return slurp_response (store, NULL, cmdid, ret, TRUE, ex); } diff --git a/camel/providers/imap/camel-imap-store.h b/camel/providers/imap/camel-imap-store.h index fcf0bcaf39..c153b11aa4 100644 --- a/camel/providers/imap/camel-imap-store.h +++ b/camel/providers/imap/camel-imap-store.h @@ -32,7 +32,7 @@ extern "C" { #pragma } #endif /* __cplusplus }*/ -#include "camel-store.h" +#include "camel-remote-store.h" #define CAMEL_IMAP_STORE_TYPE (camel_imap_store_get_type ()) #define CAMEL_IMAP_STORE(obj) (CAMEL_CHECK_CAST((obj), CAMEL_IMAP_STORE_TYPE, CamelImapStore)) @@ -47,7 +47,7 @@ typedef enum { typedef struct { - CamelStore parent_object; + CamelRemoteStore parent_object; CamelFolder *current_folder; CamelStream *istream, *ostream; @@ -64,7 +64,7 @@ typedef struct { typedef struct { - CamelStoreClass parent_class; + CamelRemoteStoreClass parent_class; } CamelImapStoreClass; @@ -83,13 +83,13 @@ enum { CAMEL_IMAP_FAIL }; -gint camel_imap_command (CamelImapStore *store, CamelFolder *folder, char **ret, char *fmt, ...); -gint camel_imap_command_extended (CamelImapStore *store, CamelFolder *folder, char **ret, char *fmt, ...); +gint camel_imap_command (CamelImapStore *store, CamelFolder *folder, CamelException *ex, char *fmt, ...); +gint camel_imap_command_extended (CamelImapStore *store, CamelFolder *folder, char **ret, CamelException *ex, char *fmt, ...); /* multi-transactional commands... */ -gint camel_imap_command_preliminary (CamelImapStore *store, char **ret, char **cmdid, char *fmt, ...); -gint camel_imap_command_continuation (CamelImapStore *store, char **ret, char *cmdid, char *cmdbuf); -gint camel_imap_command_continuation_with_stream (CamelImapStore *store, char **ret, char *cmdid, CamelStream *cstream); +gint camel_imap_command_preliminary (CamelImapStore *store, char **cmdid, CamelException *ex, char *fmt, ...); +gint camel_imap_command_continuation (CamelImapStore *store, char **ret, char *cmdid, char *cmdbuf, CamelException *ex); +gint camel_imap_command_continuation_with_stream (CamelImapStore *store, char **ret, char *cmdid, CamelStream *cstream, CamelException *ex); /* Standard Camel function */ CamelType camel_imap_store_get_type (void); diff --git a/camel/providers/imap/camel-imap-stream.c b/camel/providers/imap/camel-imap-stream.c index fcddd4c0b5..f27e782c0a 100644 --- a/camel/providers/imap/camel-imap-stream.c +++ b/camel/providers/imap/camel-imap-stream.c @@ -23,6 +23,7 @@ #include <config.h> #include "camel-imap-stream.h" +#include "camel/camel-exception.h" #include <sys/types.h> #include <errno.h> #include <stdlib.h> @@ -117,14 +118,18 @@ stream_read (CamelStream *stream, char *buffer, size_t n) if (!imap_stream->cache) { /* We need to send the IMAP command since this is our first fetch */ CamelFolder *folder = CAMEL_FOLDER (imap_stream->folder); + CamelException ex; gchar *result, *p, *q; gint status, part_len; + camel_exception_init (&ex); status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), CAMEL_FOLDER (imap_stream->folder), - &result, "%s\r\n", + &result, &ex, "%s\r\n", imap_stream->command); - + /* FIXME: exception is ignored */ + camel_exception_clear (&ex); + if (!result || status != CAMEL_IMAP_OK) { /* we got an error, dump this stuff */ g_free (result); |