summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@src.gnome.org>2001-09-27 14:39:39 +0000
committerDan Winship <danw@src.gnome.org>2001-09-27 14:39:39 +0000
commit3a83eabc1bdc9a4638df3946b4904588924ddf7d (patch)
tree399c54b6a27ce6bfcdcce555f51aa16581fa96fb
parent4f9d3e49e9fb6e5e08a7dadf52cfd78da4945fbb (diff)
downloadevolution-data-server-3a83eabc1bdc9a4638df3946b4904588924ddf7d.tar.gz
Change "gboolean connected" to "CamelServiceConnectionStatus status",
* camel-service.c: Change "gboolean connected" to "CamelServiceConnectionStatus status", which can be disconnected, connecting, connected, or disconnecting. (camel_service_init, camel_service_finalize): create/destroy the connect_op_lock. Refer to service->status rather than service->connected. (camel_service_connect): When connecting, note the current operation (and create a new one if there's none registered) and mark the connection "connecting" until we succeed or fail. (camel_service_disconnect): Likewise in reverse. (camel_service_cancel_connect): New function to cancel a connection attempt. (cancel_connect): Default implementation: Call camel_operation_cancel on the connect_op. * camel-disco-store.c (disco_connect): Only call CamelRemoteStore's connect func if we're online. (disco_cancel_connect): Fall back to offline if a connection gets cancelled. (disco_get_folder_info): Kludge: call connect explicitly before deciding whether to do the online or offline version, so if the connect fails, we fall back correctly. * camel-session.c (camel_session_get_service_connected): s/svc->connected/svc->status/ * camel-remote-store.c (camel_remote_store_finalise): Change service->connected check to service->status check. (remote_connect): Don't set service->connected here: camel_service_connect() itself does that. * camel-operation.c (camel_operation_registered): Deal with the possibility that there's no registered op.
-rw-r--r--camel/ChangeLog36
-rw-r--r--camel/camel-disco-store.c41
-rw-r--r--camel/camel-operation.c9
-rw-r--r--camel/camel-private.h1
-rw-r--r--camel/camel-remote-store.c5
-rw-r--r--camel/camel-service.c82
-rw-r--r--camel/camel-service.h13
-rw-r--r--camel/camel-session.c2
8 files changed, 160 insertions, 29 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog
index b4c552572..3c0abde3f 100644
--- a/camel/ChangeLog
+++ b/camel/ChangeLog
@@ -1,3 +1,39 @@
+2001-09-27 Dan Winship <danw@ximian.com>
+
+ * camel-service.c: Change "gboolean connected" to
+ "CamelServiceConnectionStatus status", which can be disconnected,
+ connecting, connected, or disconnecting.
+ (camel_service_init, camel_service_finalize): create/destroy the
+ connect_op_lock. Refer to service->status rather than
+ service->connected.
+ (camel_service_connect): When connecting, note the current
+ operation (and create a new one if there's none registered) and
+ mark the connection "connecting" until we succeed or fail.
+ (camel_service_disconnect): Likewise in reverse.
+ (camel_service_cancel_connect): New function to cancel a
+ connection attempt.
+ (cancel_connect): Default implementation: Call
+ camel_operation_cancel on the connect_op.
+
+ * camel-disco-store.c (disco_connect): Only call
+ CamelRemoteStore's connect func if we're online.
+ (disco_cancel_connect): Fall back to offline if a connection gets
+ cancelled.
+ (disco_get_folder_info): Kludge: call connect explicitly before
+ deciding whether to do the online or offline version, so if the
+ connect fails, we fall back correctly.
+
+ * camel-session.c (camel_session_get_service_connected):
+ s/svc->connected/svc->status/
+
+ * camel-remote-store.c (camel_remote_store_finalise):
+ Change service->connected check to service->status check.
+ (remote_connect): Don't set service->connected here:
+ camel_service_connect() itself does that.
+
+ * camel-operation.c (camel_operation_registered): Deal with the
+ possibility that there's no registered op.
+
2001-09-26 <NotZed@Ximian.com>
* camel-filter-driver.c (camel_filter_driver_filter_message): If
diff --git a/camel/camel-disco-store.c b/camel/camel-disco-store.c
index 0cc5f4fee..145636f58 100644
--- a/camel/camel-disco-store.c
+++ b/camel/camel-disco-store.c
@@ -39,6 +39,7 @@ static void disco_construct (CamelService *service, CamelSession *session,
CamelProvider *provider, CamelURL *url,
CamelException *ex);
static gboolean disco_connect (CamelService *service, CamelException *ex);
+static void disco_cancel_connect (CamelService *service);
static gboolean disco_disconnect (CamelService *service, gboolean clean, CamelException *ex);
static CamelFolder *disco_get_folder (CamelStore *store, const char *name,
guint32 flags, CamelException *ex);
@@ -68,6 +69,7 @@ camel_disco_store_class_init (CamelDiscoStoreClass *camel_disco_store_class)
camel_service_class->construct = disco_construct;
camel_service_class->connect = disco_connect;
camel_service_class->disconnect = disco_disconnect;
+ camel_service_class->cancel_connect = disco_cancel_connect;
camel_store_class->get_folder = disco_get_folder;
camel_store_class->get_folder_info = disco_get_folder_info;
@@ -111,11 +113,19 @@ static gboolean
disco_connect (CamelService *service, CamelException *ex)
{
CamelDiscoStore *store = CAMEL_DISCO_STORE (service);
+ CamelDiscoStoreStatus status;
+
+ status = camel_disco_store_status (store);
+ if (status != CAMEL_DISCO_STORE_OFFLINE) {
+ if (!CAMEL_SERVICE_CLASS (remote_store_class)->connect (service, ex)) {
+ status = camel_disco_store_status (store);
+ if (status != CAMEL_DISCO_STORE_OFFLINE)
+ return FALSE;
+ camel_exception_clear (ex);
+ }
+ }
- if (!CAMEL_SERVICE_CLASS (remote_store_class)->connect (service, ex))
- return FALSE;
-
- switch (camel_disco_store_status (store)) {
+ switch (status) {
case CAMEL_DISCO_STORE_ONLINE:
case CAMEL_DISCO_STORE_RESYNCING:
if (!CDS_CLASS (service)->connect_online (service, ex))
@@ -142,6 +152,17 @@ disco_connect (CamelService *service, CamelException *ex)
return FALSE;
}
+static void
+disco_cancel_connect (CamelService *service)
+{
+ CamelDiscoStore *store = CAMEL_DISCO_STORE (service);
+
+ /* Fall back */
+ store->status = CAMEL_DISCO_STORE_OFFLINE;
+
+ CAMEL_SERVICE_CLASS (remote_store_class)->cancel_connect (service);
+}
+
static gboolean
disco_disconnect (CamelService *service, gboolean clean, CamelException *ex)
{
@@ -190,7 +211,17 @@ disco_get_folder_info (CamelStore *store, const char *top,
guint32 flags, CamelException *ex)
{
CamelDiscoStore *disco_store = CAMEL_DISCO_STORE (store);
-
+
+ /* Do this first so if we get forced offline, we'll switch to
+ * the correct branch below. (FIXME: This only works because
+ * we know that get_folder_info is the first call that the
+ * mailer makes on a store.)
+ */
+ if (CAMEL_SERVICE (store)->status == CAMEL_SERVICE_DISCONNECTED) {
+ if (!camel_service_connect (CAMEL_SERVICE (store), ex))
+ return NULL;
+ }
+
switch (camel_disco_store_status (disco_store)) {
case CAMEL_DISCO_STORE_ONLINE:
return CDS_CLASS (store)->get_folder_info_online (store, top, flags, ex);
diff --git a/camel/camel-operation.c b/camel/camel-operation.c
index 42aa44882..95d8fa0f9 100644
--- a/camel/camel-operation.c
+++ b/camel/camel-operation.c
@@ -105,10 +105,13 @@ CamelOperation *camel_operation_registered(void)
CamelOperation *cc = NULL;
CAMEL_ACTIVE_LOCK();
- if (operation_active != NULL)
+ if (operation_active != NULL) {
cc = g_hash_table_lookup(operation_active, (void *)pthread_self());
- g_assert(cc->refcount > 0);
- cc->refcount++;
+ if (cc) {
+ g_assert(cc->refcount > 0);
+ cc->refcount++;
+ }
+ }
CAMEL_ACTIVE_UNLOCK();
return cc;
diff --git a/camel/camel-private.h b/camel/camel-private.h
index 32cde5306..73a1b7bfc 100644
--- a/camel/camel-private.h
+++ b/camel/camel-private.h
@@ -90,6 +90,7 @@ struct _CamelTransportPrivate {
struct _CamelServicePrivate {
#ifdef ENABLE_THREADS
EMutex *connect_lock; /* for locking connection operations */
+ EMutex *connect_op_lock;/* for locking the connection_op */
#endif
};
diff --git a/camel/camel-remote-store.c b/camel/camel-remote-store.c
index 00f8dce4f..e1818e47c 100644
--- a/camel/camel-remote-store.c
+++ b/camel/camel-remote-store.c
@@ -129,7 +129,7 @@ camel_remote_store_finalise (CamelObject *object)
CamelRemoteStore *remote_store = CAMEL_REMOTE_STORE (object);
CamelService *service = CAMEL_SERVICE (object);
- if (service->connected) {
+ if (service->status == CAMEL_SERVICE_CONNECTED) {
CamelException ex;
camel_exception_init (&ex);
@@ -277,9 +277,6 @@ remote_connect (CamelService *service, CamelException *ex)
store->ostream = tcp_stream;
store->istream = camel_stream_buffer_new (tcp_stream, CAMEL_STREAM_BUFFER_READ);
- /* Okay, good enough for us */
- CAMEL_SERVICE (store)->connected = TRUE;
-
/* Add a timeout so that we can hopefully prevent getting disconnected */
/* (Only if the implementation supports it) */
if (CRSC (store)->keepalive) {
diff --git a/camel/camel-service.c b/camel/camel-service.c
index 27d6a5bbe..cc254e1f2 100644
--- a/camel/camel-service.c
+++ b/camel/camel-service.c
@@ -59,7 +59,7 @@ static void construct (CamelService *service, CamelSession *session,
static gboolean service_connect(CamelService *service, CamelException *ex);
static gboolean service_disconnect(CamelService *service, gboolean clean,
CamelException *ex);
-/*static gboolean is_connected (CamelService *service);*/
+static void cancel_connect (CamelService *service);
static GList * query_auth_types (CamelService *service, CamelException *ex);
static char * get_name (CamelService *service, gboolean brief);
static char * get_path (CamelService *service);
@@ -74,6 +74,7 @@ camel_service_class_init (CamelServiceClass *camel_service_class)
camel_service_class->construct = construct;
camel_service_class->connect = service_connect;
camel_service_class->disconnect = service_disconnect;
+ camel_service_class->cancel_connect = cancel_connect;
camel_service_class->query_auth_types = query_auth_types;
camel_service_class->get_name = get_name;
camel_service_class->get_path = get_path;
@@ -87,6 +88,7 @@ camel_service_init (void *o, void *k)
service->priv = g_malloc0(sizeof(*service->priv));
#ifdef ENABLE_THREADS
service->priv->connect_lock = e_mutex_new(E_MUTEX_REC);
+ service->priv->connect_op_lock = e_mutex_new(E_MUTEX_SIMPLE);
#endif
}
@@ -95,7 +97,7 @@ camel_service_finalize (CamelObject *object)
{
CamelService *service = CAMEL_SERVICE (object);
- if (service->connected) {
+ if (service->status == CAMEL_SERVICE_CONNECTED) {
CamelException ex;
camel_exception_init (&ex);
@@ -114,6 +116,7 @@ camel_service_finalize (CamelObject *object)
#ifdef ENABLE_THREADS
e_mutex_destroy (service->priv->connect_lock);
+ e_mutex_destroy (service->priv->connect_op_lock);
#endif
g_free (service->priv);
}
@@ -178,7 +181,7 @@ construct (CamelService *service, CamelSession *session,
service->session = session;
camel_object_ref (CAMEL_OBJECT (session));
- service->connected = FALSE;
+ service->status = CAMEL_SERVICE_DISCONNECTED;
}
/**
@@ -234,17 +237,30 @@ camel_service_connect (CamelService *service, CamelException *ex)
CAMEL_SERVICE_LOCK (service, connect_lock);
- 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");
- ret = TRUE;
- } else if (CSERV_CLASS (service)->connect (service, ex)) {
- service->connected = TRUE;
- ret = TRUE;
+ if (service->status == CAMEL_SERVICE_CONNECTED) {
+ CAMEL_SERVICE_UNLOCK (service, connect_lock);
+ return TRUE;
}
-
+
+ /* Register a separate operation for connecting, so that
+ * the offline code can cancel it.
+ */
+ CAMEL_SERVICE_LOCK (service, connect_op_lock);
+ service->connect_op = camel_operation_registered ();
+ if (!service->connect_op)
+ service->connect_op = camel_operation_new (NULL, NULL);
+ camel_operation_register (service->connect_op);
+ CAMEL_SERVICE_UNLOCK (service, connect_op_lock);
+
+ service->status = CAMEL_SERVICE_CONNECTING;
+ ret = CSERV_CLASS (service)->connect (service, ex);
+ service->status = ret ? CAMEL_SERVICE_CONNECTED : CAMEL_SERVICE_DISCONNECTED;
+
+ CAMEL_SERVICE_LOCK (service, connect_op_lock);
+ camel_operation_unref (service->connect_op);
+ service->connect_op = NULL;
+ CAMEL_SERVICE_UNLOCK (service, connect_op_lock);
+
CAMEL_SERVICE_UNLOCK (service, connect_lock);
return ret;
@@ -282,9 +298,22 @@ camel_service_disconnect (CamelService *service, gboolean clean,
CAMEL_SERVICE_LOCK (service, connect_lock);
- if (service->connected) {
+ if (service->status == CAMEL_SERVICE_CONNECTED) {
+ CAMEL_SERVICE_LOCK (service, connect_op_lock);
+ service->connect_op = camel_operation_registered ();
+ if (!service->connect_op)
+ service->connect_op = camel_operation_new (NULL, NULL);
+ camel_operation_register (service->connect_op);
+ CAMEL_SERVICE_UNLOCK (service, connect_op_lock);
+
+ service->status = CAMEL_SERVICE_DISCONNECTING;
res = CSERV_CLASS (service)->disconnect (service, clean, ex);
- service->connected = FALSE;
+ service->status = CAMEL_SERVICE_DISCONNECTED;
+
+ CAMEL_SERVICE_LOCK (service, connect_op_lock);
+ camel_operation_unref (service->connect_op);
+ service->connect_op = NULL;
+ CAMEL_SERVICE_UNLOCK (service, connect_op_lock);
}
CAMEL_SERVICE_UNLOCK (service, connect_lock);
@@ -292,6 +321,29 @@ camel_service_disconnect (CamelService *service, gboolean clean,
return res;
}
+static void
+cancel_connect (CamelService *service)
+{
+ camel_operation_cancel (service->connect_op);
+}
+
+/**
+ * camel_service_cancel_connect:
+ * @service: a service
+ *
+ * If @service is currently attempting to connect to or disconnect
+ * from a server, this causes it to stop and fail. Otherwise it is a
+ * no-op.
+ **/
+void
+camel_service_cancel_connect (CamelService *service)
+{
+ CAMEL_SERVICE_LOCK (service, connect_op_lock);
+ if (service->connect_op)
+ CSERV_CLASS (service)->cancel_connect (service);
+ CAMEL_SERVICE_UNLOCK (service, connect_op_lock);
+}
+
/**
* camel_service_get_url:
* @service: a service
diff --git a/camel/camel-service.h b/camel/camel-service.h
index 41ac53c4c..a4399811c 100644
--- a/camel/camel-service.h
+++ b/camel/camel-service.h
@@ -38,6 +38,7 @@ extern "C" {
#include <camel/camel-object.h>
#include <camel/camel-url.h>
#include <camel/camel-provider.h>
+#include <camel/camel-operation.h>
#define CAMEL_SERVICE_TYPE (camel_service_get_type ())
#define CAMEL_SERVICE(obj) (CAMEL_CHECK_CAST((obj), CAMEL_SERVICE_TYPE, CamelService))
@@ -45,13 +46,21 @@ extern "C" {
#define CAMEL_IS_SERVICE(o) (CAMEL_CHECK_TYPE((o), CAMEL_SERVICE_TYPE))
+typedef enum {
+ CAMEL_SERVICE_DISCONNECTED,
+ CAMEL_SERVICE_CONNECTING,
+ CAMEL_SERVICE_CONNECTED,
+ CAMEL_SERVICE_DISCONNECTING
+} CamelServiceConnectionStatus;
+
struct _CamelService {
CamelObject parent_object;
struct _CamelServicePrivate *priv;
CamelSession *session;
CamelProvider *provider;
- gboolean connected;
+ CamelServiceConnectionStatus status;
+ CamelOperation *connect_op;
CamelURL *url;
};
@@ -70,6 +79,7 @@ typedef struct {
gboolean (*disconnect) (CamelService *service,
gboolean clean,
CamelException *ex);
+ void (*cancel_connect) (CamelService *service);
GList * (*query_auth_types) (CamelService *service,
CamelException *ex);
@@ -102,6 +112,7 @@ gboolean camel_service_connect (CamelService *service,
gboolean camel_service_disconnect (CamelService *service,
gboolean clean,
CamelException *ex);
+void camel_service_cancel_connect (CamelService *service);
char * camel_service_get_url (CamelService *service);
char * camel_service_get_name (CamelService *service,
gboolean brief);
diff --git a/camel/camel-session.c b/camel/camel-session.c
index 7f7fbe7a5..facedb940 100644
--- a/camel/camel-session.c
+++ b/camel/camel-session.c
@@ -480,7 +480,7 @@ camel_session_get_service_connected (CamelSession *session,
if (svc == NULL)
return NULL;
- if (svc->connected == FALSE) {
+ if (svc->status != CAMEL_SERVICE_CONNECTED) {
if (camel_service_connect (svc, ex) == FALSE) {
camel_object_unref (CAMEL_OBJECT (svc));
return NULL;