diff options
Diffstat (limited to 'camel')
-rw-r--r-- | camel/ChangeLog | 30 | ||||
-rw-r--r-- | camel/providers/imap4/camel-imap-engine.c | 25 | ||||
-rw-r--r-- | camel/providers/imap4/camel-imap-specials.c | 6 | ||||
-rw-r--r-- | camel/providers/imap4/camel-imap-store.c | 827 | ||||
-rw-r--r-- | camel/providers/imap4/camel-imap-store.h | 61 |
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__ */ |