diff options
Diffstat (limited to 'camel/providers/imap/camel-imap-store.c')
-rw-r--r-- | camel/providers/imap/camel-imap-store.c | 630 |
1 files changed, 0 insertions, 630 deletions
diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c deleted file mode 100644 index 80dc8dcd3c..0000000000 --- a/camel/providers/imap/camel-imap-store.c +++ /dev/null @@ -1,630 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-imap-store.c : class for an imap store */ - -/* - * Authors: Jeffrey Stedfast <fejj@helixcode.com> - * - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> - -#include <gal/util/e-util.h> - -#include "camel-imap-store.h" -#include "camel-imap-folder.h" -#include "camel-imap-utils.h" -#include "camel-imap-command.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" - -#define d(x) x - -/* Specified in RFC 2060 */ -#define IMAP_PORT 143 - -static CamelRemoteStoreClass *remote_store_class = NULL; - -static gboolean imap_connect (CamelService *service, CamelException *ex); -static gboolean imap_disconnect (CamelService *service, CamelException *ex); -static GList *query_auth_types_generic (CamelService *service, CamelException *ex); -static GList *query_auth_types_connected (CamelService *service, CamelException *ex); -static CamelFolder *get_folder (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex); -static char *get_folder_name (CamelStore *store, const char *folder_name, - CamelException *ex); -static char *get_root_folder_name (CamelStore *store, CamelException *ex); -static CamelFolderInfo *get_folder_info (CamelStore *store, const char *top, - gboolean fast, gboolean recursive, - gboolean subscribed_only, - CamelException *ex); -static void imap_keepalive (CamelRemoteStore *store); - -static void -camel_imap_store_class_init (CamelImapStoreClass *camel_imap_store_class) -{ - /* virtual method overload */ - CamelServiceClass *camel_service_class = - CAMEL_SERVICE_CLASS (camel_imap_store_class); - CamelStoreClass *camel_store_class = - CAMEL_STORE_CLASS (camel_imap_store_class); - CamelRemoteStoreClass *camel_remote_store_class = - CAMEL_REMOTE_STORE_CLASS (camel_imap_store_class); - - remote_store_class = CAMEL_REMOTE_STORE_CLASS(camel_type_get_global_classfuncs - (camel_remote_store_get_type ())); - - /* virtual method overload */ - camel_service_class->query_auth_types_generic = query_auth_types_generic; - camel_service_class->query_auth_types_connected = query_auth_types_connected; - camel_service_class->connect = imap_connect; - camel_service_class->disconnect = imap_disconnect; - - camel_store_class->get_folder = get_folder; - camel_store_class->get_folder_name = get_folder_name; - camel_store_class->get_root_folder_name = get_root_folder_name; - camel_store_class->get_folder_info = get_folder_info; - camel_store_class->free_folder_info = camel_store_free_folder_info_full; - - camel_remote_store_class->keepalive = imap_keepalive; -} - -static void -camel_imap_store_init (gpointer object, gpointer klass) -{ - CamelService *service = CAMEL_SERVICE (object); - CamelRemoteStore *remote_store = CAMEL_REMOTE_STORE (object); - CamelImapStore *imap_store = CAMEL_IMAP_STORE (object); - - service->url_flags |= (CAMEL_SERVICE_URL_NEED_USER | - CAMEL_SERVICE_URL_NEED_HOST | - CAMEL_SERVICE_URL_ALLOW_PATH | - CAMEL_SERVICE_URL_ALLOW_AUTH); - - remote_store->default_port = 143; - - imap_store->dir_sep = NULL; - imap_store->current_folder = NULL; - - imap_store->connected = FALSE; -} - -CamelType -camel_imap_store_get_type (void) -{ - static CamelType camel_imap_store_type = CAMEL_INVALID_TYPE; - - if (camel_imap_store_type == CAMEL_INVALID_TYPE) { - camel_imap_store_type = - camel_type_register (CAMEL_REMOTE_STORE_TYPE, "CamelImapStore", - sizeof (CamelImapStore), - sizeof (CamelImapStoreClass), - (CamelObjectClassInitFunc) camel_imap_store_class_init, - NULL, - (CamelObjectInitFunc) camel_imap_store_init, - (CamelObjectFinalizeFunc) NULL); - } - - return camel_imap_store_type; -} - -static CamelServiceAuthType password_authtype = { - "Password", - - "This option will connect to the IMAP server using a " - "plaintext password.", - - "", - TRUE -}; - -static GList * -query_auth_types_connected (CamelService *service, CamelException *ex) -{ -#if 0 - GList *ret = NULL; - gboolean passwd = TRUE; - - if (service->url) { - passwd = try_connect (service, ex); - if (camel_exception_get_id (ex) != CAMEL_EXCEPTION_NONE) - return NULL; - } - - if (passwd) - ret = g_list_append (ret, &password_authtype); - - if (!ret) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - "Could not connect to IMAP server on %s.", - service->url->host ? service->url->host : - "(unknown host)"); - } - - return ret; -#else - g_warning ("imap::query_auth_types_connected: not implemented. Defaulting."); - /* FIXME: use the classfunc instead of the local? */ - return query_auth_types_generic (service, ex); -#endif -} - -static GList * -query_auth_types_generic (CamelService *service, CamelException *ex) -{ - GList *prev; - - prev = CAMEL_SERVICE_CLASS (remote_store_class)->query_auth_types_generic (service, ex); - return g_list_prepend (prev, &password_authtype); -} - -static gboolean -imap_connect (CamelService *service, CamelException *ex) -{ - CamelImapStore *store = CAMEL_IMAP_STORE (service); - CamelSession *session = camel_service_get_session (CAMEL_SERVICE (store)); - gchar *result, *buf, *errbuf = NULL; - CamelImapResponse *response; - gboolean authenticated = FALSE; - - if (CAMEL_SERVICE_CLASS (remote_store_class)->connect (service, ex) == FALSE) - return FALSE; - - store->command = 0; - g_free (store->dir_sep); - store->dir_sep = g_strdup ("/"); /* default dir sep */ - if (!store->storage_path) { - store->storage_path = - camel_session_get_storage_path (session, service, ex); - if (camel_exception_is_set (ex)) - return FALSE; - } - - /* Read the greeting, if any. */ - if (camel_remote_store_recv_line (CAMEL_REMOTE_STORE (service), &buf, ex) < 0) { - return FALSE; - } - g_free (buf); - - /* authenticate the user */ - while (!authenticated) { - if (errbuf) { - /* We need to un-cache the password before prompting again */ - camel_session_query_authenticator (session, - CAMEL_AUTHENTICATOR_TELL, NULL, - TRUE, service, "password", ex); - g_free (service->url->passwd); - service->url->passwd = NULL; - } - - if (!service->url->authmech && !service->url->passwd) { - gchar *prompt; - - prompt = g_strdup_printf ("%sPlease enter the IMAP password for %s@%s", - errbuf ? errbuf : "", service->url->user, service->url->host); - service->url->passwd = - camel_session_query_authenticator (session, - CAMEL_AUTHENTICATOR_ASK, prompt, - TRUE, service, "password", ex); - g_free (prompt); - g_free (errbuf); - errbuf = NULL; - - if (!service->url->passwd) { - camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, - "You didn\'t enter a password."); - return FALSE; - } - } - - response = camel_imap_command (store, NULL, ex, - "LOGIN \"%s\" \"%s\"", - service->url->user, - service->url->passwd); - if (!response) { - errbuf = g_strdup_printf ("Unable to authenticate to IMAP server.\n" - "%s\n\n", - camel_exception_get_description (ex)); - camel_exception_clear (ex); - } else { - g_message ("IMAP Service sucessfully authenticated user %s", service->url->user); - authenticated = TRUE; - camel_imap_response_free (response); - } - } - - /* At this point we know we're connected... */ - store->connected = TRUE; - - /* Now lets find out the IMAP capabilities */ - response = camel_imap_command (store, NULL, ex, "CAPABILITY"); - if (!response) - return FALSE; - result = camel_imap_response_extract (response, "CAPABILITY", ex); - if (!result) - return FALSE; - - /* parse for capabilities here. */ - if (e_strstrcase (result, "IMAP4REV1")) - store->server_level = IMAP_LEVEL_IMAP4REV1; - else if (e_strstrcase (result, "IMAP4")) - store->server_level = IMAP_LEVEL_IMAP4; - else - store->server_level = IMAP_LEVEL_UNKNOWN; - - if ((store->server_level >= IMAP_LEVEL_IMAP4REV1) || - (e_strstrcase (result, "STATUS"))) - store->has_status_capability = TRUE; - else - store->has_status_capability = FALSE; - g_free (result); - - /* We now need to find out which directory separator this daemon - * uses. In the pre-4rev1 case, we can't do it, so we'll just - * hope that it's "/". - * FIXME: This code is wrong. The hierarchy separator is per - * namespace. - */ - if (store->server_level >= IMAP_LEVEL_IMAP4REV1) { - response = camel_imap_command (store, NULL, ex, - "LIST \"\" \"\""); - if (!response) - return FALSE; - result = camel_imap_response_extract (response, "LIST", ex); - if (!result) - return FALSE; - else { - char *flags, *sep, *folder; - - if (imap_parse_list_response (result, "", &flags, - &sep, &folder)) { - if (*sep) { - g_free (store->dir_sep); - store->dir_sep = g_strdup (sep); - } - } - - g_free (flags); - g_free (sep); - g_free (folder); - g_free (result); - } - } - - camel_remote_store_refresh_folders (CAMEL_REMOTE_STORE (store), ex); - - return ! camel_exception_is_set (ex); -} - -static gboolean -imap_disconnect (CamelService *service, CamelException *ex) -{ - CamelImapStore *store = CAMEL_IMAP_STORE (service); - CamelImapResponse *response; - - if (store->connected) { - /* send the logout command */ - response = camel_imap_command (store, NULL, ex, "LOGOUT"); - camel_imap_response_free (response); - } - - g_free (store->dir_sep); - store->dir_sep = NULL; - - store->current_folder = NULL; - - return CAMEL_SERVICE_CLASS (remote_store_class)->disconnect (service, ex); -} - -char * -camel_imap_store_folder_path (CamelImapStore *store, const char *name) -{ - CamelURL *url = CAMEL_SERVICE (store)->url; - char *namespace; - - if (url->path && *url->path) - namespace = url->path + 1; - else - namespace = ""; - - if (!*name) - return g_strdup (namespace); - else if (!g_strcasecmp (name, "INBOX") || !*namespace) - return g_strdup (name); - else - return g_strdup_printf ("%s%s%s", namespace, store->dir_sep, name); -} - -static gboolean -imap_folder_exists (CamelImapStore *store, const char *folder_path, gboolean *selectable, CamelException *ex) -{ - CamelImapResponse *response; - char *result, *flags, *sep, *dirname; - - if (!g_strcasecmp (folder_path, "INBOX")) { - if (selectable) - *selectable = TRUE; - return TRUE; - } - - /* it's always gonna be FALSE unless it's true - how's that for a comment? ;-) */ - if (selectable) - *selectable = FALSE; - - response = camel_imap_command (store, NULL, ex, - "LIST \"\" \"%s\"", folder_path); - if (!response) - return FALSE; - result = camel_imap_response_extract (response, "LIST", ex); - if (!result) - return FALSE; - - if (imap_parse_list_response (result, "", &flags, &sep, &dirname)) { - if (selectable) - *selectable = !e_strstrcase (flags, "NoSelect"); - - g_free (flags); - g_free (sep); - g_free (dirname); - g_free (result); - - return TRUE; - } - g_free (result); - - g_free (flags); - g_free (sep); - g_free (dirname); - - return FALSE; -} - -static gboolean -imap_create (CamelImapStore *store, const char *folder_path, CamelException *ex) -{ - CamelImapResponse *response; - - response = camel_imap_command (store, NULL, ex, - "CREATE \"%s\"", folder_path); - camel_imap_response_free (response); - - return !camel_exception_is_set (ex); -} - -static CamelFolder * -get_folder (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex) -{ - CamelImapStore *imap_store = CAMEL_IMAP_STORE (store); - CamelFolder *new_folder = NULL; - char *folder_path, *summary_file, *p; - gboolean selectable; - - folder_path = camel_imap_store_folder_path (imap_store, folder_name); - if (!imap_folder_exists (imap_store, folder_path, &selectable, ex)) { - if ((flags & CAMEL_STORE_FOLDER_CREATE) == 0) { - g_free (folder_path); - return NULL; - } - - if (!imap_create (imap_store, folder_path, ex)) { - g_free (folder_path); - return NULL; - } - } else if (!selectable) { - camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - "%s is not a selectable folder", - folder_name); - g_free (folder_path); - return NULL; - } - - summary_file = g_strdup_printf ("%s/%s/#summary", - imap_store->storage_path, - folder_name); - p = strrchr (summary_file, '/'); - *p = '\0'; - if (e_mkdir_hier (summary_file, S_IRWXU) == 0) { - *p = '/'; - new_folder = camel_imap_folder_new (store, folder_name, - summary_file, ex); - } else { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - "Could not create directory %s: %s", - summary_file, g_strerror (errno)); - } - g_free (summary_file); - g_free (folder_path); - - if (camel_exception_is_set (ex)) - return NULL; - - return new_folder; -} - -static char * -get_folder_name (CamelStore *store, const char *folder_name, - CamelException *ex) -{ - /* INBOX is case-insensitive */ - if (g_strcasecmp (folder_name, "INBOX") == 0) - return g_strdup ("INBOX"); - else - return g_strdup (folder_name); -} - -static char * -get_root_folder_name (CamelStore *store, CamelException *ex) -{ - return g_strdup (""); -} - -static CamelFolderInfo * -parse_list_response_as_folder_info (const char *response, - const char *namespace, - const char *base_url) -{ - CamelFolderInfo *fi; - char *flags, *sep, *dir; - - if (!imap_parse_list_response (response, namespace, - &flags, &sep, &dir)) - return NULL; - - fi = g_new0 (CamelFolderInfo, 1); - fi->full_name = dir; - if (sep) - fi->name = strrchr (dir, *sep); - if (fi->name) - fi->name = g_strdup (fi->name + 1); - else - fi->name = g_strdup (dir); - g_free (sep); - if (!e_strstrcase (flags, "\\NoSelect")) - fi->url = g_strdup_printf ("%s%s", base_url, dir); - g_free (flags); - /* FIXME: read/unread msg count */ - - return fi; -} - -static CamelFolderInfo * -get_folder_info (CamelStore *store, const char *top, gboolean fast, - gboolean recursive, gboolean subscribed_only, - CamelException *ex) -{ - CamelImapStore *imap_store = CAMEL_IMAP_STORE (store); - CamelURL *url = CAMEL_SERVICE (store)->url; - gboolean found_inbox = FALSE; - int len, i; - CamelImapResponse *response; - GPtrArray *folders; - char *dir_sep, *namespace, *base_url, *list; - CamelFolderInfo *topfi = NULL, *fi; - - if (!top) - top = ""; - dir_sep = imap_store->dir_sep; - namespace = camel_imap_store_folder_path (imap_store, top); - - /* Yah! I am complicated! */ - base_url = camel_url_to_string (url, FALSE); - len = strlen (base_url); - if (url->path && base_url[len - 1] != *dir_sep) { - base_url = g_realloc (base_url, len + 2); - base_url[len] = *dir_sep; - base_url[len + 1] = '\0'; - } else if (!url->path) { - base_url = g_realloc (base_url, len + 2); - base_url[len] = '/'; - base_url[len + 1] = '\0'; - } - - response = camel_imap_command (imap_store, NULL, ex, - "LIST \"\" \"%s\"", namespace); - if (response) { - list = camel_imap_response_extract (response, "LIST", ex); - if (list) { - topfi = parse_list_response_as_folder_info (list, - namespace, - base_url); - g_free (list); - } - } - if (!topfi) { - camel_exception_clear (ex); - topfi = g_new0 (CamelFolderInfo, 1); - topfi->full_name = g_strdup (namespace); - topfi->name = g_strdup (namespace); - } - - response = camel_imap_command (imap_store, NULL, ex, - "LIST \"\" \"%s%s%c\"", - namespace, *namespace ? dir_sep : "", - recursive ? '*' : '%'); - if (!response) { - g_free (namespace); - g_free (base_url); - return NULL; - } - - /* Turn responses into CamelFolderInfo and remove any - * extraneous responses. - */ - folders = g_ptr_array_new (); - for (i = 0; i < response->untagged->len; i++) { - list = response->untagged->pdata[i]; - fi = parse_list_response_as_folder_info (list, namespace, - base_url); - if (!fi) - continue; - g_ptr_array_add (folders, fi); - - if (!g_strcasecmp (fi->full_name, "INBOX")) - found_inbox = TRUE; - } - camel_imap_response_free (response); - - /* Add INBOX, if necessary */ - if (!*top && !found_inbox) { - fi = g_new0 (CamelFolderInfo, 1); - fi->full_name = g_strdup ("INBOX"); - fi->name = g_strdup ("INBOX"); - fi->url = g_strdup_printf ("%sINBOX", base_url); - /* FIXME: read/unread msg count */ - - g_ptr_array_add (folders, fi); - } - - /* And assemble */ - camel_folder_info_build (folders, topfi, *dir_sep, TRUE); - g_ptr_array_free (folders, FALSE); - - /* Remove the top if it's the root of the store. */ - if (!*top && !topfi->sibling) { - fi = topfi; - topfi = topfi->child; - fi->child = NULL; - camel_folder_info_free (fi); - } - - g_free (namespace); - g_free (base_url); - return topfi; -} - -static void -imap_keepalive (CamelRemoteStore *store) -{ - CamelImapStore *imap_store = CAMEL_IMAP_STORE (store); - CamelImapResponse *response; - - response = camel_imap_command (imap_store, NULL, NULL, "NOOP"); - camel_imap_response_free (response); -} |