aboutsummaryrefslogtreecommitdiffstats
path: root/camel
diff options
context:
space:
mode:
Diffstat (limited to 'camel')
-rw-r--r--camel/ChangeLog30
-rw-r--r--camel/providers/imap4/camel-imap-engine.c25
-rw-r--r--camel/providers/imap4/camel-imap-specials.c6
-rw-r--r--camel/providers/imap4/camel-imap-store.c827
-rw-r--r--camel/providers/imap4/camel-imap-store.h61
5 files changed, 914 insertions, 35 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog
index 919c647fc9..b73acb5484 100644
--- a/camel/ChangeLog
+++ b/camel/ChangeLog
@@ -1,5 +1,18 @@
2004-03-25 Jeffrey Stedfast <fejj@ximian.com>
+ * providers/imap4/camel-imap-engine.c
+ (camel_imap_engine_parse_resp_code): No longer need to split ']'
+ tokens from atom tokens due to a fixup in the ABNF grammar in
+ rfc3501.
+
+ * providers/imap4/camel-imap-specials.c: Changed ATOM_SPECIALS to
+ include ']' (this is an addition in rfc3501).
+
+ * providers/imap4/camel-imap-store.[c,h]: New Store class for
+ IMAP. Implemnted a bunch of but still got a ways to go.
+
+2004-03-25 Jeffrey Stedfast <fejj@ximian.com>
+
* providers/imap/camel-imap-folder.c (imap_update_summary): If the
server is imap.web.de, just ask for all the headers rather than
"HEADER.FIELDS.NOT (RECEIVED)". Actually, maybe we should always
@@ -31,14 +44,15 @@
from the provider description
2004-03-25 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * providers/groupwise/camel-groupwise-provider.c : removed
- ldap seetings and added a settng for SOAP port
- * providers/groupwise/camel-gw-listner.h (add_calendar_tasks_sources)
- (remove_calendar_tasks_sources), (modify_calendar_tasks_sources) : read port number
- from url instead of hardcoding
- Also removed code for adding e-sources for ldap address book and
- adding now e-sources for groupwise address book
+
+ * providers/groupwise/camel-groupwise-provider.c: removed ldap
+ seetings and added a settng for SOAP port
+
+ * providers/groupwise/camel-gw-listner.h
+ (add_calendar_tasks_sources, remove_calendar_tasks_sources),
+ (modify_calendar_tasks_sources): read port number from url instead
+ of hardcoding. Also removed code for adding e-sources for ldap
+ address book and adding now e-sources for groupwise address book
2004-03-24 Jeffrey Stedfast <fejj@ximian.com>
diff --git a/camel/providers/imap4/camel-imap-engine.c b/camel/providers/imap4/camel-imap-engine.c
index e7d6ce5899..d82bdd43d9 100644
--- a/camel/providers/imap4/camel-imap-engine.c
+++ b/camel/providers/imap4/camel-imap-engine.c
@@ -887,14 +887,6 @@ camel_imap_engine_parse_resp_code (CamelIMAPEngine *engine, CamelException *ex)
return -1;
}
- if (token.v.atom[strlen (token.v.atom) - 1] == ']') {
- /* split this atom ("FOO]") into 2 tokens: "FOO" and "]" */
- token.token = ']';
- token.v.atom[strlen (token.v.atom) - 1] = '\0';
- camel_imap_stream_unget_token (engine->istream, &token);
- token.token = CAMEL_IMAP_TOKEN_ATOM;
- }
-
for (code = 0; imap_resp_codes[code].name; code++) {
if (!strcmp (imap_resp_codes[code].name, token.v.atom)) {
if (engine->current && imap_resp_codes[code].save) {
@@ -1054,14 +1046,6 @@ camel_imap_engine_parse_resp_code (CamelIMAPEngine *engine, CamelException *ex)
goto exception;
}
- if (token.v.atom[strlen (token.v.atom) - 1] == ']') {
- /* this should be the case, but if not - no big. */
- token.token = ']';
- token.v.atom[strlen (token.v.atom) - 1] = '\0';
- camel_imap_stream_unget_token (engine->istream, &token);
- token.token = CAMEL_IMAP_TOKEN_ATOM;
- }
-
if (resp != NULL)
resp->v.copyuid.destset = g_strdup (token.v.atom);
@@ -1071,17 +1055,10 @@ camel_imap_engine_parse_resp_code (CamelIMAPEngine *engine, CamelException *ex)
/* extensions are of the form: "[" atom [SPACE 1*<any TEXT_CHAR except "]">] "]" */
- /* eat up the TEXT_CHARs, being careful to check atoms for a trailing ']' */
+ /* eat up the TEXT_CHARs */
while (token.token != ']' && token.token != '\n') {
if (camel_imap_engine_next_token (engine, &token, ex) == -1)
goto exception;
-
- if (token.token == CAMEL_IMAP_TOKEN_ATOM) {
- if (token.v.atom[strlen (token.v.atom) - 1] == ']') {
- token.token = ']';
- break;
- }
- }
}
break;
diff --git a/camel/providers/imap4/camel-imap-specials.c b/camel/providers/imap4/camel-imap-specials.c
index 5e61d1776b..5289394f19 100644
--- a/camel/providers/imap4/camel-imap-specials.c
+++ b/camel/providers/imap4/camel-imap-specials.c
@@ -26,18 +26,18 @@
#include "camel-imap-specials.h"
-#define CHARS_ATOM_SPECIALS "(){"
+#define CHARS_ATOM_SPECIALS "(){]"
#define CHARS_LWSP " \t\r\n"
#define CHARS_QUOTED_SPECIALS "\\\""
#define CHARS_LIST_WILDCARDS "*%"
unsigned char camel_imap_specials[256] = {
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 6, 2, 2, 6, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 6, 2, 2, 6, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
20, 0, 8, 0, 0, 32, 0, 0, 1, 1, 32, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
diff --git a/camel/providers/imap4/camel-imap-store.c b/camel/providers/imap4/camel-imap-store.c
new file mode 100644
index 0000000000..10019164ad
--- /dev/null
+++ b/camel/providers/imap4/camel-imap-store.c
@@ -0,0 +1,827 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* Camel
+ * Copyright (C) 1999-2004 Jeffrey Stedfast
+ *
+ * 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.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <camel/camel-sasl.h>
+#include <camel/camel-tcp-stream-raw.h>
+#include <camel/camel-tcp-stream-ssl.h>
+
+#include "camel-imap-store.h"
+#include "camel-imap-engine.h"
+#include "camel-imap-folder.h"
+#include "camel-imap-stream.h"
+#include "camel-imap-command.h"
+
+
+static void camel_imap_store_class_init (CamelIMAPStoreClass *klass);
+static void camel_imap_store_init (CamelIMAPStore *store, CamelIMAPStoreClass *klass);
+static void camel_imap_store_finalize (CamelObject *object);
+
+/* service methods */
+static void imap_construct (CamelService *service, CamelSession *session,
+ CamelProvider *provider, CamelURL *url,
+ CamelException *ex);
+static char *imap_get_name (CamelService *service, gboolean brief);
+static gboolean imap_connect (CamelService *service, CamelException *ex);
+static gboolean imap_disconnect (CamelService *service, gboolean clean, CamelException *ex);
+static GList *imap_query_auth_types (CamelService *service, CamelException *ex);
+
+static guint imap_hash_folder_name (gconstpointer key);
+static gint imap_compare_folder_name (gconstpointer a, gconstpointer b);
+
+/* store methods */
+static CamelFolder *imap_get_folder (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex);
+static CamelFolderInfo *imap_create_folder (CamelStore *store, const char *parent_name, const char *folder_name, CamelException *ex);
+static void imap_delete_folder (CamelStore *store, const char *folder_name, CamelException *ex);
+static void imap_rename_folder (CamelStore *store, const char *old_name, const char *new_name, CamelException *ex);
+static void imap_sync (CamelStore *store, gboolean expunge, CamelException *ex);
+static CamelFolderInfo *imap_get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex);
+static void imap_subscribe_folder (CamelStore *store, const char *folder_name, CamelException *ex);
+static void imap_unsubscribe_folder (CamelStore *store, const char *folder_name, CamelException *ex);
+static void imap_noop (CamelStore *store, CamelException *ex);
+
+
+static CamelStoreClass *parent_class = NULL;
+
+
+CamelType
+camel_imap_store_get_type (void)
+{
+ static CamelType type = 0;
+
+ if (!type) {
+ type = camel_type_register (CAMEL_TYPE_IMAP_STORE,
+ "CamelIMAPStore",
+ sizeof (CamelIMAPStore),
+ sizeof (CamelIMAPStoreClass),
+ (CamelObjectClassInitFunc) camel_imap_store_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_imap_store_init,
+ (CamelObjectFinalizeFunc) camel_imap_store_finalize);
+ }
+
+ return type;
+}
+
+static void
+camel_imap_store_class_init (CamelIMAPStoreClass *klass)
+{
+ CamelServiceClass *service_class = (CamelServiceClass *) klass;
+ CamelStoreClass *store_class = (CamelStoreClass *) klass;
+
+ parent_class = camel_type_get_global_classfuncs (CAMEL_STORE_TYPE);
+
+ service_class->construct = imap_construct;
+ service_class->get_name = imap_get_name;
+ service_class->connect = imap_connect;
+ service_class->disconnect = imap_disconnect;
+ service_class->query_auth_types = imap_query_auth_types;
+
+ store_class->get_folder = imap_get_folder;
+ store_class->create_folder = imap_create_folder;
+ store_class->delete_folder = imap_delete_folder;
+ store_class->rename_folder = imap_rename_folder;
+ store_class->sync = imap_sync;
+ store_class->get_folder_info = imap_get_folder_info;
+ store_class->subscribe_folder = imap_subscribe_folder;
+ store_class->unsubscribe_folder = imap_unsubscribe_folder;
+ store_class->noop = imap_noop;
+}
+
+static void
+camel_imap_store_init (CamelIMAPStore *store, CamelIMAPStoreClass *klass)
+{
+ store->engine = NULL;
+}
+
+static void
+camel_imap_store_finalize (CamelObject *object)
+{
+ CamelIMAPStore *store = (CamelIMAPStore *) object;
+
+ if (store->engine)
+ camel_object_unref (store->engine);
+}
+
+
+static void
+imap_construct (CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, CamelException *ex)
+{
+ CAMEL_SERVICE_CLASS (parent_class)->construct (service, session, provider, url, ex);
+}
+
+static char *
+imap_get_name (CamelService *service, gboolean brief)
+{
+ 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);
+}
+
+enum {
+ USE_SSL_NEVER,
+ USE_SSL_ALWAYS,
+ USE_SSL_WHEN_POSSIBLE
+};
+
+#define SSL_PORT_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3)
+#define STARTTLS_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_TLS)
+
+static gboolean
+connect_to_server (CamelService *service, struct hostent *host, int ssl_mode, int try_starttls, CamelException *ex)
+{
+ CamelIMAPStore *store = (CamelIMAPStore *) service;
+ CamelIMAPEngine *engine;
+ CamelStream *tcp_stream;
+ int port, ret;
+
+ if (store->engine) {
+ camel_object_unref (store->engine);
+ store->engine = NULL;
+ }
+
+ port = service->url->port ? service->url->port : 143;
+
+ if (ssl_mode) {
+#ifdef HAVE_SSL
+ if (try_starttls) {
+ tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, STARTTLS_FLAGS);
+ } else {
+ port = service->url->port ? service->url->port : 993;
+ tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, SSL_PORT_FLAGS);
+ }
+#else
+ if (!try_starttls)
+ port = service->url->port ? service->url->port : 993;
+
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Could not connect to %s (port %d): %s"),
+ service->url->host, port,
+ _("SSL unavailable"));
+
+ return FALSE;
+#endif /* HAVE_SSL */
+ } else {
+ tcp_stream = camel_tcp_stream_raw_new ();
+ }
+
+ fprintf (stderr, "connecting to %s:%d\n", service->url->host, port);
+ if ((ret = camel_tcp_stream_connect ((CamelTcpStream *) tcp_stream, host, port)) == -1) {
+ if (errno == EINTR)
+ camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
+ _("Connection cancelled"));
+ else
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Could not connect to %s (port %d): %s"),
+ service->url->host, port,
+ g_strerror (errno));
+
+ camel_object_unref (tcp_stream);
+
+ return FALSE;
+ }
+
+ engine = camel_imap_engine_new (service->session, service->url);
+ if (camel_imap_engine_take_stream (engine, tcp_stream, ex) == -1) {
+ camel_object_unref (engine);
+
+ return FALSE;
+ }
+
+ if (camel_imap_engine_capability (engine, ex) == -1) {
+ camel_object_unref (engine);
+
+ return FALSE;
+ }
+
+ store->engine = engine;
+
+#ifdef HAVE_SSL
+ if (ssl_mode == USE_SSL_WHEN_POSSIBLE) {
+ /* try_starttls is always TRUE here */
+ if (engine->capa & CAMEL_IMAP_CAPABILITY_STARTTLS)
+ goto starttls;
+ } else if (ssl_mode == USE_SSL_ALWAYS) {
+ if (try_starttls) {
+ if (engine->capa & CAMEL_IMAP_CAPABILITY_STARTTLS) {
+ goto starttls;
+ } else {
+ /* server doesn't support STARTTLS, abort */
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Failed to connect to IMAP server %s in secure mode: "
+ "Server does not support STARTTLS"),
+ service->url->host);
+ goto exception;
+ }
+ }
+ }
+#endif /* HAVE_SSL */
+
+ return TRUE;
+
+#ifdef HAVE_SSL
+ starttls:
+
+ if (1) {
+ CamelIMAPCommand *ic;
+ int id;
+
+ ic = camel_imap_engine_queue (engine, NULL, "STARTTLS\r\n");
+ while ((id = camel_imap_engine_iterate (engine)) < ic->id && id != -1)
+ ;
+
+ if (id == -1 || ic->result != CAMEL_IMAP_RESULT_OK) {
+ if (ic->result != CAMEL_IMAP_RESULT_OK) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to connect to IMAP server %s in secure mode: %s"),
+ service->url->host, _("Unknown error"));
+ } else {
+ camel_exception_xfer (ex, &ic->ex);
+ }
+
+ camel_imap_command_unref (ic);
+
+ goto exception;
+ }
+
+ camel_imap_command_unref (ic);
+ }
+
+ return TRUE;
+
+ exception:
+
+ camel_object_unref (store->engine);
+ store->engine = NULL;
+
+ return FALSE;
+#endif /* HAVE_SSL */
+}
+
+static struct {
+ char *value;
+ int mode;
+} ssl_options[] = {
+ { "", USE_SSL_ALWAYS },
+ { "always", USE_SSL_ALWAYS },
+ { "when-possible", USE_SSL_WHEN_POSSIBLE },
+ { "never", USE_SSL_NEVER },
+ { NULL, USE_SSL_NEVER },
+};
+
+static gboolean
+connect_to_server_wrapper (CamelService *service, CamelException *ex)
+{
+ const char *use_ssl;
+ struct hostent *h;
+ int ssl_mode;
+ int ret, i;
+
+ if (!(h = camel_service_gethost (service, ex)))
+ return FALSE;
+
+ if ((use_ssl = camel_url_get_param (service->url, "use_ssl"))) {
+ for (i = 0; ssl_options[i].value; i++)
+ if (!strcmp (ssl_options[i].value, use_ssl))
+ break;
+ ssl_mode = ssl_options[i].mode;
+ } else {
+ ssl_mode = USE_SSL_NEVER;
+ }
+
+ if (ssl_mode == USE_SSL_ALWAYS) {
+ /* First try the ssl port */
+ if (!(ret = connect_to_server (service, h, ssl_mode, FALSE, err))) {
+ if (camel_exception_get_id (ex) == CAMEL_EXCEPTION_SERVICE_UNAVAILABLE) {
+ /* The ssl port seems to be unavailable, lets try STARTTLS */
+ camel_exception_clear (ex);
+ ret = connect_to_server (service, h, ssl_mode, TRUE, ex);
+ }
+ }
+ } else if (ssl_mode == USE_SSL_WHEN_POSSIBLE) {
+ /* If the server supports STARTTLS, use it */
+ ret = connect_to_server (service, h, ssl_mode, TRUE, ex);
+ } else {
+ /* User doesn't care about SSL */
+ ret = connect_to_server (service, h, USE_SSL_ALWAYS, FALSE, err);
+ }
+
+ camel_free_host (h);
+
+ return ret;
+}
+
+static int
+sasl_auth (CamelIMAPEngine *engine, CamelIMAPCommand *ic, const unsigned char *linebuf, size_t linelen, CamelException *ex)
+{
+ /* Perform a single challenge iteration */
+ CamelSasl *sasl = ic->user_data;
+ char *challenge;
+
+ if (camel_sasl_authenticated (sasl)) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("Cannot authenticate to IMAP server %s using the %s authentication mechanism"),
+ engine->url->host, engine->url->auth);
+ return -1;
+ }
+
+ while (isspace (*linebuf))
+ linebuf++;
+
+ if (*linebuf == '\0')
+ linebuf = NULL;
+
+ if (!(challenge = camel_sasl_challenge_base64 (sasl, (const char *) linebuf, err)))
+ return -1;
+
+ fprintf (stderr, "sending : %s\r\n", challenge);
+
+ if (camel_stream_printf (engine->ostream, "%s\r\n", challenge) == -1) {
+ g_free (challenge);
+ return -1;
+ }
+
+ g_free (challenge);
+
+ if (camel_stream_flush (engine->ostream) == -1)
+ return -1;
+
+ return 0;
+}
+
+static int
+imap_try_authenticate (CamelService *service, gboolean reprompt, const char *errmsg, CamelException *ex)
+{
+ CamelIMAPStore *store = (CamelIMAPStore *) service;
+ CamelSession *session = service->session;
+ CamelSasl *sasl = NULL;
+ CamelIMAPCommand *ic;
+ int id;
+
+ if (!service->url->passwd) {
+ guint32 flags = CAMEL_SESSION_PASSWORD_SECRET;
+ char *prompt;
+
+ if (reprompt)
+ flags |= CAMEL_SESSION_PASSWORD_REPROMPT;
+
+ prompt = g_strdup_printf (_("%sPlease enter the IMAP password for %s on host %s"),
+ errmsg ? errmsg : "",
+ service->url->user,
+ service->url->host);
+
+ service->url->passwd = camel_session_get_password (session, prompt, flags, service, "password", ex);
+
+ g_free (prompt);
+
+ if (!service->url->passwd)
+ return FALSE;
+ }
+
+ if (service->url->auth) {
+ CamelServiceAuthType *mech;
+
+ mech = g_hash_table_lookup (store->engine->authtypes, service->url->auth);
+ sasl = camel_sasl_new ("imap", mech->authproto, service);
+
+ ic = camel_imap_engine_queue (store->engine, NULL, "AUTHENTICATE %s\r\n", service->url->auth);
+ ic->plus = sasl_auth;
+ ic->user_data = sasl;
+ } else {
+ ic = camel_imap_engine_queue (store->engine, NULL, "LOGIN %S %S\r\n",
+ service->url->user, service->url->passwd);
+ }
+
+ while ((id = camel_imap_engine_iterate (store->engine)) < ic->id && id != -1)
+ ;
+
+ if (sasl != NULL)
+ camel_object_unref (sasl);
+
+ if (id == -1 || ic->status == CAMEL_IMAP_COMMAND_ERROR) {
+ /* unrecoverable error */
+ camel_exception_xfer (ex, &ic->ex);
+ camel_imap_command_unref (ic);
+
+ return FALSE;
+ }
+
+ if (ic->result != CAMEL_IMAP_RESULT_OK) {
+ camel_imap_command_unref (ic);
+
+ /* try again */
+
+ return TRUE;
+ }
+
+ camel_imap_command_unref (ic);
+
+ return FALSE;
+}
+
+static gboolean
+imap_connect (CamelService *service, CamelException *ex)
+{
+ CamelIMAPStore *store = (CamelIMAPStore *) service;
+ CamelServiceAuthType *mech;
+ gboolean reprompt = FALSE;
+ char *errmsg = NULL;
+ CamelException lex;
+
+ CAMEL_SERVICE_LOCK (store, connect_lock);
+
+ if (!connect_to_server_wrapper (service, ex)) {
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+ return FALSE;
+ }
+
+#define CANT_USE_AUTHMECH (!(mech = g_hash_table_lookup (store->engine->authtypes, service->url->auth)))
+ if (service->url->auth && CANT_USE_AUTHMECH) {
+ /* Oops. We can't AUTH using the requested mechanism */
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("Cannot authenticate to IMAP server %s using %s"),
+ service->url->host, service->url->auth);
+
+ camel_object_unref (store->engine);
+ store->engine = NULL;
+
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+
+ return FALSE;
+ }
+
+ camel_exception_init (&lex);
+ while (imap_try_authenticate (service, reprompt, errmsg, &lex)) {
+ g_free (errmsg);
+ errmsg = g_strdup (lex.desc);
+ camel_exception_clear (&lex);
+ reprompt = TRUE;
+ }
+ g_free (errmsg);
+
+ if (camel_exception_is_set (&lex)) {
+ camel_exception_xfer (ex, &lex);
+ camel_object_unref (store->engine);
+ store->engine = NULL;
+
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+
+ return FALSE;
+ }
+
+ if (camel_imap_engine_namespace (store->engine, ex) == -1) {
+ camel_object_unref (store->engine);
+ store->engine = NULL;
+
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+
+ return FALSE;
+ }
+
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+
+ return TRUE;
+}
+
+static gboolean
+imap_disconnect (CamelService *service, gboolean clean, CamelException *ex)
+{
+ CamelIMAPStore *store = (CamelIMAPStore *) service;
+ CamelIMAPCommand *ic;
+ int id;
+
+ if (clean && !store->engine->istream->disconnected) {
+ ic = camel_imap_engine_queue (store->engine, NULL, "LOGOUT\r\n");
+ while ((id = camel_imap_engine_iterate (store->engine)) < ic->id && id != -1)
+ ;
+
+ camel_imap_command_unref (ic);
+ }
+
+ camel_object_unref (store->engine);
+
+ return 0;
+}
+
+extern CamelServiceAuthType camel_imap_password_authtype;
+
+static GList *
+imap_query_auth_types (CamelService *service, CamelException *ex)
+{
+ CamelIMAPStore *store = (CamelIMAPStore *) service;
+ CamelServiceAuthType *authtype;
+ GList *sasl_types, *t, *next;
+ gboolean connected;
+
+ CAMEL_SERVICE_LOCK (store, connect_lock);
+ connected = connect_to_server_wrapper (service, ex);
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+ if (!connected)
+ return NULL;
+
+ sasl_types = camel_sasl_authtype_list (FALSE);
+ for (t = sasl_types; t; t = next) {
+ authtype = t->data;
+ next = t->next;
+
+ if (!g_hash_table_lookup (store->engine->authtypes, authtype->authproto)) {
+ sasl_types = g_list_remove_link (sasl_types, t);
+ g_list_free_1 (t);
+ }
+ }
+
+ return g_list_prepend (sasl_types, &camel_imap_password_authtype);
+}
+
+
+static char *
+imap_folder_utf7_name (CamelStore *store, const char *folder_name)
+{
+ char *real_name, *p;
+
+ if (store->dir_sep != '/') {
+ p = real_name = g_alloca (strlen (folder_name) + 1);
+ strcpy (real_name, folder_name);
+ while (*p != '\0') {
+ if (*p == '/')
+ *p = store->dir_sep;
+ p++;
+ }
+
+ folder_name = real_name;
+ }
+
+ return camel_utf8_utf7 (folder_name);
+}
+
+static CamelFolder *
+imap_get_folder (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex)
+{
+ CamelIMAPStore *imap_store = (CamelIMAPStore *) store;
+
+ /* FIXME: implement me */
+
+ return NULL;
+}
+
+static CamelFolderInfo *
+imap_create_folder (CamelStore *store, const char *parent_name, const char *folder_name, CamelException *ex)
+{
+ /* FIXME: also need to deal with parent folders that can't
+ * contain subfolders - delete them and re-create with the
+ * proper hint */
+ CamelIMAPEngine *engine = ((CamelIMAPStore *) folder->store)->engine;
+ CamelFolderInfo *fi = NULL
+ CamelIMAPCommand *ic;
+ char *utf7_name;
+ const char *c;
+ char *name;
+ int id;
+
+ c = folder_name;
+ while (*c != '\0') {
+ if (*c == store->dir_sep || strchr ("#%*", *c)) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID_PATH,
+ _("The folder name \"%s\" is invalid because "
+ "it containes the character \"%c\""),
+ folder_name, *c);
+ return NULL;
+ }
+
+ c++;
+ }
+
+ if (parent_name != NULL && *parent_name)
+ name = g_strdup_printf ("%s/%s", parent_name, folder_name);
+ else
+ name = g_strdup (folder_name);
+
+ utf7_name = imap_folder_utf7_name (store, name);
+ g_free (name);
+
+ ic = camel_imap_engine_queue (engine, NULL, "CREATE %S\r\n", utf7_name);
+ g_free (utf7_name);
+
+ while ((id = camel_imap_engine_iterate (engine)) < ic->id && id != -1)
+ ;
+
+ if (id == -1 || ic->status != CAMEL_IMAP_COMMAND_COMPLETE) {
+ camel_exception_xfer (ex, &ic->ex);
+ camel_imap_command_unref (ic);
+ return NULL;
+ }
+
+ switch (ic->result) {
+ case CAMEL_IMAP_RESULT_OK:
+ /* FIXME: allocate fi */
+ break;
+ case CAMEL_IMAP_RESULT_NO:
+ /* FIXME: would be good to save the NO reason into the err message */
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot create folder `%s': Invalid mailbox name"),
+ folder_name);
+ break;
+ case CAMEL_IMAP_RESULT_BAD:
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot create folder `%s': Bad command"),
+ folder_name);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ camel_imap_command_unref (ic);
+
+ return fi;
+}
+
+static void
+imap_delete_folder (CamelStore *store, const char *folder_name, CamelException *ex)
+{
+ CamelIMAPEngine *engine = ((CamelIMAPStore *) folder->store)->engine;
+ CamelIMAPCommand *ic;
+ char *utf7_name;
+ int id;
+
+ if (!g_ascii_strcasecmp (folder_name, "INBOX")) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot delete folder `%s': Special folder"),
+ folder_name);
+
+ return;
+ }
+
+ utf7_name = imap_folder_utf7_name (store, folder_name);
+ ic = camel_imap_engine_queue (engine, NULL, "DELETE %S\r\n", utf7_name);
+ g_free (utf7_name);
+
+ while ((id = camel_imap_engine_iterate (engine)) < ic->id && id != -1)
+ ;
+
+ if (id == -1 || ic->status != CAMEL_IMAP_COMMAND_COMPLETE) {
+ camel_exception_xfer (ex, &ic->ex);
+ camel_imap_command_unref (ic);
+ return;
+ }
+
+ switch (ic->result) {
+ case CAMEL_IMAP_RESULT_OK:
+ /* deleted */
+ /*fi = imap_build_folder_info (store, folder_name);
+ camel_object_trigger_event (store, "folder_deleted", fi);
+ camel_folder_info_free (fi);*/
+ break;
+ case CAMEL_IMAP_RESULT_NO:
+ /* FIXME: would be good to save the NO reason into the err message */
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot delete folder `%s': Invalid mailbox name"),
+ folder_name);
+ break;
+ case CAMEL_IMAP_RESULT_BAD:
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot delete folder `%s': Bad command"),
+ folder_name);
+ break;
+ }
+
+ camel_imap_command_unref (ic);
+}
+
+static void
+imap_rename_folder (CamelStore *store, const char *old_name, const char *new_name, CamelException *ex)
+{
+
+}
+
+static void
+imap_sync (CamelStore *store, gboolean expunge, CamelException *ex)
+{
+
+}
+
+static CamelFolderInfo *
+imap_get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex)
+{
+
+}
+
+static void
+imap_subscribe_folder (CamelStore *store, const char *folder_name, CamelException *ex)
+{
+ CamelIMAPEngine *engine = ((CamelIMAPStore *) store)->engine;
+ CamelIMAPCommand *ic;
+ char *utf7_name;
+ int id;
+
+ utf7_name = imap_fodler_utf7_name (store, folder_name);
+ ic = camel_imap_engine_queue (engine, NULL, "SUBSCRIBE %S\r\n", utf7_name);
+ g_free (utf7_name);
+
+ while ((id = camel_imap_engine_iterate (engine)) < ic->id && id != -1)
+ ;
+
+ if (id == -1 || ic->status != CAMEL_IMAP_COMMAND_COMPLETE) {
+ camel_exception_xfer (ex, &ic->ex);
+ camel_imap_command_unref (ic);
+ return;
+ }
+
+ switch (ic->result) {
+ case CAMEL_IMAP_RESULT_OK:
+ /* subscribed */
+ /*fi = imap_build_folder_info (store, folder_name);
+ fi->flags |= CAMEL_FOLDER_NOCHILDREN;
+ camel_object_trigger_event (store, "folder_subscribed", fi);
+ camel_folder_info_free (fi);*/
+ break;
+ case CAMEL_IMAP_RESULT_NO:
+ /* FIXME: would be good to save the NO reason into the err message */
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot subscribe to folder `%s': Invalid mailbox name"),
+ folder_name);
+ break;
+ case CAMEL_IMAP_RESULT_BAD:
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot subscribe to folder `%s': Bad command"),
+ folder_name);
+ break;
+ }
+
+ camel_imap_command_unref (ic);
+}
+
+static void
+imap_unsubscribe_folder (CamelStore *store, const char *folder_name, CamelException *ex)
+{
+ CamelIMAPEngine *engine = ((CamelIMAPStore *) store)->engine;
+ CamelIMAPCommand *ic;
+ char *utf7_name;
+ int id;
+
+ utf7_name = imap_fodler_utf7_name (store, folder_name);
+ ic = camel_imap_engine_queue (engine, NULL, "UNSUBSCRIBE %S\r\n", utf7_name);
+ g_free (utf7_name);
+
+ while ((id = camel_imap_engine_iterate (engine)) < ic->id && id != -1)
+ ;
+
+ if (id == -1 || ic->status != CAMEL_IMAP_COMMAND_COMPLETE) {
+ camel_exception_xfer (ex, &ic->ex);
+ camel_imap_command_unref (ic);
+ return;
+ }
+
+ switch (ic->result) {
+ case CAMEL_IMAP_RESULT_OK:
+ /* unsubscribed */
+ /*fi = imap_build_folder_info (store, folder_name);
+ camel_object_trigger_event (store, "folder_unsubscribed", fi);
+ camel_folder_info_free (fi);*/
+ break;
+ case CAMEL_IMAP_RESULT_NO:
+ /* FIXME: would be good to save the NO reason into the err message */
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot unsubscribe from folder `%s': Invalid mailbox name"),
+ folder_name);
+ break;
+ case CAMEL_IMAP_RESULT_BAD:
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot unsubscribe from folder `%s': Bad command"),
+ folder_name);
+ break;
+ }
+
+ camel_imap_command_unref (ic);
+}
+
+static void
+imap_noop (CamelStore *store, CamelException *ex)
+{
+
+}
diff --git a/camel/providers/imap4/camel-imap-store.h b/camel/providers/imap4/camel-imap-store.h
new file mode 100644
index 0000000000..036c9808a9
--- /dev/null
+++ b/camel/providers/imap4/camel-imap-store.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* Camel
+ * Copyright (C) 1999-2004 Jeffrey Stedfast
+ *
+ * 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.
+ */
+
+
+#ifndef __CAMEL_IMAP_STORE_H__
+#define __CAMEL_IMAP_STORE_H__
+
+#include <camel/camel-store.h>
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+#define CAMEL_TYPE_IMAP_STORE (camel_imap_store_get_type ())
+#define CAMEL_IMAP_STORE(obj) (CAMEL_CHECK_CAST ((obj), CAMEL_TYPE_IMAP_STORE, CamelIMAPStore))
+#define CAMEL_IMAP_STORE_CLASS(klass) (CAMEL_CHECK_CLASS_CAST ((klass), CAMEL_TYPE_IMAP_STORE, CamelIMAPStoreClass))
+#define CAMEL_IS_IMAP_STORE(obj) (CAMEL_CHECK_TYPE ((obj), CAMEL_TYPE_IMAP_STORE))
+#define CAMEL_IS_IMAP_STORE_CLASS(klass) (CAMEL_CHECK_CLASS_TYPE ((klass), CAMEL_TYPE_IMAP_STORE))
+#define CAMEL_IMAP_STORE_GET_CLASS(obj) (CAMEL_CHECK_GET_CLASS ((obj), CAMEL_TYPE_IMAP_STORE, CamelIMAPStoreClass))
+
+typedef struct _CamelIMAPStore CamelIMAPStore;
+typedef struct _CamelIMAPStoreClass CamelIMAPStoreClass;
+
+struct _CamelIMAPEngine;
+
+struct _CamelIMAPStore {
+ CamelStore parent_object;
+
+ struct _CamelIMAPEngine *engine;
+};
+
+struct _CamelIMAPStoreClass {
+ CamelStoreClass parent_class;
+
+};
+
+
+CamelType spruce_imap_store_get_type (void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __CAMEL_IMAP_STORE_H__ */