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.c634
1 files changed, 0 insertions, 634 deletions
diff --git a/camel/providers/pop3/camel-pop3-store.c b/camel/providers/pop3/camel-pop3-store.c
deleted file mode 100644
index 515e982b95..0000000000
--- a/camel/providers/pop3/camel-pop3-store.c
+++ /dev/null
@@ -1,634 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/* camel-pop3-store.c : class for a pop3 store */
-
-/*
- * Authors:
- * Dan Winship <danw@ximian.com>
- * Michael Zucchi <notzed@ximian.com>
- *
- * Copyright (C) 2000-2002 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
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include "camel-operation.h"
-
-#include "camel-pop3-store.h"
-#include "camel-pop3-folder.h"
-#include "camel-stream-buffer.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_NSS
-#include "camel-tcp-stream-ssl.h"
-#include <prnetdb.h>
-#endif
-#ifdef HAVE_OPENSSL
-#include "camel-tcp-stream-openssl.h"
-#endif
-
-/* Specified in RFC 1939 */
-#define POP3_PORT 110
-
-static CamelStoreClass *parent_class = NULL;
-
-static void finalize (CamelObject *object);
-
-static gboolean pop3_connect (CamelService *service, CamelException *ex);
-static gboolean pop3_disconnect (CamelService *service, gboolean clean, CamelException *ex);
-static GList *query_auth_types (CamelService *service, CamelException *ex);
-
-static CamelFolder *get_folder (CamelStore *store, const char *folder_name,
- guint32 flags, CamelException *ex);
-
-static void init_trash (CamelStore *store);
-static CamelFolder *get_trash (CamelStore *store, CamelException *ex);
-
-static void
-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 ()));
-
- /* virtual method overload */
- camel_service_class->query_auth_types = query_auth_types;
- camel_service_class->connect = pop3_connect;
- camel_service_class->disconnect = pop3_disconnect;
-
- camel_store_class->get_folder = get_folder;
- camel_store_class->init_trash = init_trash;
- camel_store_class->get_trash = get_trash;
-}
-
-
-
-static void
-camel_pop3_store_init (gpointer object, gpointer klass)
-{
- ;
-}
-
-CamelType
-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),
- (CamelObjectClassInitFunc) camel_pop3_store_class_init,
- NULL,
- (CamelObjectInitFunc) camel_pop3_store_init,
- finalize);
- }
-
- return camel_pop3_store_type;
-}
-
-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 */
-
- 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);
-}
-
-enum {
- USE_SSL_NEVER,
- USE_SSL_ALWAYS,
- USE_SSL_WHEN_POSSIBLE
-};
-
-static gboolean
-connect_to_server (CamelService *service, int ssl_mode, int try_starttls, int *stls_support, 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;
-
-#if defined (HAVE_NSS) || defined (HAVE_OPENSSL)
- /* FIXME: check for "always" and "when-possible" to support STARTTLS */
- if (camel_url_get_param (service->url, "use_ssl")) {
- if (!try_starttls)
- port = service->url->port ? service->url->port : 995;
-#ifdef HAVE_NSS
- /* this is the preferred SSL implementation */
- if (try_starttls)
- tcp_stream = camel_tcp_stream_ssl_new_raw (service, service->url->host);
- else
- tcp_stream = camel_tcp_stream_ssl_new (service, service->url->host);
-#else
- /* use openssl... */
- if (try_starttls)
- tcp_stream = camel_tcp_stream_openssl_new_raw (service, service->url->host);
- else
- tcp_stream = camel_tcp_stream_openssl_new (service, service->url->host);
-#endif /* HAVE_NSS */
- } else {
- tcp_stream = camel_tcp_stream_raw_new ();
- }
-#else
- tcp_stream = camel_tcp_stream_raw_new ();
-#endif /* HAVE_NSS || HAVE_OPENSSL */
-
- 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 ? service->url->host : _("(unknown host)"),
- port, g_strerror (errno));
- return FALSE;
- }
-
- /* parent class connect initialization */
- if (CAMEL_SERVICE_CLASS (parent_class)->connect (service, ex) == FALSE) {
- camel_object_unref (CAMEL_OBJECT (tcp_stream));
- return FALSE;
- }
-
- store->engine = camel_pop3_engine_new (tcp_stream);
-
- if (stls_support)
- *stls_support = store->engine->capa & CAMEL_POP3_CAP_STLS;
-
-#if defined (HAVE_NSS) || defined (HAVE_OPENSSL)
- 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;
- }
- }
- }
- }
-#endif /* HAVE_NSS || HAVE_OPENSSL */
-
- camel_object_unref (CAMEL_OBJECT (tcp_stream));
-
- return store->engine != NULL;
-
-#if defined (HAVE_NSS) || defined (HAVE_OPENSSL)
- 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 */
-#ifdef HAVE_NSS
- ret = camel_tcp_stream_ssl_enable_ssl (CAMEL_TCP_STREAM_SSL (tcp_stream));
-#else /* HAVE_OPENSSL */
- ret = camel_tcp_stream_openssl_enable_ssl (CAMEL_TCP_STREAM_OPENSSL (tcp_stream));
-#endif
-
- 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_NSS || HAVE_OPENSSL */
-}
-
-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 },
-};
-
-#define EXCEPTION_RETRY(ex) (camel_exception_get_id (ex) != CAMEL_EXCEPTION_USER_CANCEL && \
- camel_exception_get_id (ex) != CAMEL_EXCEPTION_SERVICE_UNAVAILABLE)
-
-static gboolean
-connect_to_server_wrapper (CamelService *service, CamelException *ex)
-{
-#if defined (HAVE_NSS) || defined (HAVE_OPENSSL)
- const char *use_ssl;
- int stls_supported;
- 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 STARTTLS */
- if (!connect_to_server (service, ssl_mode, TRUE, &stls_supported, ex) &&
- !stls_supported && EXCEPTION_RETRY (ex)) {
- /* STARTTLS is unavailable - okay, now try old-style SSL */
- camel_exception_clear (ex);
- return connect_to_server (service, ssl_mode, FALSE, NULL, ex);
- }
-
- 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, NULL, ex);
- } else {
- /* User doesn't care about SSL */
- return connect_to_server (service, ssl_mode, FALSE, NULL, ex);
- }
-#else
- return connect_to_server (service, USE_SSL_NEVER, FALSE, NULL, ex);
-#endif
-}
-
-extern CamelServiceAuthType camel_pop3_password_authtype;
-extern CamelServiceAuthType camel_pop3_apop_authtype;
-
-static GList *
-query_auth_types (CamelService *service, CamelException *ex)
-{
- CamelPOP3Store *store = CAMEL_POP3_STORE (service);
- GList *types = NULL;
-
- types = CAMEL_SERVICE_CLASS (parent_class)->query_auth_types (service, ex);
- if (camel_exception_is_set (ex))
- return NULL;
-
- if (connect_to_server_wrapper (service, NULL)) {
- types = g_list_concat(types, g_list_copy(store->engine->auth));
- pop3_disconnect (service, TRUE, NULL);
- } else {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
- _("Could not connect to POP server on %s"),
- service->url->host);
- }
-
- return types;
-}
-
-/**
- * camel_pop3_store_expunge:
- * @store: the store
- * @ex: a CamelException
- *
- * Expunge messages from the store. This will result in the connection
- * being closed, which may cause later commands to fail if they can't
- * reconnect.
- **/
-void
-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_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;
- int status;
- CamelPOP3Command *pcu = NULL, *pcp = NULL;
-
- /* override, testing only */
- /*printf("Forcing authmech to 'login'\n");
- service->url->authmech = g_strdup("LOGIN");*/
-
- if (!service->url->passwd) {
- char *prompt;
-
- prompt = g_strdup_printf (_("%sPlease enter the POP password for %s@%s"),
- errmsg ? errmsg : "",
- service->url->user,
- service->url->host);
- service->url->passwd = camel_session_get_password (camel_service_get_session (service),
- prompt, TRUE, service, "password", ex);
- g_free (prompt);
- 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) {
- 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);
-
- 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);
- } 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);
- }
- camel_pop3_engine_command_free(store->engine, pcp);
-
- if (pcu)
- camel_pop3_engine_command_free(store->engine, pcu);
-
- return status;
-}
-
-static gboolean
-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))
- return FALSE;
-
- camel_exception_clear (ex);
- do {
- if (camel_exception_is_set (ex)) {
- errbuf = g_strdup_printf ("%s\n\n", camel_exception_get_description (ex));
- camel_exception_clear (ex);
-
- /* Uncache the password before prompting again. */
- camel_session_forget_password (camel_service_get_session (service),
- service, "password", ex);
- g_free (service->url->passwd);
- service->url->passwd = NULL;
- }
-
- tryagain = pop3_try_authenticate (service, errbuf, ex);
- g_free (errbuf);
- errbuf = NULL;
- } while (tryagain);
-
- if (camel_exception_is_set (ex)) {
- camel_service_disconnect (service, TRUE, ex);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static gboolean
-pop3_disconnect (CamelService *service, gboolean clean, CamelException *ex)
-{
- 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 (!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)
-{
- if (strcasecmp (folder_name, "inbox") != 0) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID,
- _("No such folder `%s'."), folder_name);
- return NULL;
- }
- return camel_pop3_folder_new (store, ex);
-}
-
-static void
-init_trash (CamelStore *store)
-{
- /* no-op */
- ;
-}
-
-static CamelFolder *
-get_trash (CamelStore *store, CamelException *ex)
-{
- /* no-op */
- return NULL;
-}