diff options
Diffstat (limited to 'camel/camel-remote-store.c')
-rw-r--r-- | camel/camel-remote-store.c | 643 |
1 files changed, 0 insertions, 643 deletions
diff --git a/camel/camel-remote-store.c b/camel/camel-remote-store.c deleted file mode 100644 index 41e16a27fc..0000000000 --- a/camel/camel-remote-store.c +++ /dev/null @@ -1,643 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-remote-store.c : class for an remote store */ - -/* - * Authors: Peter Williams <peterw@helixcode.com> - * based on camel-imap-provider.c - * - * Copyright 2000 Helix Code, Inc. (www.helixcode.com) - * - * 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. - * - */ - -#include <config.h> - -#include <sys/time.h> -#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-remote-store.h" -#include "camel-folder.h" -#include "camel-exception.h" -#include "camel-session.h" -#include "camel-stream.h" -#include "camel-stream-buffer.h" -#include "camel-stream-fs.h" -#include "camel-url.h" -#include "string-utils.h" - -#include "camel-private.h" -#include "camel-operation.h" - -#define d(x) x -#if d(!)0 -extern gboolean camel_verbose_debug; -#endif - -#define CSRVC(obj) (CAMEL_SERVICE_CLASS (CAMEL_OBJECT_GET_CLASS (obj))) -#define CSTRC(obj) (CAMEL_STORE_CLASS (CAMEL_OBJECT_GET_CLASS (obj))) -#define CRSC(obj) (CAMEL_REMOTE_STORE_CLASS (CAMEL_OBJECT_GET_CLASS (obj))) - -static CamelStoreClass *store_class = NULL; - -static gboolean remote_connect (CamelService *service, CamelException *ex); -static gboolean remote_disconnect (CamelService *service, gboolean clean, CamelException *ex); -static GList *remote_query_auth_types(CamelService *service, gboolean connect, CamelException *ex); -static void remote_free_auth_types (CamelService *service, GList *authtypes); -static char *remote_get_name (CamelService *service, gboolean brief); -static gint remote_send_string (CamelRemoteStore *store, CamelException *ex, - char *fmt, va_list ap); -static gint remote_send_stream (CamelRemoteStore *store, CamelStream *stream, - CamelException *ex); -static gint remote_recv_line (CamelRemoteStore *store, char **dest, - CamelException *ex); - -static void -camel_remote_store_class_init (CamelRemoteStoreClass *camel_remote_store_class) -{ - /* virtual method overload */ - CamelServiceClass *camel_service_class = - CAMEL_SERVICE_CLASS (camel_remote_store_class); - - store_class = CAMEL_STORE_CLASS (camel_type_get_global_classfuncs (camel_store_get_type ())); - - /* virtual method overload */ - camel_service_class->connect = remote_connect; - camel_service_class->disconnect = remote_disconnect; - camel_service_class->query_auth_types = remote_query_auth_types; - camel_service_class->free_auth_types = remote_free_auth_types; - camel_service_class->get_name = remote_get_name; - - camel_remote_store_class->send_string = remote_send_string; - camel_remote_store_class->send_stream = remote_send_stream; - camel_remote_store_class->recv_line = remote_recv_line; - camel_remote_store_class->keepalive = NULL; -} - -static void -camel_remote_store_init (CamelObject *object) -{ - CamelStore *store = CAMEL_STORE (object); - CamelRemoteStore *remote_store = CAMEL_REMOTE_STORE (object); - - store->folders = g_hash_table_new (g_str_hash, g_str_equal); - - remote_store->istream = NULL; - remote_store->ostream = NULL; - remote_store->timeout_id = 0; - - remote_store->priv = g_malloc0(sizeof(*remote_store->priv)); -#ifdef ENABLE_THREADS - remote_store->priv->stream_lock = e_mutex_new(E_MUTEX_REC); -#endif -} - -static void -camel_remote_store_finalise(CamelObject *object) -{ - CamelRemoteStore *remote_store = CAMEL_REMOTE_STORE (object); - -#ifdef ENABLE_THREADS - e_mutex_destroy(remote_store->priv->stream_lock); -#endif - g_free(remote_store->priv); -} - - -CamelType -camel_remote_store_get_type (void) -{ - static CamelType camel_remote_store_type = CAMEL_INVALID_TYPE; - - if (camel_remote_store_type == CAMEL_INVALID_TYPE) { - camel_remote_store_type = - camel_type_register (CAMEL_STORE_TYPE, "CamelRemoteStore", - sizeof (CamelRemoteStore), - sizeof (CamelRemoteStoreClass), - (CamelObjectClassInitFunc) camel_remote_store_class_init, - NULL, - (CamelObjectInitFunc) camel_remote_store_init, - (CamelObjectFinalizeFunc) camel_remote_store_finalise); - } - - return camel_remote_store_type; -} - -/* Auth stuff */ - -/* -static CamelServiceAuthType password_authtype = { - N_("SSH Tunneling"), - - N_("This option will connect to the server using a " - "SSH tunnel."), - - "", - TRUE -}; -*/ - -static GList * -remote_query_auth_types (CamelService *service, gboolean connect, CamelException *ex) -{ - return NULL; -} - -static void -remote_free_auth_types (CamelService *service, GList *authtypes) -{ - g_list_free (authtypes); -} - -static char * -remote_get_name (CamelService *service, gboolean brief) -{ - if (brief) - return g_strdup_printf (_("%s server %s"), - service->provider->name, - service->url->host); - else { - return g_strdup_printf (_("%s service for %s on %s"), - service->provider->name, - service->url->user, - service->url->host); - } -} - -static gboolean -timeout_cb (gpointer data) -{ - CamelRemoteStore *store = CAMEL_REMOTE_STORE(data); - - CRSC (data)->keepalive(store); - - return TRUE; -} - -/* this is a 'cancellable' connect, cancellable from camel_operation_cancel etc */ -/* returns -1 & errno == EINTR if the connection was cancelled */ -static int socket_connect(struct hostent *h, int port) -{ - struct sockaddr_in sin; - int fd; - int ret; - socklen_t len; - struct timeval tv; - int cancel_fd; - - /* see if we're cancelled yet */ - if (camel_operation_cancel_check(NULL)) { - errno = EINTR; - return -1; - } - - /* setup connect, we do it using a nonblocking socket so we can poll it */ - sin.sin_port = htons(port); - sin.sin_family = h->h_addrtype; - memcpy (&sin.sin_addr, h->h_addr, sizeof (sin.sin_addr)); - - fd = socket (h->h_addrtype, SOCK_STREAM, 0); - - cancel_fd = camel_operation_cancel_fd(NULL); - if (cancel_fd == -1) { - ret = connect(fd, (struct sockaddr *)&sin, sizeof (sin)); - if (ret == -1) { - close(fd); - return -1; - } - return fd; - } else { - fd_set rdset, wrset; - int flags, fdmax; - - flags = fcntl(fd, F_GETFL); - fcntl(fd, F_SETFL, flags | O_NONBLOCK); - - ret = connect(fd, (struct sockaddr *)&sin, sizeof (sin)); - if (ret == 0) { - fcntl(fd, F_SETFL, flags); - return fd; - } - - if (errno != EINPROGRESS) { - close(fd); - return -1; - } - - FD_ZERO(&rdset); - FD_ZERO(&wrset); - FD_SET(fd, &wrset); - FD_SET(cancel_fd, &rdset); - fdmax = MAX(fd, cancel_fd)+1; - tv.tv_usec = 0; - tv.tv_sec = 60*4; - if (select(fdmax, &rdset, &wrset, 0, &tv) == 0) { - close(fd); - errno = ETIMEDOUT; - return -1; - } - if (cancel_fd != -1 && FD_ISSET(cancel_fd, &rdset)) { - close(fd); - errno = EINTR; - return -1; - } else { - len = sizeof(int); - if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, &len) == -1) { - close(fd); - return -1; - } - if (ret != 0) { - close(fd); - errno = ret; - return -1; - } - } - fcntl(fd, F_SETFL, flags); - } - - return fd; -} - -static gboolean -remote_connect (CamelService *service, CamelException *ex) -{ - CamelRemoteStore *store = CAMEL_REMOTE_STORE (service); - struct hostent *h; - struct sockaddr_in sin; - gint fd; - gint port; - - h = camel_service_gethost (service, ex); - if (!h) - return FALSE; - - /* connect to the server */ - sin.sin_family = h->h_addrtype; - - if (service->url->port) - port = service->url->port; - else - port = store->default_port; - -#if 1 - fd = socket_connect(h, port); - if (fd == -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, strerror (errno)); - return FALSE; - } -#else - sin.sin_port = htons (port); - - memcpy (&sin.sin_addr, h->h_addr, sizeof (sin.sin_addr)); - - fd = socket (h->h_addrtype, SOCK_STREAM, 0); - if (fd == -1 || connect (fd, (struct sockaddr *)&sin, sizeof (sin)) == -1) { - 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)); - if (fd > -1) - close (fd); - - return FALSE; - } -#endif - - /* parent class connect initialization */ - if (CAMEL_SERVICE_CLASS (store_class)->connect (service, ex) == FALSE) - return FALSE; - - store->ostream = camel_stream_fs_new_with_fd (fd); - store->istream = camel_stream_buffer_new (store->ostream, CAMEL_STREAM_BUFFER_READ); - - /* Okay, good enough for us */ - CAMEL_SERVICE (store)->connected = TRUE; - - /* Add a timeout so that we can hopefully prevent getting disconnected */ - /* (Only if the implementation supports it) */ - if (CRSC (store)->keepalive) { - CamelSession *session = camel_service_get_session (CAMEL_SERVICE (store)); - - store->timeout_id = camel_session_register_timeout (session, 10 * 60 * 1000, - timeout_cb, - store); - } - - return TRUE; -} - -static gboolean -remote_disconnect (CamelService *service, gboolean clean, CamelException *ex) -{ - CamelRemoteStore *store = CAMEL_REMOTE_STORE (service); - - if (store->timeout_id) { - camel_session_remove_timeout (camel_service_get_session (CAMEL_SERVICE (store)), - store->timeout_id); - store->timeout_id = 0; - } - - if (!CAMEL_SERVICE_CLASS (store_class)->disconnect (service, clean, ex)) - return FALSE; - - if (store->istream) { - camel_object_unref (CAMEL_OBJECT (store->istream)); - store->istream = NULL; - } - - if (store->ostream) { - camel_object_unref (CAMEL_OBJECT (store->ostream)); - store->ostream = NULL; - } - - return TRUE; -} - -static gint -remote_send_string (CamelRemoteStore *store, CamelException *ex, char *fmt, va_list ap) -{ - gchar *cmdbuf; - - /* Check for connectedness. Failed (or cancelled) operations will - * close the connection. */ - if (!camel_remote_store_connected (store, ex)) - return -1; - - /* create the command */ - cmdbuf = g_strdup_vprintf (fmt, ap); - -#if d(!)0 - if (camel_verbose_debug) { - if (strncmp (cmdbuf, "PASS ", 5) == 0) - fprintf (stderr, "sending : PASS xxxx\n"); - else if (strstr (cmdbuf, "LOGIN \"")) - fprintf (stderr, "sending : ---- LOGIN \"xxxx\" \"xxxx\"\n"); - else - fprintf (stderr, "sending : %s", cmdbuf); - } -#endif - - if (camel_stream_printf (store->ostream, "%s", cmdbuf) == -1) { - if (errno == EINTR) - camel_exception_set(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Operation cancelled")); - else - camel_exception_set(ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, strerror(errno)); - g_free (cmdbuf); - - camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL); - return -1; - } - g_free (cmdbuf); - - return 0; -} - -/* FIXME: All of these functions need an api overhaul, they're not like - any other functions, anywhere in the world ... */ - -/** - * camel_remote_store_send_string: Writes a string to the server - * @store: a CamelRemoteStore - * @ex: a CamelException - * @fmt: the printf-style format to use for creating the string to send - * @...: the arguments to the printf string @fmt - * Return value: 0 on success, nonzero on error - * - * Formats the string and sends it to the server. - **/ - -gint -camel_remote_store_send_string (CamelRemoteStore *store, CamelException *ex, - char *fmt, ...) -{ - va_list ap; - gint ret; - - g_return_val_if_fail (CAMEL_IS_REMOTE_STORE (store), -1); - g_return_val_if_fail (fmt, -1); - - va_start (ap, fmt); - CAMEL_REMOTE_STORE_LOCK(store, stream_lock); - ret = CRSC (store)->send_string (store, ex, fmt, ap); - CAMEL_REMOTE_STORE_UNLOCK(store, stream_lock); - va_end (ap); - - return ret; -} - -static gint -remote_send_stream (CamelRemoteStore *store, CamelStream *stream, CamelException *ex) -{ - int ret; - - /* Check for connectedness. Failed (or cancelled) operations will - * close the connection. */ - - if (!camel_remote_store_connected (store, ex)) - return -1; - - d(fprintf (stderr, "(sending stream)\n")); - - ret = camel_stream_write_to_stream (stream, store->ostream); - if (ret == -1) { - if (errno == EINTR) - camel_exception_set(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Operation cancelled")); - else - camel_exception_set(ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, strerror(errno)); - - camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL); - } - - return ret; -} - -/** - * camel_remote_store_send_stream: Writes a CamelStream to the server - * @store: a CamelRemoteStore - * @stream: the stream to write - * @ex: a CamelException - * Return value: 0 on success, nonzero on error - * - * Sends the stream to the server. - **/ - -gint -camel_remote_store_send_stream (CamelRemoteStore *store, CamelStream *stream, CamelException *ex) -{ - int ret; - - g_return_val_if_fail (CAMEL_IS_REMOTE_STORE (store), -1); - g_return_val_if_fail (CAMEL_IS_STREAM (stream), -1); - - CAMEL_REMOTE_STORE_LOCK(store, stream_lock); - - ret = CRSC (store)->send_stream (store, stream, ex); - - CAMEL_REMOTE_STORE_UNLOCK(store, stream_lock); - - return ret; -} - -static int -remote_recv_line (CamelRemoteStore *store, char **dest, CamelException *ex) -{ - CamelStreamBuffer *stream = CAMEL_STREAM_BUFFER (store->istream); - GByteArray *bytes; - gchar buf[1024], *ret; - gint nread; - - *dest = NULL; - - /* Check for connectedness. Failed (or cancelled) operations will - * close the connection. We can't expect a read to have any - * meaning if we reconnect, so always set an exception. - */ - - if (!camel_remote_store_connected (store, ex)) { - camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_NOT_CONNECTED, - g_strerror (errno)); - return -1; - } - - bytes = g_byte_array_new (); - - do { - nread = camel_stream_buffer_gets (stream, buf, sizeof (buf)); - if (nread > 0) - g_byte_array_append (bytes, buf, nread); - } while (nread == sizeof (buf) - 1); - - if (nread == -1) { - if (errno == EINTR) - camel_exception_set(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Operation cancelled")); - else - camel_exception_set(ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, strerror(errno)); - } else if (bytes->len == 0) { - camel_exception_set(ex, CAMEL_EXCEPTION_SERVICE_NOT_CONNECTED, - _("Server unexpectedly disconnected")); - } - if (camel_exception_is_set (ex)) { - g_byte_array_free(bytes, TRUE); - camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL); - return -1; - } - - g_byte_array_append (bytes, "", 1); - ret = bytes->data; - nread = bytes->len - 1; - g_byte_array_free (bytes, FALSE); - - /* strip off the CRLF sequence */ - while (nread > 0 && ret[nread] != '\r') - ret[nread--] = '\0'; - ret[nread] = '\0'; - - *dest = ret; - -#if d(!)0 - if (camel_verbose_debug) - fprintf (stderr, "received: %s\n", *dest); -#endif - - return nread; -} - -/** - * camel_remote_store_recv_line: Reads a line from the server - * @store: a CamelRemoteStore - * @dest: a pointer that will be set to the location of a buffer - * holding the server's response - * @ex: a CamelException - * Return value: -1 on error, otherwise the length read. - * - * Reads a line from the server (terminated by \n or \r\n). - **/ - -gint -camel_remote_store_recv_line (CamelRemoteStore *store, char **dest, - CamelException *ex) -{ - int ret; - - g_return_val_if_fail (CAMEL_IS_REMOTE_STORE (store), -1); - g_return_val_if_fail (dest, -1); - - CAMEL_REMOTE_STORE_LOCK(store, stream_lock); - - ret = CRSC (store)->recv_line (store, dest, ex); - - CAMEL_REMOTE_STORE_UNLOCK(store, stream_lock); - - return ret; -} - -static void -refresh_folder_info (gpointer key, gpointer value, gpointer data) -{ - CamelFolder *folder = CAMEL_FOLDER (value); - - camel_folder_refresh_info (folder, (CamelException *) data); -} - -/** - * camel_remote_store_refresh_folders: Refresh the folders that I - * contain - * @store: a CamelRemoteStore - * @ex: a CamelException - * - * Refreshes the folders listed in the folders hashtable. - **/ -void -camel_remote_store_refresh_folders (CamelRemoteStore *store, CamelException *ex) -{ - CAMEL_STORE_LOCK(store, cache_lock); - - g_hash_table_foreach (CAMEL_STORE (store)->folders, refresh_folder_info, ex); - - CAMEL_STORE_UNLOCK(store, cache_lock); -} - -/** - * camel_remote_store_connected: - * @store: a CamelRemoteStore - * @ex: a CamelException - * - * Ensure that the remote store is connected. - * - * Return value: Whether or not it is connected - **/ -gboolean -camel_remote_store_connected (CamelRemoteStore *store, CamelException *ex) -{ - if (store->istream == NULL) { - camel_service_connect (CAMEL_SERVICE (store), ex); - return !camel_exception_is_set (ex); - } - return TRUE; -} |