aboutsummaryrefslogtreecommitdiffstats
path: root/camel/providers/pop3/camel-pop3-store.c
diff options
context:
space:
mode:
Diffstat (limited to 'camel/providers/pop3/camel-pop3-store.c')
-rw-r--r--camel/providers/pop3/camel-pop3-store.c753
1 files changed, 396 insertions, 357 deletions
diff --git a/camel/providers/pop3/camel-pop3-store.c b/camel/providers/pop3/camel-pop3-store.c
index dcdeefb392..6ff88d61c2 100644
--- a/camel/providers/pop3/camel-pop3-store.c
+++ b/camel/providers/pop3/camel-pop3-store.c
@@ -4,9 +4,8 @@
/*
* Authors:
* Dan Winship <danw@ximian.com>
- * Michael Zucchi <notzed@ximian.com>
*
- * Copyright (C) 2000-2002 Ximian, Inc. (www.ximian.com)
+ * Copyright (C) 2000 Ximian, Inc. (www.ximian.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
@@ -39,26 +38,36 @@
#include "camel-operation.h"
+#ifdef HAVE_KRB4
+/* Specified nowhere */
+#define KPOP_PORT 1109
+
+#include <krb.h>
+/* MIT krb4 des.h #defines _. Sigh. We don't need it. */
+#undef _
+
+#ifdef NEED_KRB_SENDAUTH_PROTO
+extern int krb_sendauth(long options, int fd, KTEXT ticket, char *service,
+ char *inst, char *realm, unsigned KRB4_32 checksum,
+ MSG_DAT *msg_data, CREDENTIALS *cred,
+ Key_schedule schedule, struct sockaddr_in *laddr,
+ struct sockaddr_in *faddr, char *version);
+#endif
+#endif
+
#include "camel-pop3-store.h"
#include "camel-pop3-folder.h"
#include "camel-stream-buffer.h"
+#include "camel-tcp-stream.h"
#include "camel-session.h"
#include "camel-exception.h"
#include "camel-url.h"
#include "e-util/md5-utils.h"
-#include "camel-pop3-engine.h"
-#include "camel-sasl.h"
-#include "camel-data-cache.h"
-#include "camel-tcp-stream.h"
-#include "camel-tcp-stream-raw.h"
-#ifdef HAVE_SSL
-#include "camel-tcp-stream-ssl.h"
-#endif
/* Specified in RFC 1939 */
#define POP3_PORT 110
-static CamelStoreClass *parent_class = NULL;
+static CamelRemoteStoreClass *parent_class = NULL;
static void finalize (CamelObject *object);
@@ -72,16 +81,20 @@ static CamelFolder *get_folder (CamelStore *store, const char *folder_name,
static void init_trash (CamelStore *store);
static CamelFolder *get_trash (CamelStore *store, CamelException *ex);
+static int pop3_get_response (CamelPop3Store *store, char **ret, CamelException *ex);
+
+
static void
-camel_pop3_store_class_init (CamelPOP3StoreClass *camel_pop3_store_class)
+camel_pop3_store_class_init (CamelPop3StoreClass *camel_pop3_store_class)
{
CamelServiceClass *camel_service_class =
CAMEL_SERVICE_CLASS (camel_pop3_store_class);
CamelStoreClass *camel_store_class =
CAMEL_STORE_CLASS (camel_pop3_store_class);
- parent_class = CAMEL_STORE_CLASS (camel_type_get_global_classfuncs (camel_store_get_type ()));
-
+ parent_class = CAMEL_REMOTE_STORE_CLASS(camel_type_get_global_classfuncs
+ (camel_remote_store_get_type ()));
+
/* virtual method overload */
camel_service_class->query_auth_types = query_auth_types;
camel_service_class->connect = pop3_connect;
@@ -97,7 +110,11 @@ camel_pop3_store_class_init (CamelPOP3StoreClass *camel_pop3_store_class)
static void
camel_pop3_store_init (gpointer object, gpointer klass)
{
- ;
+ CamelRemoteStore *remote_store = CAMEL_REMOTE_STORE (object);
+
+ remote_store->default_port = 110;
+ /* FIXME: what should this port be?? */
+ remote_store->default_ssl_port = 995;
}
CamelType
@@ -106,10 +123,9 @@ camel_pop3_store_get_type (void)
static CamelType camel_pop3_store_type = CAMEL_INVALID_TYPE;
if (!camel_pop3_store_type) {
- camel_pop3_store_type = camel_type_register (CAMEL_STORE_TYPE,
- "CamelPOP3Store",
- sizeof (CamelPOP3Store),
- sizeof (CamelPOP3StoreClass),
+ camel_pop3_store_type = camel_type_register (CAMEL_REMOTE_STORE_TYPE, "CamelPop3Store",
+ sizeof (CamelPop3Store),
+ sizeof (CamelPop3StoreClass),
(CamelObjectClassInitFunc) camel_pop3_store_class_init,
NULL,
(CamelObjectInitFunc) camel_pop3_store_init,
@@ -122,233 +138,189 @@ camel_pop3_store_get_type (void)
static void
finalize (CamelObject *object)
{
- CamelPOP3Store *pop3_store = CAMEL_POP3_STORE (object);
-
- /* force disconnect so we dont have it run later, after we've cleaned up some stuff */
- /* SIGH */
+ CamelPop3Store *pop3_store = CAMEL_POP3_STORE (object);
- camel_service_disconnect((CamelService *)pop3_store, TRUE, NULL);
-
- if (pop3_store->engine)
- camel_object_unref((CamelObject *)pop3_store->engine);
- if (pop3_store->cache)
- camel_object_unref((CamelObject *)pop3_store->cache);
+ if (pop3_store->apop_timestamp)
+ g_free (pop3_store->apop_timestamp);
+ if (pop3_store->implementation)
+ g_free (pop3_store->implementation);
}
-enum {
- USE_SSL_NEVER,
- USE_SSL_ALWAYS,
- USE_SSL_WHEN_POSSIBLE
-};
-
static gboolean
-connect_to_server (CamelService *service, int ssl_mode, int try_starttls, CamelException *ex)
+connect_to_server (CamelService *service, CamelException *ex)
{
- CamelPOP3Store *store = CAMEL_POP3_STORE (service);
- CamelStream *tcp_stream;
- CamelPOP3Command *pc;
- struct hostent *h;
- int clean_quit;
- int ret, port;
-
- h = camel_service_gethost (service, ex);
- if (!h)
- return FALSE;
-
- port = service->url->port ? service->url->port : 110;
-
-#ifdef HAVE_SSL
- if (camel_url_get_param (service->url, "use_ssl")) {
- if (try_starttls)
- tcp_stream = camel_tcp_stream_ssl_new_raw (service, service->url->host);
- else {
- port = service->url->port ? service->url->port : 995;
- tcp_stream = camel_tcp_stream_ssl_new (service, service->url->host);
- }
- } else {
- tcp_stream = camel_tcp_stream_raw_new ();
+ CamelPop3Store *store = CAMEL_POP3_STORE (service);
+ char *buf, *apoptime, *apopend;
+ int status;
+ gboolean result;
+
+#ifdef HAVE_KRB4
+ gboolean set_port = FALSE, kpop;
+
+ kpop = (service->url->authmech &&
+ !strcmp (service->url->authmech, "+KPOP"));
+
+ if (kpop && service->url->port == 0) {
+ set_port = TRUE;
+ service->url->port = KPOP_PORT;
}
-#else
- tcp_stream = camel_tcp_stream_raw_new ();
-#endif /* HAVE_SSL */
-
- ret = camel_tcp_stream_connect (CAMEL_TCP_STREAM (tcp_stream), h, port);
- camel_free_host (h);
- if (ret == -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));
+#endif
+
+ result = CAMEL_SERVICE_CLASS (parent_class)->connect (service, ex);
+
+#ifdef HAVE_KRB4
+ if (set_port)
+ service->url->port = 0;
+#endif
+
+ if (result == FALSE)
return FALSE;
+
+#ifdef HAVE_KRB4
+ if (kpop) {
+ KTEXT_ST ticket_st;
+ MSG_DAT msg_data;
+ CREDENTIALS cred;
+ Key_schedule schedule;
+ struct hostent *h;
+ int fd;
+
+ h = camel_service_gethost (service, ex);
+
+ fd = GPOINTER_TO_INT (camel_tcp_stream_get_socket (CAMEL_TCP_STREAM (CAMEL_REMOTE_STORE (service)->ostream)));
+ status = krb_sendauth (0, fd, &ticket_st, "pop", h->h_name,
+ krb_realmofhost (h->h_name), 0,
+ &msg_data, &cred, schedule,
+ NULL, NULL, "KPOPV0.1");
+ camel_free_host (h);
+ if (status != KSUCCESS) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Could not authenticate to "
+ "KPOP server: %s"),
+ krb_err_txt[status]);
+ return FALSE;
+ }
+
+ if (!service->url->passwd)
+ service->url->passwd = g_strdup (service->url->user);
}
-
- /* parent class connect initialization */
- if (CAMEL_SERVICE_CLASS (parent_class)->connect (service, ex) == FALSE) {
- camel_object_unref (CAMEL_OBJECT (tcp_stream));
+#endif /* HAVE_KRB4 */
+
+ /* Read the greeting, check status */
+ status = pop3_get_response (store, &buf, ex);
+ switch (status) {
+ case CAMEL_POP3_ERR:
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Could not connect to server: %s"),
+ buf);
+ g_free (buf);
+ /* fall through */
+ case CAMEL_POP3_FAIL:
return FALSE;
}
-
- store->engine = camel_pop3_engine_new (tcp_stream);
-
-#ifdef HAVE_SSL
- if (store->engine) {
- if (ssl_mode == USE_SSL_WHEN_POSSIBLE) {
- if (store->engine->capa & CAMEL_POP3_CAP_STLS)
- goto starttls;
- } else if (ssl_mode == USE_SSL_ALWAYS) {
- if (try_starttls) {
- if (store->engine->capa & CAMEL_POP3_CAP_STLS) {
- /* attempt to toggle STARTTLS mode */
- goto starttls;
- } else {
- /* server doesn't support STARTTLS, abort */
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Failed to connect to POP server %s in secure mode: %s"),
- service->url->host, _("SSL/TLS extension not supported."));
- /* we have the possibility of quitting cleanly here */
- clean_quit = TRUE;
- goto stls_exception;
- }
- }
+
+ if (buf) {
+ apoptime = strchr (buf, '<');
+ apopend = apoptime ? strchr (apoptime, '>') : NULL;
+ if (apopend) {
+ store->apop_timestamp =
+ g_strndup (apoptime, apopend - apoptime + 1);
+ memmove (apoptime, apopend + 1, strlen (apopend + 1));
}
+ store->implementation = buf;
}
-#endif /* HAVE_SSL */
-
- camel_object_unref (CAMEL_OBJECT (tcp_stream));
-
- return store->engine != NULL;
-
-#ifdef HAVE_SSL
- starttls:
- /* as soon as we send a STLS command, all hope is lost of a clean QUIT if problems arise */
- clean_quit = FALSE;
-
- pc = camel_pop3_engine_command_new (store->engine, 0, NULL, NULL, "STLS\r\n");
- while (camel_pop3_engine_iterate (store->engine, NULL) > 0)
- ;
-
- ret = pc->state == CAMEL_POP3_COMMAND_OK;
- camel_pop3_engine_command_free (store->engine, pc);
-
- if (ret == FALSE) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Failed to connect to POP server %s in secure mode: %s"),
- service->url->host, store->engine->line);
- goto stls_exception;
- }
-
- /* Okay, now toggle SSL/TLS mode */
- ret = camel_tcp_stream_ssl_enable_ssl (CAMEL_TCP_STREAM_SSL (tcp_stream));
-
- camel_object_unref (CAMEL_OBJECT (tcp_stream));
-
- if (ret == -1) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Failed to connect to POP server %s in secure mode: %s"),
- service->url->host, _("SSL negotiations failed"));
- goto stls_exception;
- }
-
- /* rfc2595, section 4 states that after a successful STLS
- command, the client MUST discard prior CAPA responses */
- camel_pop3_engine_reget_capabilities (store->engine);
-
- return TRUE;
-
- stls_exception:
- if (clean_quit) {
- /* try to disconnect cleanly */
- pc = camel_pop3_engine_command_new (store->engine, 0, NULL, NULL, "QUIT\r\n");
- while (camel_pop3_engine_iterate (store->engine, NULL) > 0)
- ;
- camel_pop3_engine_command_free (store->engine, pc);
- }
-
- camel_object_unref (CAMEL_OBJECT (store->engine));
- camel_object_unref (CAMEL_OBJECT (tcp_stream));
- 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 },
-};
+ /* Check extensions */
+ store->login_delay = -1;
+ store->supports_top = -1;
+ store->supports_uidl = -1;
+ store->expires = -1;
-static gboolean
-connect_to_server_wrapper (CamelService *service, CamelException *ex)
-{
-#ifdef HAVE_SSL
- const char *use_ssl;
- int i, ssl_mode;
-
- use_ssl = camel_url_get_param (service->url, "use_ssl");
- if (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 (!connect_to_server (service, ssl_mode, FALSE, ex)) {
- if (camel_exception_get_id (ex) == CAMEL_EXCEPTION_SERVICE_UNAVAILABLE) {
- /* The ssl port seems to be unavailable, lets try STARTTLS */
- camel_exception_clear (ex);
- return connect_to_server (service, ssl_mode, TRUE, ex);
- } else {
- return FALSE;
- }
+ status = camel_pop3_command (store, NULL, ex, "CAPA");
+ if (status == CAMEL_POP3_OK) {
+ char *p;
+ int len;
+
+ buf = camel_pop3_command_get_additional_data (store, 0, ex);
+ if (camel_exception_is_set (ex))
+ return FALSE;
+
+ p = buf;
+ while (*p) {
+ len = strcspn (p, "\n");
+ if (!strncmp (p, "IMPLEMENTATION ", 15)) {
+ g_free (store->implementation);
+ store->implementation =
+ g_strndup (p + 15, len - 15);
+ } else if (len == 3 && !strncmp (p, "TOP", 3))
+ store->supports_top = TRUE;
+ else if (len == 4 && !strncmp (p, "UIDL", 4))
+ store->supports_uidl = TRUE;
+ else if (!strncmp (p, "LOGIN-DELAY ", 12))
+ store->login_delay = atoi (p + 12);
+ else if (!strncmp (p, "EXPIRE NEVER", 12))
+ store->expires = FALSE;
+ else if (!strncmp (p, "EXPIRE ", 7))
+ store->expires = TRUE;
+
+ p += len;
+ if (*p)
+ p++;
}
-
- return TRUE;
- } else if (ssl_mode == USE_SSL_WHEN_POSSIBLE) {
- /* If the server supports STARTTLS, use it */
- return connect_to_server (service, ssl_mode, TRUE, ex);
- } else {
- /* User doesn't care about SSL */
- return connect_to_server (service, ssl_mode, FALSE, ex);
+
+ g_free (buf);
}
-#else
- return connect_to_server (service, USE_SSL_NEVER, FALSE, ex);
-#endif
+
+ return TRUE;
}
extern CamelServiceAuthType camel_pop3_password_authtype;
extern CamelServiceAuthType camel_pop3_apop_authtype;
+#ifdef HAVE_KRB4
+extern CamelServiceAuthType camel_pop3_kpop_authtype;
+#endif
static GList *
query_auth_types (CamelService *service, CamelException *ex)
{
- CamelPOP3Store *store = CAMEL_POP3_STORE (service);
+ CamelPop3Store *store = CAMEL_POP3_STORE (service);
GList *types = NULL;
+ gboolean passwd = TRUE, apop = TRUE;
+#ifdef HAVE_KRB4
+ gboolean kpop;
+#endif
types = CAMEL_SERVICE_CLASS (parent_class)->query_auth_types (service, ex);
if (camel_exception_is_set (ex))
- return NULL;
+ return types;
- if (connect_to_server_wrapper (service, NULL)) {
- types = g_list_concat(types, g_list_copy(store->engine->auth));
+ passwd = connect_to_server (service, NULL);
+ apop = store->apop_timestamp != NULL;
+ if (passwd)
pop3_disconnect (service, TRUE, NULL);
- } else {
+
+#ifdef HAVE_KRB4
+ service->url->authmech = "+KPOP";
+ kpop = connect_to_server (service, NULL);
+ service->url->authmech = NULL;
+ if (kpop)
+ pop3_disconnect (service, TRUE, NULL);
+#endif
+
+ if (passwd)
+ types = g_list_append (types, &camel_pop3_password_authtype);
+ if (apop)
+ types = g_list_append (types, &camel_pop3_apop_authtype);
+#ifdef HAVE_KRB4
+ if (kpop)
+ types = g_list_append (types, &camel_pop3_kpop_authtype);
+#endif
+
+ if (!types) {
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
- _("Could not connect to POP server on %s"),
- service->url->host);
+ _("Could not connect to POP server on "
+ "%s."), service->url->host);
}
-
return types;
}
@@ -362,95 +334,31 @@ query_auth_types (CamelService *service, CamelException *ex)
* reconnect.
**/
void
-camel_pop3_store_expunge (CamelPOP3Store *store, CamelException *ex)
+camel_pop3_store_expunge (CamelPop3Store *store, CamelException *ex)
{
- CamelPOP3Command *pc;
-
- pc = camel_pop3_engine_command_new(store->engine, 0, NULL, NULL, "QUIT\r\n");
- while (camel_pop3_engine_iterate(store->engine, NULL) > 0)
- ;
- camel_pop3_engine_command_free(store->engine, pc);
-
+ camel_pop3_command (store, NULL, ex, "QUIT");
camel_service_disconnect (CAMEL_SERVICE (store), FALSE, ex);
}
-static int
-try_sasl(CamelPOP3Store *store, const char *mech, CamelException *ex)
-{
- CamelPOP3Stream *stream = store->engine->stream;
- unsigned char *line, *resp;
- CamelSasl *sasl;
- unsigned int len;
- int ret;
-
- sasl = camel_sasl_new("pop3", mech, (CamelService *)store);
- if (sasl == NULL) {
- camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
- _("Unable to connect to POP server.\n"
- "No support for requested "
- "authentication mechanism."));
- return -1;
- }
-
- if (camel_stream_printf((CamelStream *)stream, "AUTH %s\r\n", mech) == -1)
- goto ioerror;
-
- while (1) {
- if (camel_pop3_stream_line(stream, &line, &len) == -1)
- goto ioerror;
- if (strncmp(line, "+OK", 3) == 0)
- break;
- if (strncmp(line, "-ERR", 4) == 0) {
- camel_exception_setv(ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
- _("SASL `%s' Login failed: %s"), mech, line);
- goto done;
- }
- /* If we dont get continuation, or the sasl object's run out of work, or we dont get a challenge,
- its a protocol error, so fail, and try reset the server */
- if (strncmp(line, "+ ", 2) != 0
- || camel_sasl_authenticated(sasl)
- || (resp = camel_sasl_challenge_base64(sasl, line+2, ex)) == NULL) {
- camel_stream_printf((CamelStream *)stream, "*\r\n");
- camel_pop3_stream_line(stream, &line, &len);
- camel_exception_setv(ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
- _("SASL Protocol error"));
- goto done;
- }
-
- ret = camel_stream_printf((CamelStream *)stream, "%s\r\n", resp);
- g_free(resp);
- if (ret == -1)
- goto ioerror;
-
- }
- camel_object_unref((CamelObject *)sasl);
- return 0;
-
-ioerror:
- camel_exception_setv(ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
- _("I/O Error: %s"), strerror(errno));
-done:
- camel_object_unref((CamelObject *)sasl);
- return -1;
-}
static gboolean
pop3_try_authenticate (CamelService *service, const char *errmsg,
CamelException *ex)
{
- CamelPOP3Store *store = (CamelPOP3Store *)service;
+ CamelPop3Store *store = (CamelPop3Store *)service;
int status;
- CamelPOP3Command *pcu = NULL, *pcp = NULL;
-
- /* override, testing only */
- /*printf("Forcing authmech to 'login'\n");
- service->url->authmech = g_strdup("LOGIN");*/
-
+ char *msg;
+
+ /* The KPOP code will have set the password to be the username
+ * in connect_to_server. Password and APOP are the only other
+ * cases, and they both need a password. So if there's no
+ * password stored, query for it.
+ */
if (!service->url->passwd) {
char *prompt;
- prompt = g_strdup_printf (_("%sPlease enter the POP password for %s@%s"),
- errmsg ? errmsg : "",
+ prompt = g_strdup_printf (_("%sPlease enter the POP3 password "
+ "for %s@%s"), errmsg ? errmsg : "",
service->url->user,
service->url->host);
service->url->passwd = camel_session_get_password (camel_service_get_session (service),
@@ -459,56 +367,59 @@ pop3_try_authenticate (CamelService *service, const char *errmsg,
if (!service->url->passwd)
return FALSE;
}
-
- if (!service->url->authmech) {
- /* pop engine will take care of pipelining ability */
- pcu = camel_pop3_engine_command_new(store->engine, 0, NULL, NULL, "USER %s\r\n", service->url->user);
- pcp = camel_pop3_engine_command_new(store->engine, 0, NULL, NULL, "PASS %s\r\n", service->url->passwd);
- } else if (strcmp(service->url->authmech, "+APOP") == 0 && store->engine->apop) {
+
+ if (!service->url->authmech || !strcmp (service->url->authmech, "+KPOP")) {
+ status = camel_pop3_command (store, &msg, ex, "USER %s",
+ service->url->user);
+ switch (status) {
+ case CAMEL_POP3_ERR:
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("Unable to connect to POP "
+ "server.\nError sending "
+ "username: %s"),
+ msg ? msg : _("(Unknown)"));
+ g_free (msg);
+ /*fallll*/
+ case CAMEL_POP3_FAIL:
+ return FALSE;
+ }
+ g_free (msg);
+
+ status = camel_pop3_command (store, &msg, ex, "PASS %s",
+ service->url->passwd);
+ } else if (!strcmp (service->url->authmech, "+APOP")
+ && store->apop_timestamp) {
char *secret, md5asc[33], *d;
unsigned char md5sum[16], *s;
- secret = alloca(strlen(store->engine->apop)+strlen(service->url->passwd)+1);
- sprintf(secret, "%s%s", store->engine->apop, service->url->passwd);
- md5_get_digest(secret, strlen (secret), md5sum);
-
+ secret = g_strdup_printf ("%s%s", store->apop_timestamp,
+ service->url->passwd);
+ md5_get_digest (secret, strlen (secret), md5sum);
+ g_free (secret);
+
for (s = md5sum, d = md5asc; d < md5asc + 32; s++, d += 2)
sprintf (d, "%.2x", *s);
- pcp = camel_pop3_engine_command_new(store->engine, 0, NULL, NULL, "APOP %s %s\r\n", service->url->user, md5asc);
+ status = camel_pop3_command (store, &msg, ex, "APOP %s %s",
+ service->url->user, md5asc);
} else {
- CamelServiceAuthType *auth;
- GList *l;
-
- l = store->engine->auth;
- while (l) {
- auth = l->data;
- if (strcmp(auth->authproto, service->url->authmech) == 0)
- return try_sasl(store, service->url->authmech, ex) == -1;
- l = l->next;
- }
-
camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
_("Unable to connect to POP server.\n"
"No support for requested "
"authentication mechanism."));
return FALSE;
}
-
- while (camel_pop3_engine_iterate(store->engine, pcp) > 0)
- ;
- status = pcp->state != CAMEL_POP3_COMMAND_OK;
- if (status) {
- camel_exception_setv(ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
- _("Unable to connect to POP server.\nError sending password: %s"),
- store->engine->line);
+
+ if (status == CAMEL_POP3_ERR) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("Unable to connect to POP server.\n"
+ "Error sending password: %s"),
+ msg ? msg : _("(Unknown)"));
}
- camel_pop3_engine_command_free(store->engine, pcp);
-
- if (pcu)
- camel_pop3_engine_command_free(store->engine, pcu);
-
- return status;
+
+ g_free (msg);
+
+ return status == CAMEL_POP3_ERR;
}
static gboolean
@@ -516,24 +427,8 @@ pop3_connect (CamelService *service, CamelException *ex)
{
char *errbuf = NULL;
gboolean tryagain;
- CamelPOP3Store *store = (CamelPOP3Store *)service;
-
- if (store->cache == NULL) {
- char *root;
-
- root = camel_session_get_storage_path(service->session, service, ex);
- if (root) {
- store->cache = camel_data_cache_new(root, 0, ex);
- g_free(root);
- if (store->cache) {
- /* Default cache expiry - 1 week or not visited in a day */
- camel_data_cache_set_expire_age(store->cache, 60*60*24*7);
- camel_data_cache_set_expire_access(store->cache, 60*60*24);
- }
- }
- }
- if (!connect_to_server_wrapper (service, ex))
+ if (!connect_to_server (service, ex))
return FALSE;
camel_exception_clear (ex);
@@ -565,30 +460,22 @@ pop3_connect (CamelService *service, CamelException *ex)
static gboolean
pop3_disconnect (CamelService *service, gboolean clean, CamelException *ex)
{
- CamelPOP3Store *store = CAMEL_POP3_STORE (service);
+ CamelPop3Store *store = CAMEL_POP3_STORE (service);
- if (clean) {
- CamelPOP3Command *pc;
-
- pc = camel_pop3_engine_command_new(store->engine, 0, NULL, NULL, "QUIT\r\n");
- while (camel_pop3_engine_iterate(store->engine, NULL) > 0)
- ;
- camel_pop3_engine_command_free(store->engine, pc);
- }
+ if (clean)
+ camel_pop3_command (store, NULL, ex, "QUIT");
if (!CAMEL_SERVICE_CLASS (parent_class)->disconnect (service, clean, ex))
return FALSE;
- camel_object_unref((CamelObject *)store->engine);
- store->engine = NULL;
-
return TRUE;
}
static CamelFolder *
-get_folder (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex)
+get_folder (CamelStore *store, const char *folder_name,
+ guint32 flags, CamelException *ex)
{
- if (strcasecmp (folder_name, "inbox") != 0) {
+ if (g_strcasecmp (folder_name, "inbox") != 0) {
camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID,
_("No such folder `%s'."), folder_name);
return NULL;
@@ -609,3 +496,155 @@ get_trash (CamelStore *store, CamelException *ex)
/* no-op */
return NULL;
}
+
+
+/**
+ * camel_pop3_command: Send a command to a POP3 server.
+ * @store: the POP3 store
+ * @ret: a pointer to return the full server response in
+ * @fmt: a printf-style format string, followed by arguments
+ *
+ * This command sends the command specified by @fmt and the following
+ * arguments to the connected POP3 store specified by @store. It then
+ * reads the server's response and parses out the status code. If
+ * the caller passed a non-NULL pointer for @ret, camel_pop3_command
+ * will set it to point to an buffer containing the rest of the
+ * response from the POP3 server. (If @ret was passed but there was
+ * no extended response, @ret will be set to NULL.) The caller must
+ * free this buffer when it is done with it.
+ *
+ * Return value: one of CAMEL_POP3_OK (command executed successfully),
+ * CAMEL_POP3_ERR (command encounted an error), or CAMEL_POP3_FAIL
+ * (a protocol-level error occurred, and Camel is uncertain of the
+ * result of the command.) @ex will be set if the return value is
+ * CAMEL_POP3_FAIL, but *NOT* if it is CAMEL_POP3_ERR.
+ **/
+int
+camel_pop3_command (CamelPop3Store *store, char **ret, CamelException *ex, char *fmt, ...)
+{
+ char *cmdbuf;
+ va_list ap;
+
+ va_start (ap, fmt);
+ cmdbuf = g_strdup_vprintf (fmt, ap);
+ va_end (ap);
+
+ /* Send the command */
+ if (camel_remote_store_send_string (CAMEL_REMOTE_STORE (store), ex, "%s\r\n", cmdbuf) < 0) {
+ g_free (cmdbuf);
+ if (ret)
+ *ret = NULL;
+ return CAMEL_POP3_FAIL;
+ }
+ g_free (cmdbuf);
+
+ return pop3_get_response (store, ret, ex);
+}
+
+static int
+pop3_get_response (CamelPop3Store *store, char **ret, CamelException *ex)
+{
+ char *respbuf;
+ int status;
+
+ if (camel_remote_store_recv_line (CAMEL_REMOTE_STORE (store), &respbuf, ex) < 0) {
+ if (ret)
+ *ret = NULL;
+ return CAMEL_POP3_FAIL;
+ }
+
+ if (!strncmp (respbuf, "+OK", 3))
+ status = CAMEL_POP3_OK;
+ else if (!strncmp (respbuf, "-ERR", 4))
+ status = CAMEL_POP3_ERR;
+ else {
+ status = CAMEL_POP3_FAIL;
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Unexpected response from POP server: %s"),
+ respbuf);
+ }
+
+ if (ret) {
+ if (status != CAMEL_POP3_FAIL) {
+ *ret = strchr (respbuf, ' ');
+ if (*ret)
+ *ret = g_strdup (*ret + 1);
+ } else
+ *ret = NULL;
+ }
+ g_free (respbuf);
+
+ return status;
+}
+
+/**
+ * camel_pop3_command_get_additional_data: get "additional data" from
+ * a POP3 command.
+ * @store: the POP3 store
+ * @total: Total bytes expected (for progress reporting), use 0 for 'unknown'.
+ *
+ * This command gets the additional data returned by "multi-line" POP
+ * commands, such as LIST, RETR, TOP, and UIDL. This command _must_
+ * be called after a successful (CAMEL_POP3_OK) call to
+ * camel_pop3_command for a command that has a multi-line response.
+ * The returned data is un-byte-stuffed, and has lines termined by
+ * newlines rather than CR/LF pairs.
+ *
+ * Return value: the data, which the caller must free.
+ **/
+char *
+camel_pop3_command_get_additional_data (CamelPop3Store *store, int total, CamelException *ex)
+{
+ GPtrArray *data;
+ char *buf, *p;
+ int i, len = 0, status = CAMEL_POP3_OK;
+ int pc = 0;
+
+ data = g_ptr_array_new ();
+ while (1) {
+ if (camel_remote_store_recv_line (CAMEL_REMOTE_STORE (store), &buf, ex) < 0) {
+ status = CAMEL_POP3_FAIL;
+ break;
+ }
+
+ if (!strcmp (buf, "."))
+ break;
+
+ g_ptr_array_add (data, buf);
+ len += strlen (buf) + 1;
+
+ if (total) {
+ pc = (len+1) * 100 / total;
+ camel_operation_progress(NULL, pc);
+ } else {
+ camel_operation_progress_count(NULL, len);
+ }
+ }
+
+ if (buf)
+ g_free (buf);
+
+ if (status == CAMEL_POP3_OK) {
+ buf = g_malloc0 (len + 1);
+
+ for (i = 0, p = buf; 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
+ buf = NULL;
+
+ for (i = 0; i < data->len; i++)
+ g_free (data->pdata[i]);
+ g_ptr_array_free (data, TRUE);
+
+ return buf;
+}
+