aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Williams <peterw@src.gnome.org>2000-08-30 05:28:46 +0800
committerPeter Williams <peterw@src.gnome.org>2000-08-30 05:28:46 +0800
commitda570c66609a9baea34d4899c4ca7e1f8329d471 (patch)
tree78f82074f39463fc8db0cfb92728d57fe9c2ac84
parentba2eaa68b17882b0fec2eac160f674d29598795f (diff)
downloadgsoc2013-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
-rw-r--r--camel/ChangeLog61
-rw-r--r--camel/Makefile.am2
-rw-r--r--camel/camel-folder.c25
-rw-r--r--camel/camel-folder.h4
-rw-r--r--camel/camel-remote-store.c496
-rw-r--r--camel/camel-remote-store.h79
-rw-r--r--camel/camel-service.c79
-rw-r--r--camel/camel-service.h10
-rw-r--r--camel/camel-session.c2
-rw-r--r--camel/camel-store.c1
-rw-r--r--camel/providers/imap/camel-imap-folder.c197
-rw-r--r--camel/providers/imap/camel-imap-store.c1018
-rw-r--r--camel/providers/imap/camel-imap-store.h16
-rw-r--r--camel/providers/imap/camel-imap-stream.c9
-rw-r--r--camel/providers/mbox/camel-mbox-folder.c14
-rw-r--r--camel/providers/mbox/camel-mbox-store.c3
-rw-r--r--camel/providers/nntp/camel-nntp-folder.c15
-rw-r--r--camel/providers/nntp/camel-nntp-store.c34
-rw-r--r--camel/providers/pop3/camel-pop3-folder.c32
-rw-r--r--camel/providers/pop3/camel-pop3-store.c21
20 files changed, 1216 insertions, 902 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog
index 54c23dc80d..a9e572537e 100644
--- a/camel/ChangeLog
+++ b/camel/ChangeLog
@@ -1,3 +1,27 @@
+2000-08-29 Peter Williams <peterw@helixcode.com>
+
+ * camel-service.c (camel_service_connect): Uncomment this.
+ (camel_service_disconnect): Same.
+
+ * camel-remote-store.[ch]: New files. Abstract remote storages
+ (IMAP, POP3, NNTP) and hides the lower-level networky stuff.
+
+ * camel-service.c (camel_service_new): Take an extra argument, the
+ provider that created us, cause it's useful.
+ (camel_service_finalize): Unref our new provider member.
+
+ * camel-session.c (camel_session_get_service): Pass the proper number of
+ arguments to camel_service_new().
+
+ * camel-imap-store.c: Massive update: 1) use the CamelRemoteService to
+ make our life Very Easy (TM). 2) Change the semantics of all
+ camel_imap_command* functions to take exceptions, centralize tons of
+ duplicate code, and use the handy RemoteStore utility functions
+
+ * camel-imap-folder.c: Use the new semantics of camel_imap_command*
+
+ * camel-imap-stream.c: Same.
+
2000-08-29 Jeffrey Stedfast <fejj@helixcode.com>
* providers/imap/camel-imap-store.c (camel_imap_command_extended):
@@ -14,6 +38,43 @@
(imap_copy_message_to): Updated.
(imap_move_message_to): Updated.
+2000-08-28 Peter Williams <peterw@helixcode.com>
+
+ * camel-folder.c (camel_folder_refresh_info): New member function,
+ refresh_info, used for rereading folder state after its state has
+ somehow become unknown. Tries to preserve last-known status of
+ messages.
+
+ * providers/mbox/camel-mbox-folder.c (mbox_refresh_info): Implement
+ ::refresh_info (split up ::init)
+
+ * providers/mbox/camel-mbox-store.c (get_folder): Call ::refresh_info.
+
+ * providers/imap/camel-imap-folder.c (camel_imap_folder_new): Call
+ ::refresh_info once initialized.
+ (imap_refresh_info): New member function; reads the summary from
+ the server (used to be in camel_imap_folder_new; split out).
+
+ * providers/imap/camel-imap-store.c (imap_connect): Set
+ CamelService::connected a little early so that
+ camel_imap_command won't try to connect while already
+ connnecting.
+ (camel_imap_command*): Try to connect if not connected already.
+
+ * providers/pop3/camel-pop3-folder.c (pop3_refresh_info): Same as above.
+
+ * providers/pop3/camel-pop3-folder.c (camel_pop3_folder_new): Same
+ as above.
+
+ * providers/pop3/camel-pop3-store.c (pop3_connect): Set
+ CamelService::connected a little early so that
+ camel_pop3_command won't try to connect while already
+ connecting
+ (connect_to_server): Same.
+
+ * providers/nntp/camel-nntp-folder.c (nntp_folder_refresh_info): Same
+ as above.
+
2000-08-28 Jeffrey Stedfast <fejj@helixcode.com>
* providers/imap/camel-imap-folder.c (imap_get_message): Fixed the
diff --git a/camel/Makefile.am b/camel/Makefile.am
index 4d2c29a4ca..320f4cc082 100644
--- a/camel/Makefile.am
+++ b/camel/Makefile.am
@@ -40,6 +40,7 @@ libcamel_la_SOURCES = \
camel-multipart.c \
camel-object.c \
camel-provider.c \
+ camel-remote-store.c \
camel-seekable-stream.c \
camel-seekable-substream.c \
camel-service.c \
@@ -87,6 +88,7 @@ libcamelinclude_HEADERS = \
camel-multipart.h \
camel-object.h \
camel-provider.h \
+ camel-remote-store.h \
camel-seekable-stream.h \
camel-seekable-substream.h \
camel-service.h \
diff --git a/camel/camel-folder.c b/camel/camel-folder.c
index 201e2cc778..888845aed8 100644
--- a/camel/camel-folder.c
+++ b/camel/camel-folder.c
@@ -44,6 +44,7 @@ static void init (CamelFolder *folder, CamelStore *parent_store,
static void camel_folder_finalize (CamelObject *object);
+static void refresh_info (CamelFolder *folder, CamelException *ex);
static void folder_sync (CamelFolder *folder, gboolean expunge,
CamelException *ex);
@@ -134,6 +135,7 @@ camel_folder_class_init (CamelFolderClass *camel_folder_class)
/* virtual method definition */
camel_folder_class->init = init;
camel_folder_class->sync = folder_sync;
+ camel_folder_class->refresh_info = refresh_info;
camel_folder_class->get_name = get_name;
camel_folder_class->get_full_name = get_full_name;
camel_folder_class->can_hold_folders = can_hold_folders;
@@ -320,6 +322,29 @@ void camel_folder_sync(CamelFolder * folder, gboolean expunge, CamelException *
CF_CLASS(folder)->sync(folder, expunge, ex);
}
+static void
+refresh_info (CamelFolder *folder, CamelException *ex)
+{
+ g_warning ("CamelFolder::refresh_info not implemented for `%s'",
+ camel_type_to_name (CAMEL_OBJECT_GET_TYPE (folder)));
+}
+
+/**
+ * camel_folder_refresh_info:
+ * @folder: The folder object
+ * @ex: exception object
+ *
+ * Updates a folder's summary to be in sync with its backing store
+ * (called upon creation and when the store's connection is lost
+ * and then reestablished).
+ **/
+void camel_folder_refresh_info (CamelFolder * folder, CamelException * ex)
+{
+ g_return_if_fail(CAMEL_IS_FOLDER(folder));
+
+ CF_CLASS(folder)->refresh_info(folder, ex);
+}
+
static const gchar *get_name(CamelFolder * folder)
{
return folder->name;
diff --git a/camel/camel-folder.h b/camel/camel-folder.h
index da76618b57..c78ed28b61 100644
--- a/camel/camel-folder.h
+++ b/camel/camel-folder.h
@@ -80,6 +80,8 @@ typedef struct {
gchar *separator, gboolean path_begins_with_sep,
CamelException *ex);
+ void (*refresh_info) (CamelFolder *folder, CamelException *ex);
+
void (*sync) (CamelFolder *folder, gboolean expunge,
CamelException *ex);
@@ -194,6 +196,8 @@ CamelFolder * camel_folder_get_subfolder (CamelFolder *folder,
gboolean create,
CamelException *ex);
+void camel_folder_refresh_info (CamelFolder * folder,
+ CamelException * ex);
void camel_folder_sync (CamelFolder *folder,
gboolean expunge,
CamelException *ex);
diff --git a/camel/camel-remote-store.c b/camel/camel-remote-store.c
new file mode 100644
index 0000000000..e86c05e909
--- /dev/null
+++ b/camel/camel-remote-store.c
@@ -0,0 +1,496 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* camel-remote-store.c : class for an remote store */
+
+/*
+ * Authors: Peter Williams <peterw@helixcode.com>
+ * based on camel-imap-provider.c
+ *
+ * Copyright 2000 Helix Code, Inc. (www.helixcode.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#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>
+
+#include "camel-remote-store.h"
+#include "camel-folder.h"
+#include "camel-exception.h"
+#include "camel-session.h"
+#include "camel-stream.h"
+#include "camel-stream-buffer.h"
+#include "camel-stream-fs.h"
+#include "camel-url.h"
+#include "string-utils.h"
+
+#define d(x) x
+
+#define CSRVC(obj) (CAMEL_SERVICE_CLASS (CAMEL_OBJECT_GET_CLASS (obj)))
+#define CSTRC(obj) (CAMEL_STORE_CLASS (CAMEL_OBJECT_GET_CLASS (obj)))
+#define CRSC(obj) (CAMEL_REMOTE_STORE_CLASS (CAMEL_OBJECT_GET_CLASS (obj)))
+
+static CamelStoreClass *store_class = NULL;
+
+static gboolean remote_connect (CamelService *service, CamelException *ex);
+static gboolean remote_disconnect (CamelService *service, CamelException *ex);
+static GList *remote_query_auth_types_generic (CamelService *service, CamelException *ex);
+static GList *remote_query_auth_types_connected (CamelService *service, CamelException *ex);
+static void remote_free_auth_types (CamelService *service, GList *authtypes);
+static char *remote_get_name (CamelService *service, gboolean brief);
+static char *remote_get_folder_name (CamelStore *store,
+ const char *folder_name,
+ CamelException *ex);
+static void remote_post_connect (CamelRemoteStore *store, CamelException *ex);
+static void remote_pre_disconnect (CamelRemoteStore *store, CamelException *ex);
+static gint remote_send_string (CamelRemoteStore *store, CamelException *ex,
+ char *fmt, va_list ap);
+static gint remote_send_stream (CamelRemoteStore *store, CamelStream *stream,
+ CamelException *ex);
+static gint remote_recv_line (CamelRemoteStore *store, char **dest,
+ CamelException *ex);
+
+static void
+camel_remote_store_class_init (CamelRemoteStoreClass *camel_remote_store_class)
+{
+ /* virtual method overload */
+ CamelServiceClass *camel_service_class =
+ CAMEL_SERVICE_CLASS (camel_remote_store_class);
+ CamelStoreClass *camel_store_class =
+ CAMEL_STORE_CLASS (camel_remote_store_class);
+
+ store_class = CAMEL_STORE_CLASS(camel_type_get_global_classfuncs (camel_store_get_type ()));
+
+ /* virtual method overload */
+ camel_service_class->connect = remote_connect;
+ camel_service_class->disconnect = remote_disconnect;
+ camel_service_class->query_auth_types_generic = remote_query_auth_types_generic;
+ camel_service_class->query_auth_types_connected = remote_query_auth_types_connected;
+ camel_service_class->free_auth_types = remote_free_auth_types;
+ camel_service_class->get_name = remote_get_name;
+
+ camel_store_class->get_folder_name = remote_get_folder_name;
+
+ camel_remote_store_class->post_connect = remote_post_connect;
+ camel_remote_store_class->pre_disconnect = remote_pre_disconnect;
+ camel_remote_store_class->send_string = remote_send_string;
+ camel_remote_store_class->send_stream = remote_send_stream;
+ camel_remote_store_class->recv_line = remote_recv_line;
+ camel_remote_store_class->keepalive = NULL;
+}
+
+static void
+camel_remote_store_init (CamelObject *object)
+{
+ CamelService *service = CAMEL_SERVICE (object);
+ CamelStore *store = CAMEL_STORE (object);
+ CamelRemoteStore *remote_store = CAMEL_REMOTE_STORE (object);
+
+ service->url_flags |= CAMEL_SERVICE_URL_NEED_HOST;
+
+ store->folders = g_hash_table_new (g_str_hash, g_str_equal);
+
+ remote_store->istream = NULL;
+ remote_store->ostream = NULL;
+ remote_store->timeout_id = 0;
+}
+
+/*
+ *static void
+ *camel_remote_store_finalize (CamelObject *object)
+ *{
+ * CamelRemoteStore *remote_store = CAMEL_REMOTE_STORE (object);
+ *
+ * g_free (remote_store->nice_name);
+ *}
+ */
+
+CamelType
+camel_remote_store_get_type (void)
+{
+ static CamelType camel_remote_store_type = CAMEL_INVALID_TYPE;
+
+ if (camel_remote_store_type == CAMEL_INVALID_TYPE) {
+ camel_remote_store_type = camel_type_register (CAMEL_STORE_TYPE, "CamelRemoteStore",
+ sizeof (CamelRemoteStore),
+ sizeof (CamelRemoteStoreClass),
+ (CamelObjectClassInitFunc) camel_remote_store_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_remote_store_init,
+ (CamelObjectFinalizeFunc) NULL);
+ }
+
+ return camel_remote_store_type;
+}
+
+/* Auth stuff */
+
+/*
+static CamelServiceAuthType password_authtype = {
+ "SSH Tunneling",
+
+ "This option will connect to the REMOTE server using a "
+ "plaintext password.",
+
+ "",
+ TRUE
+};
+*/
+
+static GList *
+remote_query_auth_types_connected (CamelService *service, CamelException *ex)
+{
+ g_warning ("remote::query_auth_types_connected: not implemented. Defaulting.");
+ return CSRVC (service)->query_auth_types_generic (service, ex);
+}
+
+static GList *
+remote_query_auth_types_generic (CamelService *service, CamelException *ex)
+{
+ g_warning ("remote::query_auth_types_generic: not implemented. Defaulting.");
+ return NULL;
+}
+
+static void
+remote_free_auth_types (CamelService *service, GList *authtypes)
+{
+ g_list_free (authtypes);
+}
+
+static char *
+remote_get_name (CamelService *service, gboolean brief)
+{
+ if (brief)
+ return g_strdup_printf ("%s server %s",
+ service->provider->name,
+ service->url->host);
+ else {
+ return g_strdup_printf ("%s service for %s on %s",
+ service->provider->name,
+ service->url->user,
+ service->url->host);
+ }
+}
+
+static void
+refresh_folder_info (gpointer key, gpointer value, gpointer data)
+{
+ CamelFolder *folder = CAMEL_FOLDER (value);
+
+ camel_folder_refresh_info (folder, (CamelException *) data);
+}
+
+static gboolean
+remote_connect (CamelService *service, CamelException *ex)
+{
+ CamelRemoteStore *store = CAMEL_REMOTE_STORE (service);
+ struct hostent *h;
+ struct sockaddr_in sin;
+ gint fd;
+ gint port;
+
+ h = camel_service_gethost (service, ex);
+ if (!h)
+ return FALSE;
+
+ /* connect to the server */
+ sin.sin_family = h->h_addrtype;
+
+ if (service->url->port)
+ port = service->url->port;
+ else {
+ CamelProvider *prov = camel_service_get_provider (service);
+
+ port = prov->default_ports[CAMEL_PROVIDER_STORE];
+ g_assert (port); /* a remote service MUST define a valid default port */
+ }
+
+ sin.sin_port = htons(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)",
+ port, strerror(errno));
+ if (fd > -1)
+ close (fd);
+
+ return FALSE;
+ }
+
+ /* parent class connect initialization */
+ CAMEL_SERVICE_CLASS (store_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);
+
+ /* Okay, good enough for us */
+ CAMEL_SERVICE (store)->connected = TRUE;
+
+ /* implementation of postconnect */
+ CRSC (store)->post_connect (store, ex);
+
+ if (camel_exception_is_set (ex)) {
+ /* FIXME: the real exception may get overridden? */
+ camel_service_disconnect (CAMEL_SERVICE (store), ex);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean timeout_cb (gpointer data)
+{
+ CRSC (data)->keepalive (CAMEL_REMOTE_STORE (data));
+ return TRUE;
+}
+
+static void
+remote_post_connect (CamelRemoteStore *store, CamelException *ex)
+{
+ /* Add a timeout so that we can hopefully prevent getting disconnected */
+ /* (Only if the implementation supports it) */
+ if (CRSC (store)->keepalive) {
+ CamelSession *session = camel_service_get_session (CAMEL_SERVICE (store));
+
+ store->timeout_id = camel_session_register_timeout (session, 10 * 60 * 1000,
+ timeout_cb,
+ store);
+ }
+
+ /* Let's make sure that any of our folders are brought up to speed */
+ g_hash_table_foreach (CAMEL_STORE (store)->folders, refresh_folder_info, ex);
+}
+
+static void
+remote_pre_disconnect (CamelRemoteStore *store, CamelException *ex)
+{
+ if (store->timeout_id) {
+ camel_session_remove_timeout (camel_service_get_session (CAMEL_SERVICE (store)),
+ store->timeout_id);
+ store->timeout_id = 0;
+ }
+}
+
+static gboolean
+remote_disconnect (CamelService *service, CamelException *ex)
+{
+ CamelRemoteStore *store = CAMEL_REMOTE_STORE (service);
+
+ CRSC (service)->pre_disconnect (store, ex);
+ /* if the exception is set, screw it and dconn anyway */
+
+ if (!CAMEL_SERVICE_CLASS (store_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;
+ }
+
+ return TRUE;
+}
+
+static gchar *
+remote_get_folder_name (CamelStore *store, const char *folder_name, CamelException *ex)
+{
+ return g_strdup (folder_name);
+}
+
+static gint
+remote_send_string (CamelRemoteStore *store, CamelException *ex, char *fmt, va_list ap)
+{
+ gchar *cmdbuf;
+
+ /* Check for connectedness. Failed (or cancelled) operations will
+ * close the connection. */
+
+ if (store->ostream == NULL) {
+ d(g_message ("remote: (send) disconnected, reconnecting."));
+
+ if (!camel_service_connect (CAMEL_SERVICE (store), ex))
+ return -1;
+ }
+
+ /* create the command */
+ cmdbuf = g_strdup_vprintf (fmt, ap);
+
+ d(fprintf (stderr, "sending : \"%s\"\n", cmdbuf));
+
+ if (camel_stream_printf (store->ostream, "%s", cmdbuf) == -1) {
+ g_free (cmdbuf);
+ camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ g_strerror (errno));
+ /* FIXME: exception may be overridden */
+ camel_service_disconnect (CAMEL_SERVICE (store), ex);
+ return -1;
+ }
+ g_free (cmdbuf);
+
+ return 0;
+}
+
+/**
+ * camel_remote_store_send_string: Writes a string to the server
+ * @store: a CamelRemoteStore
+ * @ex: a CamelException
+ * @fmt: the printf-style format to use for creating the string to send
+ * @...: the arguments to the printf string @fmt
+ * Return value: 0 on success, nonzero on error
+ *
+ * Formats the string and sends it to the server.
+ **/
+
+gint
+camel_remote_store_send_string (CamelRemoteStore *store, CamelException *ex,
+ char *fmt, ...)
+{
+ va_list ap;
+ gint ret;
+
+ g_return_val_if_fail (CAMEL_IS_REMOTE_STORE (store), -1);
+ g_return_val_if_fail (fmt, -1);
+
+ va_start (ap, fmt);
+ ret = CRSC (store)->send_string (store, ex, fmt, ap);
+ va_end (ap);
+
+ return ret;
+}
+
+static gint
+remote_send_stream (CamelRemoteStore *store, CamelStream *stream, CamelException *ex)
+{
+ /* Check for connectedness. Failed (or cancelled) operations will
+ * close the connection. */
+
+ if (store->ostream == NULL) {
+ d(g_message ("remote: (sendstream) disconnected, reconnecting."));
+
+ if (!camel_service_connect (CAMEL_SERVICE (store), ex))
+ return -1;
+ }
+
+ d(fprintf (stderr, "(sending stream)\n"));
+
+ if (camel_stream_write_to_stream (stream, store->ostream) < 0) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ g_strerror (errno));
+ /* FIXME: exception may be overridden */
+ camel_service_disconnect (CAMEL_SERVICE (store), ex);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * camel_remote_store_send_stream: Writes a CamelStream to the server
+ * @store: a CamelRemoteStore
+ * @stream: the stream to write
+ * @ex: a CamelException
+ * Return value: 0 on success, nonzero on error
+ *
+ * Sends the stream to the server.
+ **/
+
+gint
+camel_remote_store_send_stream (CamelRemoteStore *store, CamelStream *stream, CamelException *ex)
+{
+ g_return_val_if_fail (CAMEL_IS_REMOTE_STORE (store), -1);
+ g_return_val_if_fail (CAMEL_IS_STREAM (stream), -1);
+
+ return CRSC (store)->send_stream (store, stream, ex);
+}
+
+static gint
+remote_recv_line (CamelRemoteStore *store, char **dest, CamelException *ex)
+{
+ CamelStreamBuffer *stream = CAMEL_STREAM_BUFFER (store->istream);
+
+ (*dest) = NULL;
+
+ /* Check for connectedness. Failed (or cancelled) operations will
+ * close the connection. We can't expect a read to have any
+ * meaning if we reconnect, so always set an exception.
+ */
+
+ if (store->istream == NULL) {
+ g_message ("remote: (recv) disconnected, reconnecting.");
+
+ camel_service_connect (CAMEL_SERVICE (store), ex);
+
+ if (!camel_exception_is_set (ex))
+ camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_NOT_CONNECTED,
+ g_strerror (errno));
+
+ return -1;
+ }
+
+ (*dest) = camel_stream_buffer_read_line (stream);
+
+ if (!(*dest)) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ g_strerror (errno));
+ /* FIXME: exception may be overridden */
+ camel_service_disconnect (CAMEL_SERVICE (store), ex);
+ return -1;
+ }
+
+ d(fprintf (stderr, "received: %s\n", (*dest)));
+
+ return 0;
+}
+
+/**
+ * camel_remote_store_recv_line: Reads a line from the server
+ * @store: a CamelRemoteStore
+ * @dest: a pointer that will be set to the location of a buffer
+ * holding the server's response
+ * @ex: a CamelException
+ * Return value: 0 on success, -1 on error
+ *
+ * Reads a line from the server (terminated by \n or \r\n).
+ **/
+
+gint
+camel_remote_store_recv_line (CamelRemoteStore *store, char **dest,
+ CamelException *ex)
+{
+ g_return_val_if_fail (CAMEL_IS_REMOTE_STORE (store), -1);
+ g_return_val_if_fail (dest, -1);
+
+ return CRSC (store)->recv_line (store, dest, ex);
+}
+
diff --git a/camel/camel-remote-store.h b/camel/camel-remote-store.h
new file mode 100644
index 0000000000..a2b88133f6
--- /dev/null
+++ b/camel/camel-remote-store.h
@@ -0,0 +1,79 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* camel-remote-store.h : class for a remote store */
+
+/*
+ * Authors: Peter Williams <peterw@helixcode.com>
+ *
+ * Copyright (C) 2000 Helix Code, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifndef CAMEL_REMOTE_STORE_H
+#define CAMEL_REMOTE_STORE_H 1
+
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus }*/
+
+#include "camel-store.h"
+
+#define CAMEL_REMOTE_STORE_TYPE (camel_remote_store_get_type ())
+#define CAMEL_REMOTE_STORE(obj) (CAMEL_CHECK_CAST((obj), CAMEL_REMOTE_STORE_TYPE, CamelRemoteStore))
+#define CAMEL_REMOTE_STORE_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_REMOTE_STORE_TYPE, CamelRemoteStoreClass))
+#define CAMEL_IS_REMOTE_STORE(o) (CAMEL_CHECK_TYPE((o), CAMEL_REMOTE_STORE_TYPE))
+
+typedef struct {
+ CamelStore parent_object;
+
+ CamelStream *istream, *ostream;
+ guint timeout_id;
+} CamelRemoteStore;
+
+
+typedef struct {
+ CamelStoreClass parent_class;
+
+ void (*post_connect) (CamelRemoteStore *store, CamelException *ex);
+ void (*pre_disconnect)(CamelRemoteStore *store, CamelException *ex);
+ gint (*send_string) (CamelRemoteStore *store, CamelException *ex,
+ char *fmt, va_list ap);
+ gint (*send_stream) (CamelRemoteStore *store, CamelStream *stream,
+ CamelException *ex);
+ gint (*recv_line) (CamelRemoteStore *store, char **dest,
+ CamelException *ex);
+ void (*keepalive) (CamelRemoteStore *store);
+} CamelRemoteStoreClass;
+
+
+/* Standard Camel function */
+CamelType camel_remote_store_get_type (void);
+
+/* Extra public functions */
+gint camel_remote_store_send_string (CamelRemoteStore *store, CamelException *ex,
+ char *fmt, ...);
+gint camel_remote_store_send_stream (CamelRemoteStore *store, CamelStream *stream,
+ CamelException *ex);
+gint camel_remote_store_recv_line (CamelRemoteStore *store, char **dest,
+ CamelException *ex);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* CAMEL_REMOTE_STORE_H */
diff --git a/camel/camel-service.c b/camel/camel-service.c
index 6554bad5cb..9df7837bf7 100644
--- a/camel/camel-service.c
+++ b/camel/camel-service.c
@@ -151,8 +151,8 @@ check_url (CamelService *service, CamelException *ex)
* Return value: the CamelService, or NULL.
**/
CamelService *
-camel_service_new (CamelType type, CamelSession *session, CamelURL *url,
- CamelException *ex)
+camel_service_new (CamelType type, CamelSession *session, CamelProvider *provider,
+ CamelURL *url, CamelException *ex)
{
CamelService *service;
@@ -171,6 +171,9 @@ camel_service_new (CamelType type, CamelSession *session, CamelURL *url,
service->session = session;
camel_object_ref (CAMEL_OBJECT (session));
+ service->provider = provider;
+ /* don't ref -- providers are not CamelObjects */
+
service->connected = FALSE;
if (!url->empty) {
@@ -205,22 +208,24 @@ service_connect (CamelService *service, CamelException *ex)
*
* Return value: whether or not the connection succeeded
**/
-/**
- *gboolean
- *camel_service_connect (CamelService *service, CamelException *ex)
- *{
- * g_return_val_if_fail (CAMEL_IS_SERVICE (service), FALSE);
- * g_return_val_if_fail (service->session != NULL, FALSE);
- * g_return_val_if_fail (service->url != NULL, FALSE);
- *
- * if (service->connect_level > 0) {
- * service->connect_level++;
- * return TRUE;
- * }
- *
- * return CSERV_CLASS (service)->connect (service, ex);
- *}
- **/
+
+gboolean
+camel_service_connect (CamelService *service, CamelException *ex)
+{
+ g_return_val_if_fail (CAMEL_IS_SERVICE (service), FALSE);
+ g_return_val_if_fail (service->session != NULL, FALSE);
+ g_return_val_if_fail (service->url != NULL, FALSE);
+
+ if (service->connected) {
+ /* But we're still connected, so no exception
+ * and return true.
+ */
+ g_warning ("camel_service_connect: trying to connect to an already connected service");
+ return TRUE;
+ }
+
+ return CSERV_CLASS (service)->connect (service, ex);
+}
static gboolean
service_disconnect (CamelService *service, CamelException *ex)
@@ -244,19 +249,18 @@ service_disconnect (CamelService *service, CamelException *ex)
* Return value: whether or not the disconnection succeeded without
* errors. (Consult @ex if %FALSE.)
**/
-/**
- *gboolean
- *camel_service_disconnect (CamelService *service, CamelException *ex)
- *{
- * if (service->connect_level < 1) {
- * camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_NOT_CONNECTED,
- * "Trying to disconnect from a service that isn't connected");
- * return FALSE;
- * }
- *
- * return CSERV_CLASS (service)->disconnect (service, ex);
- *}
- **/
+
+gboolean
+camel_service_disconnect (CamelService *service, CamelException *ex)
+{
+ if (!service->connected) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_NOT_CONNECTED,
+ "Trying to disconnect from a service that isn't connected");
+ return FALSE;
+ }
+
+ return CSERV_CLASS (service)->disconnect (service, ex);
+}
/**
*static gboolean
@@ -341,6 +345,19 @@ camel_service_get_session (CamelService *service)
return service->session;
}
+/**
+ * camel_service_get_provider:
+ * @service: a service
+ *
+ * Returns the CamelProvider associated with the service.
+ *
+ * Return value: the provider
+ **/
+CamelProvider *
+camel_service_get_provider (CamelService *service)
+{
+ return service->provider;
+}
GList *
query_auth_types_func (CamelService *service, CamelException *ex)
diff --git a/camel/camel-service.h b/camel/camel-service.h
index 3558d5a72b..f229c5e559 100644
--- a/camel/camel-service.h
+++ b/camel/camel-service.h
@@ -36,6 +36,7 @@ extern "C" {
#include <camel/camel-object.h>
#include <camel/camel-url.h>
+#include <camel/camel-provider.h>
#include <netdb.h>
#define CAMEL_SERVICE_TYPE (camel_service_get_type ())
@@ -48,6 +49,7 @@ struct _CamelService {
CamelObject parent_object;
CamelSession *session;
+ CamelProvider *provider;
gboolean connected;
CamelURL *url;
int url_flags;
@@ -109,14 +111,18 @@ typedef struct {
/* public methods */
CamelService * camel_service_new (CamelType type,
CamelSession *session,
+ CamelProvider *provider,
CamelURL *url,
CamelException *ex);
-
+gboolean camel_service_connect (CamelService *service,
+ CamelException *ex);
+gboolean camel_service_disconnect (CamelService *service,
+ CamelException *ex);
char * camel_service_get_url (CamelService *service);
char * camel_service_get_name (CamelService *service,
gboolean brief);
CamelSession * camel_service_get_session (CamelService *service);
-
+CamelProvider * camel_service_get_provider (CamelService *service);
GList * camel_service_query_auth_types (CamelService *service,
CamelException *ex);
void camel_service_free_auth_types (CamelService *service,
diff --git a/camel/camel-session.c b/camel/camel-session.c
index f9f0584294..3454517216 100644
--- a/camel/camel-session.c
+++ b/camel/camel-session.c
@@ -244,7 +244,7 @@ camel_session_get_service (CamelSession *session, const char *url_string,
return service;
}
- service = camel_service_new (provider->object_types[type], session, url, ex);
+ service = camel_service_new (provider->object_types[type], session, provider, url, ex);
if (service) {
g_hash_table_insert (provider->service_cache, url, service);
camel_object_hook_event (CAMEL_OBJECT (service), "finalize", (CamelObjectEventHookFunc) service_cache_remove, session);
diff --git a/camel/camel-store.c b/camel/camel-store.c
index a036d52694..039490c088 100644
--- a/camel/camel-store.c
+++ b/camel/camel-store.c
@@ -370,4 +370,3 @@ camel_store_get_default_folder (CamelStore *store, CamelException *ex)
}
return folder;
}
-
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);
diff --git a/camel/providers/mbox/camel-mbox-folder.c b/camel/providers/mbox/camel-mbox-folder.c
index 00499c1f75..f924d1d4ab 100644
--- a/camel/providers/mbox/camel-mbox-folder.c
+++ b/camel/providers/mbox/camel-mbox-folder.c
@@ -58,9 +58,8 @@ static CamelFolderClass *parent_class = NULL;
static void mbox_init(CamelFolder *folder, CamelStore * parent_store,
CamelFolder *parent_folder, const gchar * name,
-
gchar * separator, gboolean path_begins_with_sep, CamelException *ex);
-
+static void mbox_refresh_info (CamelFolder *folder, CamelException *ex);
static void mbox_sync(CamelFolder *folder, gboolean expunge, CamelException *ex);
static gint mbox_get_message_count(CamelFolder *folder);
static gint mbox_get_unread_message_count(CamelFolder *folder);
@@ -100,6 +99,7 @@ camel_mbox_folder_class_init(CamelMboxFolderClass * camel_mbox_folder_class)
/* virtual method overload */
camel_folder_class->init = mbox_init;
+ camel_folder_class->refresh_info = mbox_refresh_info;
camel_folder_class->sync = mbox_sync;
camel_folder_class->get_message_count = mbox_get_message_count;
camel_folder_class->get_unread_message_count = mbox_get_unread_message_count;
@@ -167,8 +167,6 @@ mbox_init(CamelFolder *folder, CamelStore * parent_store,
CamelMboxFolder *mbox_folder = (CamelMboxFolder *) folder;
const gchar *root_dir_path;
gchar *real_name;
- int forceindex;
- struct stat st;
/* call parent method */
parent_class->init(folder, parent_store, parent_folder, name, separator, path_begins_with_sep, ex);
@@ -202,6 +200,14 @@ mbox_init(CamelFolder *folder, CamelStore * parent_store,
mbox_folder->summary_file_path = g_strdup_printf("%s/%s-ev-summary", root_dir_path, real_name);
mbox_folder->folder_dir_path = g_strdup_printf("%s/%s.sdb", root_dir_path, real_name);
mbox_folder->index_file_path = g_strdup_printf("%s/%s.ibex", root_dir_path, real_name);
+}
+
+static void
+mbox_refresh_info (CamelFolder *folder, CamelException *ex)
+{
+ CamelMboxFolder *mbox_folder = (CamelMboxFolder *) folder;
+ struct stat st;
+ int forceindex;
/* if we have no index file, force it */
forceindex = stat(mbox_folder->index_file_path, &st) == -1;
diff --git a/camel/providers/mbox/camel-mbox-store.c b/camel/providers/mbox/camel-mbox-store.c
index ed56e84407..05e5af406b 100644
--- a/camel/providers/mbox/camel-mbox-store.c
+++ b/camel/providers/mbox/camel-mbox-store.c
@@ -155,7 +155,8 @@ get_folder (CamelStore *store, const char *folder_name, gboolean create,
CF_CLASS (new_folder)->init (new_folder, store, NULL,
folder_name, "/", TRUE, ex);
-
+ CF_CLASS (new_folder)->refresh_info (new_folder, ex);
+
return new_folder;
}
diff --git a/camel/providers/nntp/camel-nntp-folder.c b/camel/providers/nntp/camel-nntp-folder.c
index 091d35e591..371c4698e2 100644
--- a/camel/providers/nntp/camel-nntp-folder.c
+++ b/camel/providers/nntp/camel-nntp-folder.c
@@ -63,7 +63,6 @@ nntp_folder_init (CamelFolder *folder, CamelStore *parent_store,
gchar *separator, gboolean path_begins_with_sep,
CamelException *ex)
{
- const gchar *root_dir_path;
CamelNNTPFolder *nntp_folder = CAMEL_NNTP_FOLDER (folder);
/* call parent method */
@@ -93,12 +92,19 @@ nntp_folder_init (CamelFolder *folder, CamelStore *parent_store,
if (!(nntp_load_uid_list (nntp_folder) > 0))
nntp_generate_uid_list (nntp_folder);
#endif
+}
- root_dir_path = camel_nntp_store_get_toplevel_dir (CAMEL_NNTP_STORE(folder->parent_store));
-
+static void
+nntp_refresh_info (CamelFolder *folder, CamelException *ex)
+{
+ CamelNNTPFolder *nntp_folder = CAMEL_NNTP_FOLDER (folder);
/* load the summary if we have that ability */
if (folder->has_summary_capability) {
+ const gchar *root_dir_path;
+
+ root_dir_path = camel_nntp_store_get_toplevel_dir (CAMEL_NNTP_STORE(folder->parent_store));
+
nntp_folder->summary_file_path = g_strdup_printf ("%s/%s-ev-summary",
root_dir_path,
nntp_folder->group_name);
@@ -118,8 +124,6 @@ nntp_folder_init (CamelFolder *folder, CamelStore *parent_store,
camel_folder_summary_save (nntp_folder->summary);
}
}
-
-
}
static void
@@ -364,6 +368,7 @@ camel_nntp_folder_class_init (CamelNNTPFolderClass *camel_nntp_folder_class)
/* virtual method overload */
camel_folder_class->init = nntp_folder_init;
+ camel_folder_class->refresh_info = nntp_refresh_info;
camel_folder_class->sync = nntp_folder_sync;
camel_folder_class->get_subfolder = nntp_folder_get_subfolder;
camel_folder_class->get_message_count = nntp_folder_get_message_count;
diff --git a/camel/providers/nntp/camel-nntp-store.c b/camel/providers/nntp/camel-nntp-store.c
index c412c0f6a3..5c9475ed14 100644
--- a/camel/providers/nntp/camel-nntp-store.c
+++ b/camel/providers/nntp/camel-nntp-store.c
@@ -176,6 +176,8 @@ nntp_store_get_folder (CamelStore *store, const gchar *folder_name,
CF_CLASS (new_folder)->init (new_folder, store, NULL,
folder_name, ".", FALSE, ex);
+ CF_CLASS (new_folder)->refresh_info (new_folder, ex);
+
return new_folder;
}
@@ -271,21 +273,22 @@ camel_nntp_command (CamelNNTPStore *store, char **ret, char *fmt, ...)
va_list ap;
int status;
int resp_code;
- CamelException *ex;
va_start (ap, fmt);
cmdbuf = g_strdup_vprintf (fmt, ap);
va_end (ap);
- ex = camel_exception_new();
-
/* make sure we're connected */
- if (store->ostream == NULL)
- nntp_store_connect (CAMEL_SERVICE (store), ex);
-
- if (camel_exception_get_id (ex)) {
- camel_exception_free (ex);
- return CAMEL_NNTP_FAIL;
+ if (store->ostream == NULL) {
+ CamelException ex;
+
+ camel_exception_init (&ex);
+ nntp_store_connect (CAMEL_SERVICE (store), &ex);
+ if (camel_exception_get_id (&ex)) {
+ camel_exception_clear (&ex);
+ return CAMEL_NNTP_FAIL;
+ }
+ camel_exception_clear (&ex);
}
/* Send the command */
@@ -344,6 +347,19 @@ camel_nntp_command_get_additional_data (CamelNNTPStore *store)
char *buf;
int i, status = CAMEL_NNTP_OK;
+ /* make sure we're connected */
+ if (store->ostream == NULL) {
+ CamelException ex;
+
+ camel_exception_init (&ex);
+ nntp_store_connect (CAMEL_SERVICE (store), &ex);
+ if (camel_exception_get_id (&ex)) {
+ camel_exception_clear (&ex);
+ return NULL;
+ }
+ camel_exception_clear (&ex);
+ }
+
data = g_ptr_array_new ();
while (1) {
buf = camel_stream_buffer_read_line (stream);
diff --git a/camel/providers/pop3/camel-pop3-folder.c b/camel/providers/pop3/camel-pop3-folder.c
index 6dbba64c20..43c8d9a958 100644
--- a/camel/providers/pop3/camel-pop3-folder.c
+++ b/camel/providers/pop3/camel-pop3-folder.c
@@ -38,6 +38,7 @@ static CamelFolderClass *parent_class;
static void pop3_finalize (CamelObject *object);
+static void pop3_refresh_info (CamelFolder *folder, CamelException *ex);
static void pop3_sync (CamelFolder *folder, gboolean expunge,
CamelException *ex);
@@ -60,6 +61,7 @@ camel_pop3_folder_class_init (CamelPop3FolderClass *camel_pop3_folder_class)
parent_class = CAMEL_FOLDER_CLASS(camel_type_get_global_classfuncs (camel_folder_get_type ()));
/* virtual method overload */
+ camel_folder_class->refresh_info = pop3_refresh_info;
camel_folder_class->sync = pop3_sync;
camel_folder_class->get_message_count = pop3_get_message_count;
@@ -111,21 +113,36 @@ pop3_finalize (CamelObject *object)
CamelFolder *
camel_pop3_folder_new (CamelStore *parent, CamelException *ex)
{
- CamelPop3Store *pop3_store = CAMEL_POP3_STORE (parent);
CamelPop3Folder *pop3_folder;
+
+ pop3_folder = CAMEL_POP3_FOLDER(camel_object_new (CAMEL_POP3_FOLDER_TYPE));
+ CF_CLASS (pop3_folder)->init ((CamelFolder *)pop3_folder, parent,
+ NULL, "inbox", "/", TRUE, ex);
+ pop3_folder->uids = NULL;
+ pop3_folder->flags = NULL;
+ CF_CLASS (pop3_folder)->refresh_info ((CamelFolder *)pop3_folder, ex);
+
+ return (CamelFolder *)pop3_folder;
+}
+
+static void
+pop3_refresh_info (CamelFolder *folder, CamelException *ex)
+{
GPtrArray *uids;
int status, count;
char *data;
+ CamelPop3Folder *pop3_folder = (CamelPop3Folder *) folder;
+ CamelPop3Store *pop3_store = CAMEL_POP3_STORE (folder->parent_store);
status = camel_pop3_command (pop3_store, &data, "STAT");
if (status != CAMEL_POP3_OK) {
- CamelService *service = CAMEL_SERVICE (parent);
+ CamelService *service = CAMEL_SERVICE (pop3_store);
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
"Could not get message count from POP "
"server %s: %s.", service->url->host,
data ? data : "Unknown error");
g_free (data);
- return NULL;
+ return;
}
count = atoi (data);
@@ -148,7 +165,7 @@ camel_pop3_folder_new (CamelStore *parent, CamelException *ex)
} else {
data = camel_pop3_command_get_additional_data (pop3_store, ex);
if (camel_exception_is_set (ex))
- return NULL;
+ return;
uids = parse_listing (count, data);
g_free (data);
@@ -157,17 +174,12 @@ camel_pop3_folder_new (CamelStore *parent, CamelException *ex)
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
"Could not open folder: message "
"listing was incomplete.");
- return NULL;
+ return;
}
}
- pop3_folder = CAMEL_POP3_FOLDER(camel_object_new (CAMEL_POP3_FOLDER_TYPE));
- CF_CLASS (pop3_folder)->init ((CamelFolder *)pop3_folder, parent,
- NULL, "inbox", "/", TRUE, ex);
pop3_folder->uids = uids;
pop3_folder->flags = g_new0 (guint32, uids->len);
-
- return (CamelFolder *)pop3_folder;
}
static void
diff --git a/camel/providers/pop3/camel-pop3-store.c b/camel/providers/pop3/camel-pop3-store.c
index 4f618e521e..6ee7361959 100644
--- a/camel/providers/pop3/camel-pop3-store.c
+++ b/camel/providers/pop3/camel-pop3-store.c
@@ -277,6 +277,9 @@ connect_to_server (CamelService *service, gboolean real, CamelException *ex)
store->supports_uidl = -1;
store->expires = -1;
+ /* good enough for us */
+ service->connected = TRUE;
+
status = camel_pop3_command (store, NULL, "CAPA");
if (status == CAMEL_POP3_OK) {
char *p;
@@ -285,6 +288,7 @@ connect_to_server (CamelService *service, gboolean real, CamelException *ex)
buf = camel_pop3_command_get_additional_data (store, ex);
if (camel_exception_is_set (ex)) {
pop3_disconnect (service, ex);
+ service->connected = FALSE;
return FALSE;
}
@@ -534,6 +538,7 @@ pop3_connect (CamelService *service, CamelException *ex)
if (camel_exception_is_set (ex)) {
pop3_disconnect (service, NULL);
+ service->connected = FALSE;
return FALSE;
}
@@ -628,6 +633,21 @@ camel_pop3_command (CamelPop3Store *store, char **ret, char *fmt, ...)
char *cmdbuf;
va_list ap;
+ /* Check for connectedness. Failed (or cancelled) operations will
+ * close the connection. */
+ if (CAMEL_SERVICE (store)->connected == FALSE) {
+ CamelException ex;
+
+ d(g_message ("pop3: disconnected, reconnecting."));
+ camel_exception_init (&ex);
+ CAMEL_SERVICE_CLASS (CAMEL_OBJECT_GET_CLASS (store))->connect (store, &ex);
+ if (camel_exception_is_set (&ex)) {
+ camel_exception_clear (&ex);
+ return CAMEL_POP3_FAIL;
+ }
+ camel_exception_clear (&ex);
+ }
+
if (!store->ostream) {
/*CamelException ex;
*
@@ -769,3 +789,4 @@ camel_pop3_command_get_additional_data (CamelPop3Store *store, CamelException *e
return buf;
}
+