diff options
author | nobody <nobody@localhost> | 2002-09-09 04:06:00 +0800 |
---|---|---|
committer | nobody <nobody@localhost> | 2002-09-09 04:06:00 +0800 |
commit | d0a26db992188b442356758477be89a312c2d02e (patch) | |
tree | f331b9f21da123bbda93ab3bfcf732e77f764471 /camel/providers/imap | |
parent | 3abb7796bcc037301601780602f7de940d89ef32 (diff) | |
download | gsoc2013-evolution-SODIPODI_0_25.tar.gz gsoc2013-evolution-SODIPODI_0_25.tar.zst gsoc2013-evolution-SODIPODI_0_25.zip |
This commit was manufactured by cvs2svn to create tagSODIPODI_0_25
'SODIPODI_0_25'.
svn path=/tags/SODIPODI_0_25/; revision=18015
Diffstat (limited to 'camel/providers/imap')
24 files changed, 0 insertions, 10338 deletions
diff --git a/camel/providers/imap/.cvsignore b/camel/providers/imap/.cvsignore deleted file mode 100644 index 3fa8afaa38..0000000000 --- a/camel/providers/imap/.cvsignore +++ /dev/null @@ -1,11 +0,0 @@ -.deps -Makefile -Makefile.in -.libs -.deps -*.lo -*.la -*.bb -*.bbg -*.da -*.gcov diff --git a/camel/providers/imap/Makefile.am b/camel/providers/imap/Makefile.am deleted file mode 100644 index 469964a9a6..0000000000 --- a/camel/providers/imap/Makefile.am +++ /dev/null @@ -1,49 +0,0 @@ -## Process this file with automake to produce Makefile.in - -libcamelimapincludedir = $(includedir)/camel - -camel_provider_LTLIBRARIES = libcamelimap.la -camel_provider_DATA = libcamelimap.urls - -INCLUDES = -I.. \ - -I$(srcdir)/.. \ - -I$(top_srcdir)/camel \ - -I$(top_srcdir)/intl \ - -I$(top_srcdir)/e-util \ - -I$(top_srcdir) \ - -I$(includedir) \ - $(CAMEL_CFLAGS) \ - $(GNOME_INCLUDEDIR) \ - $(GTK_INCLUDEDIR) \ - -DG_LOG_DOMAIN=\"camel-imap-provider\" - -libcamelimap_la_SOURCES = \ - camel-imap-command.c \ - camel-imap-folder.c \ - camel-imap-message-cache.c \ - camel-imap-provider.c \ - camel-imap-search.c \ - camel-imap-store.c \ - camel-imap-store-summary.c \ - camel-imap-summary.c \ - camel-imap-utils.c \ - camel-imap-wrapper.c - -libcamelimapinclude_HEADERS = \ - camel-imap-command.h \ - camel-imap-folder.h \ - camel-imap-message-cache.h \ - camel-imap-search.h \ - camel-imap-store.h \ - camel-imap-store-summary.h \ - camel-imap-summary.h \ - camel-imap-types.h \ - camel-imap-utils.h \ - camel-imap-wrapper.h - -libcamelimap_la_LDFLAGS = -avoid-version -module - -noinst_HEADERS = \ - camel-imap-private.h - -EXTRA_DIST = libcamelimap.urls diff --git a/camel/providers/imap/camel-imap-command.c b/camel/providers/imap/camel-imap-command.c deleted file mode 100644 index e3581c80af..0000000000 --- a/camel/providers/imap/camel-imap-command.c +++ /dev/null @@ -1,812 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-imap-command.c: IMAP command sending/parsing routines */ - -/* - * Authors: - * Dan Winship <danw@ximian.com> - * Jeffrey Stedfast <fejj@ximian.com> - * - * Copyright 2000, 2001 Ximian, Inc. - * - * 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 <stdarg.h> -#include <stdio.h> -#include <string.h> -#include <errno.h> - -#include "camel-imap-command.h" -#include "camel-imap-utils.h" -#include "camel-imap-folder.h" -#include "camel-imap-store.h" -#include "camel-imap-store-summary.h" -#include "camel-imap-private.h" -#include <camel/camel-exception.h> -#include <camel/camel-private.h> -#include <camel/camel-utf8.h> - -#define d(x) x - -extern int camel_verbose_debug; - -static gboolean imap_command_start (CamelImapStore *store, CamelFolder *folder, - const char *cmd, CamelException *ex); -CamelImapResponse *imap_read_response (CamelImapStore *store, - CamelException *ex); -static char *imap_read_untagged (CamelImapStore *store, char *line, - CamelException *ex); -static char *imap_command_strdup_vprintf (CamelImapStore *store, - const char *fmt, va_list ap); -static char *imap_command_strdup_printf (CamelImapStore *store, - const char *fmt, ...); - -/** - * camel_imap_command: - * @store: the IMAP store - * @folder: The folder to perform the operation in (or %NULL if not - * relevant). - * @ex: a CamelException - * @fmt: a sort of printf-style format string, followed by arguments - * - * This function calls camel_imap_command_start() to send the - * command, then reads the complete response to it using - * camel_imap_command_response() and returns a CamelImapResponse - * structure. - * - * As a special case, if @fmt is %NULL, it will just select @folder - * and return the response from doing so. - * - * See camel_imap_command_start() for details on @fmt. - * - * On success, the store's connect_lock will be locked. It will be freed - * when you call camel_imap_response_free. (The lock is recursive, so - * callers can grab and release it themselves if they need to run - * multiple commands atomically.) - * - * Return value: %NULL if an error occurred (in which case @ex will - * be set). Otherwise, a CamelImapResponse describing the server's - * response, which the caller must free with camel_imap_response_free(). - **/ -CamelImapResponse * -camel_imap_command (CamelImapStore *store, CamelFolder *folder, - CamelException *ex, const char *fmt, ...) -{ - va_list ap; - char *cmd; - - CAMEL_SERVICE_LOCK (store, connect_lock); - - if (fmt) { - va_start (ap, fmt); - cmd = imap_command_strdup_vprintf (store, fmt, ap); - va_end (ap); - } else { - if (store->current_folder) { - camel_object_unref (CAMEL_OBJECT (store->current_folder)); - store->current_folder = NULL; - } - store->current_folder = folder; - camel_object_ref (CAMEL_OBJECT (folder)); - cmd = imap_command_strdup_printf (store, "SELECT %F", - folder->full_name); - } - - if (!imap_command_start (store, folder, cmd, ex)) { - g_free (cmd); - CAMEL_SERVICE_UNLOCK (store, connect_lock); - return NULL; - } - g_free (cmd); - - return imap_read_response (store, ex); -} - -/** - * camel_imap_command_start: - * @store: the IMAP store - * @folder: The folder to perform the operation in (or %NULL if not - * relevant). - * @ex: a CamelException - * @fmt: a sort of printf-style format string, followed by arguments - * - * This function makes sure that @folder (if non-%NULL) is the - * currently-selected folder on @store and then sends the IMAP command - * specified by @fmt and the following arguments. - * - * @fmt can include the following %-escapes ONLY: - * %s, %d, %%: as with printf - * %S: an IMAP "string" (quoted string or literal) - * %F: an IMAP folder name - * - * %S strings will be passed as literals if the server supports LITERAL+ - * and quoted strings otherwise. (%S does not support strings that - * contain newlines.) - * - * %F will have the imap store's namespace prepended and then be processed - * like %S. - * - * On success, the store's connect_lock will be locked. It will be - * freed when %CAMEL_IMAP_RESPONSE_TAGGED or %CAMEL_IMAP_RESPONSE_ERROR - * is returned from camel_imap_command_response(). (The lock is - * recursive, so callers can grab and release it themselves if they - * need to run multiple commands atomically.) - * - * Return value: %TRUE if the command was sent successfully, %FALSE if - * an error occurred (in which case @ex will be set). - **/ -gboolean -camel_imap_command_start (CamelImapStore *store, CamelFolder *folder, - CamelException *ex, const char *fmt, ...) -{ - va_list ap; - char *cmd; - gboolean ok; - - va_start (ap, fmt); - cmd = imap_command_strdup_vprintf (store, fmt, ap); - va_end (ap); - - CAMEL_SERVICE_LOCK (store, connect_lock); - ok = imap_command_start (store, folder, cmd, ex); - g_free (cmd); - - if (!ok) - CAMEL_SERVICE_UNLOCK (store, connect_lock); - return ok; -} - -static gboolean -imap_command_start (CamelImapStore *store, CamelFolder *folder, - const char *cmd, CamelException *ex) -{ - ssize_t nwritten; - - /* Check for current folder */ - if (folder && folder != store->current_folder) { - CamelImapResponse *response; - CamelException internal_ex; - - response = camel_imap_command (store, folder, ex, NULL); - if (!response) - return FALSE; - camel_exception_init (&internal_ex); - camel_imap_folder_selected (folder, response, &internal_ex); - camel_imap_response_free (store, response); - if (camel_exception_is_set (&internal_ex)) { - camel_exception_xfer (ex, &internal_ex); - return FALSE; - } - } - - /* Send the command */ -#if d(!)0 - if (camel_verbose_debug) { - const char *mask; - - if (!strncmp ("LOGIN \"", cmd, 7)) - mask = "LOGIN \"xxx\" xxx"; - else if (!strncmp ("LOGIN {", cmd, 7)) - mask = "LOGIN {N+}\r\nxxx {N+}\r\nxxx"; - else if (!strncmp ("LOGIN ", cmd, 6)) - mask = "LOGIN xxx xxx"; - else - mask = cmd; - - fprintf (stderr, "sending : %c%.5d %s\r\n", store->tag_prefix, store->command, mask); - } -#endif - - nwritten = camel_stream_printf (store->ostream, "%c%.5d %s\r\n", - store->tag_prefix, store->command++, cmd); - - if (nwritten == -1) { - if (errno == EINTR) - camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, - _("Operation cancelled")); - else - camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - g_strerror (errno)); - - camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL); - return FALSE; - } - - return TRUE; -} - -/** - * camel_imap_command_continuation: - * @store: the IMAP store - * @cmd: buffer containing the response/request data - * @cmdlen: command length - * @ex: a CamelException - * - * This method is for sending continuing responses to the IMAP server - * after camel_imap_command() or camel_imap_command_response() returns - * a continuation response. - * - * This function assumes you have an exclusive lock on the imap stream. - * - * Return value: as for camel_imap_command(). On failure, the store's - * connect_lock will be released. - **/ -CamelImapResponse * -camel_imap_command_continuation (CamelImapStore *store, const char *cmd, - size_t cmdlen, CamelException *ex) -{ - if (!camel_imap_store_connected (store, ex)) - return NULL; - - if (camel_stream_write (store->ostream, cmd, cmdlen) == -1 || - camel_stream_write (store->ostream, "\r\n", 2) == -1) { - if (errno == EINTR) - camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, - _("Operation cancelled")); - else - camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - g_strerror (errno)); - camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL); - CAMEL_SERVICE_UNLOCK (store, connect_lock); - return NULL; - } - - return imap_read_response (store, ex); -} - -/** - * camel_imap_command_response: - * @store: the IMAP store - * @response: a pointer to pass back the response data in - * @ex: a CamelException - * - * This reads a single tagged, untagged, or continuation response from - * @store into *@response. The caller must free the string when it is - * done with it. - * - * Return value: One of %CAMEL_IMAP_RESPONSE_CONTINUATION, - * %CAMEL_IMAP_RESPONSE_UNTAGGED, %CAMEL_IMAP_RESPONSE_TAGGED, or - * %CAMEL_IMAP_RESPONSE_ERROR. If either of the last two, @store's - * command lock will be unlocked. - **/ -CamelImapResponseType -camel_imap_command_response (CamelImapStore *store, char **response, - CamelException *ex) -{ - CamelImapResponseType type; - char *respbuf; - - if (camel_imap_store_readline (store, &respbuf, ex) < 0) { - CAMEL_SERVICE_UNLOCK (store, connect_lock); - return CAMEL_IMAP_RESPONSE_ERROR; - } - - switch (*respbuf) { - case '*': - if (!g_strncasecmp (respbuf, "* BYE", 5)) { - /* Connection was lost, no more data to fetch */ - camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL); - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Server unexpectedly disconnected: %s"), - _("Unknown error")); /* g_strerror (104)); FIXME after 1.0 is released */ - store->connected = FALSE; - g_free (respbuf); - respbuf = NULL; - type = CAMEL_IMAP_RESPONSE_ERROR; - break; - } - - /* Read the rest of the response. */ - type = CAMEL_IMAP_RESPONSE_UNTAGGED; - respbuf = imap_read_untagged (store, respbuf, ex); - if (!respbuf) - type = CAMEL_IMAP_RESPONSE_ERROR; - - break; - case '+': - type = CAMEL_IMAP_RESPONSE_CONTINUATION; - break; - default: - type = CAMEL_IMAP_RESPONSE_TAGGED; - break; - } - *response = respbuf; - - if (type == CAMEL_IMAP_RESPONSE_ERROR || - type == CAMEL_IMAP_RESPONSE_TAGGED) - CAMEL_SERVICE_UNLOCK (store, connect_lock); - - return type; -} - -CamelImapResponse * -imap_read_response (CamelImapStore *store, CamelException *ex) -{ - CamelImapResponse *response; - CamelImapResponseType type; - char *respbuf, *p; - - /* Get another lock so that when we reach the tagged - * response and camel_imap_command_response unlocks, - * we're still locked. This lock is owned by response - * and gets unlocked when response is freed. - */ - CAMEL_SERVICE_LOCK (store, connect_lock); - - response = g_new0 (CamelImapResponse, 1); - if (store->current_folder && camel_disco_store_status (CAMEL_DISCO_STORE (store)) != CAMEL_DISCO_STORE_RESYNCING) { - response->folder = store->current_folder; - camel_object_ref (CAMEL_OBJECT (response->folder)); - } - - response->untagged = g_ptr_array_new (); - while ((type = camel_imap_command_response (store, &respbuf, ex)) - == CAMEL_IMAP_RESPONSE_UNTAGGED) - g_ptr_array_add (response->untagged, respbuf); - - if (type == CAMEL_IMAP_RESPONSE_ERROR) { - camel_imap_response_free_without_processing (store, response); - return NULL; - } - - response->status = respbuf; - - /* Check for OK or continuation response. */ - if (*respbuf == '+') - return response; - p = strchr (respbuf, ' '); - if (p && !g_strncasecmp (p, " OK", 3)) - return response; - - /* We should never get BAD, or anything else but +, OK, or NO - * for that matter. - */ - if (!p || g_strncasecmp (p, " NO", 3) != 0) { - g_warning ("Unexpected response from IMAP server: %s", - respbuf); - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Unexpected response from IMAP " - "server: %s"), respbuf); - camel_imap_response_free_without_processing (store, response); - return NULL; - } - - p += 3; - if (!*p++) - p = NULL; - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("IMAP command failed: %s"), - p ? p : _("Unknown error")); - camel_imap_response_free_without_processing (store, response); - return NULL; -} - -/* Given a line that is the start of an untagged response, read and - * return the complete response, which may include an arbitrary number - * of literals. - */ -static char * -imap_read_untagged (CamelImapStore *store, char *line, CamelException *ex) -{ - int fulllen, length, ldigits, nread, i; - GPtrArray *data; - GString *str; - char *end, *p, *s, *d; - - p = strrchr (line, '{'); - if (!p) - return line; - - data = g_ptr_array_new (); - fulllen = 0; - - while (1) { - str = g_string_new (line); - g_free (line); - fulllen += str->len; - g_ptr_array_add (data, str); - - p = strrchr (str->str, '{'); - if (!p) - break; - - length = strtoul (p + 1, &end, 10); - if (*end != '}' || *(end + 1) || end == p + 1) - break; - ldigits = end - (p + 1); - - /* Read the literal */ - str = g_string_sized_new (length + 2); - str->str[0] = '\n'; - nread = camel_stream_read (store->istream, str->str + 1, length); - 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, g_strerror (errno)); - camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL); - g_string_free (str, TRUE); - goto lose; - } - if (nread < length) { - camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Server response ended too soon.")); - camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL); - g_string_free (str, TRUE); - goto lose; - } - str->str[length + 1] = '\0'; - - /* Fix up the literal, turning CRLFs into LF. Also, if - * we find any embedded NULs, strip them. This is - * dubious, but: - * - The IMAP grammar says you can't have NULs here - * anyway, so this will not affect our behavior - * against any completely correct server. - * - WU-imapd 12.264 (at least) will cheerily pass - * NULs along if they are embedded in the message - */ - - s = d = str->str + 1; - end = str->str + 1 + length; - while (s < end) { - while (s < end && *s == '\0') { - s++; - length--; - } - if (*s == '\r' && *(s + 1) == '\n') { - s++; - length--; - } - *d++ = *s++; - } - *d = '\0'; - str->len = length + 1; - - /* p points to the "{" in the line that starts the - * literal. The length of the CR-less response must be - * less than or equal to the length of the response - * with CRs, therefore overwriting the old value with - * the new value cannot cause an overrun. However, we - * don't want it to be shorter either, because then the - * GString's length would be off... - */ - sprintf (p, "{%0*d}", ldigits, length); - - fulllen += str->len; - g_ptr_array_add (data, str); - - /* Read the next line. */ - if (camel_imap_store_readline (store, &line, ex) < 0) - goto lose; - } - - /* Now reassemble the data. */ - p = line = g_malloc (fulllen + 1); - for (i = 0; i < data->len; i++) { - str = data->pdata[i]; - memcpy (p, str->str, str->len); - p += str->len; - g_string_free (str, TRUE); - } - *p = '\0'; - g_ptr_array_free (data, TRUE); - return line; - - lose: - for (i = 0; i < data->len; i++) - g_string_free (data->pdata[i], TRUE); - g_ptr_array_free (data, TRUE); - return NULL; -} - - -/** - * camel_imap_response_free: - * @store: the CamelImapStore the response is from - * @response: a CamelImapResponse - * - * Frees all of the data in @response and processes any untagged - * EXPUNGE and EXISTS responses in it. Releases @store's connect_lock. - **/ -void -camel_imap_response_free (CamelImapStore *store, CamelImapResponse *response) -{ - int i, number, exists = 0; - GArray *expunged = NULL; - char *resp, *p; - - if (!response) - return; - - for (i = 0; i < response->untagged->len; i++) { - resp = response->untagged->pdata[i]; - - if (response->folder) { - /* Check if it's something we need to handle. */ - number = strtoul (resp + 2, &p, 10); - if (!g_strcasecmp (p, " EXISTS")) { - exists = number; - } else if (!g_strcasecmp (p, " EXPUNGE")) { - if (!expunged) { - expunged = g_array_new (FALSE, FALSE, - sizeof (int)); - } - g_array_append_val (expunged, number); - } - } - g_free (resp); - } - - g_ptr_array_free (response->untagged, TRUE); - g_free (response->status); - - if (response->folder) { - if (exists > 0 || expunged) { - /* Update the summary */ - camel_imap_folder_changed (response->folder, - exists, expunged, NULL); - if (expunged) - g_array_free (expunged, TRUE); - } - - camel_object_unref (CAMEL_OBJECT (response->folder)); - } - - g_free (response); - CAMEL_SERVICE_UNLOCK (store, connect_lock); -} - -/** - * camel_imap_response_free_without_processing: - * @store: the CamelImapStore the response is from. - * @response: a CamelImapResponse: - * - * Frees all of the data in @response without processing any untagged - * responses. Releases @store's command lock. - **/ -void -camel_imap_response_free_without_processing (CamelImapStore *store, - CamelImapResponse *response) -{ - if (!response) - return; - - if (response->folder) { - camel_object_unref (CAMEL_OBJECT (response->folder)); - response->folder = NULL; - } - camel_imap_response_free (store, response); -} - -/** - * camel_imap_response_extract: - * @store: the store the response came from - * @response: the response data returned from camel_imap_command - * @type: the response type to extract - * @ex: a CamelException - * - * This checks that @response contains a single untagged response of - * type @type and returns just that response data. If @response - * doesn't contain the right information, the function will set @ex - * and return %NULL. Either way, @response will be freed and the - * store's connect_lock released. - * - * Return value: the desired response string, which the caller must free. - **/ -char * -camel_imap_response_extract (CamelImapStore *store, - CamelImapResponse *response, - const char *type, - CamelException *ex) -{ - int len = strlen (type), i; - char *resp; - - len = strlen (type); - - for (i = 0; i < response->untagged->len; i++) { - resp = response->untagged->pdata[i]; - /* Skip "* ", and initial sequence number, if present */ - strtoul (resp + 2, &resp, 10); - if (*resp == ' ') - resp = (char *) imap_next_word (resp); - - if (!g_strncasecmp (resp, type, len)) - break; - } - - if (i < response->untagged->len) { - resp = response->untagged->pdata[i]; - g_ptr_array_remove_index (response->untagged, i); - } else { - resp = NULL; - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("IMAP server response did not contain " - "%s information"), type); - } - - camel_imap_response_free (store, response); - return resp; -} - -/** - * camel_imap_response_extract_continuation: - * @store: the store the response came from - * @response: the response data returned from camel_imap_command - * @ex: a CamelException - * - * This checks that @response contains a continuation response, and - * returns just that data. If @response doesn't contain a continuation - * response, the function will set @ex, release @store's connect_lock, - * and return %NULL. Either way, @response will be freed. - * - * Return value: the desired response string, which the caller must free. - **/ -char * -camel_imap_response_extract_continuation (CamelImapStore *store, - CamelImapResponse *response, - CamelException *ex) -{ - char *status; - - if (response->status && *response->status == '+') { - status = response->status; - response->status = NULL; - camel_imap_response_free (store, response); - return status; - } - - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Unexpected OK response from IMAP server: %s"), - response->status); - camel_imap_response_free (store, response); - return NULL; -} - -static char * -imap_command_strdup_vprintf (CamelImapStore *store, const char *fmt, - va_list ap) -{ - GPtrArray *args; - const char *p, *start; - char *out, *outptr, *string; - int num, len, i, arglen; - - args = g_ptr_array_new (); - - /* Determine the length of the data */ - len = strlen (fmt); - p = start = fmt; - while (*p) { - p = strchr (start, '%'); - if (!p) - break; - - switch (*++p) { - case 'd': - num = va_arg (ap, int); - g_ptr_array_add (args, GINT_TO_POINTER (num)); - start = p + 1; - len += 10; - break; - case 's': - string = va_arg (ap, char *); - g_ptr_array_add (args, string); - start = p + 1; - len += strlen (string); - break; - case 'S': - case 'F': - string = va_arg (ap, char *); - arglen = strlen (string); - g_ptr_array_add (args, string); - if (imap_is_atom (string)) { - len += arglen; - } else { - if (store->capabilities & IMAP_CAPABILITY_LITERALPLUS) - len += arglen + 15; - else - len += arglen * 2; - } - start = p + 1; - break; - case '%': - start = p; - break; - default: - g_warning ("camel-imap-command is not printf. I don't " - "know what '%%%c' means.", *p); - start = *p ? p + 1 : p; - break; - } - } - - /* Now write out the string */ - outptr = out = g_malloc (len + 1); - p = start = fmt; - i = 0; - while (*p) { - p = strchr (start, '%'); - if (!p) { - strcpy (outptr, start); - break; - } else { - strncpy (outptr, start, p - start); - outptr += p - start; - } - - switch (*++p) { - case 'd': - num = GPOINTER_TO_INT (args->pdata[i++]); - outptr += sprintf (outptr, "%d", num); - break; - - case 's': - string = args->pdata[i++]; - outptr += sprintf (outptr, "%s", string); - break; - case 'S': - case 'F': - string = args->pdata[i++]; - if (*p == 'F') { - char *s = camel_imap_store_summary_full_from_path(store->summary, string); - string = s?s:camel_utf8_utf7(string); - } - - if (imap_is_atom (string)) { - outptr += sprintf (outptr, "%s", string); - } else { - if (store->capabilities & IMAP_CAPABILITY_LITERALPLUS) { - outptr += sprintf (outptr, "{%d+}\r\n%s", strlen (string), string); - } else { - char *quoted = imap_quote_string (string); - - outptr += sprintf (outptr, "%s", quoted); - g_free (quoted); - } - } - - if (*p == 'F') - g_free (string); - break; - default: - *outptr++ = '%'; - *outptr++ = *p; - } - - start = *p ? p + 1 : p; - } - - return out; -} - -static char * -imap_command_strdup_printf (CamelImapStore *store, const char *fmt, ...) -{ - va_list ap; - char *result; - - va_start (ap, fmt); - result = imap_command_strdup_vprintf (store, fmt, ap); - va_end (ap); - - return result; -} diff --git a/camel/providers/imap/camel-imap-command.h b/camel/providers/imap/camel-imap-command.h deleted file mode 100644 index 3539ac63d2..0000000000 --- a/camel/providers/imap/camel-imap-command.h +++ /dev/null @@ -1,80 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-imap-command.h: IMAP command sending/parsing routines */ - -/* - * Authors: - * Dan Winship <danw@ximian.com> - * Jeffrey Stedfast <fejj@ximian.com> - * - * Copyright (C) 2000, 2001 Ximian, Inc. - * - * 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 - */ - - -#ifndef CAMEL_IMAP_COMMAND_H -#define CAMEL_IMAP_COMMAND_H 1 - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus }*/ - -#include <glib.h> -#include "camel-imap-types.h" - -typedef enum { - CAMEL_IMAP_RESPONSE_ERROR, - CAMEL_IMAP_RESPONSE_CONTINUATION, - CAMEL_IMAP_RESPONSE_UNTAGGED, - CAMEL_IMAP_RESPONSE_TAGGED -} CamelImapResponseType; - -struct _CamelImapResponse { - CamelFolder *folder; - GPtrArray *untagged; - char *status; -}; - -CamelImapResponse *camel_imap_command (CamelImapStore *store, - CamelFolder *folder, - CamelException *ex, - const char *fmt, ...); -CamelImapResponse *camel_imap_command_continuation (CamelImapStore *store, - const char *cmd, - size_t cmdlen, - CamelException *ex); - -void camel_imap_response_free (CamelImapStore *store, - CamelImapResponse *response); -void camel_imap_response_free_without_processing (CamelImapStore *store, - CamelImapResponse *response); -char *camel_imap_response_extract (CamelImapStore *store, - CamelImapResponse *response, - const char *type, - CamelException *ex); -char *camel_imap_response_extract_continuation (CamelImapStore *store, - CamelImapResponse *response, - CamelException *ex); - -gboolean camel_imap_command_start (CamelImapStore *store, - CamelFolder *folder, - CamelException *ex, - const char *fmt, ...); -CamelImapResponseType camel_imap_command_response (CamelImapStore *store, - char **respbuf, - CamelException *ex); - -#endif /* CAMEL_IMAP_COMMAND_H */ diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c deleted file mode 100644 index 1a2f5a79e9..0000000000 --- a/camel/providers/imap/camel-imap-folder.c +++ /dev/null @@ -1,2590 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-imap-folder.c: class for an imap folder */ - -/* - * Authors: - * Dan Winship <danw@ximian.com> - * Jeffrey Stedfast <fejj@ximian.com> - * - * Copyright (C) 2000, 2001 Ximian, Inc. - * - * 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 <stdlib.h> -#include <sys/types.h> -#include <dirent.h> -#include <sys/stat.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <fcntl.h> -#include <ctype.h> - -#include "e-util/e-path.h" - -#include "camel-imap-folder.h" -#include "camel-imap-command.h" -#include "camel-imap-message-cache.h" -#include "camel-imap-private.h" -#include "camel-imap-search.h" -#include "camel-imap-store.h" -#include "camel-imap-summary.h" -#include "camel-imap-utils.h" -#include "camel-imap-wrapper.h" -#include "camel-data-wrapper.h" -#include "camel-disco-diary.h" -#include "camel-exception.h" -#include "camel-mime-filter-crlf.h" -#include "camel-mime-filter-from.h" -#include "camel-mime-message.h" -#include "camel-mime-utils.h" -#include "camel-multipart.h" -#include "camel-multipart-signed.h" -#include "camel-multipart-encrypted.h" -#include "camel-operation.h" -#include "camel-session.h" -#include "camel-stream-buffer.h" -#include "camel-stream-filter.h" -#include "camel-stream-mem.h" -#include "camel-stream.h" -#include "string-utils.h" -#include "camel-private.h" - - -#define d(x) x - -/* set to -1 for infinite size */ -#define UID_SET_LIMIT (4096) - - -#define CF_CLASS(o) (CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(o))) -static CamelDiscoFolderClass *disco_folder_class = NULL; - -static void imap_finalize (CamelObject *object); -static int imap_getv(CamelObject *object, CamelException *ex, CamelArgGetV *args); - -static void imap_rescan (CamelFolder *folder, int exists, CamelException *ex); -static void imap_refresh_info (CamelFolder *folder, CamelException *ex); -static void imap_sync_online (CamelFolder *folder, CamelException *ex); -static void imap_sync_offline (CamelFolder *folder, CamelException *ex); -static void imap_expunge_uids_online (CamelFolder *folder, GPtrArray *uids, CamelException *ex); -static void imap_expunge_uids_offline (CamelFolder *folder, GPtrArray *uids, CamelException *ex); -static void imap_expunge_uids_resyncing (CamelFolder *folder, GPtrArray *uids, CamelException *ex); -static void imap_cache_message (CamelDiscoFolder *disco_folder, const char *uid, CamelException *ex); -static void imap_rename (CamelFolder *folder, const char *new); - -/* message manipulation */ -static CamelMimeMessage *imap_get_message (CamelFolder *folder, const gchar *uid, - CamelException *ex); -static void imap_append_online (CamelFolder *folder, CamelMimeMessage *message, - const CamelMessageInfo *info, char **appended_uid, - CamelException *ex); -static void imap_append_offline (CamelFolder *folder, CamelMimeMessage *message, - const CamelMessageInfo *info, char **appended_uid, - CamelException *ex); -static void imap_append_resyncing (CamelFolder *folder, CamelMimeMessage *message, - const CamelMessageInfo *info, char **appended_uid, - CamelException *ex); - -static void imap_transfer_online (CamelFolder *source, GPtrArray *uids, - CamelFolder *dest, GPtrArray **transferred_uids, - gboolean delete_originals, - CamelException *ex); -static void imap_transfer_offline (CamelFolder *source, GPtrArray *uids, - CamelFolder *dest, GPtrArray **transferred_uids, - gboolean delete_originals, - CamelException *ex); -static void imap_transfer_resyncing (CamelFolder *source, GPtrArray *uids, - CamelFolder *dest, GPtrArray **transferred_uids, - gboolean delete_originals, - CamelException *ex); - -/* searching */ -static GPtrArray *imap_search_by_expression (CamelFolder *folder, const char *expression, CamelException *ex); -static GPtrArray *imap_search_by_uids (CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex); -static void imap_search_free (CamelFolder *folder, GPtrArray *uids); - -static void imap_thaw (CamelFolder *folder); - -static CamelObjectClass *parent_class; - -static GData *parse_fetch_response (CamelImapFolder *imap_folder, char *msg_att); - -static void -camel_imap_folder_class_init (CamelImapFolderClass *camel_imap_folder_class) -{ - CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS (camel_imap_folder_class); - CamelDiscoFolderClass *camel_disco_folder_class = CAMEL_DISCO_FOLDER_CLASS (camel_imap_folder_class); - - disco_folder_class = CAMEL_DISCO_FOLDER_CLASS (camel_type_get_global_classfuncs (camel_disco_folder_get_type ())); - - /* virtual method overload */ - ((CamelObjectClass *)camel_imap_folder_class)->getv = imap_getv; - - camel_folder_class->get_message = imap_get_message; - camel_folder_class->rename = imap_rename; - camel_folder_class->search_by_expression = imap_search_by_expression; - camel_folder_class->search_by_uids = imap_search_by_uids; - camel_folder_class->search_free = imap_search_free; - camel_folder_class->thaw = imap_thaw; - - camel_disco_folder_class->refresh_info_online = imap_refresh_info; - camel_disco_folder_class->sync_online = imap_sync_online; - camel_disco_folder_class->sync_offline = imap_sync_offline; - /* We don't sync flags at resync time: the online code will - * deal with it eventually. - */ - camel_disco_folder_class->sync_resyncing = imap_sync_offline; - camel_disco_folder_class->expunge_uids_online = imap_expunge_uids_online; - camel_disco_folder_class->expunge_uids_offline = imap_expunge_uids_offline; - camel_disco_folder_class->expunge_uids_resyncing = imap_expunge_uids_resyncing; - camel_disco_folder_class->append_online = imap_append_online; - camel_disco_folder_class->append_offline = imap_append_offline; - camel_disco_folder_class->append_resyncing = imap_append_resyncing; - camel_disco_folder_class->transfer_online = imap_transfer_online; - camel_disco_folder_class->transfer_offline = imap_transfer_offline; - camel_disco_folder_class->transfer_resyncing = imap_transfer_resyncing; - camel_disco_folder_class->cache_message = imap_cache_message; -} - -static void -camel_imap_folder_init (gpointer object, gpointer klass) -{ - CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (object); - CamelFolder *folder = CAMEL_FOLDER (object); - - folder->permanent_flags = CAMEL_MESSAGE_ANSWERED | CAMEL_MESSAGE_DELETED | - CAMEL_MESSAGE_DRAFT | CAMEL_MESSAGE_FLAGGED | CAMEL_MESSAGE_SEEN; - - folder->folder_flags |= (CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY | - CAMEL_FOLDER_HAS_SEARCH_CAPABILITY); - - imap_folder->priv = g_malloc0(sizeof(*imap_folder->priv)); -#ifdef ENABLE_THREADS - imap_folder->priv->search_lock = e_mutex_new(E_MUTEX_SIMPLE); - imap_folder->priv->cache_lock = e_mutex_new(E_MUTEX_REC); -#endif - - imap_folder->need_rescan = TRUE; -} - -CamelType -camel_imap_folder_get_type (void) -{ - static CamelType camel_imap_folder_type = CAMEL_INVALID_TYPE; - - if (camel_imap_folder_type == CAMEL_INVALID_TYPE) { - parent_class = camel_disco_folder_get_type(); - camel_imap_folder_type = - camel_type_register (parent_class, "CamelImapFolder", - sizeof (CamelImapFolder), - sizeof (CamelImapFolderClass), - (CamelObjectClassInitFunc) camel_imap_folder_class_init, - NULL, - (CamelObjectInitFunc) camel_imap_folder_init, - (CamelObjectFinalizeFunc) imap_finalize); - } - - return camel_imap_folder_type; -} - -CamelFolder * -camel_imap_folder_new (CamelStore *parent, const char *folder_name, - const char *folder_dir, CamelException *ex) -{ - CamelImapStore *imap_store = CAMEL_IMAP_STORE (parent); - CamelFolder *folder; - CamelImapFolder *imap_folder; - const char *short_name; - char *summary_file; - - if (camel_mkdir_hier (folder_dir, S_IRWXU) != 0) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not create directory %s: %s"), - folder_dir, g_strerror (errno)); - return NULL; - } - - folder = CAMEL_FOLDER (camel_object_new (camel_imap_folder_get_type ())); - short_name = strrchr (folder_name, imap_store->dir_sep); - if (short_name) - short_name++; - else - short_name = folder_name; - camel_folder_construct (folder, parent, folder_name, short_name); - - summary_file = g_strdup_printf ("%s/summary", folder_dir); - folder->summary = camel_imap_summary_new (summary_file); - g_free (summary_file); - if (!folder->summary) { - camel_object_unref (CAMEL_OBJECT (folder)); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not load summary for %s"), - folder_name); - return NULL; - } - - imap_folder = CAMEL_IMAP_FOLDER (folder); - imap_folder->cache = camel_imap_message_cache_new (folder_dir, folder->summary, ex); - if (!imap_folder->cache) { - camel_object_unref (CAMEL_OBJECT (folder)); - return NULL; - } - - if ((imap_store->parameters & IMAP_PARAM_FILTER_INBOX) && - !g_strcasecmp (folder_name, "INBOX")) - folder->folder_flags |= CAMEL_FOLDER_FILTER_RECENT; - - imap_folder->search = camel_imap_search_new(folder_dir); - - return folder; -} - -/* Called with the store's connect_lock locked */ -void -camel_imap_folder_selected (CamelFolder *folder, CamelImapResponse *response, - CamelException *ex) -{ - CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder); - CamelImapSummary *imap_summary = CAMEL_IMAP_SUMMARY (folder->summary); - unsigned long exists = 0, validity = 0, val, uid; - CamelMessageInfo *info; - GData *fetch_data; - int i, count; - char *resp; - - CAMEL_SERVICE_ASSERT_LOCKED (folder->parent_store, connect_lock); - - count = camel_folder_summary_count (folder->summary); - - for (i = 0; i < response->untagged->len; i++) { - resp = response->untagged->pdata[i] + 2; - if (!g_strncasecmp (resp, "FLAGS ", 6) && - !folder->permanent_flags) { - resp += 6; - folder->permanent_flags = imap_parse_flag_list (&resp); - } else if (!g_strncasecmp (resp, "OK [PERMANENTFLAGS ", 19)) { - resp += 19; - folder->permanent_flags = imap_parse_flag_list (&resp); - } else if (!g_strncasecmp (resp, "OK [UIDVALIDITY ", 16)) { - validity = strtoul (resp + 16, NULL, 10); - } else if (isdigit ((unsigned char)*resp)) { - unsigned long num = strtoul (resp, &resp, 10); - - if (!g_strncasecmp (resp, " EXISTS", 7)) { - exists = num; - /* Remove from the response so nothing - * else tries to interpret it. - */ - g_free (response->untagged->pdata[i]); - g_ptr_array_remove_index (response->untagged, i--); - } - } - } - - if (camel_disco_store_status (CAMEL_DISCO_STORE (folder->parent_store)) == CAMEL_DISCO_STORE_RESYNCING) { - if (validity != imap_summary->validity) { - camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_SUMMARY_INVALID, - _("Folder was destroyed and recreated on server.")); - return; - } - - /* FIXME: find missing UIDs ? */ - return; - } - - if (!imap_summary->validity) - imap_summary->validity = validity; - else if (validity != imap_summary->validity) { - imap_summary->validity = validity; - camel_folder_summary_clear (folder->summary); - CAMEL_IMAP_FOLDER_LOCK (imap_folder, cache_lock); - camel_imap_message_cache_clear (imap_folder->cache); - CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock); - imap_folder->need_rescan = FALSE; - camel_imap_folder_changed (folder, exists, NULL, ex); - return; - } - - /* If we've lost messages, we have to rescan everything */ - if (exists < count) - imap_folder->need_rescan = TRUE; - else if (count != 0 && !imap_folder->need_rescan) { - CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store); - - /* Similarly, if the UID of the highest message we - * know about has changed, then that indicates that - * messages have been both added and removed, so we - * have to rescan to find the removed ones. (We pass - * NULL for the folder since we know that this folder - * is selected, and we don't want camel_imap_command - * to worry about it.) - */ - response = camel_imap_command (store, NULL, ex, "FETCH %d UID", count); - if (!response) - return; - uid = 0; - for (i = 0; i < response->untagged->len; i++) { - resp = response->untagged->pdata[i]; - val = strtoul (resp + 2, &resp, 10); - if (val == 0) - continue; - if (!g_strcasecmp (resp, " EXISTS")) { - /* Another one?? */ - exists = val; - continue; - } - if (uid != 0 || val != count || g_strncasecmp (resp, " FETCH (", 8) != 0) - continue; - - fetch_data = parse_fetch_response (imap_folder, resp + 7); - uid = strtoul (g_datalist_get_data (&fetch_data, "UID"), NULL, 10); - g_datalist_clear (&fetch_data); - } - camel_imap_response_free_without_processing (store, response); - - info = camel_folder_summary_index (folder->summary, count - 1); - val = strtoul (camel_message_info_uid (info), NULL, 10); - camel_folder_summary_info_free (folder->summary, info); - if (uid == 0 || uid != val) - imap_folder->need_rescan = TRUE; - } - - /* Now rescan if we need to */ - if (imap_folder->need_rescan) { - imap_rescan (folder, exists, ex); - return; - } - - /* If we don't need to rescan completely, but new messages - * have been added, find out about them. - */ - if (exists > count) - camel_imap_folder_changed (folder, exists, NULL, ex); - - /* And we're done. */ -} - -static void -imap_finalize (CamelObject *object) -{ - CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (object); - - if (imap_folder->search) - camel_object_unref (CAMEL_OBJECT (imap_folder->search)); - if (imap_folder->cache) - camel_object_unref (CAMEL_OBJECT (imap_folder->cache)); - -#ifdef ENABLE_THREADS - e_mutex_destroy(imap_folder->priv->search_lock); - e_mutex_destroy(imap_folder->priv->cache_lock); -#endif - g_free(imap_folder->priv); -} - -static int -imap_getv(CamelObject *object, CamelException *ex, CamelArgGetV *args) -{ - CamelFolder *folder = (CamelFolder *)object; - int i, count=args->argc; - guint32 tag; - - for (i=0;i<args->argc;i++) { - CamelArgGet *arg = &args->argv[i]; - - tag = arg->tag; - - switch (tag & CAMEL_ARG_TAG) { - /* CamelObject args */ - case CAMEL_OBJECT_ARG_DESCRIPTION: - if (folder->description == NULL) { - CamelURL *uri = ((CamelService *)folder->parent_store)->url; - - /* what if the full name doesn't incclude /'s? does it matter? */ - folder->description = g_strdup_printf("%s@%s:%s", uri->user, uri->host, folder->full_name); - } - *arg->ca_str = folder->description; - break; - default: - count--; - continue; - } - - arg->tag = (tag & CAMEL_ARG_TYPE) | CAMEL_ARG_IGNORE; - } - - if (count) - return ((CamelObjectClass *)parent_class)->getv(object, ex, args); - - return 0; -} - -static void -imap_rename (CamelFolder *folder, const char *new) -{ - CamelImapFolder *imap_folder = (CamelImapFolder *)folder; - CamelImapStore *imap_store = (CamelImapStore *)folder->parent_store; - char *folder_dir, *summary_path; - char *folders; - - folders = g_strconcat (imap_store->storage_path, "/folders", NULL); - folder_dir = e_path_to_physical (folders, new); - g_free (folders); - summary_path = g_strdup_printf("%s/summary", folder_dir); - - CAMEL_IMAP_FOLDER_LOCK (folder, cache_lock); - camel_imap_message_cache_set_path(imap_folder->cache, folder_dir); - CAMEL_IMAP_FOLDER_UNLOCK (folder, cache_lock); - - camel_folder_summary_set_filename(folder->summary, summary_path); - - g_free(summary_path); - g_free(folder_dir); - - ((CamelFolderClass *)disco_folder_class)->rename(folder, new); -} - -static void -imap_refresh_info (CamelFolder *folder, CamelException *ex) -{ - CamelImapStore *imap_store = CAMEL_IMAP_STORE (folder->parent_store); - CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder); - CamelImapResponse *response; - - if (camel_disco_store_status (CAMEL_DISCO_STORE (imap_store)) == CAMEL_DISCO_STORE_OFFLINE) - return; - - if (camel_folder_is_frozen (folder)) { - imap_folder->need_refresh = TRUE; - return; - } - - /* If the folder isn't selected, select it (which will force - * a rescan if one is needed). - * Also, if this is the INBOX, some servers (cryus) wont tell - * us with a NOOP of new messages, so force a reselect which - * should do it. */ - CAMEL_SERVICE_LOCK (imap_store, connect_lock); - if (imap_store->current_folder != folder - || strcasecmp(folder->full_name, "INBOX") == 0) { - CAMEL_SERVICE_UNLOCK (imap_store, connect_lock); - response = camel_imap_command (imap_store, folder, ex, NULL); - if (response) { - camel_imap_folder_selected (folder, response, NULL); - camel_imap_response_free (imap_store, response); - } - return; - } - CAMEL_SERVICE_UNLOCK (imap_store, connect_lock); - - /* Otherwise, if we need a rescan, do it, and if not, just do - * a NOOP to give the server a chance to tell us about new - * messages. - */ - if (imap_folder->need_rescan) - imap_rescan (folder, camel_folder_summary_count (folder->summary), ex); - else { -#if 0 - /* on some servers need to CHECKpoint INBOX to recieve new messages?? */ - /* rfc2060 suggests this, but havent seen a server that requires it */ - if (strcasecmp(folder->full_name, "INBOX") == 0) { - response = camel_imap_command (imap_store, folder, ex, "CHECK"); - camel_imap_response_free (imap_store, response); - } -#endif - response = camel_imap_command (imap_store, folder, ex, "NOOP"); - camel_imap_response_free (imap_store, response); - } -} - -/* Called with the store's connect_lock locked */ -static void -imap_rescan (CamelFolder *folder, int exists, CamelException *ex) -{ - CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder); - CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store); - struct { - char *uid; - guint32 flags; - } *new; - char *resp; - CamelImapResponseType type; - int i, seq, summary_len, summary_got; - CamelMessageInfo *info; - CamelImapMessageInfo *iinfo; - GArray *removed; - gboolean ok; - CamelFolderChangeInfo *changes = NULL; - - CAMEL_SERVICE_ASSERT_LOCKED (store, connect_lock); - imap_folder->need_rescan = FALSE; - - summary_len = camel_folder_summary_count (folder->summary); - if (summary_len == 0) { - if (exists) - camel_imap_folder_changed (folder, exists, NULL, ex); - return; - } - - /* Check UIDs and flags of all messages we already know of. */ - camel_operation_start (NULL, _("Scanning for changed messages")); - info = camel_folder_summary_index (folder->summary, summary_len - 1); - ok = camel_imap_command_start (store, folder, ex, - "UID FETCH 1:%s (FLAGS)", - camel_message_info_uid (info)); - camel_folder_summary_info_free (folder->summary, info); - if (!ok) { - camel_operation_end (NULL); - return; - } - - new = g_malloc0 (summary_len * sizeof (*new)); - summary_got = 0; - while ((type = camel_imap_command_response (store, &resp, ex)) == CAMEL_IMAP_RESPONSE_UNTAGGED) { - GData *data; - char *uid; - guint32 flags; - - data = parse_fetch_response (imap_folder, resp); - g_free (resp); - if (!data) - continue; - - seq = GPOINTER_TO_INT (g_datalist_get_data (&data, "SEQUENCE")); - uid = g_datalist_get_data (&data, "UID"); - flags = GPOINTER_TO_UINT (g_datalist_get_data (&data, "FLAGS")); - - if (!uid || !seq || seq > summary_len) { - g_datalist_clear (&data); - continue; - } - - camel_operation_progress (NULL, ++summary_got * 100 / summary_len); - new[seq - 1].uid = g_strdup (uid); - new[seq - 1].flags = flags; - g_datalist_clear (&data); - } - - camel_operation_end (NULL); - if (type == CAMEL_IMAP_RESPONSE_ERROR) { - for (i = 0; i < summary_len && new[i].uid; i++) - g_free (new[i].uid); - g_free (new); - return; - } - - /* Free the final tagged response */ - g_free (resp); - - /* If we find a UID in the summary that doesn't correspond to - * the UID in the folder, then either: (a) it's a real UID, - * but the message was deleted on the server, or (b) it's a - * fake UID, and needs to be removed from the summary in order - * to sync up with the server. So either way, we remove it - * from the summary. - */ - removed = g_array_new (FALSE, FALSE, sizeof (int)); - for (i = 0; i < summary_len && new[i].uid; i++) { - info = camel_folder_summary_index (folder->summary, i); - iinfo = (CamelImapMessageInfo *)info; - - if (strcmp (camel_message_info_uid (info), new[i].uid) != 0) { - camel_folder_summary_info_free(folder->summary, info); - seq = i + 1; - g_array_append_val (removed, seq); - i--; - summary_len--; - continue; - } - - /* Update summary flags */ - if (new[i].flags != iinfo->server_flags) { - guint32 server_set, server_cleared; - - server_set = new[i].flags & ~iinfo->server_flags; - server_cleared = iinfo->server_flags & ~new[i].flags; - - info->flags = (info->flags | server_set) & ~server_cleared; - iinfo->server_flags = new[i].flags; - - if (changes == NULL) - changes = camel_folder_change_info_new(); - camel_folder_change_info_change_uid(changes, new[i].uid); - } - - camel_folder_summary_info_free (folder->summary, info); - g_free (new[i].uid); - } - - if (changes) { - camel_object_trigger_event(CAMEL_OBJECT (folder), "folder_changed", changes); - camel_folder_change_info_free(changes); - } - - seq = i + 1; - - /* Free remaining memory. */ - while (i < summary_len && new[i].uid) - g_free (new[i++].uid); - g_free (new); - - /* Remove any leftover cached summary messages. (Yes, we - * repeatedly add the same number to the removed array. - * See RFC2060 7.4.1) - */ - - for (i = seq; i <= summary_len; i++) - g_array_append_val (removed, seq); - - /* And finally update the summary. */ - camel_imap_folder_changed (folder, exists, removed, ex); - g_array_free (removed, TRUE); -} - -/* the max number of chars that an unsigned 32-bit int can be is 10 chars plus 1 for a possible : */ -#define UID_SET_FULL(setlen, maxlen) (maxlen > 0 ? setlen + 11 >= maxlen : FALSE) - -/* Find all messages in @folder with flags matching @flags and @mask. - * If no messages match, returns %NULL. Otherwise, returns an array of - * CamelMessageInfo and sets *@set to a message set corresponding the - * UIDs of the matched messages (up to @UID_SET_LIMIT bytes). The - * caller must free the infos, the array, and the set string. - */ -static GPtrArray * -get_matching (CamelFolder *folder, guint32 flags, guint32 mask, char **set) -{ - GPtrArray *matches; - CamelMessageInfo *info; - int i, max, range; - GString *gset; - - matches = g_ptr_array_new (); - gset = g_string_new (""); - max = camel_folder_summary_count (folder->summary); - range = -1; - for (i = 0; i < max && !UID_SET_FULL (gset->len, UID_SET_LIMIT); i++) { - info = camel_folder_summary_index (folder->summary, i); - if (!info) - continue; - if ((info->flags & mask) != flags) { - camel_folder_summary_info_free (folder->summary, info); - if (range != -1) { - if (range != i - 1) { - info = matches->pdata[matches->len - 1]; - g_string_sprintfa (gset, ":%s", camel_message_info_uid (info)); - } - range = -1; - } - continue; - } - - g_ptr_array_add (matches, info); - if (range != -1) - continue; - range = i; - if (gset->len) - g_string_append_c (gset, ','); - g_string_sprintfa (gset, "%s", camel_message_info_uid (info)); - } - - if (range != -1 && range != max - 1) { - info = matches->pdata[matches->len - 1]; - g_string_sprintfa (gset, ":%s", camel_message_info_uid (info)); - } - - if (matches->len) { - *set = gset->str; - g_string_free (gset, FALSE); - return matches; - } else { - g_string_free (gset, TRUE); - g_ptr_array_free (matches, TRUE); - return NULL; - } -} - -static void -imap_sync_offline (CamelFolder *folder, CamelException *ex) -{ - camel_folder_summary_save (folder->summary); -} - -static void -imap_sync_online (CamelFolder *folder, CamelException *ex) -{ - CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store); - CamelImapResponse *response = NULL; - CamelMessageInfo *info; - CamelException local_ex; - GPtrArray *matches; - char *set, *flaglist; - gboolean unset; - int i, j, max; - - camel_exception_init (&local_ex); - CAMEL_SERVICE_LOCK (store, connect_lock); - - /* Find a message with changed flags, find all of the other - * messages like it, sync them as a group, mark them as - * updated, and continue. - */ - max = camel_folder_summary_count (folder->summary); - for (i = 0; i < max; i++) { - info = camel_folder_summary_index (folder->summary, i); - if (!info) - continue; - if (!(info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED)) { - camel_folder_summary_info_free (folder->summary, info); - continue; - } - - /* Note: Cyrus is broken and will not accept an - empty-set of flags so... if this is true then we - want to unset the previously set flags.*/ - unset = !(info->flags & CAMEL_IMAP_SERVER_FLAGS); - - /* FIXME: since we don't know the previously set flags, - if unset is TRUE then just unset all the flags? */ - flaglist = imap_create_flag_list (unset ? CAMEL_IMAP_SERVER_FLAGS : info->flags); - - /* Note: get_matching() uses UID_SET_LIMIT to limit - the size of the uid-set string. We don't have to - loop here to flush all the matching uids because - they will be scooped up later by our parent loop (I - think?). -- Jeff */ - matches = get_matching (folder, info->flags & (CAMEL_IMAP_SERVER_FLAGS | CAMEL_MESSAGE_FOLDER_FLAGGED), - CAMEL_IMAP_SERVER_FLAGS | CAMEL_MESSAGE_FOLDER_FLAGGED, &set); - camel_folder_summary_info_free (folder->summary, info); - - /* Note: to `unset' flags, use -FLAGS.SILENT (<flag list>) */ - response = camel_imap_command (store, folder, &local_ex, - "UID STORE %s %sFLAGS.SILENT %s", - set, unset ? "-" : "", flaglist); - g_free (set); - g_free (flaglist); - - if (response) - camel_imap_response_free (store, response); - - if (!camel_exception_is_set (&local_ex)) { - for (j = 0; j < matches->len; j++) { - info = matches->pdata[j]; - info->flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED; - ((CamelImapMessageInfo*)info)->server_flags = - info->flags & CAMEL_IMAP_SERVER_FLAGS; - } - camel_folder_summary_touch (folder->summary); - } - - for (j = 0; j < matches->len; j++) { - info = matches->pdata[j]; - camel_folder_summary_info_free (folder->summary, info); - } - g_ptr_array_free (matches, TRUE); - - /* We unlock here so that other threads can have a chance to grab the connect_lock */ - CAMEL_SERVICE_UNLOCK (store, connect_lock); - - /* check for an exception */ - if (camel_exception_is_set (&local_ex)) { - camel_exception_xfer (ex, &local_ex); - return; - } - - /* Re-lock the connect_lock */ - CAMEL_SERVICE_LOCK (store, connect_lock); - } - - /* Save the summary */ - imap_sync_offline (folder, ex); - - CAMEL_SERVICE_UNLOCK (store, connect_lock); -} - -static void -imap_expunge_uids_offline (CamelFolder *folder, GPtrArray *uids, CamelException *ex) -{ - CamelFolderChangeInfo *changes; - int i; - - changes = camel_folder_change_info_new (); - - for (i = 0; i < uids->len; i++) { - camel_folder_summary_remove_uid (folder->summary, uids->pdata[i]); - camel_folder_change_info_remove_uid (changes, uids->pdata[i]); - /* We intentionally don't remove it from the cache because - * the cached data may be useful in replaying a COPY later. - */ - } - camel_folder_summary_save (folder->summary); - - camel_disco_diary_log (CAMEL_DISCO_STORE (folder->parent_store)->diary, - CAMEL_DISCO_DIARY_FOLDER_EXPUNGE, folder, uids); - - camel_object_trigger_event (CAMEL_OBJECT (folder), "folder_changed", changes); - camel_folder_change_info_free (changes); -} - -static void -imap_expunge_uids_online (CamelFolder *folder, GPtrArray *uids, CamelException *ex) -{ - CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store); - CamelImapResponse *response; - int uid = 0; - char *set; - - CAMEL_SERVICE_LOCK (store, connect_lock); - - if ((store->capabilities & IMAP_CAPABILITY_UIDPLUS) == 0) { - ((CamelFolderClass *)CAMEL_OBJECT_GET_CLASS(folder))->sync(folder, 0, ex); - if (camel_exception_is_set(ex)) { - CAMEL_SERVICE_UNLOCK (store, connect_lock); - return; - } - } - - while (uid < uids->len) { - set = imap_uid_array_to_set (folder->summary, uids, uid, UID_SET_LIMIT, &uid); - response = camel_imap_command (store, folder, ex, - "UID STORE %s +FLAGS.SILENT \\Deleted", - set); - if (response) - camel_imap_response_free (store, response); - if (camel_exception_is_set (ex)) { - CAMEL_SERVICE_UNLOCK (store, connect_lock); - g_free (set); - return; - } - - if (store->capabilities & IMAP_CAPABILITY_UIDPLUS) { - response = camel_imap_command (store, folder, ex, - "UID EXPUNGE %s", set); - } else - response = camel_imap_command (store, folder, ex, "EXPUNGE"); - - if (response) - camel_imap_response_free (store, response); - } - - CAMEL_SERVICE_UNLOCK (store, connect_lock); -} - -static int -uid_compar (const void *va, const void *vb) -{ - const char **sa = (const char **)va, **sb = (const char **)vb; - unsigned long a, b; - - a = strtoul (*sa, NULL, 10); - b = strtoul (*sb, NULL, 10); - if (a < b) - return -1; - else if (a == b) - return 0; - else - return 1; -} - -static void -imap_expunge_uids_resyncing (CamelFolder *folder, GPtrArray *uids, CamelException *ex) -{ - CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store); - GPtrArray *keep_uids, *mark_uids; - CamelImapResponse *response; - char *result; - - if (store->capabilities & IMAP_CAPABILITY_UIDPLUS) { - imap_expunge_uids_online (folder, uids, ex); - return; - } - - /* If we don't have UID EXPUNGE we need to avoid expunging any - * of the wrong messages. So we search for deleted messages, - * and any that aren't in our to-expunge list get temporarily - * marked un-deleted. - */ - - CAMEL_SERVICE_LOCK (store, connect_lock); - - ((CamelFolderClass *)CAMEL_OBJECT_GET_CLASS(folder))->sync(folder, 0, ex); - if (camel_exception_is_set(ex)) { - CAMEL_SERVICE_UNLOCK (store, connect_lock); - return; - } - - response = camel_imap_command (store, folder, ex, "UID SEARCH DELETED"); - if (!response) { - CAMEL_SERVICE_UNLOCK (store, connect_lock); - return; - } - result = camel_imap_response_extract (store, response, "SEARCH", ex); - if (!result) { - CAMEL_SERVICE_UNLOCK (store, connect_lock); - return; - } - - if (result[8] == ' ') { - char *uid, *lasts = NULL; - unsigned long euid, kuid; - int ei, ki; - - keep_uids = g_ptr_array_new (); - mark_uids = g_ptr_array_new (); - - /* Parse SEARCH response */ - for (uid = strtok_r (result + 9, " ", &lasts); uid; uid = strtok_r (NULL, " ", &lasts)) - g_ptr_array_add (keep_uids, uid); - qsort (keep_uids->pdata, keep_uids->len, - sizeof (void *), uid_compar); - - /* Fill in "mark_uids", empty out "keep_uids" as needed */ - for (ei = ki = 0; ei < uids->len; ei++) { - euid = strtoul (uids->pdata[ei], NULL, 10); - - for (kuid = 0; ki < keep_uids->len; ki++) { - kuid = strtoul (keep_uids->pdata[ki], NULL, 10); - - if (kuid >= euid) - break; - } - - if (euid == kuid) - g_ptr_array_remove_index (keep_uids, ki); - else - g_ptr_array_add (mark_uids, uids->pdata[ei]); - } - } else { - /* Empty SEARCH result, meaning nothing is marked deleted - * on server. - */ - - keep_uids = NULL; - mark_uids = uids; - } - - /* Unmark messages to be kept */ - - if (keep_uids) { - char *uidset; - int uid = 0; - - while (uid < keep_uids->len) { - uidset = imap_uid_array_to_set (folder->summary, keep_uids, uid, UID_SET_LIMIT, &uid); - - response = camel_imap_command (store, folder, ex, - "UID STORE %s -FLAGS.SILENT \\Deleted", - uidset); - - g_free (uidset); - - if (!response) { - g_ptr_array_free (keep_uids, TRUE); - g_ptr_array_free (mark_uids, TRUE); - CAMEL_SERVICE_UNLOCK (store, connect_lock); - return; - } - camel_imap_response_free (store, response); - } - } - - /* Mark any messages that still need to be marked */ - if (mark_uids) { - char *uidset; - int uid = 0; - - while (uid < mark_uids->len) { - uidset = imap_uid_array_to_set (folder->summary, mark_uids, uid, UID_SET_LIMIT, &uid); - - response = camel_imap_command (store, folder, ex, - "UID STORE %s +FLAGS.SILENT \\Deleted", - uidset); - - g_free (uidset); - - if (!response) { - g_ptr_array_free (keep_uids, TRUE); - g_ptr_array_free (mark_uids, TRUE); - CAMEL_SERVICE_UNLOCK (store, connect_lock); - return; - } - camel_imap_response_free (store, response); - } - - if (mark_uids != uids) - g_ptr_array_free (mark_uids, TRUE); - } - - /* Do the actual expunging */ - response = camel_imap_command (store, folder, ex, "EXPUNGE"); - if (response) - camel_imap_response_free (store, response); - - /* And fix the remaining messages if we mangled them */ - if (keep_uids) { - char *uidset; - int uid = 0; - - while (uid < keep_uids->len) { - uidset = imap_uid_array_to_set (folder->summary, keep_uids, uid, UID_SET_LIMIT, &uid); - - /* Don't pass ex if it's already been set */ - response = camel_imap_command (store, folder, - camel_exception_is_set (ex) ? NULL : ex, - "UID STORE %s +FLAGS.SILENT \\Deleted", - uidset); - - g_free (uidset); - if (response) - camel_imap_response_free (store, response); - } - - g_ptr_array_free (keep_uids, TRUE); - } - - /* now we can free this, now that we're done with keep_uids */ - g_free (result); - - CAMEL_SERVICE_UNLOCK (store, connect_lock); -} - -static gchar * -get_temp_uid (void) -{ - gchar *res; - - static int counter = 0; - G_LOCK_DEFINE_STATIC (lock); - - G_LOCK (lock); - res = g_strdup_printf ("tempuid-%lx-%d", - (unsigned long) time (NULL), - counter++); - G_UNLOCK (lock); - - return res; -} - -static void -imap_append_offline (CamelFolder *folder, CamelMimeMessage *message, - const CamelMessageInfo *info, char **appended_uid, - CamelException *ex) -{ - CamelImapStore *imap_store = CAMEL_IMAP_STORE (folder->parent_store); - CamelImapMessageCache *cache = CAMEL_IMAP_FOLDER (folder)->cache; - CamelFolderChangeInfo *changes; - char *uid; - - uid = get_temp_uid (); - - camel_imap_summary_add_offline (folder->summary, uid, message, info); - CAMEL_IMAP_FOLDER_LOCK (folder, cache_lock); - camel_imap_message_cache_insert_wrapper (cache, uid, "", - CAMEL_DATA_WRAPPER (message), ex); - CAMEL_IMAP_FOLDER_UNLOCK (folder, cache_lock); - - changes = camel_folder_change_info_new (); - camel_folder_change_info_add_uid (changes, uid); - camel_object_trigger_event (CAMEL_OBJECT (folder), "folder_changed", - changes); - camel_folder_change_info_free (changes); - - camel_disco_diary_log (CAMEL_DISCO_STORE (imap_store)->diary, - CAMEL_DISCO_DIARY_FOLDER_APPEND, folder, uid); - if (appended_uid) - *appended_uid = uid; - else - g_free (uid); -} - -static CamelImapResponse * -do_append (CamelFolder *folder, CamelMimeMessage *message, - const CamelMessageInfo *info, char **uid, - CamelException *ex) -{ - CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store); - CamelImapResponse *response; - CamelStream *memstream; - CamelMimeFilter *crlf_filter; - CamelStreamFilter *streamfilter; - GByteArray *ba; - char *flagstr, *result, *end; - - /* create flag string param */ - if (info && info->flags) - flagstr = imap_create_flag_list (info->flags); - else - flagstr = NULL; - - /* encode any 8bit parts so we avoid sending embedded nul-chars and such */ - camel_mime_message_encode_8bit_parts (message); - - /* FIXME: We could avoid this if we knew how big the message was. */ - memstream = camel_stream_mem_new (); - ba = g_byte_array_new (); - camel_stream_mem_set_byte_array (CAMEL_STREAM_MEM (memstream), ba); - - streamfilter = camel_stream_filter_new_with_stream (memstream); - crlf_filter = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_ENCODE, - CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY); - camel_stream_filter_add (streamfilter, crlf_filter); - camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), - CAMEL_STREAM (streamfilter)); - camel_object_unref (CAMEL_OBJECT (streamfilter)); - camel_object_unref (CAMEL_OBJECT (crlf_filter)); - camel_object_unref (CAMEL_OBJECT (memstream)); - - response = camel_imap_command (store, NULL, ex, "APPEND %F%s%s {%d}", - folder->full_name, flagstr ? " " : "", - flagstr ? flagstr : "", ba->len); - g_free (flagstr); - - if (!response) { - g_byte_array_free (ba, TRUE); - return NULL; - } - - result = camel_imap_response_extract_continuation (store, response, ex); - if (!result) { - g_byte_array_free (ba, TRUE); - return NULL; - } - g_free (result); - - /* send the rest of our data - the mime message */ - response = camel_imap_command_continuation (store, ba->data, ba->len, ex); - g_byte_array_free (ba, TRUE); - if (!response) - return response; - - if (store->capabilities & IMAP_CAPABILITY_UIDPLUS) { - *uid = strstrcase (response->status, "[APPENDUID "); - if (*uid) - *uid = strchr (*uid + 11, ' '); - if (*uid) { - *uid = g_strndup (*uid + 1, strcspn (*uid + 1, "]")); - /* Make sure it's a number */ - if (strtoul (*uid, &end, 10) == 0 || *end) { - g_free (*uid); - *uid = NULL; - } - } - } else - *uid = NULL; - - return response; -} - -static void -imap_append_online (CamelFolder *folder, CamelMimeMessage *message, - const CamelMessageInfo *info, char **appended_uid, - CamelException *ex) -{ - CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store); - CamelImapResponse *response; - char *uid; - int count; - - count = camel_folder_summary_count (folder->summary); - response = do_append (folder, message, info, &uid, ex); - if (!response) - return; - - if (uid) { - /* Cache first, since freeing response may trigger a - * summary update that will want this information. - */ - CAMEL_IMAP_FOLDER_LOCK (folder, cache_lock); - camel_imap_message_cache_insert_wrapper ( - CAMEL_IMAP_FOLDER (folder)->cache, uid, - "", CAMEL_DATA_WRAPPER (message), ex); - CAMEL_IMAP_FOLDER_UNLOCK (folder, cache_lock); - if (appended_uid) - *appended_uid = uid; - else - g_free (uid); - } else if (appended_uid) - *appended_uid = NULL; - - camel_imap_response_free (store, response); - - /* Make sure a "folder_changed" is emitted. */ - CAMEL_SERVICE_LOCK (store, connect_lock); - if (store->current_folder != folder || - camel_folder_summary_count (folder->summary) == count) - imap_refresh_info (folder, ex); - CAMEL_SERVICE_UNLOCK (store, connect_lock); -} - -static void -imap_append_resyncing (CamelFolder *folder, CamelMimeMessage *message, - const CamelMessageInfo *info, char **appended_uid, - CamelException *ex) -{ - CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store); - CamelImapResponse *response; - char *uid; - - response = do_append (folder, message, info, &uid, ex); - if (!response) - return; - - if (uid) { - CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder); - const char *olduid = camel_message_info_uid (info); - - CAMEL_IMAP_FOLDER_LOCK (imap_folder, cache_lock); - camel_imap_message_cache_copy (imap_folder->cache, olduid, - imap_folder->cache, uid, ex); - CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock); - - if (appended_uid) - *appended_uid = uid; - else - g_free (uid); - } else if (appended_uid) - *appended_uid = NULL; - - camel_imap_response_free (store, response); -} - - -static void -imap_transfer_offline (CamelFolder *source, GPtrArray *uids, - CamelFolder *dest, GPtrArray **transferred_uids, - gboolean delete_originals, CamelException *ex) -{ - CamelImapStore *store = CAMEL_IMAP_STORE (source->parent_store); - CamelImapMessageCache *sc = CAMEL_IMAP_FOLDER (source)->cache; - CamelImapMessageCache *dc = CAMEL_IMAP_FOLDER (dest)->cache; - CamelFolderChangeInfo *changes; - CamelMimeMessage *message; - CamelMessageInfo *mi; - char *uid, *destuid; - int i; - - /* We grab the store's command lock first, and then grab the - * source and destination cache_locks. This way we can't - * deadlock in the case where we're simultaneously also trying - * to copy messages in the other direction from another thread. - */ - CAMEL_SERVICE_LOCK (store, connect_lock); - CAMEL_IMAP_FOLDER_LOCK (source, cache_lock); - CAMEL_IMAP_FOLDER_LOCK (dest, cache_lock); - CAMEL_SERVICE_UNLOCK (store, connect_lock); - - if (transferred_uids) { - *transferred_uids = g_ptr_array_new (); - g_ptr_array_set_size (*transferred_uids, uids->len); - } - - changes = camel_folder_change_info_new (); - - for (i = 0; i < uids->len; i++) { - uid = uids->pdata[i]; - - destuid = get_temp_uid (); - - mi = camel_folder_summary_uid (source->summary, uid); - g_return_if_fail (mi != NULL); - - message = camel_folder_get_message (source, uid, NULL); - - if (message) { - camel_imap_summary_add_offline (dest->summary, destuid, message, mi); - camel_object_unref (CAMEL_OBJECT (message)); - } else - camel_imap_summary_add_offline_uncached (dest->summary, destuid, mi); - - camel_imap_message_cache_copy (sc, uid, dc, destuid, ex); - camel_folder_summary_info_free (source->summary, mi); - - camel_folder_change_info_add_uid (changes, destuid); - if (transferred_uids) - (*transferred_uids)->pdata[i] = destuid; - else - g_free (destuid); - - if (delete_originals) - camel_folder_delete_message (source, uid); - } - - CAMEL_IMAP_FOLDER_UNLOCK (dest, cache_lock); - CAMEL_IMAP_FOLDER_UNLOCK (source, cache_lock); - - camel_object_trigger_event (CAMEL_OBJECT (dest), "folder_changed", changes); - camel_folder_change_info_free (changes); - - camel_disco_diary_log (CAMEL_DISCO_STORE (store)->diary, - CAMEL_DISCO_DIARY_FOLDER_TRANSFER, - source, dest, uids, delete_originals); -} - -static void -handle_copyuid (CamelImapResponse *response, CamelFolder *source, - CamelFolder *destination) -{ - CamelImapMessageCache *scache = CAMEL_IMAP_FOLDER (source)->cache; - CamelImapMessageCache *dcache = CAMEL_IMAP_FOLDER (destination)->cache; - char *validity, *srcset, *destset; - GPtrArray *src, *dest; - int i; - - validity = strstrcase (response->status, "[COPYUID "); - if (!validity) - return; - validity += 9; - if (strtoul (validity, NULL, 10) != - CAMEL_IMAP_SUMMARY (destination->summary)->validity) - return; - - srcset = strchr (validity, ' '); - if (!srcset++) - goto lose; - destset = strchr (srcset, ' '); - if (!destset++) - goto lose; - - src = imap_uid_set_to_array (source->summary, srcset); - dest = imap_uid_set_to_array (destination->summary, destset); - - if (src && dest && src->len == dest->len) { - /* We don't have to worry about deadlocking on the - * cache locks here, because we've got the store's - * command lock too, so no one else could be here. - */ - CAMEL_IMAP_FOLDER_LOCK (source, cache_lock); - CAMEL_IMAP_FOLDER_LOCK (destination, cache_lock); - for (i = 0; i < src->len; i++) { - camel_imap_message_cache_copy (scache, src->pdata[i], - dcache, dest->pdata[i], - NULL); - } - CAMEL_IMAP_FOLDER_UNLOCK (source, cache_lock); - CAMEL_IMAP_FOLDER_UNLOCK (destination, cache_lock); - - imap_uid_array_free (src); - imap_uid_array_free (dest); - return; - } - - imap_uid_array_free (src); - imap_uid_array_free (dest); - lose: - g_warning ("Bad COPYUID response from server"); -} - -static void -do_copy (CamelFolder *source, GPtrArray *uids, - CamelFolder *destination, CamelException *ex) -{ - CamelImapStore *store = CAMEL_IMAP_STORE (source->parent_store); - CamelImapResponse *response; - char *uidset; - int uid = 0; - - while (uid < uids->len && !camel_exception_is_set (ex)) { - uidset = imap_uid_array_to_set (source->summary, uids, uid, UID_SET_LIMIT, &uid); - - response = camel_imap_command (store, source, ex, "UID COPY %s %F", - uidset, destination->full_name); - - g_free (uidset); - - if (response && (store->capabilities & IMAP_CAPABILITY_UIDPLUS)) - handle_copyuid (response, source, destination); - - camel_imap_response_free (store, response); - } -} - -static void -imap_transfer_online (CamelFolder *source, GPtrArray *uids, - CamelFolder *dest, GPtrArray **transferred_uids, - gboolean delete_originals, CamelException *ex) -{ - CamelImapStore *store = CAMEL_IMAP_STORE (source->parent_store); - int count, i; - - /* Sync message flags if needed. */ - imap_sync_online (source, ex); - if (camel_exception_is_set (ex)) - return; - - count = camel_folder_summary_count (dest->summary); - - /* Now copy the messages */ - do_copy (source, uids, dest, ex); - if (camel_exception_is_set (ex)) - return; - - /* Make the destination notice its new messages */ - CAMEL_SERVICE_LOCK (store, connect_lock); - if (store->current_folder != dest || - camel_folder_summary_count (dest->summary) == count) - camel_folder_refresh_info (dest, ex); - CAMEL_SERVICE_UNLOCK (store, connect_lock); - - if (delete_originals) { - for (i = 0; i < uids->len; i++) - camel_folder_delete_message (source, uids->pdata[i]); - } - - /* FIXME */ - if (transferred_uids) - *transferred_uids = NULL; -} - -static void -imap_transfer_resyncing (CamelFolder *source, GPtrArray *uids, - CamelFolder *dest, GPtrArray **transferred_uids, - gboolean delete_originals, CamelException *ex) -{ - CamelDiscoDiary *diary = CAMEL_DISCO_STORE (source->parent_store)->diary; - GPtrArray *realuids; - int first, i; - const char *uid; - CamelMimeMessage *message; - CamelMessageInfo *info; - - /* This is trickier than append_resyncing, because some of - * the messages we are copying may have been copied or - * appended into @source while we were offline, in which case - * if we don't have UIDPLUS, we won't know their real UIDs, - * so we'll have to append them rather than copying. - */ - - realuids = g_ptr_array_new (); - - i = 0; - while (i < uids->len) { - /* Skip past real UIDs */ - for (first = i; i < uids->len; i++) { - uid = uids->pdata[i]; - - if (!isdigit ((unsigned char)*uid)) { - uid = camel_disco_diary_uidmap_lookup (diary, uid); - if (!uid) - break; - } - g_ptr_array_add (realuids, (char *)uid); - - if (delete_originals) - camel_folder_delete_message (source, uid); - } - - /* If we saw any real UIDs, do a COPY */ - if (i != first) { - do_copy (source, realuids, dest, ex); - g_ptr_array_set_size (realuids, 0); - if (i == uids->len || camel_exception_is_set (ex)) - break; - } - - /* Deal with fake UIDs */ - while (i < uids->len && - !isdigit (*(unsigned char *)(uids->pdata[i])) && - !camel_exception_is_set (ex)) { - uid = uids->pdata[i]; - message = camel_folder_get_message (source, uid, NULL); - if (!message) { - /* Message must have been expunged */ - continue; - } - info = camel_folder_get_message_info (source, uid); - g_return_if_fail (info != NULL); - - imap_append_online (dest, message, info, NULL, ex); - camel_folder_free_message_info (source, info); - camel_object_unref (CAMEL_OBJECT (message)); - if (delete_originals) - camel_folder_delete_message (source, uid); - i++; - } - } - - g_ptr_array_free (realuids, FALSE); - - /* FIXME */ - if (transferred_uids) - *transferred_uids = NULL; -} - -static GPtrArray * -imap_search_by_expression (CamelFolder *folder, const char *expression, CamelException *ex) -{ - CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder); - GPtrArray *matches, *summary; - - /* we could get around this by creating a new search object each time, - but i doubt its worth it since any long operation would lock the - command channel too */ - CAMEL_IMAP_FOLDER_LOCK(folder, search_lock); - - camel_folder_search_set_folder (imap_folder->search, folder); - summary = camel_folder_get_summary(folder); - camel_folder_search_set_summary(imap_folder->search, summary); - matches = camel_folder_search_execute_expression (imap_folder->search, expression, ex); - - CAMEL_IMAP_FOLDER_UNLOCK(folder, search_lock); - - camel_folder_free_summary(folder, summary); - - return matches; -} - -static GPtrArray * -imap_search_by_uids(CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex) -{ - CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER(folder); - GPtrArray *summary, *matches; - int i; - - /* NOTE: could get away without the search lock by creating a new - search object each time */ - - summary = g_ptr_array_new(); - for (i=0;i<uids->len;i++) { - CamelMessageInfo *info; - - info = camel_folder_get_message_info(folder, uids->pdata[i]); - if (info) - g_ptr_array_add(summary, info); - } - - if (summary->len == 0) - return summary; - - CAMEL_IMAP_FOLDER_LOCK(folder, search_lock); - - camel_folder_search_set_folder(imap_folder->search, folder); - camel_folder_search_set_summary(imap_folder->search, summary); - - matches = camel_folder_search_execute_expression(imap_folder->search, expression, ex); - - CAMEL_IMAP_FOLDER_UNLOCK(folder, search_lock); - - for (i=0;i<summary->len;i++) - camel_folder_free_message_info(folder, summary->pdata[i]); - g_ptr_array_free(summary, TRUE); - - return matches; -} - -static void -imap_search_free (CamelFolder *folder, GPtrArray *uids) -{ - CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder); - - g_return_if_fail (imap_folder->search); - - CAMEL_IMAP_FOLDER_LOCK(folder, search_lock); - - camel_folder_search_free_result (imap_folder->search, uids); - - CAMEL_IMAP_FOLDER_UNLOCK(folder, search_lock); -} - -static CamelMimeMessage *get_message (CamelImapFolder *imap_folder, - const char *uid, - const char *part_specifier, - CamelMessageContentInfo *ci, - CamelException *ex); - -struct _part_spec_stack { - struct _part_spec_stack *parent; - int part; -}; - -static void -part_spec_push (struct _part_spec_stack **stack, int part) -{ - struct _part_spec_stack *node; - - node = g_new (struct _part_spec_stack, 1); - node->parent = *stack; - node->part = part; - - *stack = node; -} - -static int -part_spec_pop (struct _part_spec_stack **stack) -{ - struct _part_spec_stack *node; - int part; - - g_return_val_if_fail (*stack != NULL, 0); - - node = *stack; - *stack = node->parent; - - part = node->part; - g_free (node); - - return part; -} - -static char * -content_info_get_part_spec (CamelMessageContentInfo *ci) -{ - struct _part_spec_stack *stack = NULL; - CamelMessageContentInfo *node; - char *part_spec, *buf; - size_t len = 1; - int part; - - node = ci; - while (node->parent) { - CamelMessageContentInfo *child; - - /* FIXME: is this only supposed to apply if 'node' is a multipart? */ - if (node->parent->parent && header_content_type_is (node->parent->type, "message", "*")) { - node = node->parent; - continue; - } - - child = node->parent->childs; - for (part = 1; child; part++) { - if (child == node) - break; - - child = child->next; - } - - part_spec_push (&stack, part); - - len += 2; - while ((part = part / 10)) - len++; - - node = node->parent; - } - - buf = part_spec = g_malloc (len); - part_spec[0] = '\0'; - - while (stack) { - part = part_spec_pop (&stack); - buf += sprintf (buf, "%d%s", part, stack ? "." : ""); - } - - return part_spec; -} - -/* Fetch the contents of the MIME part indicated by @ci, which is part - * of message @uid in @folder. - */ -static CamelDataWrapper * -get_content (CamelImapFolder *imap_folder, const char *uid, - CamelMimePart *part, CamelMessageContentInfo *ci, - CamelException *ex) -{ - CamelDataWrapper *content = NULL; - CamelStream *stream; - char *part_spec; - - part_spec = content_info_get_part_spec (ci); - - /* There are three cases: multipart/signed, multipart, message/rfc822, and "other" */ - if (header_content_type_is (ci->type, "multipart", "signed")) { - CamelMultipartSigned *body_mp; - char *spec; - int ret; - - /* Note: because we get the content parts uninterpreted anyway, we could potentially - just use the normalmultipart code, except that multipart/signed wont let you yet! */ - - body_mp = camel_multipart_signed_new (); - /* need to set this so it grabs the boundary and other info about the signed type */ - /* we assume that part->content_type is more accurate/full than ci->type */ - camel_data_wrapper_set_mime_type_field (CAMEL_DATA_WRAPPER (body_mp), part->content_type); - - spec = alloca (strlen (part_spec) + 6); - sprintf (spec, part_spec[0] ? "%s.TEXT" : "TEXT", part_spec); - g_free (part_spec); - - stream = camel_imap_folder_fetch_data (imap_folder, uid, spec, FALSE, ex); - if (stream) { - ret = camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (body_mp), stream); - camel_object_unref (CAMEL_OBJECT (stream)); - if (ret == -1) { - camel_object_unref ((CamelObject *) body_mp); - return NULL; - } - } - - return (CamelDataWrapper *) body_mp; - } else if (header_content_type_is (ci->type, "multipart", "*")) { - CamelMultipart *body_mp; - char *child_spec; - int speclen, num; - - if (header_content_type_is (ci->type, "multipart", "encrypted")) - body_mp = (CamelMultipart *) camel_multipart_encrypted_new (); - else - body_mp = camel_multipart_new (); - - /* need to set this so it grabs the boundary and other info about the multipart */ - /* we assume that part->content_type is more accurate/full than ci->type */ - camel_data_wrapper_set_mime_type_field (CAMEL_DATA_WRAPPER (body_mp), part->content_type); - - speclen = strlen (part_spec); - child_spec = g_malloc (speclen + 17); /* dot + 10 + dot + MIME + nul */ - memcpy (child_spec, part_spec, speclen); - if (speclen > 0) - child_spec[speclen++] = '.'; - g_free (part_spec); - - ci = ci->childs; - num = 1; - while (ci) { - sprintf (child_spec + speclen, "%d.MIME", num++); - stream = camel_imap_folder_fetch_data (imap_folder, uid, child_spec, FALSE, ex); - if (stream) { - int ret; - - part = camel_mime_part_new (); - ret = camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (part), stream); - camel_object_unref (CAMEL_OBJECT (stream)); - if (ret == -1) { - camel_object_unref (CAMEL_OBJECT (part)); - camel_object_unref (CAMEL_OBJECT (body_mp)); - g_free (child_spec); - return NULL; - } - - content = get_content (imap_folder, uid, part, ci, ex); - } - - if (!stream || !content) { - camel_object_unref (CAMEL_OBJECT (body_mp)); - g_free (child_spec); - return NULL; - } - - camel_medium_set_content_object (CAMEL_MEDIUM (part), content); - camel_object_unref (CAMEL_OBJECT (content)); - camel_multipart_add_part (body_mp, part); - camel_object_unref (CAMEL_OBJECT (part)); - - ci = ci->next; - } - - g_free (child_spec); - - return (CamelDataWrapper *) body_mp; - } else if (header_content_type_is (ci->type, "message", "rfc822")) { - content = (CamelDataWrapper *) get_message (imap_folder, uid, part_spec, ci->childs, ex); - g_free (part_spec); - return content; - } else { - content = camel_imap_wrapper_new (imap_folder, ci->type, uid, *part_spec ? part_spec : "1", part); - g_free (part_spec); - return content; - } -} - -static CamelMimeMessage * -get_message (CamelImapFolder *imap_folder, const char *uid, - const char *part_spec, CamelMessageContentInfo *ci, - CamelException *ex) -{ - CamelImapStore *store = CAMEL_IMAP_STORE (CAMEL_FOLDER (imap_folder)->parent_store); - CamelDataWrapper *content; - CamelMimeMessage *msg; - CamelStream *stream; - char *section_text; - int ret; - - section_text = g_strdup_printf ("%s%s%s", part_spec, *part_spec ? "." : "", - store->server_level >= IMAP_LEVEL_IMAP4REV1 ? "HEADER" : "0"); - stream = camel_imap_folder_fetch_data (imap_folder, uid, section_text, FALSE, ex); - g_free (section_text); - if (!stream) - return NULL; - - msg = camel_mime_message_new (); - ret = camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (msg), stream); - camel_object_unref (CAMEL_OBJECT (stream)); - if (ret == -1) { - camel_object_unref (CAMEL_OBJECT (msg)); - return NULL; - } - - content = get_content (imap_folder, uid, CAMEL_MIME_PART (msg), ci, ex); - if (!content) { - camel_object_unref (CAMEL_OBJECT (msg)); - return NULL; - } - - camel_medium_set_content_object (CAMEL_MEDIUM (msg), content); - camel_object_unref (CAMEL_OBJECT (content)); - - return msg; -} - -/* FIXME: I pulled this number out of my butt. */ -#define IMAP_SMALL_BODY_SIZE 5120 - -static CamelMimeMessage * -get_message_simple (CamelImapFolder *imap_folder, const char *uid, - CamelStream *stream, CamelException *ex) -{ - CamelMimeMessage *msg; - CamelImapStore *imap_store = - CAMEL_IMAP_STORE (CAMEL_FOLDER (imap_folder)->parent_store); - int ret; - - if (!stream) { - stream = camel_imap_folder_fetch_data (imap_folder, uid, "", - FALSE, ex); - if (!stream) - return NULL; - } - - msg = camel_mime_message_new (); - ret = camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (msg), - stream); - camel_object_unref (CAMEL_OBJECT (stream)); - if (ret == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Unable to retrieve message: %s"), strerror(errno)); - camel_object_unref (CAMEL_OBJECT (msg)); - return NULL; - } - - /* FIXME, this shouldn't be done this way. */ - camel_medium_set_header (CAMEL_MEDIUM (msg), "X-Evolution-Source", - imap_store->base_url); - return msg; -} - -static CamelMimeMessage * -imap_get_message (CamelFolder *folder, const char *uid, CamelException *ex) -{ - CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder); - CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store); - CamelMessageInfo *mi; - CamelMimeMessage *msg; - CamelStream *stream = NULL; - - /* If the server doesn't support IMAP4rev1, or we already have - * the whole thing cached, fetch it in one piece. - */ - if (store->server_level < IMAP_LEVEL_IMAP4REV1 || - (stream = camel_imap_folder_fetch_data (imap_folder, uid, "", TRUE, NULL))) - return get_message_simple (imap_folder, uid, stream, ex); - - /* If we're not actually connected and it's not in the cache, - * that's as far as we can go. - */ - if (camel_disco_store_check_online (CAMEL_DISCO_STORE (store), ex) == FALSE) - return NULL; - - mi = camel_folder_summary_uid (folder->summary, uid); - if (mi == NULL) { - camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID, - _("Cannot get message: %s\n %s"), uid, _("No such message")); - return NULL; - } - - /* If the message is small, fetch it in one piece. */ - if (mi->size < IMAP_SMALL_BODY_SIZE) { - camel_folder_summary_info_free (folder->summary, mi); - return get_message_simple (imap_folder, uid, NULL, ex); - } - - /* For larger messages, fetch the structure and build a message - * with offline parts. (We check mi->content->type rather than - * mi->content because camel_folder_summary_info_new always creates - * an empty content struct.) - */ - if (!mi->content->type) { - CamelImapResponse *response; - GData *fetch_data = NULL; - char *body, *found_uid; - int i; - - if (camel_disco_store_status (CAMEL_DISCO_STORE (store)) == CAMEL_DISCO_STORE_OFFLINE) { - camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("This message is not currently available")); - return NULL; - } - - response = camel_imap_command (store, folder, ex, - "UID FETCH %s BODY", uid); - if (!response) { - camel_folder_summary_info_free (folder->summary, mi); - return NULL; - } - - for (i = 0, body = NULL; i < response->untagged->len; i++) { - fetch_data = parse_fetch_response (imap_folder, response->untagged->pdata[i]); - if (fetch_data) { - found_uid = g_datalist_get_data (&fetch_data, "UID"); - body = g_datalist_get_data (&fetch_data, "BODY"); - if (found_uid && body && !strcmp (found_uid, uid)) - break; - g_datalist_clear (&fetch_data); - fetch_data = NULL; - body = NULL; - } - } - - if (body) - imap_parse_body ((const char **) &body, folder, mi->content); - - if (fetch_data) - g_datalist_clear (&fetch_data); - - camel_imap_response_free (store, response); - - d(camel_content_info_dump (mi->content, 0)); - - if (!mi->content->type) { - /* FETCH returned OK, but we didn't parse a BODY - * response. Courier will return invalid BODY - * responses for invalidly MIMEd messages, so - * fall back to fetching the entire thing and - * let the mailer's "bad MIME" code handle it. - */ - camel_folder_summary_info_free (folder->summary, mi); - return get_message_simple (imap_folder, uid, NULL, ex); - } - } - - msg = get_message (imap_folder, uid, "", mi->content, ex); - /* FIXME, this shouldn't be done this way. */ - camel_medium_set_header (CAMEL_MEDIUM (msg), "X-Evolution-Source", - store->base_url); - camel_folder_summary_info_free (folder->summary, mi); - - return msg; -} - -static void -imap_cache_message (CamelDiscoFolder *disco_folder, const char *uid, - CamelException *ex) -{ - CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (disco_folder); - CamelStream *stream; - - stream = camel_imap_folder_fetch_data (imap_folder, uid, "", FALSE, ex); - if (stream) - camel_object_unref (CAMEL_OBJECT (stream)); -} - -/* We pretend that a FLAGS or RFC822.SIZE response is always exactly - * 20 bytes long, and a BODY[HEADERS] response is always 2000 bytes - * long. Since we know how many of each kind of response we're - * expecting, we can find the total (pretend) amount of server traffic - * to expect and then count off the responses as we read them to update - * the progress bar. - */ -#define IMAP_PRETEND_SIZEOF_FLAGS 20 -#define IMAP_PRETEND_SIZEOF_SIZE 20 -#define IMAP_PRETEND_SIZEOF_HEADERS 2000 - -static void -add_message_from_data (CamelFolder *folder, GPtrArray *messages, - int first, GData *data) -{ - CamelMimeMessage *msg; - CamelStream *stream; - CamelMessageInfo *mi; - int seq; - - seq = GPOINTER_TO_INT (g_datalist_get_data (&data, "SEQUENCE")); - if (seq < first) - return; - stream = g_datalist_get_data (&data, "BODY_PART_STREAM"); - if (!stream) - return; - - if (seq - first >= messages->len) - g_ptr_array_set_size (messages, seq - first + 1); - - msg = camel_mime_message_new (); - if (camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (msg), stream) == -1) { - camel_object_unref (CAMEL_OBJECT (msg)); - return; - } - - mi = camel_folder_summary_info_new_from_message (folder->summary, msg); - camel_object_unref (CAMEL_OBJECT (msg)); - - messages->pdata[seq - first] = mi; -} - -static void -imap_update_summary (CamelFolder *folder, int exists, - CamelFolderChangeInfo *changes, - CamelException *ex) -{ - CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store); - CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder); - GPtrArray *fetch_data = NULL, *messages = NULL, *needheaders; - guint32 flags, uidval, maxuid; - int i, seq, first, size, got; - CamelImapResponseType type; - const char *header_spec; - CamelMessageInfo *mi, *info; - CamelStream *stream; - char *uid, *resp; - GData *data; - - CAMEL_SERVICE_ASSERT_LOCKED (store, connect_lock); - if (store->server_level >= IMAP_LEVEL_IMAP4REV1) - header_spec = "HEADER"; - else - header_spec = "0"; - - /* Figure out if any of the new messages are already cached (which - * may be the case if we're re-syncing after disconnected operation). - * If so, get their UIDs, FLAGS, and SIZEs. If not, get all that - * and ask for the headers too at the same time. - */ - seq = camel_folder_summary_count (folder->summary); - first = seq + 1; - if (seq > 0) { - mi = camel_folder_summary_index (folder->summary, seq - 1); - uidval = atoi (camel_message_info_uid (mi)); - camel_folder_summary_info_free (folder->summary, mi); - } else - uidval = 0; - - size = (exists - seq) * (IMAP_PRETEND_SIZEOF_FLAGS + IMAP_PRETEND_SIZEOF_SIZE); - got = 0; - - maxuid = camel_imap_message_cache_max_uid (imap_folder->cache); - if (uidval >= maxuid) { - /* None of the new messages are cached */ - size += (exists - seq) * IMAP_PRETEND_SIZEOF_HEADERS; - if (!camel_imap_command_start (store, folder, ex, - "UID FETCH %d:* (FLAGS RFC822.SIZE BODY.PEEK[%s])", - maxuid + 1, header_spec)) - return; - camel_operation_start (NULL, _("Fetching summary information for new messages")); - } else { - if (!camel_imap_command_start (store, folder, ex, - "UID FETCH %d:* (FLAGS RFC822.SIZE)", - uidval + 1)) - return; - camel_operation_start (NULL, _("Scanning for new messages")); - } - - /* Parse the responses. We can't add a message to the summary - * until we've gotten its headers, and there's no guarantee - * the server will send the responses in a useful order... - */ - fetch_data = g_ptr_array_new (); - messages = g_ptr_array_new (); - while ((type = camel_imap_command_response (store, &resp, ex)) == - CAMEL_IMAP_RESPONSE_UNTAGGED) { - data = parse_fetch_response (imap_folder, resp); - g_free (resp); - if (!data) - continue; - - seq = GPOINTER_TO_INT (g_datalist_get_data (&data, "SEQUENCE")); - if (seq < first) { - g_datalist_clear (&data); - continue; - } - - if (g_datalist_get_data (&data, "FLAGS")) - got += IMAP_PRETEND_SIZEOF_FLAGS; - if (g_datalist_get_data (&data, "RFC822.SIZE")) - got += IMAP_PRETEND_SIZEOF_SIZE; - stream = g_datalist_get_data (&data, "BODY_PART_STREAM"); - if (stream) { - got += IMAP_PRETEND_SIZEOF_HEADERS; - - /* Use the stream now so we don't tie up many - * many fds if we're fetching many many messages. - */ - add_message_from_data (folder, messages, first, data); - g_datalist_set_data (&data, "BODY_PART_STREAM", NULL); - } - - camel_operation_progress (NULL, got * 100 / size); - g_ptr_array_add (fetch_data, data); - } - camel_operation_end (NULL); - - if (type == CAMEL_IMAP_RESPONSE_ERROR) - goto lose; - - /* Free the final tagged response */ - g_free (resp); - - /* Figure out which headers we still need to fetch. */ - needheaders = g_ptr_array_new (); - size = got = 0; - for (i = 0; i < fetch_data->len; i++) { - data = fetch_data->pdata[i]; - if (g_datalist_get_data (&data, "BODY_PART_LEN")) - continue; - - uid = g_datalist_get_data (&data, "UID"); - if (uid) { - g_ptr_array_add (needheaders, uid); - size += IMAP_PRETEND_SIZEOF_HEADERS; - } - } - - /* And fetch them */ - if (needheaders->len) { - char *uidset; - int uid = 0; - - qsort (needheaders->pdata, needheaders->len, - sizeof (void *), uid_compar); - - camel_operation_start (NULL, _("Fetching summary information for new messages")); - - while (uid < needheaders->len) { - uidset = imap_uid_array_to_set (folder->summary, needheaders, uid, UID_SET_LIMIT, &uid); - if (!camel_imap_command_start (store, folder, ex, - "UID FETCH %s BODY.PEEK[%s]", - uidset, header_spec)) { - g_ptr_array_free (needheaders, TRUE); - camel_operation_end (NULL); - g_free (uidset); - goto lose; - } - g_free (uidset); - - while ((type = camel_imap_command_response (store, &resp, ex)) - == CAMEL_IMAP_RESPONSE_UNTAGGED) { - data = parse_fetch_response (imap_folder, resp); - g_free (resp); - if (!data) - continue; - - stream = g_datalist_get_data (&data, "BODY_PART_STREAM"); - if (stream) { - add_message_from_data (folder, messages, first, data); - got += IMAP_PRETEND_SIZEOF_HEADERS; - camel_operation_progress (NULL, got * 100 / size); - } - g_datalist_clear (&data); - } - - if (type == CAMEL_IMAP_RESPONSE_ERROR) { - g_ptr_array_free (needheaders, TRUE); - camel_operation_end (NULL); - goto lose; - } - } - - g_ptr_array_free (needheaders, TRUE); - camel_operation_end (NULL); - } - - /* Now finish up summary entries (fix UIDs, set flags and size) */ - for (i = 0; i < fetch_data->len; i++) { - data = fetch_data->pdata[i]; - - seq = GPOINTER_TO_INT (g_datalist_get_data (&data, "SEQUENCE")); - if (seq >= first + messages->len) { - g_datalist_clear (&data); - continue; - } - - mi = messages->pdata[seq - first]; - if (mi == NULL) { - CamelMessageInfo *pmi = NULL; - int j; - - /* This is a kludge around a bug in Exchange - * 5.5 that sometimes claims multiple messages - * have the same UID. See bug #17694 for - * details. The "solution" is to create a fake - * message-info with the same details as the - * previously valid message. Yes, the user - * will have a clone in his/her message-list, - * but at least we don't crash. - */ - - /* find the previous valid message info */ - for (j = seq - first - 1; j >= 0; j--) { - pmi = messages->pdata[j]; - if (pmi != NULL) - break; - } - - if (pmi == NULL) { - /* Server response is *really* fucked up, - I guess we just pretend it never happened? */ - continue; - } - - mi = camel_message_info_new (); - camel_message_info_dup_to (pmi, mi); - } - - uid = g_datalist_get_data (&data, "UID"); - if (uid) - camel_message_info_set_uid (mi, g_strdup (uid)); - flags = GPOINTER_TO_INT (g_datalist_get_data (&data, "FLAGS")); - if (flags) { - ((CamelImapMessageInfo *)mi)->server_flags = flags; - /* "or" them in with the existing flags that may - * have been set by summary_info_new_from_message. - */ - mi->flags |= flags; - } - size = GPOINTER_TO_INT (g_datalist_get_data (&data, "RFC822.SIZE")); - if (size) - mi->size = size; - - g_datalist_clear (&data); - } - g_ptr_array_free (fetch_data, TRUE); - - /* And add the entries to the summary, etc. */ - for (i = 0; i < messages->len; i++) { - mi = messages->pdata[i]; - if (!mi) { - g_warning ("No information for message %d", i + first); - continue; - } - uid = (char *)camel_message_info_uid(mi); - if (uid[0] == 0) { - g_warning("Server provided no uid: message %d", i + first); - continue; - } - info = camel_folder_summary_uid(folder->summary, uid); - if (info) { - g_warning("Message already present? %s", camel_message_info_uid(mi)); - camel_folder_summary_info_free(folder->summary, info); - camel_folder_summary_info_free(folder->summary, mi); - continue; - } - - camel_folder_summary_add (folder->summary, mi); - camel_folder_change_info_add_uid (changes, camel_message_info_uid (mi)); - - if ((mi->flags & CAMEL_IMAP_MESSAGE_RECENT)) - camel_folder_change_info_recent_uid(changes, camel_message_info_uid (mi)); - } - g_ptr_array_free (messages, TRUE); - - /* Kludge around Microsoft Exchange 5.5 IMAP - See bug #5348 for details */ - if (camel_folder_summary_count (folder->summary) != exists) { - CamelImapStore *imap_store = (CamelImapStore *) folder->parent_store; - CamelImapResponse *response; - - /* forget the currently selected folder */ - if (imap_store->current_folder) { - camel_object_unref (CAMEL_OBJECT (imap_store->current_folder)); - imap_store->current_folder = NULL; - } - - /* now re-select it and process the EXISTS response */ - response = camel_imap_command (imap_store, folder, ex, NULL); - if (response) { - camel_imap_folder_selected (folder, response, NULL); - camel_imap_response_free (imap_store, response); - } - } - - return; - - lose: - if (fetch_data) { - for (i = 0; i < fetch_data->len; i++) { - data = fetch_data->pdata[i]; - g_datalist_clear (&data); - } - g_ptr_array_free (fetch_data, TRUE); - } - if (messages) { - for (i = 0; i < messages->len; i++) { - if (messages->pdata[i]) - camel_folder_summary_info_free (folder->summary, messages->pdata[i]); - } - g_ptr_array_free (messages, TRUE); - } -} - -/* Called with the store's connect_lock locked */ -void -camel_imap_folder_changed (CamelFolder *folder, int exists, - GArray *expunged, CamelException *ex) -{ - CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder); - CamelFolderChangeInfo *changes; - CamelMessageInfo *info; - int len; - - CAMEL_SERVICE_ASSERT_LOCKED (folder->parent_store, connect_lock); - - changes = camel_folder_change_info_new (); - if (expunged) { - int i, id; - - for (i = 0; i < expunged->len; i++) { - id = g_array_index (expunged, int, i); - info = camel_folder_summary_index (folder->summary, id - 1); - if (info == NULL) { - /* FIXME: danw: does this mean that the summary is corrupt? */ - /* I guess a message that we never retrieved got expunged? */ - continue; - } - - camel_folder_change_info_remove_uid (changes, camel_message_info_uid (info)); - CAMEL_IMAP_FOLDER_LOCK (imap_folder, cache_lock); - camel_imap_message_cache_remove (imap_folder->cache, camel_message_info_uid (info)); - CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock); - camel_folder_summary_remove (folder->summary, info); - camel_folder_summary_info_free(folder->summary, info); - } - } - - len = camel_folder_summary_count (folder->summary); - if (exists > len) - imap_update_summary (folder, exists, changes, ex); - - if (camel_folder_change_info_changed (changes)) - camel_object_trigger_event (CAMEL_OBJECT (folder), "folder_changed", changes); - - camel_folder_change_info_free (changes); - camel_folder_summary_save (folder->summary); -} - -static void -imap_thaw (CamelFolder *folder) -{ - CamelImapFolder *imap_folder; - - CAMEL_FOLDER_CLASS (disco_folder_class)->thaw (folder); - if (camel_folder_is_frozen (folder)) - return; - - imap_folder = CAMEL_IMAP_FOLDER (folder); - if (imap_folder->need_refresh) { - imap_folder->need_refresh = FALSE; - imap_refresh_info (folder, NULL); - } -} - - -CamelStream * -camel_imap_folder_fetch_data (CamelImapFolder *imap_folder, const char *uid, - const char *section_text, gboolean cache_only, - CamelException *ex) -{ - CamelFolder *folder = CAMEL_FOLDER (imap_folder); - CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store); - CamelImapResponse *response; - CamelStream *stream; - GData *fetch_data; - char *found_uid; - int i; - - /* EXPUNGE responses have to modify the cache, which means - * they have to grab the cache_lock while holding the - * connect_lock. So we grab the connect_lock now, in case - * we're going to need it below, since we can't grab it - * after the cache_lock. - */ - CAMEL_SERVICE_LOCK (store, connect_lock); - - CAMEL_IMAP_FOLDER_LOCK (imap_folder, cache_lock); - stream = camel_imap_message_cache_get (imap_folder->cache, uid, section_text); - if (!stream && (!strcmp (section_text, "HEADER") || !strcmp (section_text, "0"))) - stream = camel_imap_message_cache_get (imap_folder->cache, uid, ""); - if (stream || cache_only) { - CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock); - CAMEL_SERVICE_UNLOCK (store, connect_lock); - return stream; - } - - if (camel_disco_store_status (CAMEL_DISCO_STORE (store)) == CAMEL_DISCO_STORE_OFFLINE) { - camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("This message is not currently available")); - CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock); - CAMEL_SERVICE_UNLOCK (store, connect_lock); - return NULL; - } - - if (store->server_level < IMAP_LEVEL_IMAP4REV1 && !*section_text) { - response = camel_imap_command (store, folder, ex, - "UID FETCH %s RFC822.PEEK", - uid); - } else { - response = camel_imap_command (store, folder, ex, - "UID FETCH %s BODY.PEEK[%s]", - uid, section_text); - } - /* We won't need the connect_lock again after this. */ - CAMEL_SERVICE_UNLOCK (store, connect_lock); - - if (!response) { - CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock); - return NULL; - } - - for (i = 0; i < response->untagged->len; i++) { - fetch_data = parse_fetch_response (imap_folder, response->untagged->pdata[i]); - found_uid = g_datalist_get_data (&fetch_data, "UID"); - stream = g_datalist_get_data (&fetch_data, "BODY_PART_STREAM"); - if (found_uid && stream && !strcmp (uid, found_uid)) - break; - - g_datalist_clear (&fetch_data); - stream = NULL; - } - camel_imap_response_free (store, response); - CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock); - if (!stream) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Could not find message body in FETCH response.")); - } else { - camel_object_ref (CAMEL_OBJECT (stream)); - g_datalist_clear (&fetch_data); - } - - return stream; -} - -static GData * -parse_fetch_response (CamelImapFolder *imap_folder, char *response) -{ - GData *data = NULL; - char *start, *part_spec = NULL, *body = NULL, *uid = NULL; - gboolean header = FALSE; - int body_len = 0; - - if (*response != '(') { - long seq; - - if (*response != '*' || *(response + 1) != ' ') - return NULL; - seq = strtol (response + 2, &response, 10); - if (seq == 0) - return NULL; - if (g_strncasecmp (response, " FETCH (", 8) != 0) - return NULL; - response += 7; - - g_datalist_set_data (&data, "SEQUENCE", GINT_TO_POINTER (seq)); - } - - do { - /* Skip the initial '(' or the ' ' between elements */ - response++; - - if (!g_strncasecmp (response, "FLAGS ", 6)) { - guint32 flags; - - response += 6; - /* FIXME user flags */ - flags = imap_parse_flag_list (&response); - - g_datalist_set_data (&data, "FLAGS", GUINT_TO_POINTER (flags)); - } else if (!g_strncasecmp (response, "RFC822.SIZE ", 12)) { - unsigned long size; - - response += 12; - size = strtoul (response, &response, 10); - g_datalist_set_data (&data, "RFC822.SIZE", GUINT_TO_POINTER (size)); - } else if (!g_strncasecmp (response, "BODY[", 5) || - !g_strncasecmp (response, "RFC822 ", 7)) { - char *p; - - if (*response == 'B') { - response += 5; - - if (!g_strncasecmp (response, "HEADER]", 7) || !g_strncasecmp (response, "0]", 2)) - header = TRUE; - - p = strchr (response, ']'); - if (!p || *(p + 1) != ' ') - break; - part_spec = g_strndup (response, p - response); - response = p + 2; - } else { - part_spec = g_strdup (""); - response += 7; - - if (!g_strncasecmp (response, "HEADER", 6)) - header = TRUE; - } - - body = imap_parse_nstring ((const char **) &response, &body_len); - if (!response) { - g_free (part_spec); - break; - } - - if (!body) - body = g_strdup (""); - g_datalist_set_data_full (&data, "BODY_PART_SPEC", part_spec, g_free); - g_datalist_set_data_full (&data, "BODY_PART_DATA", body, g_free); - g_datalist_set_data (&data, "BODY_PART_LEN", GINT_TO_POINTER (body_len)); - } else if (!g_strncasecmp (response, "BODY ", 5) || - !g_strncasecmp (response, "BODYSTRUCTURE ", 14)) { - response = strchr (response, ' ') + 1; - start = response; - imap_skip_list ((const char **) &response); - g_datalist_set_data_full (&data, "BODY", g_strndup (start, response - start), g_free); - } else if (!g_strncasecmp (response, "UID ", 4)) { - int len; - - len = strcspn (response + 4, " )"); - uid = g_strndup (response + 4, len); - g_datalist_set_data_full (&data, "UID", uid, g_free); - response += 4 + len; - } else { - g_warning ("Unexpected FETCH response from server: (%s", response); - break; - } - } while (response && *response != ')'); - - if (!response || *response != ')') { - g_datalist_clear (&data); - return NULL; - } - - if (uid && body) { - CamelStream *stream; - - if (FALSE /*header*/) { - g_free (part_spec); - stream = camel_stream_mem_new_with_buffer (body, body_len); - } else { - CAMEL_IMAP_FOLDER_LOCK (imap_folder, cache_lock); - stream = camel_imap_message_cache_insert (imap_folder->cache, - uid, part_spec, - body, body_len, NULL); - CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock); - } - - if (stream) - g_datalist_set_data_full (&data, "BODY_PART_STREAM", stream, - (GDestroyNotify) camel_object_unref); - } - - return data; -} - diff --git a/camel/providers/imap/camel-imap-folder.h b/camel/providers/imap/camel-imap-folder.h deleted file mode 100644 index a49f7bd497..0000000000 --- a/camel/providers/imap/camel-imap-folder.h +++ /dev/null @@ -1,90 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-imap-folder.h: class for an imap folder */ - -/* - * Authors: - * Dan Winship <danw@ximian.com> - * Jeffrey Stedfast <fejj@ximian.com> - * - * Copyright (C) 2000, 2001 Ximian, Inc. - * - * 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 - */ - - -#ifndef CAMEL_IMAP_FOLDER_H -#define CAMEL_IMAP_FOLDER_H 1 - - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus */ - -#include "camel-imap-types.h" -#include <camel/camel-disco-folder.h> -#include <camel/camel-folder-search.h> - -#define CAMEL_IMAP_FOLDER_TYPE (camel_imap_folder_get_type ()) -#define CAMEL_IMAP_FOLDER(obj) (CAMEL_CHECK_CAST((obj), CAMEL_IMAP_FOLDER_TYPE, CamelImapFolder)) -#define CAMEL_IMAP_FOLDER_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_IMAP_FOLDER_TYPE, CamelImapFolderClass)) -#define CAMEL_IS_IMAP_FOLDER(o) (CAMEL_CHECK_TYPE((o), CAMEL_IMAP_FOLDER_TYPE)) - -struct _CamelImapFolder { - CamelDiscoFolder parent_object; - - struct _CamelImapFolderPrivate *priv; - - gboolean need_rescan, need_refresh; - CamelFolderSearch *search; - CamelImapMessageCache *cache; -}; - - -typedef struct { - CamelDiscoFolderClass parent_class; - - /* Virtual methods */ - -} CamelImapFolderClass; - - -/* public methods */ -CamelFolder *camel_imap_folder_new (CamelStore *parent, - const char *folder_name, - const char *folder_dir, - CamelException *ex); - -void camel_imap_folder_selected (CamelFolder *folder, - CamelImapResponse *response, - CamelException *ex); - -void camel_imap_folder_changed (CamelFolder *folder, int exists, - GArray *expunged, CamelException *ex); - -CamelStream *camel_imap_folder_fetch_data (CamelImapFolder *imap_folder, - const char *uid, - const char *section_text, - gboolean cache_only, - CamelException *ex); - -/* Standard Camel function */ -CamelType camel_imap_folder_get_type (void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CAMEL_IMAP_FOLDER_H */ diff --git a/camel/providers/imap/camel-imap-message-cache.c b/camel/providers/imap/camel-imap-message-cache.c deleted file mode 100644 index 0701ca45e4..0000000000 --- a/camel/providers/imap/camel-imap-message-cache.c +++ /dev/null @@ -1,518 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-imap-message-cache.c: Class for an IMAP message cache */ - -/* - * Author: - * Dan Winship <danw@ximian.com> - * - * Copyright (C) 2001 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 <dirent.h> -#include <errno.h> -#include <string.h> -#include <ctype.h> - -#include "camel-imap-message-cache.h" -#include "camel-data-wrapper.h" -#include "camel-exception.h" -#include "camel-stream-fs.h" - -static void finalize (CamelImapMessageCache *cache); -static void stream_finalize (CamelObject *stream, gpointer event_data, gpointer user_data); - - -CamelType -camel_imap_message_cache_get_type (void) -{ - static CamelType camel_imap_message_cache_type = CAMEL_INVALID_TYPE; - - if (camel_imap_message_cache_type == CAMEL_INVALID_TYPE) { - camel_imap_message_cache_type = camel_type_register ( - CAMEL_OBJECT_TYPE, "CamelImapMessageCache", - sizeof (CamelImapMessageCache), - sizeof (CamelImapMessageCacheClass), - NULL, - NULL, - NULL, - (CamelObjectFinalizeFunc) finalize); - } - - return camel_imap_message_cache_type; -} - -static void -free_part (gpointer key, gpointer value, gpointer data) -{ - if (value) { - if (strchr (key, '.')) { - camel_object_unhook_event (value, "finalize", - stream_finalize, data); - camel_object_unref (value); - } else - g_ptr_array_free (value, TRUE); - } - g_free (key); -} - -static void -finalize (CamelImapMessageCache *cache) -{ - if (cache->path) - g_free (cache->path); - if (cache->parts) { - g_hash_table_foreach (cache->parts, free_part, cache); - g_hash_table_destroy (cache->parts); - } - if (cache->cached) - g_hash_table_destroy (cache->cached); -} - -static void -cache_put (CamelImapMessageCache *cache, const char *uid, const char *key, - CamelStream *stream) -{ - char *hash_key; - GPtrArray *subparts; - gpointer okey, ostream; - guint32 uidval; - - uidval = strtoul (uid, NULL, 10); - if (uidval > cache->max_uid) - cache->max_uid = uidval; - - subparts = g_hash_table_lookup (cache->parts, uid); - if (!subparts) { - subparts = g_ptr_array_new (); - g_hash_table_insert (cache->parts, g_strdup (uid), subparts); - } - - if (g_hash_table_lookup_extended (cache->parts, key, &okey, &ostream)) { - if (ostream) { - camel_object_unhook_event (ostream, "finalize", - stream_finalize, cache); - g_hash_table_remove (cache->cached, ostream); - camel_object_unref (ostream); - } - hash_key = okey; - } else { - hash_key = g_strdup (key); - g_ptr_array_add (subparts, hash_key); - } - - g_hash_table_insert (cache->parts, hash_key, stream); - g_hash_table_insert (cache->cached, stream, hash_key); - - if (stream) { - camel_object_hook_event (CAMEL_OBJECT (stream), "finalize", - stream_finalize, cache); - } -} - -/** - * camel_imap_message_cache_new: - * @path: directory to use for storage - * @summary: CamelFolderSummary for the folder we are caching - * @ex: a CamelException - * - * Return value: a new CamelImapMessageCache object using @path for - * storage. If cache files already exist in @path, then any that do not - * correspond to messages in @summary will be deleted. - **/ -CamelImapMessageCache * -camel_imap_message_cache_new (const char *path, CamelFolderSummary *summary, - CamelException *ex) -{ - CamelImapMessageCache *cache; - DIR *dir; - struct dirent *d; - char *uid, *p; - GPtrArray *deletes; - CamelMessageInfo *info; - - dir = opendir (path); - if (!dir) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not open cache directory: %s"), - g_strerror (errno)); - return NULL; - } - - cache = (CamelImapMessageCache *)camel_object_new (CAMEL_IMAP_MESSAGE_CACHE_TYPE); - cache->path = g_strdup (path); - - cache->parts = g_hash_table_new (g_str_hash, g_str_equal); - cache->cached = g_hash_table_new (NULL, NULL); - deletes = g_ptr_array_new (); - while ((d = readdir (dir))) { - if (!isdigit (d->d_name[0])) - continue; - - p = strchr (d->d_name, '.'); - if (p) - uid = g_strndup (d->d_name, p - d->d_name); - else - uid = g_strdup (d->d_name); - - info = camel_folder_summary_uid (summary, uid); - if (info) { - camel_folder_summary_info_free (summary, info); - cache_put (cache, uid, d->d_name, NULL); - } else - g_ptr_array_add (deletes, g_strdup_printf ("%s/%s", cache->path, d->d_name)); - g_free (uid); - } - closedir (dir); - - while (deletes->len) { - unlink (deletes->pdata[0]); - g_free (deletes->pdata[0]); - g_ptr_array_remove_index_fast (deletes, 0); - } - g_ptr_array_free (deletes, TRUE); - - return cache; -} - -/** - * camel_imap_message_cache_max_uid: - * @cache: the cache - * - * Return value: the largest (real) UID in the cache. - **/ -guint32 -camel_imap_message_cache_max_uid (CamelImapMessageCache *cache) -{ - return cache->max_uid; -} - -/** - * camel_imap_message_cache_set_path: - * @cache: - * @path: - * - * Set the path used for the message cache. - **/ -void -camel_imap_message_cache_set_path (CamelImapMessageCache *cache, const char *path) -{ - g_free(cache->path); - cache->path = g_strdup(path); -} - -static void -stream_finalize (CamelObject *stream, gpointer event_data, gpointer user_data) -{ - CamelImapMessageCache *cache = user_data; - char *key; - - key = g_hash_table_lookup (cache->cached, stream); - if (!key) - return; - g_hash_table_remove (cache->cached, stream); - g_hash_table_insert (cache->parts, key, NULL); -} - - -static CamelStream * -insert_setup (CamelImapMessageCache *cache, const char *uid, const char *part_spec, - char **path, char **key, CamelException *ex) -{ - CamelStream *stream; - int fd; - - *path = g_strdup_printf ("%s/%s.%s", cache->path, uid, part_spec); - *key = strrchr (*path, '/') + 1; - stream = g_hash_table_lookup (cache->parts, *key); - if (stream) - camel_object_unref (CAMEL_OBJECT (stream)); - - fd = open (*path, O_RDWR | O_CREAT | O_TRUNC, 0600); - if (fd == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Failed to cache message %s: %s"), - uid, g_strerror (errno)); - g_free (*path); - return NULL; - } - - return camel_stream_fs_new_with_fd (fd); -} - -static CamelStream * -insert_abort (char *path, CamelStream *stream) -{ - unlink (path); - g_free (path); - camel_object_unref (CAMEL_OBJECT (stream)); - return NULL; -} - -static CamelStream * -insert_finish (CamelImapMessageCache *cache, const char *uid, char *path, - char *key, CamelStream *stream) -{ - camel_stream_flush (stream); - camel_stream_reset (stream); - cache_put (cache, uid, key, stream); - g_free (path); - - return stream; -} - -/** - * camel_imap_message_cache_insert: - * @cache: the cache - * @uid: UID of the message data to cache - * @part_spec: the IMAP part_spec of the data - * @data: the data - * @len: length of @data - * - * Caches the provided data into @cache. - * - * Return value: a CamelStream containing the cached data, which the - * caller must unref. - **/ -CamelStream * -camel_imap_message_cache_insert (CamelImapMessageCache *cache, const char *uid, - const char *part_spec, const char *data, - int len, CamelException *ex) -{ - char *path, *key; - CamelStream *stream; - - stream = insert_setup (cache, uid, part_spec, &path, &key, ex); - if (!stream) - return NULL; - - if (camel_stream_write (stream, data, len) == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Failed to cache message %s: %s"), - uid, g_strerror (errno)); - return insert_abort (path, stream); - } - - return insert_finish (cache, uid, path, key, stream); -} - -/** - * camel_imap_message_cache_insert_stream: - * @cache: the cache - * @uid: UID of the message data to cache - * @part_spec: the IMAP part_spec of the data - * @data_stream: the stream to cache - * - * Caches the provided data into @cache. - **/ -void -camel_imap_message_cache_insert_stream (CamelImapMessageCache *cache, - const char *uid, const char *part_spec, - CamelStream *data_stream, CamelException *ex) -{ - char *path, *key; - CamelStream *stream; - - stream = insert_setup (cache, uid, part_spec, &path, &key, ex); - if (!stream) - return; - - if (camel_stream_write_to_stream (data_stream, stream) == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Failed to cache message %s: %s"), - uid, g_strerror (errno)); - insert_abort (path, stream); - } else { - insert_finish (cache, uid, path, key, stream); - camel_object_unref (CAMEL_OBJECT (stream)); - } -} - -/** - * camel_imap_message_cache_insert_wrapper: - * @cache: the cache - * @uid: UID of the message data to cache - * @part_spec: the IMAP part_spec of the data - * @wrapper: the wrapper to cache - * - * Caches the provided data into @cache. - **/ -void -camel_imap_message_cache_insert_wrapper (CamelImapMessageCache *cache, - const char *uid, const char *part_spec, - CamelDataWrapper *wrapper, CamelException *ex) -{ - char *path, *key; - CamelStream *stream; - - stream = insert_setup (cache, uid, part_spec, &path, &key, ex); - if (!stream) - return; - - if (camel_data_wrapper_write_to_stream (wrapper, stream) == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Failed to cache message %s: %s"), - uid, g_strerror (errno)); - insert_abort (path, stream); - } else { - insert_finish (cache, uid, path, key, stream); - camel_object_unref (CAMEL_OBJECT (stream)); - } -} - - -/** - * camel_imap_message_cache_get: - * @cache: the cache - * @uid: the UID of the data to get - * @part_spec: the part_spec of the data to get - * - * Return value: a CamelStream containing the cached data (which the - * caller must unref), or %NULL if that data is not cached. - **/ -CamelStream * -camel_imap_message_cache_get (CamelImapMessageCache *cache, const char *uid, - const char *part_spec) -{ - CamelStream *stream; - char *path, *key; - - if (uid[0] == 0) - return NULL; - - path = g_strdup_printf ("%s/%s.%s", cache->path, uid, part_spec); - key = strrchr (path, '/') + 1; - stream = g_hash_table_lookup (cache->parts, key); - if (stream) { - camel_stream_reset (CAMEL_STREAM (stream)); - camel_object_ref (CAMEL_OBJECT (stream)); - g_free (path); - return stream; - } - - stream = camel_stream_fs_new_with_name (path, O_RDONLY, 0); - if (stream) - cache_put (cache, uid, key, stream); - g_free (path); - - return stream; -} - -/** - * camel_imap_message_cache_remove: - * @cache: the cache - * @uid: UID of the data to remove - * - * Removes all data associated with @uid from @cache. - **/ -void -camel_imap_message_cache_remove (CamelImapMessageCache *cache, const char *uid) -{ - GPtrArray *subparts; - char *key, *path; - CamelObject *stream; - int i; - - subparts = g_hash_table_lookup (cache->parts, uid); - if (!subparts) - return; - for (i = 0; i < subparts->len; i++) { - key = subparts->pdata[i]; - path = g_strdup_printf ("%s/%s", cache->path, key); - unlink (path); - g_free (path); - stream = g_hash_table_lookup (cache->parts, key); - if (stream) { - camel_object_unhook_event (stream, "finalize", - stream_finalize, cache); - camel_object_unref (stream); - g_hash_table_remove (cache->cached, stream); - } - g_hash_table_remove (cache->parts, key); - g_free (key); - } - g_hash_table_remove (cache->parts, uid); - g_ptr_array_free (subparts, TRUE); -} - -static void -add_uids (gpointer key, gpointer value, gpointer data) -{ - if (!strchr (key, '.')) - g_ptr_array_add (data, key); -} - -/** - * camel_imap_message_cache_clear: - * @cache: the cache - * - * Removes all cached data from @cache. - **/ -void -camel_imap_message_cache_clear (CamelImapMessageCache *cache) -{ - GPtrArray *uids; - int i; - - uids = g_ptr_array_new (); - g_hash_table_foreach (cache->parts, add_uids, uids); - - for (i = 0; i < uids->len; i++) - camel_imap_message_cache_remove (cache, uids->pdata[i]); - g_ptr_array_free (uids, TRUE); -} - - -/** - * camel_imap_message_cache_copy: - * @source: the source message cache - * @source_uid: UID of a message in @source - * @dest: the destination message cache - * @dest_uid: UID of the message in @dest - * - * Copies all cached parts from @source_uid in @source to @dest_uid in - * @destination. - **/ -void -camel_imap_message_cache_copy (CamelImapMessageCache *source, - const char *source_uid, - CamelImapMessageCache *dest, - const char *dest_uid, - CamelException *ex) -{ - GPtrArray *subparts; - CamelStream *stream; - char *part; - int i; - - subparts = g_hash_table_lookup (source->parts, source_uid); - if (!subparts || !subparts->len) - return; - - for (i = 0; i < subparts->len; i++) { - part = strchr (subparts->pdata[i], '.'); - if (!part++) - continue; - stream = camel_imap_message_cache_get (source, source_uid, part); - camel_imap_message_cache_insert_stream (dest, dest_uid, part, stream, ex); - camel_object_unref (CAMEL_OBJECT (stream)); - } -} diff --git a/camel/providers/imap/camel-imap-message-cache.h b/camel/providers/imap/camel-imap-message-cache.h deleted file mode 100644 index eb3f056b44..0000000000 --- a/camel/providers/imap/camel-imap-message-cache.h +++ /dev/null @@ -1,109 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-imap-message-cache.h: Class for an IMAP message cache */ - -/* - * Author: - * Dan Winship <danw@ximian.com> - * - * Copyright (C) 2001 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 - */ - - -#ifndef CAMEL_IMAP_MESSAGE_CACHE_H -#define CAMEL_IMAP_MESSAGE_CACHE_H 1 - - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus }*/ - -#include "camel-imap-types.h" -#include "camel-folder.h" -#include <camel/camel-folder-search.h> - -#define CAMEL_IMAP_MESSAGE_CACHE_TYPE (camel_imap_message_cache_get_type ()) -#define CAMEL_IMAP_MESSAGE_CACHE(obj) (CAMEL_CHECK_CAST((obj), CAMEL_IMAP_MESSAGE_CACHE_TYPE, CamelImapFolder)) -#define CAMEL_IMAP_MESSAGE_CACHE_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_IMAP_MESSAGE_CACHE_TYPE, CamelImapFolderClass)) -#define CAMEL_IS_IMAP_MESSAGE_CACHE(o) (CAMEL_CHECK_TYPE((o), CAMEL_IMAP_MESSAGE_CACHE_TYPE)) - -struct _CamelImapMessageCache { - CamelObject parent_object; - - char *path; - GHashTable *parts, *cached; - guint32 max_uid; -}; - - -typedef struct { - CamelFolderClass parent_class; - - /* Virtual methods */ - -} CamelImapMessageCacheClass; - - -/* public methods */ -CamelImapMessageCache *camel_imap_message_cache_new (const char *path, - CamelFolderSummary *summ, - CamelException *ex); - -void camel_imap_message_cache_set_path (CamelImapMessageCache *cache, - const char *path); - -guint32 camel_imap_message_cache_max_uid (CamelImapMessageCache *cache); - -CamelStream *camel_imap_message_cache_insert (CamelImapMessageCache *cache, - const char *uid, - const char *part_spec, - const char *data, - int len, - CamelException *ex); -void camel_imap_message_cache_insert_stream (CamelImapMessageCache *cache, - const char *uid, - const char *part_spec, - CamelStream *data_stream, - CamelException *ex); -void camel_imap_message_cache_insert_wrapper (CamelImapMessageCache *cache, - const char *uid, - const char *part_spec, - CamelDataWrapper *wrapper, - CamelException *ex); - -CamelStream *camel_imap_message_cache_get (CamelImapMessageCache *cache, - const char *uid, - const char *part_spec); -void camel_imap_message_cache_remove (CamelImapMessageCache *cache, - const char *uid); - -void camel_imap_message_cache_clear (CamelImapMessageCache *cache); - -void camel_imap_message_cache_copy (CamelImapMessageCache *source, - const char *source_uid, - CamelImapMessageCache *dest, - const char *dest_uid, - CamelException *ex); - -/* Standard Camel function */ -CamelType camel_imap_message_cache_get_type (void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CAMEL_IMAP_MESSAGE_CACHE_H */ diff --git a/camel/providers/imap/camel-imap-private.h b/camel/providers/imap/camel-imap-private.h deleted file mode 100644 index 0f80dbfd1c..0000000000 --- a/camel/providers/imap/camel-imap-private.h +++ /dev/null @@ -1,76 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * camel-imap-private.h: Private info for imap. - * - * Authors: Michael Zucchi <notzed@ximian.com> - * - * Copyright 1999, 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 - * 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 - */ - -#ifndef CAMEL_IMAP_PRIVATE_H -#define CAMEL_IMAP_PRIVATE_H 1 - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus */ - -/* need a way to configure and save this data, if this header is to - be installed. For now, dont install it */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#ifdef ENABLE_THREADS -#include "e-util/e-msgport.h" -#endif - -struct _CamelImapFolderPrivate { -#ifdef ENABLE_THREADS - EMutex *search_lock; /* for locking the search object */ - EMutex *cache_lock; /* for locking the cache object */ -#endif -}; - -#ifdef ENABLE_THREADS -#define CAMEL_IMAP_FOLDER_LOCK(f, l) (e_mutex_lock(((CamelImapFolder *)f)->priv->l)) -#define CAMEL_IMAP_FOLDER_UNLOCK(f, l) (e_mutex_unlock(((CamelImapFolder *)f)->priv->l)) -#else -#define CAMEL_IMAP_FOLDER_LOCK(f, l) -#define CAMEL_IMAP_FOLDER_UNLOCK(f, l) -#endif - -struct _CamelImapWrapperPrivate { -#ifdef ENABLE_THREADS - GMutex *lock; -#endif -}; - -#ifdef ENABLE_THREADS -#define CAMEL_IMAP_WRAPPER_LOCK(f, l) (g_mutex_lock(((CamelImapWrapper *)f)->priv->l)) -#define CAMEL_IMAP_WRAPPER_UNLOCK(f, l) (g_mutex_unlock(((CamelImapWrapper *)f)->priv->l)) -#else -#define CAMEL_IMAP_WRAPPER_LOCK(f, l) -#define CAMEL_IMAP_WRAPPER_UNLOCK(f, l) -#endif - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CAMEL_IMAP_PRIVATE_H */ - diff --git a/camel/providers/imap/camel-imap-provider.c b/camel/providers/imap/camel-imap-provider.c deleted file mode 100644 index 44e41a3d30..0000000000 --- a/camel/providers/imap/camel-imap-provider.c +++ /dev/null @@ -1,149 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-imap-provider.c: imap provider registration code */ - -/* - * Authors: Jeffrey Stedfast <fejj@ximian.com> - * - * Copyright 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 - * 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 <string.h> -#include "camel-imap-store.h" -#include "camel-provider.h" -#include "camel-session.h" -#include "camel-url.h" -#include "camel-sasl.h" - -static void add_hash (guint *hash, char *s); -static guint imap_url_hash (gconstpointer key); -static gint check_equal (char *s1, char *s2); -static gint imap_url_equal (gconstpointer a, gconstpointer b); - -CamelProviderConfEntry imap_conf_entries[] = { - { CAMEL_PROVIDER_CONF_SECTION_START, "mailcheck", NULL, - N_("Checking for new mail") }, - { CAMEL_PROVIDER_CONF_CHECKBOX, "check_all", NULL, - N_("Check for new messages in all folders"), "1" }, - { CAMEL_PROVIDER_CONF_SECTION_END }, - { CAMEL_PROVIDER_CONF_SECTION_START, "folders", NULL, - N_("Folders") }, - { CAMEL_PROVIDER_CONF_CHECKBOX, "use_lsub", NULL, - N_("Show only subscribed folders"), "1" }, - { CAMEL_PROVIDER_CONF_CHECKBOX, "override_namespace", NULL, - N_("Override server-supplied folder namespace"), "0" }, - { CAMEL_PROVIDER_CONF_ENTRY, "namespace", "override_namespace", - N_("Namespace") }, - { CAMEL_PROVIDER_CONF_SECTION_END }, - { CAMEL_PROVIDER_CONF_CHECKBOX, "filter", NULL, - N_("Apply filters to new messages in INBOX on this server"), "0" }, - { CAMEL_PROVIDER_CONF_END } -}; - -static CamelProvider imap_provider = { - "imap", - N_("IMAP"), - - N_("For reading and storing mail on IMAP servers."), - - "mail", - - CAMEL_PROVIDER_IS_REMOTE | CAMEL_PROVIDER_IS_SOURCE | - CAMEL_PROVIDER_IS_STORAGE | CAMEL_PROVIDER_SUPPORTS_SSL, - - CAMEL_URL_NEED_USER | CAMEL_URL_NEED_HOST | CAMEL_URL_ALLOW_AUTH, - - imap_conf_entries, - - /* ... */ -}; - -CamelServiceAuthType camel_imap_password_authtype = { - N_("Password"), - - N_("This option will connect to the IMAP server using a " - "plaintext password."), - - "", - TRUE -}; - -void -camel_provider_module_init (CamelSession *session) -{ - imap_provider.object_types[CAMEL_PROVIDER_STORE] = - camel_imap_store_get_type (); - imap_provider.url_hash = imap_url_hash; - imap_provider.url_equal = imap_url_equal; - imap_provider.authtypes = camel_sasl_authtype_list (FALSE); - imap_provider.authtypes = g_list_prepend (imap_provider.authtypes, - &camel_imap_password_authtype); - - camel_session_register_provider (session, &imap_provider); -} - -static void -add_hash (guint *hash, char *s) -{ - if (s) - *hash ^= g_str_hash(s); -} - -static guint -imap_url_hash (gconstpointer key) -{ - const CamelURL *u = (CamelURL *)key; - guint hash = 0; - - add_hash (&hash, u->user); - add_hash (&hash, u->authmech); - add_hash (&hash, u->host); - hash ^= u->port; - - return hash; -} - -static gint -check_equal (char *s1, char *s2) -{ - if (s1 == NULL) { - if (s2 == NULL) - return TRUE; - else - return FALSE; - } - - if (s2 == NULL) - return FALSE; - - return strcmp (s1, s2) == 0; -} - -static gint -imap_url_equal (gconstpointer a, gconstpointer b) -{ - const CamelURL *u1 = a, *u2 = b; - - return check_equal (u1->user, u2->user) - && check_equal (u1->authmech, u2->authmech) - && check_equal (u1->host, u2->host) - && u1->port == u2->port; -} diff --git a/camel/providers/imap/camel-imap-search.c b/camel/providers/imap/camel-imap-search.c deleted file mode 100644 index c30fa5611e..0000000000 --- a/camel/providers/imap/camel-imap-search.c +++ /dev/null @@ -1,499 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-imap-search.c: IMAP folder search */ - -/* - * Authors: - * Dan Winship <danw@ximian.com> - * Michael Zucchi <notzed@ximian.com> - * - * Copyright 2000, 2001, 2002 Ximian, Inc. - * - * 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 <string.h> - -#include "camel-imap-command.h" -#include "camel-imap-folder.h" -#include "camel-imap-store.h" -#include "camel-imap-search.h" -#include "camel-imap-private.h" -#include "camel-imap-utils.h" -#include "camel-imap-summary.h" - -#include "e-util/md5-utils.h" /* md5 hash building */ -#include "camel-mime-utils.h" /* base64 encoding */ - -#include "camel-seekable-stream.h" -#include "camel-search-private.h" - -#define d(x) x - -/* - File is: - BODY (as in body search) - Last uid when search performed - termcount: number of search terms - matchcount: number of matches - term0, term1 ... - match0, match1, match2, ... -*/ - -/* size of in-memory cache */ -#define MATCH_CACHE_SIZE (32) - -/* Also takes care of 'endianness' file magic */ -#define MATCH_MARK (('B' << 24) | ('O' << 16) | ('D' << 8) | 'Y') - -/* on-disk header, in native endianness format, matches follow */ -struct _match_header { - guint32 mark; - guint32 validity; /* uidvalidity for this folder */ - guint32 lastuid; - guint32 termcount; - guint32 matchcount; -}; - -/* in-memory record */ -struct _match_record { - struct _match_record *next; - struct _match_record *prev; - - char hash[17]; - - guint32 lastuid; - guint32 validity; - - unsigned int termcount; - char **terms; - GArray *matches; -}; - - -static void free_match(CamelImapSearch *is, struct _match_record *mr); -static ESExpResult *imap_body_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s); - -static CamelFolderSearchClass *imap_search_parent_class; - -static void -camel_imap_search_class_init (CamelImapSearchClass *camel_imap_search_class) -{ - /* virtual method overload */ - CamelFolderSearchClass *camel_folder_search_class = - CAMEL_FOLDER_SEARCH_CLASS (camel_imap_search_class); - - imap_search_parent_class = (CamelFolderSearchClass *)camel_type_get_global_classfuncs (camel_folder_search_get_type ()); - - /* virtual method overload */ - camel_folder_search_class->body_contains = imap_body_contains; -} - -static void -camel_imap_search_init(CamelImapSearch *is) -{ - e_dlist_init(&is->matches); - is->matches_hash = g_hash_table_new(g_str_hash, g_str_equal); - is->matches_count = 0; - is->lastuid = 0; -} - -static void -camel_imap_search_finalise(CamelImapSearch *is) -{ - struct _match_record *mr; - - while ( (mr = (struct _match_record *)e_dlist_remtail(&is->matches)) ) - free_match(is, mr); - g_hash_table_destroy(is->matches_hash); - if (is->cache) - camel_object_unref((CamelObject *)is->cache); -} - -CamelType -camel_imap_search_get_type (void) -{ - static CamelType camel_imap_search_type = CAMEL_INVALID_TYPE; - - if (camel_imap_search_type == CAMEL_INVALID_TYPE) { - camel_imap_search_type = camel_type_register ( - CAMEL_FOLDER_SEARCH_TYPE, "CamelImapSearch", - sizeof (CamelImapSearch), - sizeof (CamelImapSearchClass), - (CamelObjectClassInitFunc) camel_imap_search_class_init, NULL, - (CamelObjectInitFunc) camel_imap_search_init, - (CamelObjectFinalizeFunc) camel_imap_search_finalise); - } - - return camel_imap_search_type; -} - -/** - * camel_imap_search_new: - * - * Return value: A new CamelImapSearch widget. - **/ -CamelFolderSearch * -camel_imap_search_new (const char *cachedir) -{ - CamelFolderSearch *new = CAMEL_FOLDER_SEARCH (camel_object_new (camel_imap_search_get_type ())); - CamelImapSearch *is = (CamelImapSearch *)new; - - camel_folder_search_construct (new); - - is->cache = camel_data_cache_new(cachedir, 0, NULL); - if (is->cache) { - /* Expire entries after 14 days of inactivity */ - camel_data_cache_set_expire_access(is->cache, 60*60*24*14); - } - - return new; -} - - -static void -hash_match(char hash[17], int argc, struct _ESExpResult **argv) -{ - MD5Context ctx; - unsigned char digest[16]; - unsigned int state = 0, save = 0; - int i; - - md5_init(&ctx); - for (i=0;i<argc;i++) { - if (argv[i]->type == ESEXP_RES_STRING) - md5_update(&ctx, argv[i]->value.string, strlen(argv[i]->value.string)); - } - md5_final(&ctx, digest); - - base64_encode_close(digest, 12, FALSE, hash, &state, &save); - - for (i=0;i<16;i++) { - if (hash[i] == '+') - hash[i] = ','; - if (hash[i] == '/') - hash[i] = '_'; - } - - hash[16] = 0; -} - -static int -save_match(CamelImapSearch *is, struct _match_record *mr) -{ - guint32 mark = MATCH_MARK; - int ret = 0; - struct _match_header header; - CamelStream *stream; - - /* since its a cache, doesn't matter if it doesn't save, at least we have the in-memory cache - for this session */ - if (is->cache == NULL) - return -1; - - stream = camel_data_cache_add(is->cache, "search/body-contains", mr->hash, NULL); - if (stream == NULL) - return -1; - - d(printf("Saving search cache entry to '%s': %s\n", mr->hash, mr->terms[0])); - - /* we write the whole thing, then re-write the header magic, saves fancy sync code */ - memcpy(&header.mark, " ", 4); - header.termcount = 0; - header.matchcount = mr->matches->len; - header.lastuid = mr->lastuid; - header.validity = mr->validity; - - if (camel_stream_write(stream, (char *)&header, sizeof(header)) != sizeof(header) - || camel_stream_write(stream, mr->matches->data, mr->matches->len*sizeof(guint32)) != mr->matches->len*sizeof(guint32) - || camel_seekable_stream_seek((CamelSeekableStream *)stream, 0, CAMEL_STREAM_SET) == -1 - || camel_stream_write(stream, (char *)&mark, sizeof(mark)) != sizeof(mark)) { - d(printf(" saving failed, removing cache entry\n")); - camel_data_cache_remove(is->cache, "search/body-contains", mr->hash, NULL); - ret = -1; - } - - camel_object_unref((CamelObject *)stream); - return ret; -} - -static void -free_match(CamelImapSearch *is, struct _match_record *mr) -{ - int i; - - for (i=0;i<mr->termcount;i++) - g_free(mr->terms[i]); - g_free(mr->terms); - g_array_free(mr->matches, TRUE); - g_free(mr); -} - -static struct _match_record * -load_match(CamelImapSearch *is, char hash[17], int argc, struct _ESExpResult **argv) -{ - struct _match_record *mr; - CamelStream *stream = NULL; - struct _match_header header; - int i; - - mr = g_malloc0(sizeof(*mr)); - mr->matches = g_array_new(0, 0, sizeof(guint32)); - g_assert(strlen(hash) == 16); - strcpy(mr->hash, hash); - mr->terms = g_malloc0(sizeof(mr->terms[0]) * argc); - for (i=0;i<argc;i++) { - if (argv[i]->type == ESEXP_RES_STRING) { - mr->termcount++; - mr->terms[i] = g_strdup(argv[i]->value.string); - } - } - - d(printf("Loading search cache entry to '%s': %s\n", mr->hash, mr->terms[0])); - - memset(&header, 0, sizeof(header)); - if (is->cache) - stream = camel_data_cache_get(is->cache, "search/body-contains", mr->hash, NULL); - if (stream != NULL) { - /* 'cause i'm gonna be lazy, i'm going to have the termcount == 0 for now, - and not load or save them since i can't think of a nice way to do it, the hash - should be sufficient to key it */ - /* This check should also handle endianness changes, we just throw away - the data (its only a cache) */ - if (camel_stream_read(stream, (char *)&header, sizeof(header)) == sizeof(header) - && header.validity == is->validity - && header.mark == MATCH_MARK - && header.termcount == 0) { - d(printf(" found %d matches\n", header.matchcount)); - g_array_set_size(mr->matches, header.matchcount); - camel_stream_read(stream, mr->matches->data, sizeof(guint32)*header.matchcount); - } else { - d(printf(" file format invalid/validity changed\n")); - memset(&header, 0, sizeof(header)); - } - camel_object_unref((CamelObject *)stream); - } else { - d(printf(" no cache entry found\n")); - } - - mr->validity = header.validity; - if (mr->validity != is->validity) - mr->lastuid = 0; - else - mr->lastuid = header.lastuid; - - return mr; -} - -static int -sync_match(CamelImapSearch *is, struct _match_record *mr) -{ - char *p, *result, *lasts = NULL; - CamelImapResponse *response = NULL; - guint32 uid; - CamelFolder *folder = ((CamelFolderSearch *)is)->folder; - CamelImapStore *store = (CamelImapStore *)folder->parent_store; - struct _camel_search_words *words; - GString *search; - int i; - - if (mr->lastuid >= is->lastuid && mr->validity == is->validity) - return 0; - - d(printf("updating match record for uid's %d:%d\n", mr->lastuid+1, is->lastuid)); - - /* TODO: Handle multiple search terms */ - - /* This handles multiple search words within a single term */ - words = camel_search_words_split(mr->terms[0]); - search = g_string_new(""); - g_string_sprintfa(search, "UID %d:%d", mr->lastuid+1, is->lastuid); - for (i=0;i<words->len;i++) { - char *w = words->words[i]->word, c; - - g_string_sprintfa(search, " BODY \""); - while ((c = *w++)) { - if (c == '\\' || c == '"') - g_string_append_c(search, '\\'); - g_string_append_c(search, c); - } - g_string_append_c(search, '"'); - } - camel_search_words_free(words); - - /* We only try search using utf8 if its non us-ascii text? */ - if ((words->type & CAMEL_SEARCH_WORD_8BIT) && (store->capabilities & IMAP_CAPABILITY_utf8_search)) { - response = camel_imap_command(store, folder, NULL, - "UID SEARCH CHARSET UTF-8 %s", search->str); - /* We can't actually tell if we got a NO response, so assume always */ - if (response == NULL) - store->capabilities &= ~IMAP_CAPABILITY_utf8_search; - } - if (response == NULL) - response = camel_imap_command (store, folder, NULL, - "UID SEARCH %s", search->str); - g_string_free(search, TRUE); - - if (!response) - return -1; - result = camel_imap_response_extract (store, response, "SEARCH", NULL); - if (!result) - return -1; - - p = result + sizeof ("* SEARCH"); - for (p = strtok_r (p, " ", &lasts); p; p = strtok_r (NULL, " ", &lasts)) { - uid = strtoul(p, NULL, 10); - g_array_append_vals(mr->matches, &uid, 1); - } - g_free(result); - - mr->validity = is->validity; - mr->lastuid = is->lastuid; - save_match(is, mr); - - return 0; -} - -static struct _match_record * -get_match(CamelImapSearch *is, int argc, struct _ESExpResult **argv) -{ - char hash[17]; - struct _match_record *mr; - - hash_match(hash, argc, argv); - - mr = g_hash_table_lookup(is->matches_hash, hash); - if (mr == NULL) { - while (is->matches_count >= MATCH_CACHE_SIZE) { - mr = (struct _match_record *)e_dlist_remtail(&is->matches); - if (mr) { - printf("expiring match '%s' (%s)\n", mr->hash, mr->terms[0]); - g_hash_table_remove(is->matches_hash, mr->hash); - free_match(is, mr); - is->matches_count--; - } else { - is->matches_count = 0; - } - } - mr = load_match(is, hash, argc, argv); - g_hash_table_insert(is->matches_hash, mr->hash, mr); - is->matches_count++; - } else { - e_dlist_remove((EDListNode *)mr); - } - - e_dlist_addhead(&is->matches, (EDListNode *)mr); - - /* what about offline mode? */ - /* We could cache those results too, or should we cache them elsewhere? */ - sync_match(is, mr); - - return mr; -} - -static ESExpResult * -imap_body_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s) -{ - CamelImapStore *store = CAMEL_IMAP_STORE (s->folder->parent_store); - CamelImapSearch *is = (CamelImapSearch *)s; - char *uid; - ESExpResult *r; - CamelMessageInfo *info; - GHashTable *uid_hash = NULL; - GPtrArray *array; - int i, j; - struct _match_record *mr; - guint32 uidn, *uidp; - - d(printf("Performing body search '%s'\n", argv[0]->value.string)); - - /* TODO: Cache offline searches too? */ - - /* If offline, search using the parent class, which can handle this manually */ - if (!camel_disco_store_check_online (CAMEL_DISCO_STORE (store), NULL)) - return imap_search_parent_class->body_contains(f, argc, argv, s); - - /* optimise the match "" case - match everything */ - if (argc == 1 && argv[0]->value.string[0] == '\0') { - if (s->current) { - r = e_sexp_result_new(f, ESEXP_RES_BOOL); - r->value.bool = TRUE; - } else { - r = e_sexp_result_new(f, ESEXP_RES_ARRAY_PTR); - r->value.ptrarray = g_ptr_array_new (); - for (i = 0; i < s->summary->len; i++) { - info = g_ptr_array_index(s->summary, i); - g_ptr_array_add(r->value.ptrarray, (char *)camel_message_info_uid(info)); - } - } - } else if (argc == 0 || s->summary->len == 0) { - /* nothing to match case, do nothing (should be handled higher up?) */ - if (s->current) { - r = e_sexp_result_new(f, ESEXP_RES_BOOL); - r->value.bool = FALSE; - } else { - r = e_sexp_result_new(f, ESEXP_RES_ARRAY_PTR); - r->value.ptrarray = g_ptr_array_new (); - } - } else { - int truth = FALSE; - - /* setup lastuid/validity for synchronising */ - info = g_ptr_array_index(s->summary, s->summary->len-1); - is->lastuid = strtoul(camel_message_info_uid(info), NULL, 10); - is->validity = ((CamelImapSummary *)(s->folder->summary))->validity; - - mr = get_match(is, argc, argv); - - if (s->current) { - uidn = strtoul(camel_message_info_uid(s->current), NULL, 10); - uidp = (guint32 *)mr->matches->data; - j = mr->matches->len; - for (i=0;i<j && !truth;i++) - truth = *uidp++ == uidn; - r = e_sexp_result_new(f, ESEXP_RES_BOOL); - r->value.bool = truth; - } else { - r = e_sexp_result_new(f, ESEXP_RES_ARRAY_PTR); - array = r->value.ptrarray = g_ptr_array_new(); - - /* We use a hash to map the uid numbers to uid strings as required by the search api */ - /* We use the summary's strings so we dont need to alloc more */ - uid_hash = g_hash_table_new(NULL, NULL); - for (i = 0; i < s->summary->len; i++) { - info = s->summary->pdata[i]; - uid = (char *)camel_message_info_uid(info); - uidn = strtoul(uid, NULL, 10); - g_hash_table_insert(uid_hash, (void *)uidn, uid); - } - - uidp = (guint32 *)mr->matches->data; - j = mr->matches->len; - for (i=0;i<j && !truth;i++) { - uid = g_hash_table_lookup(uid_hash, (void *)*uidp++); - if (uid) - g_ptr_array_add(array, uid); - } - - g_hash_table_destroy(uid_hash); - } - } - - return r; -} diff --git a/camel/providers/imap/camel-imap-search.h b/camel/providers/imap/camel-imap-search.h deleted file mode 100644 index 7664c4c2ed..0000000000 --- a/camel/providers/imap/camel-imap-search.h +++ /dev/null @@ -1,62 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-imap-search.h: IMAP folder search */ - -/* - * Authors: - * Dan Winship <danw@ximian.com> - * - * Copyright 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 - * 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. - * - */ - -#ifndef _CAMEL_IMAP_SEARCH_H -#define _CAMEL_IMAP_SEARCH_H - -#include <camel/camel-folder-search.h> -#include <e-util/e-msgport.h> -#include <camel/camel-data-cache.h> - -#define CAMEL_IMAP_SEARCH_TYPE (camel_imap_search_get_type ()) -#define CAMEL_IMAP_SEARCH(obj) CAMEL_CHECK_CAST (obj, camel_imap_search_get_type (), CamelImapSearch) -#define CAMEL_IMAP_SEARCH_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_imap_search_get_type (), CamelImapSearchClass) -#define CAMEL_IS_IMAP_SEARCH(obj) CAMEL_CHECK_TYPE (obj, camel_imap_search_get_type ()) - -typedef struct _CamelImapSearchClass CamelImapSearchClass; - -struct _CamelImapSearch { - CamelFolderSearch parent; - - guint32 lastuid; /* current 'last uid' for the folder */ - guint32 validity; /* validity of the current folder */ - - CamelDataCache *cache; /* disk-cache for searches */ - - /* cache of body search matches */ - unsigned int matches_count; - EDList matches; - GHashTable *matches_hash; -}; - -struct _CamelImapSearchClass { - CamelFolderSearchClass parent_class; - -}; - -CamelType camel_imap_search_get_type (void); -CamelFolderSearch *camel_imap_search_new (const char *cachedir); - -#endif /* ! _CAMEL_IMAP_SEARCH_H */ diff --git a/camel/providers/imap/camel-imap-store-summary.c b/camel/providers/imap/camel-imap-store-summary.c deleted file mode 100644 index 4ba5bb9b68..0000000000 --- a/camel/providers/imap/camel-imap-store-summary.c +++ /dev/null @@ -1,519 +0,0 @@ -/* - * Copyright (C) 2002 Ximian Inc. - * - * Authors: Michael Zucchi <notzed@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 <unistd.h> -#include <ctype.h> -#include <string.h> -#include <errno.h> -#include <stdlib.h> - -#include "camel-imap-store-summary.h" - -#include "camel-file-utils.h" - -#include "hash-table-utils.h" -#include "e-util/md5-utils.h" -#include "e-util/e-memory.h" - -#include "camel-private.h" -#include "camel-utf8.h" - -#define d(x) -#define io(x) /* io debug */ - -#define CAMEL_IMAP_STORE_SUMMARY_VERSION_0 (0) - -#define CAMEL_IMAP_STORE_SUMMARY_VERSION (0) - -#define _PRIVATE(o) (((CamelImapStoreSummary *)(o))->priv) - -static int summary_header_load(CamelStoreSummary *, FILE *); -static int summary_header_save(CamelStoreSummary *, FILE *); - -/*static CamelStoreInfo * store_info_new(CamelStoreSummary *, const char *);*/ -static CamelStoreInfo * store_info_load(CamelStoreSummary *, FILE *); -static int store_info_save(CamelStoreSummary *, FILE *, CamelStoreInfo *); -static void store_info_free(CamelStoreSummary *, CamelStoreInfo *); - -static const char *store_info_string(CamelStoreSummary *, const CamelStoreInfo *, int); -static void store_info_set_string(CamelStoreSummary *, CamelStoreInfo *, int, const char *); - -static void camel_imap_store_summary_class_init (CamelImapStoreSummaryClass *klass); -static void camel_imap_store_summary_init (CamelImapStoreSummary *obj); -static void camel_imap_store_summary_finalise (CamelObject *obj); - -static CamelStoreSummaryClass *camel_imap_store_summary_parent; - -static void -camel_imap_store_summary_class_init (CamelImapStoreSummaryClass *klass) -{ - CamelStoreSummaryClass *ssklass = (CamelStoreSummaryClass *)klass; - - ssklass->summary_header_load = summary_header_load; - ssklass->summary_header_save = summary_header_save; - - /*ssklass->store_info_new = store_info_new;*/ - ssklass->store_info_load = store_info_load; - ssklass->store_info_save = store_info_save; - ssklass->store_info_free = store_info_free; - - ssklass->store_info_string = store_info_string; - ssklass->store_info_set_string = store_info_set_string; -} - -static void -camel_imap_store_summary_init (CamelImapStoreSummary *s) -{ - /*struct _CamelImapStoreSummaryPrivate *p; - - p = _PRIVATE(s) = g_malloc0(sizeof(*p));*/ - - ((CamelStoreSummary *)s)->store_info_size = sizeof(CamelImapStoreInfo); - s->version = CAMEL_IMAP_STORE_SUMMARY_VERSION; -} - -static void -camel_imap_store_summary_finalise (CamelObject *obj) -{ - /*struct _CamelImapStoreSummaryPrivate *p;*/ - /*CamelImapStoreSummary *s = (CamelImapStoreSummary *)obj;*/ - - /*p = _PRIVATE(obj); - g_free(p);*/ -} - -CamelType -camel_imap_store_summary_get_type (void) -{ - static CamelType type = CAMEL_INVALID_TYPE; - - if (type == CAMEL_INVALID_TYPE) { - camel_imap_store_summary_parent = (CamelStoreSummaryClass *)camel_store_summary_get_type(); - type = camel_type_register((CamelType)camel_imap_store_summary_parent, "CamelImapStoreSummary", - sizeof (CamelImapStoreSummary), - sizeof (CamelImapStoreSummaryClass), - (CamelObjectClassInitFunc) camel_imap_store_summary_class_init, - NULL, - (CamelObjectInitFunc) camel_imap_store_summary_init, - (CamelObjectFinalizeFunc) camel_imap_store_summary_finalise); - } - - return type; -} - -/** - * camel_imap_store_summary_new: - * - * Create a new CamelImapStoreSummary object. - * - * Return value: A new CamelImapStoreSummary widget. - **/ -CamelImapStoreSummary * -camel_imap_store_summary_new (void) -{ - CamelImapStoreSummary *new = CAMEL_IMAP_STORE_SUMMARY ( camel_object_new (camel_imap_store_summary_get_type ())); - - return new; -} - -/** - * camel_imap_store_summary_full_name: - * @s: - * @path: - * - * Retrieve a summary item by full name. - * - * A referenced to the summary item is returned, which may be - * ref'd or free'd as appropriate. - * - * Return value: The summary item, or NULL if the @full_name name - * is not available. - * It must be freed using camel_store_summary_info_free(). - **/ -CamelImapStoreInfo * -camel_imap_store_summary_full_name(CamelImapStoreSummary *s, const char *full_name) -{ - int count, i; - CamelImapStoreInfo *info; - - count = camel_store_summary_count((CamelStoreSummary *)s); - for (i=0;i<count;i++) { - info = (CamelImapStoreInfo *)camel_store_summary_index((CamelStoreSummary *)s, i); - if (info) { - if (strcmp(info->full_name, full_name) == 0) - return info; - camel_store_summary_info_free((CamelStoreSummary *)s, (CamelStoreInfo *)info); - } - } - - return NULL; -} - -char * -camel_imap_store_summary_full_to_path(CamelImapStoreSummary *s, const char *full_name, char dir_sep) -{ - char *path, *p; - int c; - const char *f; - - if (dir_sep != '/') { - p = path = alloca(strlen(full_name)*3+1); - f = full_name; - while ( (c = *f++ & 0xff) ) { - if (c == dir_sep) - *p++ = '/'; - else if (c == '/' || c == '%') - p += sprintf(p, "%%%02X", c); - else - *p++ = c; - } - *p = 0; - } else - path = (char *)full_name; - - return camel_utf7_utf8(path); -} - -static guint32 hexnib(guint32 c) -{ - if (c >= '0' && c <= '9') - return c-'0'; - else if (c>='A' && c <= 'Z') - return c-'A'+10; - else - return 0; -} - -char * -camel_imap_store_summary_path_to_full(CamelImapStoreSummary *s, const char *path, char dir_sep) -{ - unsigned char *full, *f; - guint32 c, v = 0; - const char *p; - int state=0; - char *subpath, *last = NULL; - CamelStoreInfo *si; - - /* check to see if we have a subpath of path already defined */ - subpath = alloca(strlen(path)+1); - strcpy(subpath, path); - do { - si = camel_store_summary_path((CamelStoreSummary *)s, subpath); - if (si == NULL) { - last = strrchr(subpath, '/'); - if (last) - *last = 0; - } - } while (si == NULL && last); - - /* path is already present, use the raw version we have */ - if (si && strlen(subpath) == strlen(path)) { - f = g_strdup(camel_imap_store_info_full_name(s, si)); - camel_store_summary_info_free((CamelStoreSummary *)s, si); - return f; - } - - f = full = alloca(strlen(path)*2+1); - if (si) - p = path + strlen(subpath); - else - p = path; - while ( (c = camel_utf8_getc((const unsigned char **)&p)) ) { - switch(state) { - case 0: - if (c == '%') - state = 1; - else { - if (c == '/') - c = dir_sep; - camel_utf8_putc(&f, c); - } - break; - case 1: - state = 2; - v = hexnib(c)<<4; - break; - case 2: - state = 0; - v |= hexnib(c); - camel_utf8_putc(&f, v); - break; - } - } - camel_utf8_putc(&f, c); - - /* merge old path part if required */ - f = camel_utf8_utf7(full); - if (si) { - full = g_strdup_printf("%s%s", camel_imap_store_info_full_name(s, si), f); - g_free(f); - camel_store_summary_info_free((CamelStoreSummary *)s, si); - f = full; - } - - return f; -} - -CamelImapStoreInfo * -camel_imap_store_summary_add_from_full(CamelImapStoreSummary *s, const char *full_name, char dir_sep) -{ - CamelImapStoreInfo *info; - char *pathu8; - - d(printf("adding full name '%s' '%c'\n", full_name, dir_sep)); - - info = camel_imap_store_summary_full_name(s, full_name); - if (info) { - camel_store_summary_info_free((CamelStoreSummary *)s, (CamelStoreInfo *)info); - d(printf(" already there\n")); - return info; - } - - pathu8 = camel_imap_store_summary_full_to_path(s, full_name, dir_sep); - - info = (CamelImapStoreInfo *)camel_store_summary_add_from_path((CamelStoreSummary *)s, pathu8); - if (info) { - d(printf(" '%s' -> '%s'\n", pathu8, full_name)); - camel_store_info_set_string((CamelStoreSummary *)s, (CamelStoreInfo *)info, CAMEL_IMAP_STORE_INFO_FULL_NAME, full_name); - } else - d(printf(" failed\n")); - - return info; -} - -/* should this be const? */ -char * -camel_imap_store_summary_full_from_path(CamelImapStoreSummary *s, const char *path) -{ - CamelImapStoreInfo *si; - - si = (CamelImapStoreInfo *)camel_store_summary_path((CamelStoreSummary *)s, path); - - d(printf("looking up path %s -> %s\n", path, si?si->full_name:"not found")); - - if (si) - return g_strdup(si->full_name); - - return NULL; -} - -/* TODO: this api needs some more work */ -CamelImapStoreNamespace *camel_imap_store_summary_namespace_new(CamelImapStoreSummary *s, const char *full_name, char dir_sep) -{ - CamelImapStoreNamespace *ns; - - ns = g_malloc0(sizeof(*ns)); - ns->full_name = g_strdup(full_name); - ns->sep = dir_sep; - ns->path = camel_imap_store_summary_full_to_path(s, full_name, dir_sep); - - return ns; -} - -void camel_imap_store_summary_namespace_set(CamelImapStoreSummary *s, CamelImapStoreNamespace *ns) -{ - static void namespace_clear(CamelStoreSummary *s); - - namespace_clear((CamelStoreSummary *)s); - s->namespace = ns; - camel_store_summary_touch((CamelStoreSummary *)s); -} - -static void -namespace_free(CamelStoreSummary *s, CamelImapStoreNamespace *ns) -{ - g_free(ns->path); - g_free(ns->full_name); - g_free(ns); -} - -static void -namespace_clear(CamelStoreSummary *s) -{ - CamelImapStoreSummary *is = (CamelImapStoreSummary *)s; - - if (is->namespace) - namespace_free(s, is->namespace); - is->namespace = NULL; -} - -static CamelImapStoreNamespace * -namespace_load(CamelStoreSummary *s, FILE *in) -{ - CamelImapStoreNamespace *ns; - guint32 sep = '/'; - - ns = g_malloc0(sizeof(*ns)); - if (camel_file_util_decode_string(in, &ns->path) == -1 - || camel_file_util_decode_string(in, &ns->full_name) == -1 - || camel_file_util_decode_uint32(in, &sep) == -1) { - namespace_free(s, ns); - ns = NULL; - } else { - ns->sep = sep; - } - - return ns; -} - -static int -namespace_save(CamelStoreSummary *s, FILE *in, CamelImapStoreNamespace *ns) -{ - if (camel_file_util_encode_string(in, ns->path) == -1 - || camel_file_util_encode_string(in, ns->full_name) == -1 - || camel_file_util_encode_uint32(in, (guint32)ns->sep) == -1) - return -1; - - return 0; -} - -static int -summary_header_load(CamelStoreSummary *s, FILE *in) -{ - CamelImapStoreSummary *is = (CamelImapStoreSummary *)s; - gint32 version, capabilities, count; - - namespace_clear(s); - - if (camel_imap_store_summary_parent->summary_header_load((CamelStoreSummary *)s, in) == -1 - || camel_file_util_decode_fixed_int32(in, &version) == -1) - return -1; - - is->version = version; - - if (version < CAMEL_IMAP_STORE_SUMMARY_VERSION_0) { - g_warning("Store summary header version too low"); - return -1; - } - - /* note file format can be expanded to contain more namespaces, but only 1 at the moment */ - if (camel_file_util_decode_fixed_int32(in, &capabilities) == -1 - || camel_file_util_decode_fixed_int32(in, &count) == -1 - || count > 1) - return -1; - - is->capabilities = capabilities; - if (count == 1) { - if ((is->namespace = namespace_load(s, in)) == NULL) - return -1; - } - - return 0; -} - -static int -summary_header_save(CamelStoreSummary *s, FILE *out) -{ - CamelImapStoreSummary *is = (CamelImapStoreSummary *)s; - guint32 count; - - count = is->namespace?1:0; - - /* always write as latest version */ - if (camel_imap_store_summary_parent->summary_header_save((CamelStoreSummary *)s, out) == -1 - || camel_file_util_encode_fixed_int32(out, CAMEL_IMAP_STORE_SUMMARY_VERSION) == -1 - || camel_file_util_encode_fixed_int32(out, is->capabilities) == -1 - || camel_file_util_encode_fixed_int32(out, count) == -1) - return -1; - - if (is->namespace && namespace_save(s, out, is->namespace) == -1) - return -1; - - return 0; -} - -static CamelStoreInfo * -store_info_load(CamelStoreSummary *s, FILE *in) -{ - CamelImapStoreInfo *mi; - - mi = (CamelImapStoreInfo *)camel_imap_store_summary_parent->store_info_load(s, in); - if (mi) { - if (camel_file_util_decode_string(in, &mi->full_name) == -1) { - camel_store_summary_info_free(s, (CamelStoreInfo *)mi); - mi = NULL; - } - } - - return (CamelStoreInfo *)mi; -} - -static int -store_info_save(CamelStoreSummary *s, FILE *out, CamelStoreInfo *mi) -{ - CamelImapStoreInfo *isi = (CamelImapStoreInfo *)mi; - - if (camel_imap_store_summary_parent->store_info_save(s, out, mi) == -1 - || camel_file_util_encode_string(out, isi->full_name) == -1) - return -1; - - return 0; -} - -static void -store_info_free(CamelStoreSummary *s, CamelStoreInfo *mi) -{ - CamelImapStoreInfo *isi = (CamelImapStoreInfo *)mi; - - g_free(isi->full_name); - camel_imap_store_summary_parent->store_info_free(s, mi); -} - -static const char * -store_info_string(CamelStoreSummary *s, const CamelStoreInfo *mi, int type) -{ - CamelImapStoreInfo *isi = (CamelImapStoreInfo *)mi; - - /* FIXME: Locks? */ - - g_assert (mi != NULL); - - switch (type) { - case CAMEL_IMAP_STORE_INFO_FULL_NAME: - return isi->full_name; - default: - return camel_imap_store_summary_parent->store_info_string(s, mi, type); - } -} - -static void -store_info_set_string(CamelStoreSummary *s, CamelStoreInfo *mi, int type, const char *str) -{ - CamelImapStoreInfo *isi = (CamelImapStoreInfo *)mi; - - g_assert(mi != NULL); - - switch(type) { - case CAMEL_IMAP_STORE_INFO_FULL_NAME: - d(printf("Set full name %s -> %s\n", isi->full_name, str)); - CAMEL_STORE_SUMMARY_LOCK(s, summary_lock); - g_free(isi->full_name); - isi->full_name = g_strdup(str); - CAMEL_STORE_SUMMARY_UNLOCK(s, summary_lock); - break; - default: - camel_imap_store_summary_parent->store_info_set_string(s, mi, type, str); - break; - } -} diff --git a/camel/providers/imap/camel-imap-store-summary.h b/camel/providers/imap/camel-imap-store-summary.h deleted file mode 100644 index 013283b5c1..0000000000 --- a/camel/providers/imap/camel-imap-store-summary.h +++ /dev/null @@ -1,100 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2002 Ximian Inc. - * - * Authors: Michael Zucchi <notzed@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. - */ - - -#ifndef _CAMEL_IMAP_STORE_SUMMARY_H -#define _CAMEL_IMAP_STORE_SUMMARY_H - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus */ - -#include <camel/camel-object.h> -#include <camel/camel-store-summary.h> - -#define CAMEL_IMAP_STORE_SUMMARY(obj) CAMEL_CHECK_CAST (obj, camel_imap_store_summary_get_type (), CamelImapStoreSummary) -#define CAMEL_IMAP_STORE_SUMMARY_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_imap_store_summary_get_type (), CamelImapStoreSummaryClass) -#define CAMEL_IS_IMAP_STORE_SUMMARY(obj) CAMEL_CHECK_TYPE (obj, camel_imap_store_summary_get_type ()) - -typedef struct _CamelImapStoreSummary CamelImapStoreSummary; -typedef struct _CamelImapStoreSummaryClass CamelImapStoreSummaryClass; - -typedef struct _CamelImapStoreInfo CamelImapStoreInfo; - -enum { - CAMEL_IMAP_STORE_INFO_FULL_NAME = CAMEL_STORE_INFO_LAST, - CAMEL_IMAP_STORE_INFO_LAST, -}; - -struct _CamelImapStoreInfo { - CamelStoreInfo info; - char *full_name; -}; - -typedef struct _CamelImapStoreNamespace CamelImapStoreNamespace; - -struct _CamelImapStoreNamespace { - char *path; /* display path */ - char *full_name; /* real name */ - char sep; /* directory separator */ -}; - -struct _CamelImapStoreSummary { - CamelStoreSummary summary; - - struct _CamelImapStoreSummaryPrivate *priv; - - /* header info */ - guint32 version; /* version of base part of file */ - guint32 capabilities; - CamelImapStoreNamespace *namespace; /* eventually to be a list */ -}; - -struct _CamelImapStoreSummaryClass { - CamelStoreSummaryClass summary_class; -}; - -CamelType camel_imap_store_summary_get_type (void); -CamelImapStoreSummary *camel_imap_store_summary_new (void); - -/* TODO: this api needs some more work */ -CamelImapStoreNamespace *camel_imap_store_summary_namespace_new(CamelImapStoreSummary *s, const char *full_name, char dir_sep); -void camel_imap_store_summary_namespace_set(CamelImapStoreSummary *s, CamelImapStoreNamespace *ns); - -/* converts to/from utf8 canonical nasmes */ -char *camel_imap_store_summary_full_to_path(CamelImapStoreSummary *s, const char *full_name, char dir_sep); -char *camel_imap_store_summary_path_to_full(CamelImapStoreSummary *s, const char *path, char dir_sep); - -CamelImapStoreInfo *camel_imap_store_summary_full_name(CamelImapStoreSummary *s, const char *full_name); -CamelImapStoreInfo *camel_imap_store_summary_add_from_full(CamelImapStoreSummary *s, const char *full_name, char dir_sep); - -/* a convenience lookup function. always use this if path known */ -char *camel_imap_store_summary_full_from_path(CamelImapStoreSummary *s, const char *path); - -/* helper macro's */ -#define camel_imap_store_info_full_name(s, i) (camel_store_info_string((CamelStoreSummary *)s, (const CamelStoreInfo *)i, CAMEL_IMAP_STORE_INFO_FULL_NAME)) - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* ! _CAMEL_IMAP_STORE_SUMMARY_H */ diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c deleted file mode 100644 index af4192e0c6..0000000000 --- a/camel/providers/imap/camel-imap-store.c +++ /dev/null @@ -1,2607 +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: - * Dan Winship <danw@ximian.com> - * Jeffrey Stedfast <fejj@ximian.com> - * - * Copyright 2000, 2001 Ximian, Inc. - * - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> - -#include "e-util/e-path.h" - -#include "camel-imap-store.h" -#include "camel-imap-store-summary.h" -#include "camel-imap-folder.h" -#include "camel-imap-utils.h" -#include "camel-imap-command.h" -#include "camel-imap-summary.h" -#include "camel-imap-message-cache.h" -#include "camel-disco-diary.h" -#include "camel-file-utils.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-tcp-stream-raw.h" -#include "camel-tcp-stream-ssl.h" -#include "camel-url.h" -#include "camel-sasl.h" -#include "camel-utf8.h" -#include "string-utils.h" - -#include "camel-imap-private.h" -#include "camel-private.h" - -#define d(x) - -/* Specified in RFC 2060 */ -#define IMAP_PORT 143 -#define SIMAP_PORT 993 - - -extern int camel_verbose_debug; - -static CamelDiscoStoreClass *parent_class = NULL; - -static char imap_tag_prefix = 'A'; - -static void construct (CamelService *service, CamelSession *session, - CamelProvider *provider, CamelURL *url, - CamelException *ex); - -static int imap_setv (CamelObject *object, CamelException *ex, CamelArgV *args); -static int imap_getv (CamelObject *object, CamelException *ex, CamelArgGetV *args); - -static char *imap_get_name (CamelService *service, gboolean brief); - -static gboolean can_work_offline (CamelDiscoStore *disco_store); -static gboolean imap_connect_online (CamelService *service, CamelException *ex); -static gboolean imap_connect_offline (CamelService *service, CamelException *ex); -static gboolean imap_disconnect_online (CamelService *service, gboolean clean, CamelException *ex); -static gboolean imap_disconnect_offline (CamelService *service, gboolean clean, CamelException *ex); -static void imap_noop (CamelStore *store, CamelException *ex); -static GList *query_auth_types (CamelService *service, CamelException *ex); -static guint hash_folder_name (gconstpointer key); -static gint compare_folder_name (gconstpointer a, gconstpointer b); -static CamelFolder *get_folder_online (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex); -static CamelFolder *get_folder_offline (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex); -static CamelFolderInfo *create_folder (CamelStore *store, const char *parent_name, const char *folder_name, CamelException *ex); -static void delete_folder (CamelStore *store, const char *folder_name, CamelException *ex); -static void rename_folder (CamelStore *store, const char *old_name, const char *new_name, CamelException *ex); -static CamelFolderInfo *get_folder_info_online (CamelStore *store, - const char *top, - guint32 flags, - CamelException *ex); -static CamelFolderInfo *get_folder_info_offline (CamelStore *store, - const char *top, - guint32 flags, - CamelException *ex); -static gboolean folder_subscribed (CamelStore *store, const char *folder_name); -static void subscribe_folder (CamelStore *store, const char *folder_name, - CamelException *ex); -static void unsubscribe_folder (CamelStore *store, const char *folder_name, - CamelException *ex); - -static void get_folders_online (CamelImapStore *imap_store, const char *pattern, - GPtrArray *folders, gboolean lsub, CamelException *ex); - - -static void imap_folder_effectively_unsubscribed(CamelImapStore *imap_store, const char *folder_name, CamelException *ex); -static gboolean imap_check_folder_still_extant (CamelImapStore *imap_store, const char *full_name, CamelException *ex); -static void imap_forget_folder(CamelImapStore *imap_store, const char *folder_name, CamelException *ex); -static void imap_set_server_level (CamelImapStore *store); - -static void -camel_imap_store_class_init (CamelImapStoreClass *camel_imap_store_class) -{ - CamelObjectClass *camel_object_class = - CAMEL_OBJECT_CLASS (camel_imap_store_class); - CamelServiceClass *camel_service_class = - CAMEL_SERVICE_CLASS (camel_imap_store_class); - CamelStoreClass *camel_store_class = - CAMEL_STORE_CLASS (camel_imap_store_class); - CamelDiscoStoreClass *camel_disco_store_class = - CAMEL_DISCO_STORE_CLASS (camel_imap_store_class); - - parent_class = CAMEL_DISCO_STORE_CLASS (camel_type_get_global_classfuncs (camel_disco_store_get_type ())); - - /* virtual method overload */ - camel_object_class->setv = imap_setv; - camel_object_class->getv = imap_getv; - - camel_service_class->construct = construct; - camel_service_class->query_auth_types = query_auth_types; - camel_service_class->get_name = imap_get_name; - - camel_store_class->hash_folder_name = hash_folder_name; - camel_store_class->compare_folder_name = compare_folder_name; - camel_store_class->create_folder = create_folder; - camel_store_class->delete_folder = delete_folder; - camel_store_class->rename_folder = rename_folder; - camel_store_class->free_folder_info = camel_store_free_folder_info_full; - camel_store_class->folder_subscribed = folder_subscribed; - camel_store_class->subscribe_folder = subscribe_folder; - camel_store_class->unsubscribe_folder = unsubscribe_folder; - camel_store_class->noop = imap_noop; - - camel_disco_store_class->can_work_offline = can_work_offline; - camel_disco_store_class->connect_online = imap_connect_online; - camel_disco_store_class->connect_offline = imap_connect_offline; - camel_disco_store_class->disconnect_online = imap_disconnect_online; - camel_disco_store_class->disconnect_offline = imap_disconnect_offline; - camel_disco_store_class->get_folder_online = get_folder_online; - camel_disco_store_class->get_folder_offline = get_folder_offline; - camel_disco_store_class->get_folder_resyncing = get_folder_online; - camel_disco_store_class->get_folder_info_online = get_folder_info_online; - camel_disco_store_class->get_folder_info_offline = get_folder_info_offline; - camel_disco_store_class->get_folder_info_resyncing = get_folder_info_online; -} - -static gboolean -free_key (gpointer key, gpointer value, gpointer user_data) -{ - g_free (key); - return TRUE; -} - -static void -camel_imap_store_finalize (CamelObject *object) -{ - CamelImapStore *imap_store = CAMEL_IMAP_STORE (object); - - /* This frees current_folder, folders, authtypes, streams, and namespace. */ - camel_service_disconnect((CamelService *)imap_store, TRUE, NULL); - - if (imap_store->summary) { - camel_store_summary_save((CamelStoreSummary *)imap_store->summary); - camel_object_unref(imap_store->summary); - } - - if (imap_store->base_url) - g_free (imap_store->base_url); - if (imap_store->storage_path) - g_free (imap_store->storage_path); - -#ifdef ENABLE_THREADS - e_thread_destroy (imap_store->async_thread); -#endif -} - -#ifdef ENABLE_THREADS -static void async_destroy(EThread *et, EMsg *em, void *data) -{ - CamelImapStore *imap_store = data; - CamelImapMsg *msg = (CamelImapMsg *)em; - - if (msg->free) - msg->free (imap_store, msg); - - g_free (msg); -} - -static void async_received(EThread *et, EMsg *em, void *data) -{ - CamelImapStore *imap_store = data; - CamelImapMsg *msg = (CamelImapMsg *)em; - - if (msg->receive) - msg->receive(imap_store, msg); -} - -CamelImapMsg *camel_imap_msg_new(void (*receive)(CamelImapStore *store, struct _CamelImapMsg *m), - void (*free)(CamelImapStore *store, struct _CamelImapMsg *m), - size_t size) -{ - CamelImapMsg *msg; - - g_assert(size >= sizeof(*msg)); - - msg = g_malloc0(size); - msg->receive = receive; - msg->free = free; - - return msg; -} - -void camel_imap_msg_queue(CamelImapStore *store, CamelImapMsg *msg) -{ - e_thread_put(store->async_thread, (EMsg *)msg); -} - -#endif - -static void -camel_imap_store_init (gpointer object, gpointer klass) -{ - CamelImapStore *imap_store = CAMEL_IMAP_STORE (object); - - imap_store->istream = NULL; - imap_store->ostream = NULL; - - imap_store->dir_sep = '\0'; - imap_store->current_folder = NULL; - imap_store->connected = FALSE; - - imap_store->tag_prefix = imap_tag_prefix++; - if (imap_tag_prefix > 'Z') - imap_tag_prefix = 'A'; - -#ifdef ENABLE_THREADS - imap_store->async_thread = e_thread_new(E_THREAD_QUEUE); - e_thread_set_msg_destroy(imap_store->async_thread, async_destroy, imap_store); - e_thread_set_msg_received(imap_store->async_thread, async_received, imap_store); -#endif /* ENABLE_THREADS */ -} - -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_DISCO_STORE_TYPE, - "CamelImapStore", - sizeof (CamelImapStore), - sizeof (CamelImapStoreClass), - (CamelObjectClassInitFunc) camel_imap_store_class_init, - NULL, - (CamelObjectInitFunc) camel_imap_store_init, - (CamelObjectFinalizeFunc) camel_imap_store_finalize); - } - - return camel_imap_store_type; -} - -static void -construct (CamelService *service, CamelSession *session, - CamelProvider *provider, CamelURL *url, - CamelException *ex) -{ - CamelImapStore *imap_store = CAMEL_IMAP_STORE (service); - CamelStore *store = CAMEL_STORE (service); - char *tmp; - CamelURL *summary_url; - - CAMEL_SERVICE_CLASS (parent_class)->construct (service, session, provider, url, ex); - if (camel_exception_is_set (ex)) - return; - - imap_store->storage_path = camel_session_get_storage_path (session, service, ex); - if (!imap_store->storage_path) - return; - - /* FIXME */ - imap_store->base_url = camel_url_to_string (service->url, (CAMEL_URL_HIDE_PASSWORD | - CAMEL_URL_HIDE_PARAMS | - CAMEL_URL_HIDE_AUTH)); - - imap_store->parameters = 0; - if (camel_url_get_param (url, "use_lsub")) - store->flags |= CAMEL_STORE_SUBSCRIPTIONS; - if (camel_url_get_param (url, "namespace")) { - imap_store->parameters |= IMAP_PARAM_OVERRIDE_NAMESPACE; - g_free(imap_store->namespace); - imap_store->namespace = g_strdup (camel_url_get_param (url, "namespace")); - } - if (camel_url_get_param (url, "check_all")) - imap_store->parameters |= IMAP_PARAM_CHECK_ALL; - if (camel_url_get_param (url, "filter")) { - imap_store->parameters |= IMAP_PARAM_FILTER_INBOX; - store->flags |= CAMEL_STORE_FILTER_INBOX; - } - - /* setup/load the store summary */ - tmp = alloca(strlen(imap_store->storage_path)+32); - sprintf(tmp, "%s/.ev-store-summary", imap_store->storage_path); - imap_store->summary = camel_imap_store_summary_new(); - camel_store_summary_set_filename((CamelStoreSummary *)imap_store->summary, tmp); - summary_url = camel_url_new(imap_store->base_url, NULL); - camel_store_summary_set_uri_base((CamelStoreSummary *)imap_store->summary, summary_url); - camel_url_free(summary_url); - if (camel_store_summary_load((CamelStoreSummary *)imap_store->summary) == 0) { - CamelImapStoreSummary *is = imap_store->summary; - - if (is->namespace) { - /* if namespace has changed, clear folder list */ - if (imap_store->namespace && strcmp(imap_store->namespace, is->namespace->full_name) != 0) { - camel_store_summary_clear((CamelStoreSummary *)is); - } else { - imap_store->namespace = g_strdup(is->namespace->full_name); - imap_store->dir_sep = is->namespace->sep; - store->dir_sep = is->namespace->sep; - } - } - - imap_store->capabilities = is->capabilities; - imap_set_server_level(imap_store); - } -} - -static int -imap_setv (CamelObject *object, CamelException *ex, CamelArgV *args) -{ - CamelImapStore *store = (CamelImapStore *) object; - guint32 tag, flags; - int i; - - for (i = 0; i < args->argc; i++) { - tag = args->argv[i].tag; - - /* make sure this arg wasn't already handled */ - if (tag & CAMEL_ARG_IGNORE) - continue; - - /* make sure this is an arg we're supposed to handle */ - if ((tag & CAMEL_ARG_TAG) <= CAMEL_IMAP_STORE_ARG_FIRST || - (tag & CAMEL_ARG_TAG) >= CAMEL_IMAP_STORE_ARG_FIRST + 100) - continue; - - if (tag == CAMEL_IMAP_STORE_NAMESPACE) { - if (strcmp (store->namespace, args->argv[i].ca_str) != 0) { - g_free (store->namespace); - store->namespace = g_strdup (args->argv[i].ca_str); - /* the current imap code will need to do a reconnect for this to take effect */ - /*reconnect = TRUE;*/ - } - } else if (tag == CAMEL_IMAP_STORE_OVERRIDE_NAMESPACE) { - flags = args->argv[i].ca_int ? IMAP_PARAM_OVERRIDE_NAMESPACE : 0; - flags |= (store->parameters & ~IMAP_PARAM_OVERRIDE_NAMESPACE); - - if (store->parameters != flags) { - store->parameters = flags; - /* the current imap code will need to do a reconnect for this to take effect */ - /*reconnect = TRUE;*/ - } - } else if (tag == CAMEL_IMAP_STORE_CHECK_ALL) { - flags = args->argv[i].ca_int ? IMAP_PARAM_CHECK_ALL : 0; - flags |= (store->parameters & ~IMAP_PARAM_CHECK_ALL); - store->parameters = flags; - /* no need to reconnect for this option to take effect... */ - } else if (tag == CAMEL_IMAP_STORE_FILTER_INBOX) { - flags = args->argv[i].ca_int ? IMAP_PARAM_FILTER_INBOX : 0; - flags |= (store->parameters & ~IMAP_PARAM_FILTER_INBOX); - store->parameters = flags; - /* no need to reconnect for this option to take effect... */ - } else { - /* error?? */ - continue; - } - - /* let our parent know that we've handled this arg */ - camel_argv_ignore (args, i); - } - - /* FIXME: if we need to reconnect for a change to take affect, - we need to do it here... or, better yet, somehow chain it - up to CamelService's setv implementation. */ - - return CAMEL_OBJECT_CLASS (parent_class)->setv (object, ex, args); -} - -static int -imap_getv (CamelObject *object, CamelException *ex, CamelArgGetV *args) -{ - CamelImapStore *store = (CamelImapStore *) object; - guint32 tag; - int i; - - for (i = 0; i < args->argc; i++) { - tag = args->argv[i].tag; - - /* make sure this is an arg we're supposed to handle */ - if ((tag & CAMEL_ARG_TAG) <= CAMEL_IMAP_STORE_ARG_FIRST || - (tag & CAMEL_ARG_TAG) >= CAMEL_IMAP_STORE_ARG_FIRST + 100) - continue; - - switch (tag) { - case CAMEL_IMAP_STORE_NAMESPACE: - /* get the username */ - *args->argv[i].ca_str = store->namespace; - break; - case CAMEL_IMAP_STORE_OVERRIDE_NAMESPACE: - /* get the auth mechanism */ - *args->argv[i].ca_int = store->parameters & IMAP_PARAM_OVERRIDE_NAMESPACE ? TRUE : FALSE; - break; - case CAMEL_IMAP_STORE_CHECK_ALL: - /* get the hostname */ - *args->argv[i].ca_int = store->parameters & IMAP_PARAM_CHECK_ALL ? TRUE : FALSE; - break; - case CAMEL_IMAP_STORE_FILTER_INBOX: - /* get the port */ - *args->argv[i].ca_int = store->parameters & IMAP_PARAM_FILTER_INBOX ? TRUE : FALSE; - break; - default: - /* error? */ - } - } - - return CAMEL_OBJECT_CLASS (parent_class)->getv (object, ex, args); -} - -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); -} - -static void -imap_set_server_level (CamelImapStore *store) -{ - if (store->capabilities & IMAP_CAPABILITY_IMAP4REV1) { - store->server_level = IMAP_LEVEL_IMAP4REV1; - store->capabilities |= IMAP_CAPABILITY_STATUS; - } else if (store->capabilities & IMAP_CAPABILITY_IMAP4) - store->server_level = IMAP_LEVEL_IMAP4; - else - store->server_level = IMAP_LEVEL_UNKNOWN; -} - -static struct { - const char *name; - guint32 flag; -} capabilities[] = { - { "IMAP4", IMAP_CAPABILITY_IMAP4 }, - { "IMAP4REV1", IMAP_CAPABILITY_IMAP4REV1 }, - { "STATUS", IMAP_CAPABILITY_STATUS }, - { "NAMESPACE", IMAP_CAPABILITY_NAMESPACE }, - { "UIDPLUS", IMAP_CAPABILITY_UIDPLUS }, - { "LITERAL+", IMAP_CAPABILITY_LITERALPLUS }, - { "STARTTLS", IMAP_CAPABILITY_STARTTLS }, - { NULL, 0 } -}; - - -static gboolean -imap_get_capability (CamelService *service, CamelException *ex) -{ - CamelImapStore *store = CAMEL_IMAP_STORE (service); - CamelImapResponse *response; - char *result, *capa, *lasts; - int i; - - CAMEL_SERVICE_ASSERT_LOCKED (store, connect_lock); - - /* Find out the IMAP capabilities */ - /* We assume we have utf8 capable search until a failed search tells us otherwise */ - store->capabilities = IMAP_CAPABILITY_utf8_search; - store->authtypes = g_hash_table_new (g_str_hash, g_str_equal); - response = camel_imap_command (store, NULL, ex, "CAPABILITY"); - if (!response) - return FALSE; - result = camel_imap_response_extract (store, response, "CAPABILITY ", ex); - if (!result) - return FALSE; - - /* Skip over "* CAPABILITY ". */ - capa = result + 13; - for (capa = strtok_r (capa, " ", &lasts); capa; - capa = strtok_r (NULL, " ", &lasts)) { - if (!strncmp (capa, "AUTH=", 5)) { - g_hash_table_insert (store->authtypes, - g_strdup (capa + 5), - GINT_TO_POINTER (1)); - continue; - } - for (i = 0; capabilities[i].name; i++) { - if (g_strcasecmp (capa, capabilities[i].name) == 0) { - store->capabilities |= capabilities[i].flag; - break; - } - } - } - g_free (result); - - imap_set_server_level (store); - - if (store->summary->capabilities != store->capabilities) { - store->summary->capabilities = store->capabilities; - camel_store_summary_touch((CamelStoreSummary *)store->summary); - camel_store_summary_save((CamelStoreSummary *)store->summary); - } - - return TRUE; -} - -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) -{ - CamelImapStore *store = (CamelImapStore *) service; - CamelImapResponse *response; - CamelStream *tcp_stream; - struct hostent *h; - int clean_quit; - int port, ret; - char *buf; - - h = camel_service_gethost (service, ex); - if (!h) - return FALSE; - - port = service->url->port ? service->url->port : 143; - -#ifdef HAVE_SSL - if (ssl_mode != USE_SSL_NEVER) { - if (try_starttls) - tcp_stream = camel_tcp_stream_ssl_new_raw (service, service->url->host); - else { - port = service->url->port ? service->url->port : 993; - tcp_stream = camel_tcp_stream_ssl_new (service, service->url->host); - } - } else { - tcp_stream = camel_tcp_stream_raw_new (); - } -#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)); - - camel_object_unref (CAMEL_OBJECT (tcp_stream)); - - return FALSE; - } - - store->ostream = tcp_stream; - store->istream = camel_stream_buffer_new (tcp_stream, CAMEL_STREAM_BUFFER_READ); - - store->connected = TRUE; - store->command = 0; - - /* Read the greeting, if any. FIXME: deal with PREAUTH */ - if (camel_imap_store_readline (store, &buf, ex) < 0) { - 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; - } - - store->connected = FALSE; - return FALSE; - } - g_free (buf); - - /* get the imap server capabilities */ - if (!imap_get_capability (service, ex)) { - 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; - } - - store->connected = FALSE; - return FALSE; - } - -#ifdef HAVE_SSL - if (ssl_mode == USE_SSL_WHEN_POSSIBLE) { - if (store->capabilities & IMAP_CAPABILITY_STARTTLS) - goto starttls; - } else if (ssl_mode == USE_SSL_ALWAYS) { - if (try_starttls) { - if (store->capabilities & IMAP_CAPABILITY_STARTTLS) { - /* 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 IMAP 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 exception; - } - } - } -#endif /* HAVE_SSL */ - - return TRUE; - -#ifdef HAVE_SSL - starttls: - - /* as soon as we send a STARTTLS command, all hope is lost of a clean QUIT if problems arise */ - clean_quit = FALSE; - - response = camel_imap_command (store, NULL, ex, "STARTTLS"); - if (!response) { - camel_object_unref (CAMEL_OBJECT (store->istream)); - camel_object_unref (CAMEL_OBJECT (store->ostream)); - store->istream = store->ostream = NULL; - return FALSE; - } - - camel_imap_response_free_without_processing (store, response); - - /* Okay, now toggle SSL/TLS mode */ - if (camel_tcp_stream_ssl_enable_ssl (CAMEL_TCP_STREAM_SSL (tcp_stream)) == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Failed to connect to IMAP server %s in secure mode: %s"), - service->url->host, _("SSL negotiations failed")); - goto exception; - } - - /* rfc2595, section 4 states that after a successful STLS - command, the client MUST discard prior CAPA responses */ - if (!imap_get_capability (service, ex)) { - camel_object_unref (CAMEL_OBJECT (store->istream)); - camel_object_unref (CAMEL_OBJECT (store->ostream)); - store->istream = NULL; - store->ostream = NULL; - return FALSE; - } - - return TRUE; - - exception: - if (clean_quit) { - /* try to disconnect cleanly */ - response = camel_imap_command (store, NULL, ex, "LOGOUT"); - if (response) - camel_imap_response_free_without_processing (store, response); - } - - camel_object_unref (CAMEL_OBJECT (store->istream)); - camel_object_unref (CAMEL_OBJECT (store->ostream)); - store->istream = NULL; - store->ostream = 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) -{ -#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; - } - } - - 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); - } -#else - return connect_to_server (service, USE_SSL_NEVER, FALSE, ex); -#endif -} - -extern CamelServiceAuthType camel_imap_password_authtype; - -static GList * -query_auth_types (CamelService *service, CamelException *ex) -{ - CamelImapStore *store = CAMEL_IMAP_STORE (service); - CamelServiceAuthType *authtype; - GList *sasl_types, *t, *next; - gboolean connected; - - if (!camel_disco_store_check_online (CAMEL_DISCO_STORE (store), ex)) - return NULL; - - 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->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); -} - -/* folder_name is path name */ -static CamelFolderInfo * -imap_build_folder_info(CamelImapStore *imap_store, const char *folder_name) -{ - CamelURL *url; - const char *name; - CamelFolderInfo *fi; - - fi = g_malloc0(sizeof(*fi)); - - fi->full_name = g_strdup(folder_name); - fi->unread_message_count = 0; - - url = camel_url_new (imap_store->base_url, NULL); - g_free (url->path); - url->path = g_strdup_printf ("/%s", folder_name); - fi->url = camel_url_to_string (url, CAMEL_URL_HIDE_ALL); - camel_url_free(url); - fi->path = g_strdup_printf("/%s", folder_name); - name = strrchr (fi->path, '/'); - if (name) - name++; - else - name = fi->path; - - fi->name = g_strdup (name); - - return fi; -} - -static void -imap_folder_effectively_unsubscribed(CamelImapStore *imap_store, - const char *folder_name, CamelException *ex) -{ - CamelFolderInfo *fi; - CamelStoreInfo *si; - - si = camel_store_summary_path((CamelStoreSummary *)imap_store->summary, folder_name); - if (si) { - if (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) { - si->flags &= ~CAMEL_STORE_INFO_FOLDER_SUBSCRIBED; - camel_store_summary_touch((CamelStoreSummary *)imap_store->summary); - camel_store_summary_save((CamelStoreSummary *)imap_store->summary); - } - camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si); - } - - if (imap_store->renaming) { - /* we don't need to emit a "folder_unsubscribed" signal - if we are in the process of renaming folders, so we - are done here... */ - return; - - } - - fi = imap_build_folder_info(imap_store, folder_name); - camel_object_trigger_event (CAMEL_OBJECT (imap_store), "folder_unsubscribed", fi); - camel_folder_info_free (fi); -} - -static void -imap_forget_folder (CamelImapStore *imap_store, const char *folder_name, CamelException *ex) -{ - CamelFolderSummary *summary; - CamelImapMessageCache *cache; - char *summary_file; - char *journal_file; - char *folder_dir, *storage_path; - CamelFolderInfo *fi; - const char *name; - - name = strrchr (folder_name, imap_store->dir_sep); - if (name) - name++; - else - name = folder_name; - - storage_path = g_strdup_printf ("%s/folders", imap_store->storage_path); - folder_dir = e_path_to_physical (storage_path, folder_name); - g_free (storage_path); - if (access (folder_dir, F_OK) != 0) { - g_free (folder_dir); - goto event; - } - - summary_file = g_strdup_printf ("%s/summary", folder_dir); - summary = camel_imap_summary_new (summary_file); - if (!summary) { - g_free (summary_file); - g_free (folder_dir); - goto event; - } - - cache = camel_imap_message_cache_new (folder_dir, summary, ex); - if (cache) - camel_imap_message_cache_clear (cache); - - camel_object_unref (CAMEL_OBJECT (cache)); - camel_object_unref (CAMEL_OBJECT (summary)); - - unlink (summary_file); - g_free (summary_file); - - journal_file = g_strdup_printf ("%s/summary", folder_dir); - unlink (journal_file); - g_free (journal_file); - - rmdir (folder_dir); - g_free (folder_dir); - - event: - - camel_store_summary_remove_path((CamelStoreSummary *)imap_store->summary, folder_name); - camel_store_summary_save((CamelStoreSummary *)imap_store->summary); - - fi = imap_build_folder_info(imap_store, folder_name); - camel_object_trigger_event (CAMEL_OBJECT (imap_store), "folder_deleted", fi); - camel_folder_info_free (fi); -} - -static gboolean -imap_check_folder_still_extant (CamelImapStore *imap_store, const char *full_name, - CamelException *ex) -{ - CamelImapResponse *response; - - response = camel_imap_command (imap_store, NULL, ex, "LIST \"\" %S", - full_name); - - if (response) { - gboolean stillthere = FALSE; - - if (response->untagged->len) - stillthere = TRUE; - - camel_imap_response_free_without_processing (imap_store, response); - - if (stillthere) - return TRUE; - } - - /* either LIST command was rejected or it gave no results, - * we can be sure that the folder is gone. */ - - camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID, - _("The folder %s no longer exists"), - full_name); - return FALSE; -} - -static void -copy_folder(char *key, CamelFolder *folder, GPtrArray *out) -{ - g_ptr_array_add(out, folder); - camel_object_ref((CamelObject *)folder); -} - -/* This is a little 'hack' to avoid the deadlock conditions that would otherwise - ensue when calling camel_folder_refresh_info from inside a lock */ -/* NB: on second thougts this is probably not entirely safe, but it'll do for now */ -/* No, its definetly not safe. So its been changed to copy the folders first */ -/* the alternative is to: - make the camel folder->lock recursive (which should probably be done) - or remove it from camel_folder_refresh_info, and use another locking mechanism */ -/* also see get_folder_info_online() for the same hack repeated */ -static void -imap_store_refresh_folders (CamelImapStore *store, CamelException *ex) -{ - GPtrArray *folders; - int i; - - folders = g_ptr_array_new(); - CAMEL_STORE_LOCK(store, cache_lock); - g_hash_table_foreach (CAMEL_STORE (store)->folders, (GHFunc)copy_folder, folders); - CAMEL_STORE_UNLOCK(store, cache_lock); - - for (i = 0; i <folders->len; i++) { - CamelFolder *folder = folders->pdata[i]; - - CAMEL_IMAP_FOLDER (folder)->need_rescan = TRUE; - if (!camel_exception_is_set(ex)) - CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(folder))->refresh_info(folder, ex); - - if (camel_exception_is_set (ex) && - imap_check_folder_still_extant (store, folder->full_name, ex) == FALSE) { - gchar *namedup; - - /* the folder was deleted (may happen when we come back online - * after being offline */ - - namedup = g_strdup (folder->full_name); - camel_object_unref((CamelObject *)folder); - imap_folder_effectively_unsubscribed (store, namedup, ex); - imap_forget_folder (store, namedup, ex); - camel_exception_clear (ex); - g_free (namedup); - } else - camel_object_unref((CamelObject *)folder); - } - - g_ptr_array_free (folders, TRUE); -} - -static gboolean -try_auth (CamelImapStore *store, const char *mech, CamelException *ex) -{ - CamelSasl *sasl; - CamelImapResponse *response; - char *resp; - char *sasl_resp; - - CAMEL_SERVICE_ASSERT_LOCKED (store, connect_lock); - - response = camel_imap_command (store, NULL, ex, "AUTHENTICATE %s", mech); - if (!response) - return FALSE; - - sasl = camel_sasl_new ("imap", mech, CAMEL_SERVICE (store)); - while (!camel_sasl_authenticated (sasl)) { - resp = camel_imap_response_extract_continuation (store, response, ex); - if (!resp) - goto lose; - - sasl_resp = camel_sasl_challenge_base64 (sasl, imap_next_word (resp), ex); - g_free (resp); - if (camel_exception_is_set (ex)) - goto break_and_lose; - - response = camel_imap_command_continuation (store, sasl_resp, strlen (sasl_resp), ex); - g_free (sasl_resp); - if (!response) - goto lose; - } - - resp = camel_imap_response_extract_continuation (store, response, NULL); - if (resp) { - /* Oops. SASL claims we're done, but the IMAP server - * doesn't think so... - */ - g_free (resp); - goto lose; - } - - camel_object_unref (CAMEL_OBJECT (sasl)); - - return TRUE; - - break_and_lose: - /* Get the server out of "waiting for continuation data" mode. */ - response = camel_imap_command_continuation (store, "*", 1, NULL); - if (response) - camel_imap_response_free (store, response); - - lose: - if (!camel_exception_is_set (ex)) { - camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE, - _("Bad authentication response from server.")); - } - - camel_object_unref (CAMEL_OBJECT (sasl)); - - return FALSE; -} - -static gboolean -imap_auth_loop (CamelService *service, CamelException *ex) -{ - CamelImapStore *store = CAMEL_IMAP_STORE (service); - CamelSession *session = camel_service_get_session (service); - CamelServiceAuthType *authtype = NULL; - CamelImapResponse *response; - char *errbuf = NULL; - gboolean authenticated = FALSE; - - CAMEL_SERVICE_ASSERT_LOCKED (store, connect_lock); - - if (service->url->authmech) { - if (!g_hash_table_lookup (store->authtypes, service->url->authmech)) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE, - _("IMAP server %s does not support requested " - "authentication type %s"), - service->url->host, - service->url->authmech); - return FALSE; - } - - authtype = camel_sasl_authtype (service->url->authmech); - if (!authtype) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE, - _("No support for authentication type %s"), - service->url->authmech); - return FALSE; - } - - if (!authtype->need_password) { - authenticated = try_auth (store, authtype->authproto, ex); - if (!authenticated) - return FALSE; - } - } - - while (!authenticated) { - if (errbuf) { - /* We need to un-cache the password before prompting again */ - camel_session_forget_password ( - session, service, "password", ex); - g_free (service->url->passwd); - service->url->passwd = NULL; - } - - if (!service->url->passwd) { - char *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_get_password ( - session, 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; - } - } - - if (!store->connected) { - /* Some servers (eg, courier) will disconnect on - * a bad password. So reconnect here. - */ - if (!connect_to_server_wrapper (service, ex)) - return FALSE; - } - - if (authtype) - authenticated = try_auth (store, authtype->authproto, ex); - else { - response = camel_imap_command (store, NULL, ex, - "LOGIN %S %S", - service->url->user, - service->url->passwd); - if (response) { - camel_imap_response_free (store, response); - authenticated = TRUE; - } - } - if (!authenticated) { - if (camel_exception_get_id(ex) == CAMEL_EXCEPTION_USER_CANCEL) - return FALSE; - - errbuf = g_strdup_printf (_("Unable to authenticate " - "to IMAP server.\n%s\n\n"), - camel_exception_get_description (ex)); - camel_exception_clear (ex); - } - } - - return TRUE; -} - -static gboolean -can_work_offline (CamelDiscoStore *disco_store) -{ - CamelImapStore *store = CAMEL_IMAP_STORE (disco_store); - - return camel_store_summary_count((CamelStoreSummary *)store->summary) != 0; -} - -static gboolean -imap_connect_online (CamelService *service, CamelException *ex) -{ - CamelImapStore *store = CAMEL_IMAP_STORE (service); - CamelDiscoStore *disco_store = CAMEL_DISCO_STORE (service); - CamelImapResponse *response; - struct _namespaces *namespaces; - char *result, *name, *path; - int i; - size_t len; - CamelImapStoreNamespace *ns; - - CAMEL_SERVICE_LOCK (store, connect_lock); - if (!connect_to_server_wrapper (service, ex) || - !imap_auth_loop (service, ex)) { - CAMEL_SERVICE_UNLOCK (store, connect_lock); - camel_service_disconnect (service, TRUE, NULL); - return FALSE; - } - - /* Get namespace and hierarchy separator */ - if ((store->capabilities & IMAP_CAPABILITY_NAMESPACE) && - !(store->parameters & IMAP_PARAM_OVERRIDE_NAMESPACE)) { - response = camel_imap_command (store, NULL, ex, "NAMESPACE"); - if (!response) - goto done; - - result = camel_imap_response_extract (store, response, "NAMESPACE", ex); - if (!result) - goto done; - - /* new code... */ - namespaces = imap_parse_namespace_response (result); - imap_namespaces_destroy (namespaces); - /* end new code */ - - name = strstrcase (result, "NAMESPACE (("); - if (name) { - char *sep; - - name += 12; - store->namespace = imap_parse_string ((const char **) &name, &len); - if (name && *name++ == ' ') { - sep = imap_parse_string ((const char **) &name, &len); - if (sep) { - store->dir_sep = *sep; - ((CamelStore *)store)->dir_sep = store->dir_sep; - g_free (sep); - } - } - } - g_free (result); - } - - if (!store->namespace) - store->namespace = g_strdup (""); - - if (!store->dir_sep) { - if (store->server_level >= IMAP_LEVEL_IMAP4REV1) { - /* This idiom means "tell me the hierarchy separator - * for the given path, even if that path doesn't exist. - */ - response = camel_imap_command (store, NULL, ex, - "LIST %S \"\"", - store->namespace); - } else { - /* Plain IMAP4 doesn't have that idiom, so we fall back - * to "tell me about this folder", which will fail if - * the folder doesn't exist (eg, if namespace is ""). - */ - response = camel_imap_command (store, NULL, ex, - "LIST \"\" %S", - store->namespace); - } - if (!response) - goto done; - - result = camel_imap_response_extract (store, response, "LIST", NULL); - if (result) { - imap_parse_list_response (store, result, NULL, &store->dir_sep, NULL); - g_free (result); - } - if (!store->dir_sep) { - store->dir_sep = '/'; /* Guess */ - ((CamelStore *)store)->dir_sep = store->dir_sep; - } - } - - /* canonicalize the namespace to end with dir_sep */ - len = strlen (store->namespace); - if (len && store->namespace[len - 1] != store->dir_sep) { - gchar *tmp; - - tmp = g_strdup_printf ("%s%c", store->namespace, store->dir_sep); - g_free (store->namespace); - store->namespace = tmp; - } - - ns = camel_imap_store_summary_namespace_new(store->summary, store->namespace, store->dir_sep); - camel_imap_store_summary_namespace_set(store->summary, ns); - - if (CAMEL_STORE (store)->flags & CAMEL_STORE_SUBSCRIPTIONS) { - GPtrArray *folders; - - /* this pre-fills the summary, and checks that lsub is useful */ - folders = g_ptr_array_new(); - get_folders_online(store, "*", folders, TRUE, ex); - for (i=0;i<folders->len;i++) { - CamelFolderInfo *fi = folders->pdata[i]; - - if (fi->flags & (CAMEL_IMAP_FOLDER_MARKED | CAMEL_IMAP_FOLDER_UNMARKED)) - store->capabilities |= IMAP_CAPABILITY_useful_lsub; - camel_folder_info_free(fi); - } - g_ptr_array_free(folders, TRUE); - } - - path = g_strdup_printf ("%s/journal", store->storage_path); - disco_store->diary = camel_disco_diary_new (disco_store, path, ex); - g_free (path); - - done: - /* save any changes we had */ - camel_store_summary_save((CamelStoreSummary *)store->summary); - - CAMEL_SERVICE_UNLOCK (store, connect_lock); - - if (camel_exception_is_set (ex)) - camel_service_disconnect (service, TRUE, NULL); - else if (camel_disco_diary_empty (disco_store->diary)) - imap_store_refresh_folders (store, ex); - - return !camel_exception_is_set (ex); -} - -static gboolean -imap_connect_offline (CamelService *service, CamelException *ex) -{ - CamelImapStore *store = CAMEL_IMAP_STORE (service); - CamelDiscoStore *disco_store = CAMEL_DISCO_STORE (service); - char *path; - - path = g_strdup_printf ("%s/journal", store->storage_path); - disco_store->diary = camel_disco_diary_new (disco_store, path, ex); - g_free (path); - if (!disco_store->diary) - return FALSE; - - imap_store_refresh_folders (store, ex); - - store->connected = !camel_exception_is_set (ex); - return store->connected; -} - -static gboolean -imap_disconnect_offline (CamelService *service, gboolean clean, CamelException *ex) -{ - CamelImapStore *store = CAMEL_IMAP_STORE (service); - CamelDiscoStore *disco = CAMEL_DISCO_STORE (service); - - store->connected = FALSE; - if (store->current_folder) { - camel_object_unref (CAMEL_OBJECT (store->current_folder)); - store->current_folder = NULL; - } - - if (store->authtypes) { - g_hash_table_foreach_remove (store->authtypes, - free_key, NULL); - g_hash_table_destroy (store->authtypes); - store->authtypes = NULL; - } - - if (store->namespace && !(store->parameters & IMAP_PARAM_OVERRIDE_NAMESPACE)) { - g_free (store->namespace); - store->namespace = NULL; - } - - if (disco->diary) { - camel_object_unref (CAMEL_OBJECT (disco->diary)); - disco->diary = NULL; - } - - return TRUE; -} - -static gboolean -imap_disconnect_online (CamelService *service, gboolean clean, CamelException *ex) -{ - CamelImapStore *store = CAMEL_IMAP_STORE (service); - CamelImapResponse *response; - - if (store->connected && clean) { - response = camel_imap_command (store, NULL, NULL, "LOGOUT"); - camel_imap_response_free (store, response); - } - - 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; - } - - imap_disconnect_offline (service, clean, ex); - - return TRUE; -} - - -static gboolean -imap_summary_is_dirty (CamelFolderSummary *summary) -{ - CamelMessageInfo *info; - int max, i; - - max = camel_folder_summary_count (summary); - for (i = 0; i < max; i++) { - info = camel_folder_summary_index (summary, i); - if (info && (info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED)) - return TRUE; - } - - return FALSE; -} - -static void -imap_noop (CamelStore *store, CamelException *ex) -{ - CamelImapStore *imap_store = (CamelImapStore *) store; - CamelDiscoStore *disco = (CamelDiscoStore *) store; - CamelImapResponse *response; - CamelFolder *current_folder; - - if (camel_disco_store_status (disco) != CAMEL_DISCO_STORE_ONLINE) - return; - - CAMEL_SERVICE_LOCK (imap_store, connect_lock); - - current_folder = imap_store->current_folder; - if (current_folder && imap_summary_is_dirty (current_folder->summary)) { - /* let's sync the flags instead */ - camel_folder_sync (current_folder, FALSE, ex); - } else { - response = camel_imap_command (imap_store, NULL, ex, "NOOP"); - if (response) - camel_imap_response_free (imap_store, response); - } - - CAMEL_SERVICE_UNLOCK (imap_store, connect_lock); -} - -static guint -hash_folder_name (gconstpointer key) -{ - if (g_strcasecmp (key, "INBOX") == 0) - return g_str_hash ("INBOX"); - else - return g_str_hash (key); -} - -static gint -compare_folder_name (gconstpointer a, gconstpointer b) -{ - gconstpointer aname = a, bname = b; - - if (g_strcasecmp (a, "INBOX") == 0) - aname = "INBOX"; - if (g_strcasecmp (b, "INBOX") == 0) - bname = "INBOX"; - return g_str_equal (aname, bname); -} - -static CamelFolder * -no_such_folder (const char *name, CamelException *ex) -{ - camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("No such folder %s"), name); - return NULL; -} - -static int -get_folder_status (CamelImapStore *imap_store, const char *folder_name, const char *type) -{ - CamelImapResponse *response; - char *status, *p; - int out; - - /* FIXME: we assume the server is STATUS-capable */ - - response = camel_imap_command (imap_store, NULL, NULL, - "STATUS %F (%s)", - folder_name, - type); - - if (!response) { - CamelException ex; - - camel_exception_init (&ex); - if (imap_check_folder_still_extant (imap_store, folder_name, &ex) == FALSE) { - imap_folder_effectively_unsubscribed (imap_store, folder_name, &ex); - imap_forget_folder (imap_store, folder_name, &ex); - } - camel_exception_clear (&ex); - return -1; - } - - status = camel_imap_response_extract (imap_store, response, - "STATUS", NULL); - if (!status) - return -1; - - p = strstrcase (status, type); - if (p) - out = strtoul (p + strlen (type), NULL, 10); - else - out = -1; - - g_free (status); - return out; -} - -static CamelFolder * -get_folder_online (CamelStore *store, const char *folder_name, - guint32 flags, CamelException *ex) -{ - CamelImapStore *imap_store = CAMEL_IMAP_STORE (store); - CamelImapResponse *response; - CamelFolder *new_folder; - char *folder_dir, *storage_path; - - if (!camel_imap_store_connected (imap_store, ex)) - return NULL; - - if (!g_strcasecmp (folder_name, "INBOX")) - folder_name = "INBOX"; - - /* Lock around the whole lot to check/create atomically */ - CAMEL_SERVICE_LOCK (imap_store, connect_lock); - if (imap_store->current_folder) { - camel_object_unref (CAMEL_OBJECT (imap_store->current_folder)); - imap_store->current_folder = NULL; - } - response = camel_imap_command (imap_store, NULL, NULL, "SELECT %F", folder_name); - if (!response) { - char *folder_real; - - if (!flags & CAMEL_STORE_FOLDER_CREATE) { - CAMEL_SERVICE_UNLOCK (imap_store, connect_lock); - return no_such_folder (folder_name, ex); - } - - folder_real = camel_imap_store_summary_path_to_full(imap_store->summary, folder_name, store->dir_sep); - - response = camel_imap_command (imap_store, NULL, ex, "CREATE %S", folder_real); - - if (response) { - camel_imap_store_summary_add_from_full(imap_store->summary, folder_real, store->dir_sep); - - camel_imap_response_free (imap_store, response); - - response = camel_imap_command (imap_store, NULL, NULL, "SELECT %F", folder_name); - } - g_free(folder_real); - if (!response) { - CAMEL_SERVICE_UNLOCK (imap_store, connect_lock); - return NULL; - } - } - - storage_path = g_strdup_printf("%s/folders", imap_store->storage_path); - folder_dir = e_path_to_physical (storage_path, folder_name); - g_free(storage_path); - new_folder = camel_imap_folder_new (store, folder_name, folder_dir, ex); - g_free (folder_dir); - if (new_folder) { - CamelException local_ex; - - imap_store->current_folder = new_folder; - camel_object_ref (CAMEL_OBJECT (new_folder)); - camel_exception_init (&local_ex); - camel_imap_folder_selected (new_folder, response, &local_ex); - - if (camel_exception_is_set (&local_ex)) { - camel_exception_xfer (ex, &local_ex); - camel_object_unref (CAMEL_OBJECT (imap_store->current_folder)); - imap_store->current_folder = NULL; - camel_object_unref (CAMEL_OBJECT (new_folder)); - new_folder = NULL; - } - } - camel_imap_response_free_without_processing (imap_store, response); - - CAMEL_SERVICE_UNLOCK (imap_store, connect_lock); - - return new_folder; -} - -static CamelFolder * -get_folder_offline (CamelStore *store, const char *folder_name, - guint32 flags, CamelException *ex) -{ - CamelImapStore *imap_store = CAMEL_IMAP_STORE (store); - CamelFolder *new_folder; - char *folder_dir, *storage_path; - - if (!imap_store->connected && - !camel_service_connect (CAMEL_SERVICE (store), ex)) - return NULL; - - if (!g_strcasecmp (folder_name, "INBOX")) - folder_name = "INBOX"; - - storage_path = g_strdup_printf("%s/folders", imap_store->storage_path); - folder_dir = e_path_to_physical (storage_path, folder_name); - g_free(storage_path); - if (!folder_dir || access (folder_dir, F_OK) != 0) { - g_free (folder_dir); - camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("No such folder %s"), folder_name); - return NULL; - } - - new_folder = camel_imap_folder_new (store, folder_name, folder_dir, ex); - g_free (folder_dir); - - return new_folder; -} - -static void -delete_folder (CamelStore *store, const char *folder_name, CamelException *ex) -{ - CamelImapStore *imap_store = CAMEL_IMAP_STORE (store); - CamelImapResponse *response; - - if (!camel_disco_store_check_online (CAMEL_DISCO_STORE (store), ex)) - return; - - /* make sure this folder isn't currently SELECTed */ - response = camel_imap_command (imap_store, NULL, ex, "SELECT INBOX"); - if (response) { - camel_imap_response_free_without_processing (imap_store, response); - - CAMEL_SERVICE_LOCK (imap_store, connect_lock); - - if (imap_store->current_folder) - camel_object_unref (CAMEL_OBJECT (imap_store->current_folder)); - /* no need to actually create a CamelFolder for INBOX */ - imap_store->current_folder = NULL; - - CAMEL_SERVICE_UNLOCK (imap_store, connect_lock); - } else - return; - - response = camel_imap_command (imap_store, NULL, ex, "DELETE %F", - folder_name); - - if (response) { - camel_imap_response_free (imap_store, response); - imap_forget_folder (imap_store, folder_name, ex); - } -} - -static void -manage_subscriptions (CamelStore *store, const char *old_name, gboolean subscribe) -{ - CamelImapStore *imap_store = CAMEL_IMAP_STORE (store); - CamelStoreInfo *si; - int olen = strlen(old_name); - const char *path; - int i, count; - - count = camel_store_summary_count((CamelStoreSummary *)imap_store->summary); - for (i=0;i<count;i++) { - si = camel_store_summary_index((CamelStoreSummary *)imap_store->summary, i); - if (si) { - path = camel_store_info_path(imap_store->summary, si); - if (strncmp(path, old_name, olen) == 0) { - if (subscribe) - subscribe_folder(store, path, NULL); - else - unsubscribe_folder(store, path, NULL); - } - camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si); - } - } -} - -static void -rename_folder_info (CamelImapStore *imap_store, const char *old_name, const char *new_name) -{ - int i, count; - CamelStoreInfo *si; - int olen = strlen(old_name); - const char *path; - char *npath, *nfull; - - count = camel_store_summary_count((CamelStoreSummary *)imap_store->summary); - for (i=0;i<count;i++) { - si = camel_store_summary_index((CamelStoreSummary *)imap_store->summary, i); - if (si == NULL) - continue; - path = camel_store_info_path(imap_store->summary, si); - if (strncmp(path, old_name, olen) == 0) { - if (strlen(path) > olen) - npath = g_strdup_printf("%s/%s", new_name, path+olen+1); - else - npath = g_strdup(new_name); - nfull = camel_imap_store_summary_path_to_full(imap_store->summary, npath, imap_store->dir_sep); - - /* workaround for broken server (courier uses '.') that doesn't rename - subordinate folders as required by rfc 2060 */ - if (imap_store->dir_sep == '.') { - CamelImapResponse *response; - - response = camel_imap_command (imap_store, NULL, NULL, "RENAME %F %S", path, nfull); - if (response) - camel_imap_response_free (imap_store, response); - } - - camel_store_info_set_string((CamelStoreSummary *)imap_store->summary, si, CAMEL_STORE_INFO_PATH, npath); - camel_store_info_set_string((CamelStoreSummary *)imap_store->summary, si, CAMEL_IMAP_STORE_INFO_FULL_NAME, nfull); - - camel_store_summary_touch((CamelStoreSummary *)imap_store->summary); - g_free(nfull); - g_free(npath); - } - camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si); - } -} - -static void -rename_folder (CamelStore *store, const char *old_name, const char *new_name_in, CamelException *ex) -{ - CamelImapStore *imap_store = CAMEL_IMAP_STORE (store); - CamelImapResponse *response; - char *oldpath, *newpath, *storage_path, *new_name; - - if (!camel_disco_store_check_online (CAMEL_DISCO_STORE (store), ex)) - return; - - /* make sure this folder isn't currently SELECTed - it's - actually possible to rename INBOX but if you do another - INBOX will immediately be created by the server */ - response = camel_imap_command (imap_store, NULL, ex, "SELECT INBOX"); - if (response) { - camel_imap_response_free_without_processing (imap_store, response); - - CAMEL_SERVICE_LOCK (imap_store, connect_lock); - - if (imap_store->current_folder) - camel_object_unref (CAMEL_OBJECT (imap_store->current_folder)); - /* no need to actually create a CamelFolder for INBOX */ - imap_store->current_folder = NULL; - - CAMEL_SERVICE_UNLOCK (imap_store, connect_lock); - } else - return; - - imap_store->renaming = TRUE; - - if (store->flags & CAMEL_STORE_SUBSCRIPTIONS) - manage_subscriptions(store, old_name, FALSE); - - new_name = camel_imap_store_summary_path_to_full(imap_store->summary, new_name_in, store->dir_sep); - response = camel_imap_command (imap_store, NULL, ex, "RENAME %F %S", old_name, new_name); - - if (!response) { - if (store->flags & CAMEL_STORE_SUBSCRIPTIONS) - manage_subscriptions(store, old_name, TRUE); - g_free(new_name); - imap_store->renaming = FALSE; - return; - } - - camel_imap_response_free (imap_store, response); - - /* rename summary, and handle broken server */ - rename_folder_info(imap_store, old_name, new_name_in); - - if (store->flags & CAMEL_STORE_SUBSCRIPTIONS) - manage_subscriptions(store, new_name_in, TRUE); - - storage_path = g_strdup_printf("%s/folders", imap_store->storage_path); - oldpath = e_path_to_physical (storage_path, old_name); - newpath = e_path_to_physical (storage_path, new_name_in); - g_free(storage_path); - - /* So do we care if this didn't work? Its just a cache? */ - if (rename (oldpath, newpath) == -1) { - g_warning ("Could not rename message cache '%s' to '%s': %s: cache reset", - oldpath, newpath, strerror (errno)); - } - - g_free (oldpath); - g_free (newpath); - g_free(new_name); - - imap_store->renaming = FALSE; -} - -static CamelFolderInfo * -create_folder (CamelStore *store, const char *parent_name, - const char *folder_name, CamelException *ex) -{ - CamelImapStore *imap_store = CAMEL_IMAP_STORE (store); - char *full_name, *resp, *thisone, *parent_real, *real_name; - CamelImapResponse *response; - CamelException internal_ex; - CamelFolderInfo *root = NULL; - gboolean need_convert; - int i = 0, flags; - - if (!camel_disco_store_check_online (CAMEL_DISCO_STORE (store), ex)) - return NULL; - if (!parent_name) - parent_name = ""; - - if (strchr (folder_name, imap_store->dir_sep)) { - camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID_PATH, - _("The folder name \"%s\" is invalid because " - "it containes the character \"%c\""), - folder_name, imap_store->dir_sep); - return NULL; - } - - /* check if the parent allows inferiors */ - - /* FIXME: use storesummary directly */ - parent_real = camel_imap_store_summary_full_from_path(imap_store->summary, parent_name); - if (parent_real == NULL) { - camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_STATE, - _("Unknown parent folder: %s"), parent_name); - return NULL; - } - - need_convert = FALSE; - response = camel_imap_command (imap_store, NULL, ex, "LIST \"\" %S", - parent_real); - if (!response) /* whoa, this is bad */ { - g_free(parent_real); - return NULL; - } - - /* FIXME: does not handle unexpected circumstances very well */ - for (i = 0; i < response->untagged->len; i++) { - resp = response->untagged->pdata[i]; - - if (!imap_parse_list_response (imap_store, resp, &flags, NULL, &thisone)) - continue; - - if (strcmp (thisone, parent_name) == 0) { - if (flags & CAMEL_FOLDER_NOINFERIORS) - need_convert = TRUE; - break; - } - } - - camel_imap_response_free (imap_store, response); - - camel_exception_init (&internal_ex); - - /* if not, check if we can delete it and recreate it */ - if (need_convert) { - char *name; - - if (get_folder_status (imap_store, parent_name, "MESSAGES")) { - camel_exception_set (ex, CAMEL_EXCEPTION_FOLDER_INVALID_STATE, - _("The parent folder is not allowed to contain subfolders")); - g_free(parent_real); - return NULL; - } - - /* delete the old parent and recreate it */ - delete_folder (store, parent_name, &internal_ex); - if (camel_exception_is_set (&internal_ex)) { - camel_exception_xfer (ex, &internal_ex); - return NULL; - } - - /* add the dirsep to the end of parent_name */ - name = g_strdup_printf ("%s%c", parent_real, imap_store->dir_sep); - response = camel_imap_command (imap_store, NULL, ex, "CREATE %S", - name); - g_free (name); - - if (!response) { - g_free(parent_real); - return NULL; - } else - camel_imap_response_free (imap_store, response); - - root = imap_build_folder_info(imap_store, parent_name); - } - - /* ok now we can create the folder */ - real_name = camel_imap_store_summary_path_to_full(imap_store->summary, folder_name, store->dir_sep); - full_name = imap_concat (imap_store, parent_real, real_name); - g_free(real_name); - response = camel_imap_command (imap_store, NULL, ex, "CREATE %S", full_name); - - if (response) { - CamelImapStoreInfo *si; - CamelFolderInfo *fi; - - camel_imap_response_free (imap_store, response); - - si = camel_imap_store_summary_add_from_full(imap_store->summary, full_name, store->dir_sep); - camel_store_summary_save((CamelStoreSummary *)imap_store->summary); - fi = imap_build_folder_info(imap_store, camel_store_info_path(imap_store->summary, si)); - if (root) { - root->child = fi; - fi->parent = root; - } else { - root = fi; - } - camel_object_trigger_event (CAMEL_OBJECT (store), "folder_created", root); - } else if (root) { - /* need to re-recreate the folder we just deleted */ - camel_object_trigger_event (CAMEL_OBJECT (store), "folder_created", root); - camel_folder_info_free(root); - root = NULL; - } - - g_free (full_name); - g_free(parent_real); - - return root; -} - -static CamelFolderInfo * -parse_list_response_as_folder_info (CamelImapStore *imap_store, - const char *response) -{ - CamelFolderInfo *fi; - int flags, i; - char sep, *dir, *name = NULL, *path; - CamelURL *url; - - if (!imap_parse_list_response (imap_store, response, &flags, &sep, &dir)) - return NULL; - - /* FIXME: should use imap_build_folder_info, note the differences with param setting tho */ - path = camel_utf7_utf8(dir); - - /* hack: pokes in value from any list response */ - camel_imap_store_summary_add_from_full(imap_store->summary, dir, sep?sep:'/'); - - if (sep && (name = strrchr(path, sep))) { - if (!*++name) { - g_free(dir); - g_free(path); - return NULL; - } - } else - name = path; - - fi = g_new0 (CamelFolderInfo, 1); - fi->flags = flags; - /*fi->full_name = dir;*/ - fi->name = g_strdup(name); - fi->path = g_strdup_printf("/%s", path); - - if (sep && sep != '/') { - for (i=0;fi->path[i];i++) - if (fi->path[i] == sep) - fi->path[i] = '/'; - } - fi->full_name = g_strdup(fi->path+1); - - url = camel_url_new (imap_store->base_url, NULL); - g_free (url->path); - url->path = g_strdup_printf ("/%s", fi->full_name); - - if (flags & CAMEL_FOLDER_NOSELECT || fi->name[0] == 0) - camel_url_set_param (url, "noselect", "yes"); - fi->url = camel_url_to_string (url, 0); - camel_url_free (url); - - /* FIXME: redundant */ - if (flags & CAMEL_IMAP_FOLDER_UNMARKED) - fi->unread_message_count = -1; - - return fi; -} - -/* this is used when lsub doesn't provide very useful information */ -static GPtrArray * -get_subscribed_folders (CamelImapStore *imap_store, const char *top, CamelException *ex) -{ - GPtrArray *names, *folders; - int i, toplen = strlen (top); - CamelStoreInfo *si; - CamelImapResponse *response; - CamelFolderInfo *fi; - char *result; - - folders = g_ptr_array_new (); - names = g_ptr_array_new (); - for (i=0;(si = camel_store_summary_index((CamelStoreSummary *)imap_store->summary, i));i++) { - if (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) - g_ptr_array_add(names, (char *)camel_imap_store_info_full_name(imap_store->summary, si)); - camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si); - } - - if (names->len == 0) - g_ptr_array_add (names, "INBOX"); - - for (i = 0; i < names->len; i++) { - response = camel_imap_command (imap_store, NULL, ex, - "LIST \"\" %S", - names->pdata[i]); - if (!response) - break; - - result = camel_imap_response_extract (imap_store, response, "LIST", NULL); - if (!result) { - camel_store_summary_remove_path((CamelStoreSummary *)imap_store->summary, names->pdata[i]); - g_ptr_array_remove_index_fast (names, i); - i--; - continue; - } - - fi = parse_list_response_as_folder_info (imap_store, result); - if (!fi) - continue; - - if (strncmp (top, fi->full_name, toplen) != 0) { - camel_folder_info_free (fi); - continue; - } - - g_ptr_array_add (folders, fi); - } - - g_ptr_array_free (names, TRUE); - - return folders; -} - -static int imap_match_pattern(char dir_sep, const char *pattern, const char *name) -{ - char p, n; - - p = *pattern++; - n = *name++; - while (n && p) { - if (n == p) { - p = *pattern++; - n = *name++; - } else if (p == '%') { - if (n != dir_sep) { - n = *name++; - } else { - p = *pattern++; - } - } else if (p == '*') { - return TRUE; - } else - return FALSE; - } - - return n == 0 && (p == '%' || p == 0); -} - -static void -get_folders_online (CamelImapStore *imap_store, const char *pattern, - GPtrArray *folders, gboolean lsub, CamelException *ex) -{ - CamelImapResponse *response; - CamelFolderInfo *fi; - char *list; - int i, count; - GHashTable *present; - CamelStoreInfo *si; - - response = camel_imap_command (imap_store, NULL, ex, - "%s \"\" %S", lsub ? "LSUB" : "LIST", - pattern); - if (!response) - return; - - present = g_hash_table_new(g_str_hash, g_str_equal); - for (i = 0; i < response->untagged->len; i++) { - list = response->untagged->pdata[i]; - fi = parse_list_response_as_folder_info (imap_store, list); - if (fi) { - g_ptr_array_add(folders, fi); - g_hash_table_insert(present, fi->full_name, fi); - } - } - camel_imap_response_free (imap_store, response); - - /* update our summary to match the server */ - count = camel_store_summary_count((CamelStoreSummary *)imap_store->summary); - for (i=0;i<count;i++) { - si = camel_store_summary_index((CamelStoreSummary *)imap_store->summary, i); - if (si == NULL) - continue; - - if (imap_match_pattern(((CamelStore *)imap_store)->dir_sep, pattern, camel_imap_store_info_full_name(imap_store->summary, si))) { - if (g_hash_table_lookup(present, camel_store_info_path(imap_store->summary, si)) != NULL) { - if (lsub && (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) == 0) { - si->flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED; - camel_store_summary_touch((CamelStoreSummary *)imap_store->summary); - } - } else { - if (lsub) { - if (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) { - si->flags &= ~CAMEL_STORE_INFO_FOLDER_SUBSCRIBED; - camel_store_summary_touch((CamelStoreSummary *)imap_store->summary); - } - } else { - camel_store_summary_remove((CamelStoreSummary *)imap_store->summary, si); - count--; - i--; - } - } - } - camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si); - } - g_hash_table_destroy(present); -} - -#if 1 -static void -dumpfi(CamelFolderInfo *fi) -{ - int depth; - CamelFolderInfo *n = fi; - - if (fi == NULL) - return; - - depth = 0; - while (n->parent) { - depth++; - n = n->parent; - } - - while (fi) { - printf("%-40s %-30s %*s\n", fi->path, fi->full_name, depth*2+strlen(fi->url), fi->url); - if (fi->child) - dumpfi(fi->child); - fi = fi->sibling; - } -} -#endif - -static void -get_folder_counts(CamelImapStore *imap_store, CamelFolderInfo *fi, CamelException *ex) -{ - GSList *q; - - /* non-recursive breath first search */ - - q = g_slist_append(NULL, fi); - - while (q) { - fi = q->data; - q = g_slist_remove_link(q, q); - - while (fi) { - /* ignore noselect folders, and check only inbox if we only check inbox */ - if ((fi->flags & CAMEL_FOLDER_NOSELECT) == 0 - && ( (imap_store->parameters & IMAP_PARAM_CHECK_ALL) - || strcasecmp(fi->full_name, "inbox") == 0) ) { - - CAMEL_SERVICE_LOCK (imap_store, connect_lock); - /* For the current folder, poke it to check for new - * messages and then report that number, rather than - * doing a STATUS command. - */ - if (imap_store->current_folder && strcmp(imap_store->current_folder->full_name, fi->full_name) == 0) { - /* we bypass the folder locking otherwise we can deadlock. we use the command lock for - any operations anyway so this is 'safe'. See comment above imap_store_refresh_folders() for info */ - CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(imap_store->current_folder))->refresh_info(imap_store->current_folder, ex); - fi->unread_message_count = camel_folder_get_unread_message_count (imap_store->current_folder); - } else - fi->unread_message_count = get_folder_status (imap_store, fi->full_name, "UNSEEN"); - - CAMEL_SERVICE_UNLOCK (imap_store, connect_lock); - } else { - fi->unread_message_count = -1; - } - - if (fi->child) - q = g_slist_append(q, fi->child); - fi = fi->sibling; - } - } -} - -/* imap needs to treat inbox case insensitive */ -/* we'll assume the names are normalised already */ -static guint folder_hash(const void *ap) -{ - const char *a = ap; - - if (strcasecmp(a, "INBOX") == 0) - a = "INBOX"; - - return g_str_hash(a); -} - -static int folder_eq(const void *ap, const void *bp) -{ - const char *a = ap; - const char *b = bp; - - if (strcasecmp(a, "INBOX") == 0) - a = "INBOX"; - if (strcasecmp(b, "INBOX") == 0) - b = "INBOX"; - - return g_str_equal(a, b); -} - -static GPtrArray * -get_folders(CamelStore *store, const char *top, guint32 flags, CamelException *ex) -{ - CamelImapStore *imap_store = CAMEL_IMAP_STORE (store); - GSList *p = NULL; - GHashTable *infos; - int i; - GPtrArray *folders, *folders_out; - CamelFolderInfo *fi; - char *name; - int depth = 0; - int haveinbox = 0; - static int imap_max_depth = 0; - - if (!camel_imap_store_connected (imap_store, ex)) - return NULL; - - /* allow megalomaniacs to override the max of 10 */ - if (imap_max_depth == 0) { - name = getenv("CAMEL_IMAP_MAX_DEPTH"); - if (name) { - imap_max_depth = atoi (name); - imap_max_depth = MIN (MAX (imap_max_depth, 0), 2); - } else - imap_max_depth = 10; - } - - infos = g_hash_table_new(folder_hash, folder_eq); - - /* get starting point & strip trailing '/' */ - if (top[0] == 0) { - if (imap_store->namespace) { - top = imap_store->namespace; - i = strlen(top)-1; - name = g_malloc(i+2); - strcpy(name, top); - while (i>0 && name[i] == store->dir_sep) - name[i--] = 0; - } else - name = g_strdup(""); - } else { - name = camel_imap_store_summary_full_from_path(imap_store->summary, top); - if (name == NULL) - name = camel_imap_store_summary_path_to_full(imap_store->summary, top, store->dir_sep); - } - - d(printf("\n\nList '%s' %s\n", name, flags&CAMEL_STORE_FOLDER_INFO_RECURSIVE?"RECURSIVE":"NON-RECURSIVE")); - - folders_out = g_ptr_array_new(); - folders = g_ptr_array_new(); - - /* first get working list of names */ - get_folders_online (imap_store, name[0]?name:"%", folders, flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, ex); - if (camel_exception_is_set(ex)) - goto fail; - for (i=0; i<folders->len && !haveinbox; i++) { - fi = folders->pdata[i]; - haveinbox = (strcasecmp(fi->full_name, "INBOX")) == 0; - } - - if (!haveinbox && top == imap_store->namespace) { - get_folders_online(imap_store, "INBOX", folders, flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, ex); - if (camel_exception_is_set(ex)) - goto fail; - } - - for (i=0; i<folders->len; i++) - p = g_slist_prepend(p, folders->pdata[i]); - - g_ptr_array_set_size(folders, 0); - - /* p is a reversed list of pending folders for the next level, q is the list of folders for this */ - while (p) { - GSList *q = g_slist_reverse(p); - - p = NULL; - while (q) { - fi = q->data; - - q = g_slist_remove_link(q, q); - g_ptr_array_add(folders_out, fi); - - d(printf("Checking folder '%s'\n", fi->full_name)); - - /* First if we're not recursive mode on the top level, and we know it has or doesn't - or can't have children, no need to go further - a bit ugly */ - if ( top == imap_store->namespace - && (flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE) == 0 - && (fi->flags & (CAMEL_FOLDER_CHILDREN|CAMEL_IMAP_FOLDER_NOCHILDREN|CAMEL_FOLDER_NOINFERIORS)) != 0) { - /* do nothing */ - } - /* Otherwise, if this has (or might have) children, scan it */ - else if ( (fi->flags & (CAMEL_IMAP_FOLDER_NOCHILDREN|CAMEL_FOLDER_NOINFERIORS)) == 0 - || (fi->flags & CAMEL_FOLDER_CHILDREN) != 0) { - char *n, *real; - - real = camel_imap_store_summary_full_from_path(imap_store->summary, fi->full_name); - n = imap_concat(imap_store, real?real:fi->full_name, "%"); - get_folders_online(imap_store, n, folders, flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, ex); - g_free(n); - g_free(real); - - if (folders->len > 0) - fi->flags |= CAMEL_FOLDER_CHILDREN; - - for (i=0;i<folders->len;i++) { - fi = folders->pdata[i]; - if (g_hash_table_lookup(infos, fi->full_name) == NULL) { - g_hash_table_insert(infos, fi->full_name, fi); - if ((flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE) && depth<imap_max_depth) - p = g_slist_prepend(p, fi); - else - g_ptr_array_add(folders_out, fi); - } else { - camel_folder_info_free(fi); - } - } - g_ptr_array_set_size(folders, 0); - } - } - depth++; - } - - g_ptr_array_free(folders, TRUE); - g_hash_table_destroy(infos); - g_free(name); - - return folders_out; -fail: - g_ptr_array_free(folders, TRUE); - g_ptr_array_free(folders_out, TRUE); - g_hash_table_destroy(infos); - g_free(name); - - return NULL; -} - -static CamelFolderInfo * -get_folder_info_online (CamelStore *store, const char *top, guint32 flags, CamelException *ex) -{ - CamelImapStore *imap_store = CAMEL_IMAP_STORE (store); - GPtrArray *folders; - CamelFolderInfo *tree; - - if (top == NULL) - top = ""; - - if ((flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) - && !(imap_store->capabilities & IMAP_CAPABILITY_useful_lsub) - && (imap_store->parameters & IMAP_PARAM_CHECK_ALL)) - folders = get_subscribed_folders(imap_store, top, ex); - else - folders = get_folders(store, top, flags, ex); - - if (folders == NULL) - return NULL; - - /* note the weird top stuff, it is so a namespace based list "" is properly tree-ised */ - tree = camel_folder_info_build(folders, top[0] == 0 && imap_store->namespace?"":top, '/', TRUE); - g_ptr_array_free(folders, TRUE); - - if (!(flags & CAMEL_STORE_FOLDER_INFO_FAST)) - get_folder_counts(imap_store, tree, ex); - - dumpfi(tree); - camel_store_summary_save((CamelStoreSummary *)imap_store->summary); - - return tree; -} - -static gboolean -get_one_folder_offline (const char *physical_path, const char *path, gpointer data) -{ - GPtrArray *folders = data; - CamelImapStore *imap_store = folders->pdata[0]; - CamelFolderInfo *fi; - CamelStoreInfo *si; - - if (*path != '/') - return TRUE; - - /* folder_info_build will insert parent nodes as necessary and mark - * them as noselect, which is information we actually don't have at - * the moment. So let it do the right thing by bailing out if it's - * not a folder we're explicitly interested in. - */ - - si = camel_store_summary_path((CamelStoreSummary *)imap_store->summary, path+1); - if (si) { - if ((((CamelStore *)imap_store)->flags & CAMEL_STORE_SUBSCRIPTIONS) == 0 - || si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) { - fi = imap_build_folder_info(imap_store, path+1); - g_ptr_array_add (folders, fi); - } - camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si); - } - - return TRUE; -} - -static CamelFolderInfo * -get_folder_info_offline (CamelStore *store, const char *top, - guint32 flags, CamelException *ex) -{ - CamelImapStore *imap_store = CAMEL_IMAP_STORE (store); - CamelFolderInfo *fi; - GPtrArray *folders; - char *storage_path; - - if (!imap_store->connected && - !camel_service_connect (CAMEL_SERVICE (store), ex)) - return NULL; - - if ((store->flags & CAMEL_STORE_SUBSCRIPTIONS) && - !(flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED)) { - camel_disco_store_check_online (CAMEL_DISCO_STORE (store), ex); - return NULL; - } - - /* FIXME: obey other flags */ - - folders = g_ptr_array_new (); - - /* A kludge to avoid having to pass a struct to the callback */ - g_ptr_array_add (folders, imap_store); - storage_path = g_strdup_printf("%s/folders", imap_store->storage_path); - if (!e_path_find_folders (storage_path, get_one_folder_offline, folders)) { - camel_disco_store_check_online (CAMEL_DISCO_STORE (imap_store), ex); - fi = NULL; - } else { - g_ptr_array_remove_index_fast (folders, 0); - fi = camel_folder_info_build (folders, "", '/', TRUE); - } - g_free(storage_path); - - g_ptr_array_free (folders, TRUE); - return fi; -} - -static gboolean -folder_subscribed (CamelStore *store, const char *folder_name) -{ - CamelImapStore *imap_store = CAMEL_IMAP_STORE (store); - CamelStoreInfo *si; - int truth = FALSE; - - si = camel_store_summary_path((CamelStoreSummary *)imap_store->summary, folder_name); - if (si) { - truth = (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) != 0; - camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si); - } - - return truth; -} - -/* Note: folder_name must match a folder as listed with get_folder_info() -> full_name */ -static void -subscribe_folder (CamelStore *store, const char *folder_name, - CamelException *ex) -{ - CamelImapStore *imap_store = CAMEL_IMAP_STORE (store); - CamelImapResponse *response; - CamelFolderInfo *fi; - CamelStoreInfo *si; - - if (!camel_disco_store_check_online (CAMEL_DISCO_STORE (store), ex)) - return; - if (!camel_imap_store_connected (imap_store, ex)) - return; - - response = camel_imap_command (imap_store, NULL, ex, - "SUBSCRIBE %F", folder_name); - if (!response) - return; - camel_imap_response_free (imap_store, response); - - si = camel_store_summary_path((CamelStoreSummary *)imap_store->summary, folder_name); - if (si) { - if ((si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) == 0) { - si->flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED; - camel_store_summary_touch((CamelStoreSummary *)imap_store->summary); - camel_store_summary_save((CamelStoreSummary *)imap_store->summary); - } - camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si); - } - - if (imap_store->renaming) { - /* we don't need to emit a "folder_subscribed" signal - if we are in the process of renaming folders, so we - are done here... */ - return; - } - - fi = imap_build_folder_info(imap_store, folder_name); - camel_object_trigger_event (CAMEL_OBJECT (store), "folder_subscribed", fi); - camel_folder_info_free (fi); -} - -static void -unsubscribe_folder (CamelStore *store, const char *folder_name, - CamelException *ex) -{ - CamelImapStore *imap_store = CAMEL_IMAP_STORE (store); - CamelImapResponse *response; - - if (!camel_disco_store_check_online (CAMEL_DISCO_STORE (store), ex)) - return; - if (!camel_imap_store_connected (imap_store, ex)) - return; - - response = camel_imap_command (imap_store, NULL, ex, - "UNSUBSCRIBE %F", folder_name); - if (!response) - return; - camel_imap_response_free (imap_store, response); - - imap_folder_effectively_unsubscribed (imap_store, folder_name, ex); -} - -#if 0 -static gboolean -folder_flags_have_changed (CamelFolder *folder) -{ - CamelMessageInfo *info; - int i, max; - - max = camel_folder_summary_count (folder->summary); - for (i = 0; i < max; i++) { - info = camel_folder_summary_index (folder->summary, i); - if (!info) - continue; - if (info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) { - return TRUE; - } - } - - return FALSE; -} -#endif - - -gboolean -camel_imap_store_connected (CamelImapStore *store, CamelException *ex) -{ - if (store->istream == NULL || !store->connected) - return camel_service_connect (CAMEL_SERVICE (store), ex); - return TRUE; -} - - -/* FIXME: please god, when will the hurting stop? Thus function is so - fucking broken it's not even funny. */ -ssize_t -camel_imap_store_readline (CamelImapStore *store, char **dest, CamelException *ex) -{ - CamelStreamBuffer *stream; - char linebuf[1024]; - GByteArray *ba; - ssize_t nread; - - g_return_val_if_fail (CAMEL_IS_IMAP_STORE (store), -1); - g_return_val_if_fail (dest, -1); - - *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_imap_store_connected (store, ex)) { - camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_NOT_CONNECTED, - g_strerror (errno)); - return -1; - } - - stream = CAMEL_STREAM_BUFFER (store->istream); - - ba = g_byte_array_new (); - while ((nread = camel_stream_buffer_gets (stream, linebuf, sizeof (linebuf))) > 0) { - g_byte_array_append (ba, linebuf, nread); - if (linebuf[nread - 1] == '\n') - break; - } - - if (nread <= 0) { - if (errno == EINTR) - camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, _("Operation cancelled")); - else - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Server unexpectedly disconnected: %s"), - g_strerror (errno)); - - camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL); - g_byte_array_free (ba, TRUE); - return -1; - } - - if (camel_verbose_debug) { - fprintf (stderr, "received: "); - fwrite (ba->data, 1, ba->len, stderr); - } - - /* camel-imap-command.c:imap_read_untagged expects the CRLFs - to be stripped off and be nul-terminated *sigh* */ - nread = ba->len - 1; - ba->data[nread] = '\0'; - if (ba->data[nread - 1] == '\r') { - ba->data[nread - 1] = '\0'; - nread--; - } - - *dest = ba->data; - g_byte_array_free (ba, FALSE); - - return nread; -} diff --git a/camel/providers/imap/camel-imap-store.h b/camel/providers/imap/camel-imap-store.h deleted file mode 100644 index 38df1880a0..0000000000 --- a/camel/providers/imap/camel-imap-store.h +++ /dev/null @@ -1,146 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-imap-store.h : class for an imap store */ - -/* - * Authors: Jeffrey Stedfast <fejj@ximian.com> - * - * Copyright (C) 2000 Ximian, Inc. - * - * 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 - */ - - -#ifndef CAMEL_IMAP_STORE_H -#define CAMEL_IMAP_STORE_H 1 - - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus */ - -#include "camel-imap-types.h" -#include <camel/camel-disco-store.h> - -#ifdef ENABLE_THREADS -#include <e-util/e-msgport.h> - -typedef struct _CamelImapMsg CamelImapMsg; - -struct _CamelImapMsg { - EMsg msg; - - void (*receive)(CamelImapStore *store, struct _CamelImapMsg *m); - void (*free)(CamelImapStore *store, struct _CamelImapMsg *m); -}; - -CamelImapMsg *camel_imap_msg_new(void (*receive)(CamelImapStore *store, struct _CamelImapMsg *m), - void (*free)(CamelImapStore *store, struct _CamelImapMsg *m), - size_t size); -void camel_imap_msg_queue(CamelImapStore *store, CamelImapMsg *msg); - -#endif - -#define CAMEL_IMAP_STORE_TYPE (camel_imap_store_get_type ()) -#define CAMEL_IMAP_STORE(obj) (CAMEL_CHECK_CAST((obj), CAMEL_IMAP_STORE_TYPE, CamelImapStore)) -#define CAMEL_IMAP_STORE_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_IMAP_STORE_TYPE, CamelImapStoreClass)) -#define CAMEL_IS_IMAP_STORE(o) (CAMEL_CHECK_TYPE((o), CAMEL_IMAP_STORE_TYPE)) - -enum { - CAMEL_IMAP_STORE_ARG_FIRST = CAMEL_DISCO_STORE_ARG_FIRST + 100, - CAMEL_IMAP_STORE_ARG_NAMESPACE, - CAMEL_IMAP_STORE_ARG_OVERRIDE_NAMESPACE, - CAMEL_IMAP_STORE_ARG_CHECK_ALL, - CAMEL_IMAP_STORE_ARG_FILTER_INBOX -}; - -#define CAMEL_IMAP_STORE_NAMESPACE (CAMEL_IMAP_STORE_ARG_NAMESPACE | CAMEL_ARG_STR) -#define CAMEL_IMAP_STORE_OVERRIDE_NAMESPACE (CAMEL_IMAP_STORE_ARG_OVERRIDE_NAMESPACE | CAMEL_ARG_INT) -#define CAMEL_IMAP_STORE_CHECK_ALL (CAMEL_IMAP_STORE_ARG_CHECK_ALL | CAMEL_ARG_INT) -#define CAMEL_IMAP_STORE_FILTER_INBOX (CAMEL_IMAP_STORE_ARG_FILTER_INBOX | CAMEL_ARG_INT) - -/* CamelFolderInfo flags */ -#define CAMEL_IMAP_FOLDER_MARKED (1<<16) -#define CAMEL_IMAP_FOLDER_UNMARKED (1<<17) -#define CAMEL_IMAP_FOLDER_NOCHILDREN (1<<18) - - -typedef enum { - IMAP_LEVEL_UNKNOWN, - IMAP_LEVEL_IMAP4, - IMAP_LEVEL_IMAP4REV1 -} CamelImapServerLevel; - -#define IMAP_CAPABILITY_IMAP4 (1 << 0) -#define IMAP_CAPABILITY_IMAP4REV1 (1 << 1) -#define IMAP_CAPABILITY_STATUS (1 << 2) -#define IMAP_CAPABILITY_NAMESPACE (1 << 3) -#define IMAP_CAPABILITY_UIDPLUS (1 << 4) -#define IMAP_CAPABILITY_LITERALPLUS (1 << 5) -#define IMAP_CAPABILITY_STARTTLS (1 << 6) -#define IMAP_CAPABILITY_useful_lsub (1 << 7) -#define IMAP_CAPABILITY_utf8_search (1 << 8) - -#define IMAP_PARAM_OVERRIDE_NAMESPACE (1 << 0) -#define IMAP_PARAM_CHECK_ALL (1 << 1) -#define IMAP_PARAM_FILTER_INBOX (1 << 2) - -struct _CamelImapStore { - CamelDiscoStore parent_object; - - CamelStream *istream; - CamelStream *ostream; - - struct _CamelImapStoreSummary *summary; - - /* Information about the command channel / connection status */ - gboolean connected; - char tag_prefix; - guint32 command; - CamelFolder *current_folder; - - /* Information about the server */ - CamelImapServerLevel server_level; - guint32 capabilities, parameters; - char *namespace, dir_sep, *base_url, *storage_path; - GHashTable *authtypes; - - gboolean renaming; - -#ifdef ENABLE_THREADS - EThread *async_thread; -#endif -}; - - -typedef struct { - CamelDiscoStoreClass parent_class; - -} CamelImapStoreClass; - - -/* Standard Camel function */ -CamelType camel_imap_store_get_type (void); - - -gboolean camel_imap_store_connected (CamelImapStore *store, CamelException *ex); - -ssize_t camel_imap_store_readline (CamelImapStore *store, char **dest, CamelException *ex); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CAMEL_IMAP_STORE_H */ diff --git a/camel/providers/imap/camel-imap-summary.c b/camel/providers/imap/camel-imap-summary.c deleted file mode 100644 index dba1134fa1..0000000000 --- a/camel/providers/imap/camel-imap-summary.c +++ /dev/null @@ -1,255 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2000 Ximian Inc. - * - * Authors: - * Michael Zucchi <notzed@ximian.com> - * Dan Winship <danw@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/stat.h> -#include <sys/uio.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <stdlib.h> - -#include "camel-imap-summary.h" -#include "camel-file-utils.h" - -#define CAMEL_IMAP_SUMMARY_VERSION (0x300) - -static int summary_header_load (CamelFolderSummary *, FILE *); -static int summary_header_save (CamelFolderSummary *, FILE *); - -static CamelMessageInfo *message_info_load (CamelFolderSummary *s, FILE *in); -static int message_info_save (CamelFolderSummary *s, FILE *out, - CamelMessageInfo *info); -static CamelMessageContentInfo *content_info_load (CamelFolderSummary *s, FILE *in); -static int content_info_save (CamelFolderSummary *s, FILE *out, - CamelMessageContentInfo *info); - -static void camel_imap_summary_class_init (CamelImapSummaryClass *klass); -static void camel_imap_summary_init (CamelImapSummary *obj); - -static CamelFolderSummaryClass *camel_imap_summary_parent; - -CamelType -camel_imap_summary_get_type (void) -{ - static CamelType type = CAMEL_INVALID_TYPE; - - if (type == CAMEL_INVALID_TYPE) { - type = camel_type_register( - camel_folder_summary_get_type(), "CamelImapSummary", - sizeof (CamelImapSummary), - sizeof (CamelImapSummaryClass), - (CamelObjectClassInitFunc) camel_imap_summary_class_init, - NULL, - (CamelObjectInitFunc) camel_imap_summary_init, - NULL); - } - - return type; -} - -static void -camel_imap_summary_class_init (CamelImapSummaryClass *klass) -{ - CamelFolderSummaryClass *cfs_class = (CamelFolderSummaryClass *) klass; - - camel_imap_summary_parent = CAMEL_FOLDER_SUMMARY_CLASS (camel_type_get_global_classfuncs (camel_folder_summary_get_type())); - - cfs_class->summary_header_load = summary_header_load; - cfs_class->summary_header_save = summary_header_save; - cfs_class->message_info_load = message_info_load; - cfs_class->message_info_save = message_info_save; - cfs_class->content_info_load = content_info_load; - cfs_class->content_info_save = content_info_save; -} - -static void -camel_imap_summary_init (CamelImapSummary *obj) -{ - CamelFolderSummary *s = (CamelFolderSummary *)obj; - - /* subclasses need to set the right instance data sizes */ - s->message_info_size = sizeof(CamelImapMessageInfo); - s->content_info_size = sizeof(CamelImapMessageContentInfo); - - /* and a unique file version */ - s->version += CAMEL_IMAP_SUMMARY_VERSION; -} - -/** - * camel_imap_summary_new: - * @filename: the file to store the summary in. - * - * This will create a new CamelImapSummary object and read in the - * summary data from disk, if it exists. - * - * Return value: A new CamelImapSummary object. - **/ -CamelFolderSummary * -camel_imap_summary_new (const char *filename) -{ - CamelFolderSummary *summary = CAMEL_FOLDER_SUMMARY ( - camel_object_new (camel_imap_summary_get_type ())); - - camel_folder_summary_set_build_content (summary, TRUE); - camel_folder_summary_set_filename (summary, filename); - - if (camel_folder_summary_load (summary) == -1) { - camel_folder_summary_clear (summary); - camel_folder_summary_touch (summary); - } - - return summary; -} - - -static int -summary_header_load (CamelFolderSummary *s, FILE *in) -{ - CamelImapSummary *ims = CAMEL_IMAP_SUMMARY (s); - - if (camel_imap_summary_parent->summary_header_load (s, in) == -1) - return -1; - - return camel_file_util_decode_uint32 (in, &ims->validity); -} - -static int -summary_header_save (CamelFolderSummary *s, FILE *out) -{ - CamelImapSummary *ims = CAMEL_IMAP_SUMMARY(s); - - if (camel_imap_summary_parent->summary_header_save (s, out) == -1) - return -1; - - return camel_file_util_encode_uint32 (out, ims->validity); -} - - -static CamelMessageInfo * -message_info_load (CamelFolderSummary *s, FILE *in) -{ - CamelMessageInfo *info; - CamelImapMessageInfo *iinfo; - - info = camel_imap_summary_parent->message_info_load (s, in); - if (info) { - iinfo = (CamelImapMessageInfo *)info; - - if (camel_file_util_decode_uint32 (in, &iinfo->server_flags) == -1) - goto error; - } - - return info; -error: - camel_folder_summary_info_free (s, info); - return NULL; -} - -static int -message_info_save (CamelFolderSummary *s, FILE *out, CamelMessageInfo *info) -{ - CamelImapMessageInfo *iinfo = (CamelImapMessageInfo *)info; - - if (camel_imap_summary_parent->message_info_save (s, out, info) == -1) - return -1; - - return camel_file_util_encode_uint32 (out, iinfo->server_flags); -} - - -static CamelMessageContentInfo * -content_info_load (CamelFolderSummary *s, FILE *in) -{ - if (fgetc (in)) - return camel_imap_summary_parent->content_info_load (s, in); - else - return camel_folder_summary_content_info_new (s); -} - -static int -content_info_save (CamelFolderSummary *s, FILE *out, - CamelMessageContentInfo *info) -{ - if (info->type) { - fputc (1, out); - return camel_imap_summary_parent->content_info_save (s, out, info); - } else - return fputc (0, out); -} - -void -camel_imap_summary_add_offline (CamelFolderSummary *summary, const char *uid, - CamelMimeMessage *message, - const CamelMessageInfo *info) -{ - CamelMessageInfo *mi; - CamelFlag *flag; - CamelTag *tag; - - /* Create summary entry */ - mi = camel_folder_summary_info_new_from_message (summary, message); - - /* Copy flags 'n' tags */ - mi->flags = info->flags; - flag = info->user_flags; - while (flag) { - camel_flag_set (&mi->user_flags, flag->name, TRUE); - flag = flag->next; - } - tag = info->user_tags; - while (tag) { - camel_tag_set (&mi->user_tags, tag->name, tag->value); - tag = tag->next; - } - - /* Set uid and add to summary */ - camel_message_info_set_uid (mi, g_strdup (uid)); - camel_folder_summary_add (summary, mi); -} - -void -camel_imap_summary_add_offline_uncached (CamelFolderSummary *summary, const char *uid, - const CamelMessageInfo *info) -{ - CamelMessageInfo *mi; - CamelMessageContentInfo *ci; - - /* Create summary entry */ - mi = camel_folder_summary_info_new (summary); - ci = camel_folder_summary_content_info_new (summary); - - camel_message_info_dup_to (info, mi); - mi->content = ci; - - /* copy our private fields */ - ((CamelImapMessageInfo *)mi)->server_flags = - ((CamelImapMessageInfo *)info)->server_flags; - - /* Set uid and add to summary */ - camel_message_info_set_uid (mi, g_strdup (uid)); - camel_folder_summary_add (summary, mi); -} diff --git a/camel/providers/imap/camel-imap-summary.h b/camel/providers/imap/camel-imap-summary.h deleted file mode 100644 index 817e884408..0000000000 --- a/camel/providers/imap/camel-imap-summary.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2000 Ximian Inc. - * - * Authors: - * Michael Zucchi <notzed@ximian.com> - * Dan Winship <danw@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. - */ - -#ifndef _CAMEL_IMAP_SUMMARY_H -#define _CAMEL_IMAP_SUMMARY_H - -#include "camel-imap-types.h" -#include <camel/camel-folder-summary.h> -#include <camel/camel-exception.h> - -#define CAMEL_IMAP_SUMMARY(obj) CAMEL_CHECK_CAST (obj, camel_imap_summary_get_type (), CamelImapSummary) -#define CAMEL_IMAP_SUMMARY_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_imap_summary_get_type (), CamelImapSummaryClass) -#define CAMEL_IS_IMAP_SUMMARY(obj) CAMEL_CHECK_TYPE (obj, camel_imap_summary_get_type ()) - -#define CAMEL_IMAP_SERVER_FLAGS (CAMEL_MESSAGE_ANSWERED | \ - CAMEL_MESSAGE_DELETED | \ - CAMEL_MESSAGE_DRAFT | \ - CAMEL_MESSAGE_FLAGGED | \ - CAMEL_MESSAGE_SEEN) - -#define CAMEL_IMAP_MESSAGE_RECENT (1 << 8) - -typedef struct _CamelImapSummaryClass CamelImapSummaryClass; - -typedef struct _CamelImapMessageContentInfo { - CamelMessageContentInfo info; - -} CamelImapMessageContentInfo; - -typedef struct _CamelImapMessageInfo { - CamelMessageInfo info; - - guint32 server_flags; -} CamelImapMessageInfo; - -struct _CamelImapSummary { - CamelFolderSummary parent; - - guint32 validity; -}; - -struct _CamelImapSummaryClass { - CamelFolderSummaryClass parent_class; - -}; - -CamelType camel_imap_summary_get_type (void); -CamelFolderSummary *camel_imap_summary_new (const char *filename); - -void camel_imap_summary_add_offline (CamelFolderSummary *summary, - const char *uid, - CamelMimeMessage *message, - const CamelMessageInfo *info); - -void camel_imap_summary_add_offline_uncached (CamelFolderSummary *summary, - const char *uid, - const CamelMessageInfo *info); - -#endif /* ! _CAMEL_IMAP_SUMMARY_H */ - diff --git a/camel/providers/imap/camel-imap-types.h b/camel/providers/imap/camel-imap-types.h deleted file mode 100644 index c5ea41acff..0000000000 --- a/camel/providers/imap/camel-imap-types.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-imap-types.h: IMAP types */ - -/* - * Copyright (C) 2001 Ximian, Inc. - * - * 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 - */ - -#ifndef CAMEL_IMAP_TYPES_H -#define CAMEL_IMAP_TYPES_H 1 - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus }*/ - -#include "camel-types.h" - -typedef struct _CamelImapFolder CamelImapFolder; -typedef struct _CamelImapMessageCache CamelImapMessageCache; -typedef struct _CamelImapResponse CamelImapResponse; -typedef struct _CamelImapSearch CamelImapSearch; -typedef struct _CamelImapStore CamelImapStore; -typedef struct _CamelImapSummary CamelImapSummary; - -#endif /* CAMEL_IMAP_TYPES_H */ diff --git a/camel/providers/imap/camel-imap-utils.c b/camel/providers/imap/camel-imap-utils.c deleted file mode 100644 index fc507398db..0000000000 --- a/camel/providers/imap/camel-imap-utils.c +++ /dev/null @@ -1,1156 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Authors: Jeffrey Stedfast <fejj@ximian.com> - * - * Copyright 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 - * 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 <ctype.h> -#include <stdio.h> -#include <string.h> -#include <time.h> -#include <errno.h> - -#ifdef HAVE_ALLOCA_H -#include <alloca.h> -#endif - -#include "camel-imap-utils.h" -#include "camel-imap-summary.h" -#include "camel-imap-store.h" -#include "camel-folder.h" -#include "camel-utf8.h" - -#define d(x) x - -const char * -imap_next_word (const char *buf) -{ - const char *word; - - /* skip over current word */ - word = buf; - while (*word && *word != ' ') - word++; - - /* skip over white space */ - while (*word && *word == ' ') - word++; - - return word; -} - - -static void -imap_namespace_destroy (struct _namespace *namespace) -{ - struct _namespace *node, *next; - - node = namespace; - while (node) { - next = node->next; - g_free (node->prefix); - g_free (node); - node = next; - } -} - -void -imap_namespaces_destroy (struct _namespaces *namespaces) -{ - if (namespaces) { - imap_namespace_destroy (namespaces->personal); - imap_namespace_destroy (namespaces->other); - imap_namespace_destroy (namespaces->shared); - g_free (namespaces); - } -} - -static gboolean -imap_namespace_decode (const char **in, struct _namespace **namespace) -{ - struct _namespace *list, *tail, *node; - const char *inptr; - char *astring; - size_t len; - - inptr = *in; - - list = NULL; - tail = (struct _namespace *) &list; - - if (g_strncasecmp (inptr, "NIL", 3) != 0) { - if (*inptr++ != '(') - goto exception; - - while (*inptr && *inptr != ')') { - if (*inptr++ != '(') - goto exception; - - node = g_new (struct _namespace, 1); - node->next = NULL; - - /* get the namespace prefix */ - astring = imap_parse_astring (&inptr, &len); - if (!astring) { - g_free (node); - goto exception; - } - - /* decode IMAP's modified UTF-7 into UTF-8 */ - node->prefix = imap_mailbox_decode (astring, len); - g_free (astring); - if (!node->prefix) { - g_free (node); - goto exception; - } - - tail->next = node; - tail = node; - - /* get the namespace directory delimiter */ - inptr = imap_next_word (inptr); - - if (!g_strncasecmp (inptr, "NIL", 3)) { - inptr = imap_next_word (inptr); - node->delim = '\0'; - } else if (*inptr++ == '"') { - if (*inptr == '\\') - inptr++; - - node->delim = *inptr++; - - if (*inptr++ != '"') - goto exception; - } else - goto exception; - - if (*inptr == ' ') { - /* parse extra flags... for now we - don't save them, but in the future - we may want to? */ - while (*inptr == ' ') - inptr++; - - while (*inptr && *inptr != ')') { - /* this should be a QSTRING or ATOM */ - inptr = imap_next_word (inptr); - if (*inptr == '(') { - /* skip over the param list */ - imap_skip_list (&inptr); - } - - while (*inptr == ' ') - inptr++; - } - } - - if (*inptr++ != ')') - goto exception; - - /* there shouldn't be spaces according to the - ABNF grammar, but we all know how closely - people follow specs */ - while (*inptr == ' ') - inptr++; - } - - if (*inptr == ')') - inptr++; - } else { - inptr += 3; - } - - *in = inptr; - *namespace = list; - - return TRUE; - - exception: - - /* clean up any namespaces we may have allocated */ - imap_namespace_destroy (list); - - return FALSE; -} - -static void -namespace_dump (struct _namespace *namespace) -{ - struct _namespace *node; - - if (namespace) { - printf ("("); - node = namespace; - while (node) { - printf ("(\"%s\" ", node->prefix); - if (node->delim) - printf ("\"%c\")", node->delim); - else - printf ("NUL)"); - - node = node->next; - if (node) - printf (" "); - } - - printf (")"); - } else { - printf ("NIL"); - } -} - -static void -namespaces_dump (struct _namespaces *namespaces) -{ - printf ("namespace dump: "); - namespace_dump (namespaces->personal); - printf (" "); - namespace_dump (namespaces->other); - printf (" "); - namespace_dump (namespaces->shared); - printf ("\n"); -} - -struct _namespaces * -imap_parse_namespace_response (const char *response) -{ - struct _namespaces *namespaces; - const char *inptr; - - printf ("parsing: %s\n", response); - - if (*response != '*') - return NULL; - - inptr = imap_next_word (response); - if (g_strncasecmp (inptr, "NAMESPACE", 9) != 0) - return NULL; - - inptr = imap_next_word (inptr); - - namespaces = g_new (struct _namespaces, 1); - namespaces->personal = NULL; - namespaces->other = NULL; - namespaces->shared = NULL; - - if (!imap_namespace_decode (&inptr, &namespaces->personal)) - goto exception; - - if (*inptr != ' ') - goto exception; - - while (*inptr == ' ') - inptr++; - - if (!imap_namespace_decode (&inptr, &namespaces->other)) - goto exception; - - if (*inptr != ' ') - goto exception; - - while (*inptr == ' ') - inptr++; - - if (!imap_namespace_decode (&inptr, &namespaces->shared)) - goto exception; - - namespaces_dump (namespaces); - - return namespaces; - - exception: - - imap_namespaces_destroy (namespaces); - - return NULL; -} - -/** - * imap_parse_list_response: - * @store: the IMAP store whose list response we're parsing - * @buf: the LIST or LSUB response - * @flags: a pointer to a variable to store the flags in, or %NULL - * @sep: a pointer to a variable to store the hierarchy separator in, or %NULL - * @folder: a pointer to a variable to store the folder name in, or %NULL - * - * Parses a LIST or LSUB response and returns the desired parts of it. - * If @folder is non-%NULL, its value must be freed by the caller. - * - * Return value: whether or not the response was successfully parsed. - **/ -gboolean -imap_parse_list_response (CamelImapStore *store, const char *buf, int *flags, char *sep, char **folder) -{ - gboolean is_lsub = FALSE; - const char *word; - size_t len; - - if (*buf != '*') - return FALSE; - - word = imap_next_word (buf); - if (g_strncasecmp (word, "LIST", 4) && g_strncasecmp (word, "LSUB", 4)) - return FALSE; - - /* check if we are looking at an LSUB response */ - if (word[1] == 'S' || word[1] == 's') - is_lsub = TRUE; - - /* get the flags */ - word = imap_next_word (word); - if (*word != '(') - return FALSE; - - if (flags) - *flags = 0; - - word++; - while (*word != ')') { - len = strcspn (word, " )"); - if (flags) { - if (!g_strncasecmp (word, "\\NoInferiors", len)) - *flags |= CAMEL_FOLDER_NOINFERIORS; - else if (!g_strncasecmp (word, "\\NoSelect", len)) - *flags |= CAMEL_FOLDER_NOSELECT; - else if (!g_strncasecmp (word, "\\Marked", len)) - *flags |= CAMEL_IMAP_FOLDER_MARKED; - else if (!g_strncasecmp (word, "\\Unmarked", len)) - *flags |= CAMEL_IMAP_FOLDER_UNMARKED; - else if (!g_strncasecmp (word, "\\HasChildren", len)) - *flags |= CAMEL_FOLDER_CHILDREN; - else if (!g_strncasecmp (word, "\\HasNoChildren", len)) - *flags |= CAMEL_IMAP_FOLDER_NOCHILDREN; - } - - word += len; - while (*word == ' ') - word++; - } - - /* get the directory separator */ - word = imap_next_word (word); - if (!strncmp (word, "NIL", 3)) { - if (sep) - *sep = '\0'; - } else if (*word++ == '"') { - if (*word == '\\') - word++; - if (sep) - *sep = *word; - word++; - if (*word++ != '"') - return FALSE; - } else - return FALSE; - - if (folder) { - char *astring, *mailbox; - - /* get the folder name */ - word = imap_next_word (word); - astring = imap_parse_astring (&word, &len); - if (!astring) - return FALSE; - - *folder = astring; -#if 0 - mailbox = imap_mailbox_decode (astring, strlen (astring)); - g_free (astring); - if (!mailbox) - return FALSE; - - /* Kludge around Courier imap's LSUB response for INBOX when it - * isn't subscribed to. - * - * Ignore any \Noselect flags for INBOX when parsing - * an LSUB response to work around the following response: - * - * * LSUB (\Noselect \HasChildren) "." "INBOX" - * - * Fixes bug #28929 (albeight in a very dodgy way imho, but what - * can ya do when ya got the ignorance of marketing breathing - * down your neck?) - */ - if (is_lsub && flags && !strcasecmp (mailbox, "INBOX")) - *flags &= ~CAMEL_FOLDER_NOSELECT; - - *folder = mailbox; -#endif - } - - return TRUE; -} - - -/** - * imap_parse_folder_name: - * @store: - * @folder_name: - * - * Return an array of folder paths representing the folder heirarchy. - * For example: - * Full/Path/"to / from"/Folder - * Results in: - * Full, Full/Path, Full/Path/"to / from", Full/Path/"to / from"/Folder - **/ -char ** -imap_parse_folder_name (CamelImapStore *store, const char *folder_name) -{ - GPtrArray *heirarchy; - char **paths; - const char *p; - - p = folder_name; - if (*p == store->dir_sep) - p++; - - heirarchy = g_ptr_array_new (); - - while (*p) { - if (*p == '"') { - p++; - while (*p && *p != '"') - p++; - if (*p) - p++; - continue; - } - - if (*p == store->dir_sep) - g_ptr_array_add (heirarchy, g_strndup (folder_name, p - folder_name)); - - p++; - } - - g_ptr_array_add (heirarchy, g_strdup (folder_name)); - g_ptr_array_add (heirarchy, NULL); - - paths = (char **) heirarchy->pdata; - g_ptr_array_free (heirarchy, FALSE); - - return paths; -} - -char * -imap_create_flag_list (guint32 flags) -{ - GString *gstr; - char *flag_list; - - gstr = g_string_new ("("); - - if (flags & CAMEL_MESSAGE_ANSWERED) - g_string_append (gstr, "\\Answered "); - if (flags & CAMEL_MESSAGE_DELETED) - g_string_append (gstr, "\\Deleted "); - if (flags & CAMEL_MESSAGE_DRAFT) - g_string_append (gstr, "\\Draft "); - if (flags & CAMEL_MESSAGE_FLAGGED) - g_string_append (gstr, "\\Flagged "); - if (flags & CAMEL_MESSAGE_SEEN) - g_string_append (gstr, "\\Seen "); - - if (gstr->str[gstr->len - 1] == ' ') - gstr->str[gstr->len - 1] = ')'; - else - g_string_append_c (gstr, ')'); - - flag_list = gstr->str; - g_string_free (gstr, FALSE); - return flag_list; -} - -guint32 -imap_parse_flag_list (char **flag_list_p) -{ - char *flag_list = *flag_list_p; - guint32 flags = 0; - int len; - - if (*flag_list++ != '(') { - *flag_list_p = NULL; - return 0; - } - - while (*flag_list && *flag_list != ')') { - len = strcspn (flag_list, " )"); - if (!g_strncasecmp (flag_list, "\\Answered", len)) - flags |= CAMEL_MESSAGE_ANSWERED; - else if (!g_strncasecmp (flag_list, "\\Deleted", len)) - flags |= CAMEL_MESSAGE_DELETED; - else if (!g_strncasecmp (flag_list, "\\Draft", len)) - flags |= CAMEL_MESSAGE_DRAFT; - else if (!g_strncasecmp (flag_list, "\\Flagged", len)) - flags |= CAMEL_MESSAGE_FLAGGED; - else if (!g_strncasecmp (flag_list, "\\Seen", len)) - flags |= CAMEL_MESSAGE_SEEN; - else if (!g_strncasecmp (flag_list, "\\Recent", len)) - flags |= CAMEL_IMAP_MESSAGE_RECENT; - - flag_list += len; - if (*flag_list == ' ') - flag_list++; - } - - if (*flag_list++ != ')') { - *flag_list_p = NULL; - return 0; - } - - *flag_list_p = flag_list; - return flags; -} - -/* - From rfc2060 - -ATOM_CHAR ::= <any CHAR except atom_specials> - -atom_specials ::= "(" / ")" / "{" / SPACE / CTL / list_wildcards / - quoted_specials - -CHAR ::= <any 7-bit US-ASCII character except NUL, - 0x01 - 0x7f> - -CTL ::= <any ASCII control character and DEL, - 0x00 - 0x1f, 0x7f> - -SPACE ::= <ASCII SP, space, 0x20> - -list_wildcards ::= "%" / "*" - -quoted_specials ::= <"> / "\" -*/ - -static unsigned char imap_atom_specials[256] = { -/* 00 */0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -/* 10 */0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -/* 20 */0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, -/* 30 */1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -/* 40 */1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -/* 50 */1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, -/* 60 */1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -/* 70 */1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 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, 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, 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, 0, 0, -}; - -#define imap_is_atom_char(c) ((imap_atom_specials[(c)&0xff] & 0x01) != 0) - -gboolean -imap_is_atom(const char *in) -{ - register unsigned char c; - register const char *p = in; - - while ((c = (unsigned char)*p)) { - if (!imap_is_atom_char(c)) - return FALSE; - p++; - } - - /* check for empty string */ - return p!=in; -} - -/** - * imap_parse_string_generic: - * @str_p: a pointer to a string - * @len: a pointer to a size_t to return the length in - * @type: type of string (#IMAP_STRING, #IMAP_ASTRING, or #IMAP_NSTRING) - * to parse. - * - * This parses an IMAP "string" (quoted string or literal), "nstring" - * (NIL or string), or "astring" (atom or string) starting at *@str_p. - * On success, *@str_p will point to the first character after the end - * of the string, and *@len will contain the length of the returned - * string. On failure, *@str_p will be set to %NULL. - * - * This assumes that the string is in the form returned by - * camel_imap_command(): that line breaks are indicated by LF rather - * than CRLF. - * - * Return value: the parsed string, or %NULL if a NIL or no string - * was parsed. (In the former case, *@str_p will be %NULL; in the - * latter, it will point to the character after the NIL.) - **/ -char * -imap_parse_string_generic (const char **str_p, size_t *len, int type) -{ - const char *str = *str_p; - char *out; - - if (!str) - return NULL; - else if (*str == '"') { - char *p; - size_t size; - - str++; - size = strcspn (str, "\"") + 1; - p = out = g_malloc (size); - - /* a quoted string cannot be broken into multiple lines */ - while (*str && *str != '"' && *str != '\n') { - if (*str == '\\') - str++; - *p++ = *str++; - if (p - out == size) { - out = g_realloc (out, size * 2); - p = out + size; - size *= 2; - } - } - if (*str != '"') { - *str_p = NULL; - g_free (out); - return NULL; - } - *p = '\0'; - *str_p = str + 1; - *len = strlen (out); - return out; - } else if (*str == '{') { - *len = strtoul (str + 1, (char **)&str, 10); - if (*str++ != '}' || *str++ != '\n' || strlen (str) < *len) { - *str_p = NULL; - return NULL; - } - - out = g_strndup (str, *len); - *str_p = str + *len; - return out; - } else if (type == IMAP_NSTRING && !g_strncasecmp (str, "nil", 3)) { - *str_p += 3; - *len = 0; - return NULL; - } else if (type == IMAP_ASTRING && imap_is_atom_char ((unsigned char)*str)) { - while (imap_is_atom_char ((unsigned char) *str)) - str++; - - *len = str - *str_p; - out = g_strndup (*str_p, *len); - *str_p += *len; - return out; - } else { - *str_p = NULL; - return NULL; - } -} - -static inline void -skip_char (const char **in, char ch) -{ - if (*in && **in == ch) - *in = *in + 1; - else - *in = NULL; -} - -/* Skip atom, string, or number */ -static void -skip_asn (const char **str_p) -{ - const char *str = *str_p; - - if (!str) - return; - else if (*str == '"') { - while (*++str && *str != '"') { - if (*str == '\\') { - str++; - if (!*str) - break; - } - } - if (*str == '"') - *str_p = str + 1; - else - *str_p = NULL; - } else if (*str == '{') { - unsigned long len; - - len = strtoul (str + 1, (char **) &str, 10); - if (*str != '}' || *(str + 1) != '\n' || - strlen (str + 2) < len) { - *str_p = NULL; - return; - } - *str_p = str + 2 + len; - } else { - /* We assume the string is well-formed and don't - * bother making sure it's a valid atom. - */ - while (*str && *str != ')' && *str != ' ') - str++; - *str_p = str; - } -} - -void -imap_skip_list (const char **str_p) -{ - skip_char (str_p, '('); - while (*str_p && **str_p != ')') { - if (**str_p == '(') - imap_skip_list (str_p); - else - skip_asn (str_p); - if (*str_p && **str_p == ' ') - skip_char (str_p, ' '); - } - skip_char (str_p, ')'); -} - -static void -parse_params (const char **parms_p, CamelContentType *type) -{ - const char *parms = *parms_p; - char *name, *value; - int len; - - if (!g_strncasecmp (parms, "nil", 3)) { - *parms_p += 3; - return; - } - - if (*parms++ != '(') { - *parms_p = NULL; - return; - } - - while (parms && *parms != ')') { - name = imap_parse_nstring (&parms, &len); - skip_char (&parms, ' '); - value = imap_parse_nstring (&parms, &len); - - if (name && value) - header_content_type_set_param (type, name, value); - g_free (name); - g_free (value); - - if (parms && *parms == ' ') - parms++; - } - - if (!parms || *parms++ != ')') { - *parms_p = NULL; - return; - } - *parms_p = parms; -} - -/** - * imap_parse_body: - * @body_p: pointer to the start of an IMAP "body" - * @folder: an imap folder - * @ci: a CamelMessageContentInfo to fill in - * - * This fills in @ci with data from *@body_p. On success *@body_p - * will point to the character after the body. On failure, it will be - * set to %NULL and @ci will be unchanged. - **/ -void -imap_parse_body (const char **body_p, CamelFolder *folder, - CamelMessageContentInfo *ci) -{ - const char *body = *body_p; - CamelMessageContentInfo *child; - CamelContentType *type; - size_t len; - - if (!body || *body++ != '(') { - *body_p = NULL; - return; - } - - if (*body == '(') { - /* multipart */ - GPtrArray *children; - char *subtype; - int i; - - /* Parse the child body parts */ - children = g_ptr_array_new (); - while (body && *body == '(') { - child = camel_folder_summary_content_info_new (folder->summary); - g_ptr_array_add (children, child); - imap_parse_body (&body, folder, child); - if (!body) - break; - child->parent = ci; - } - skip_char (&body, ' '); - - /* Parse the multipart subtype */ - subtype = imap_parse_string (&body, &len); - - /* If there is a parse error, abort. */ - if (!body) { - for (i = 0; i < children->len; i++) { - child = children->pdata[i]; - camel_folder_summary_content_info_free (folder->summary, child); - } - g_ptr_array_free (children, TRUE); - *body_p = NULL; - return; - } - - g_strdown (subtype); - ci->type = header_content_type_new ("multipart", subtype); - g_free (subtype); - - /* Chain the children. */ - ci->childs = children->pdata[0]; - ci->size = 0; - for (i = 0; i < children->len - 1; i++) { - child = children->pdata[i]; - child->next = children->pdata[i + 1]; - ci->size += child->size; - } - g_ptr_array_free (children, TRUE); - } else { - /* single part */ - char *main_type, *subtype; - char *id, *description, *encoding; - guint32 size = 0; - - main_type = imap_parse_string (&body, &len); - skip_char (&body, ' '); - subtype = imap_parse_string (&body, &len); - skip_char (&body, ' '); - if (!body) { - g_free (main_type); - g_free (subtype); - *body_p = NULL; - return; - } - g_strdown (main_type); - g_strdown (subtype); - type = header_content_type_new (main_type, subtype); - g_free (main_type); - g_free (subtype); - parse_params (&body, type); - skip_char (&body, ' '); - - id = imap_parse_nstring (&body, &len); - skip_char (&body, ' '); - description = imap_parse_nstring (&body, &len); - skip_char (&body, ' '); - encoding = imap_parse_string (&body, &len); - skip_char (&body, ' '); - if (body) - size = strtoul (body, (char **) &body, 10); - - child = NULL; - if (header_content_type_is (type, "message", "rfc822")) { - skip_char (&body, ' '); - imap_skip_list (&body); /* envelope */ - skip_char (&body, ' '); - child = camel_folder_summary_content_info_new (folder->summary); - imap_parse_body (&body, folder, child); - if (!body) - camel_folder_summary_content_info_free (folder->summary, child); - skip_char (&body, ' '); - if (body) - strtoul (body, (char **) &body, 10); - child->parent = ci; - } else if (header_content_type_is (type, "text", "*")) { - if (body) - strtoul (body, (char **) &body, 10); - } - - if (body) { - ci->type = type; - ci->id = id; - ci->description = description; - ci->encoding = encoding; - ci->size = size; - ci->childs = child; - } else { - header_content_type_unref (type); - g_free (id); - g_free (description); - g_free (encoding); - } - } - - if (!body || *body++ != ')') { - *body_p = NULL; - return; - } - - *body_p = body; -} - -/** - * imap_quote_string: - * @str: the string to quote, which must not contain CR or LF - * - * Return value: an IMAP "quoted" corresponding to the string, which - * the caller must free. - **/ -char * -imap_quote_string (const char *str) -{ - const char *p; - char *quoted, *q; - int len; - - g_assert (strchr (str, '\r') == NULL); - - len = strlen (str); - p = str; - while ((p = strpbrk (p, "\"\\"))) { - len++; - p++; - } - - quoted = q = g_malloc (len + 3); - *q++ = '"'; - for (p = str; *p; ) { - if (strchr ("\"\\", *p)) - *q++ = '\\'; - *q++ = *p++; - } - *q++ = '"'; - *q = '\0'; - - return quoted; -} - - -static inline unsigned long -get_summary_uid_numeric (CamelFolderSummary *summary, int index) -{ - CamelMessageInfo *info; - unsigned long uid; - - info = camel_folder_summary_index (summary, index); - uid = strtoul (camel_message_info_uid (info), NULL, 10); - camel_folder_summary_info_free (summary, info); - return uid; -} - -/* the max number of chars that an unsigned 32-bit int can be is 10 chars plus 1 for a possible : */ -#define UID_SET_FULL(setlen, maxlen) (maxlen > 0 ? setlen + 11 >= maxlen : FALSE) - -/** - * imap_uid_array_to_set: - * @summary: summary for the folder the UIDs come from - * @uids: a (sorted) array of UIDs - * @uid: uid index to start at - * @maxlen: max length of the set string (or -1 for infinite) - * @lastuid: index offset of the last uid used - * - * Creates an IMAP "set" up to @maxlen bytes long, covering the listed - * UIDs starting at index @uid and not covering any UIDs that are in - * @summary but not in @uids. It doesn't actually require that all (or - * any) of the UIDs be in @summary. - * - * After calling, @lastuid will be set the index of the first uid - * *not* included in the returned set string. - * - * Return value: the set, which the caller must free with g_free() - **/ -char * -imap_uid_array_to_set (CamelFolderSummary *summary, GPtrArray *uids, int uid, ssize_t maxlen, int *lastuid) -{ - unsigned long last_uid, next_summary_uid, this_uid; - gboolean range = FALSE; - int si, scount; - GString *gset; - char *set; - - g_return_val_if_fail (uids->len > uid, NULL); - - gset = g_string_new (uids->pdata[uid]); - last_uid = strtoul (uids->pdata[uid], NULL, 10); - next_summary_uid = 0; - scount = camel_folder_summary_count (summary); - - for (uid++, si = 0; uid < uids->len && !UID_SET_FULL (gset->len, maxlen); uid++) { - /* Find the next UID in the summary after the one we - * just wrote out. - */ - for ( ; last_uid >= next_summary_uid && si < scount; si++) - next_summary_uid = get_summary_uid_numeric (summary, si); - if (last_uid >= next_summary_uid) - next_summary_uid = (unsigned long) -1; - - /* Now get the next UID from @uids */ - this_uid = strtoul (uids->pdata[uid], NULL, 10); - if (this_uid == next_summary_uid || this_uid == last_uid + 1) - range = TRUE; - else { - if (range) { - g_string_sprintfa (gset, ":%lu", last_uid); - range = FALSE; - } - g_string_sprintfa (gset, ",%lu", this_uid); - } - - last_uid = this_uid; - } - - if (range) - g_string_sprintfa (gset, ":%lu", last_uid); - - *lastuid = uid; - - set = gset->str; - g_string_free (gset, FALSE); - - return set; -} - -/** - * imap_uid_set_to_array: - * @summary: summary for the folder the UIDs come from - * @uids: a pointer to the start of an IMAP "set" of UIDs - * - * Fills an array with the UIDs corresponding to @uids and @summary. - * There can be text after the uid set in @uids, which will be - * ignored. - * - * If @uids specifies a range of UIDs that extends outside the range - * of @summary, the function will assume that all of the "missing" UIDs - * do exist. - * - * Return value: the array of uids, which the caller must free with - * imap_uid_array_free(). (Or %NULL if the uid set can't be parsed.) - **/ -GPtrArray * -imap_uid_set_to_array (CamelFolderSummary *summary, const char *uids) -{ - GPtrArray *arr; - char *p, *q; - unsigned long uid, suid; - int si, scount; - - arr = g_ptr_array_new (); - scount = camel_folder_summary_count (summary); - - p = (char *)uids; - si = 0; - do { - uid = strtoul (p, &q, 10); - if (p == q) - goto lose; - g_ptr_array_add (arr, g_strndup (p, q - p)); - - if (*q == ':') { - /* Find the summary entry for the UID after the one - * we just saw. - */ - while (++si < scount) { - suid = get_summary_uid_numeric (summary, si); - if (suid > uid) - break; - } - if (si >= scount) - suid = uid + 1; - - uid = strtoul (q + 1, &p, 10); - if (p == q + 1) - goto lose; - - /* Add each summary UID until we find one - * larger than the end of the range - */ - while (suid <= uid) { - g_ptr_array_add (arr, g_strdup_printf ("%lu", suid)); - if (++si < scount) - suid = get_summary_uid_numeric (summary, si); - else - suid++; - } - } else - p = q; - } while (*p++ == ','); - - return arr; - - lose: - g_warning ("Invalid uid set %s", uids); - imap_uid_array_free (arr); - return NULL; -} - -/** - * imap_uid_array_free: - * @arr: an array returned from imap_uid_set_to_array() - * - * Frees @arr - **/ -void -imap_uid_array_free (GPtrArray *arr) -{ - int i; - - for (i = 0; i < arr->len; i++) - g_free (arr->pdata[i]); - g_ptr_array_free (arr, TRUE); -} - -char * -imap_concat (CamelImapStore *imap_store, const char *prefix, const char *suffix) -{ - size_t len; - - len = strlen (prefix); - if (len == 0 || prefix[len - 1] == imap_store->dir_sep) - return g_strdup_printf ("%s%s", prefix, suffix); - else - return g_strdup_printf ("%s%c%s", prefix, imap_store->dir_sep, suffix); -} - -char * -imap_mailbox_encode (const unsigned char *in, size_t inlen) -{ - char *buf; - - buf = alloca(inlen+1); - memcpy(buf, in, inlen); - buf[inlen] = 0; - - return camel_utf8_utf7(buf); -} - -char * -imap_mailbox_decode (const unsigned char *in, size_t inlen) -{ - char *buf; - - buf = alloca(inlen+1); - memcpy(buf, in, inlen); - buf[inlen] = 0; - - return camel_utf7_utf8(buf); -} diff --git a/camel/providers/imap/camel-imap-utils.h b/camel/providers/imap/camel-imap-utils.h deleted file mode 100644 index e8f570137f..0000000000 --- a/camel/providers/imap/camel-imap-utils.h +++ /dev/null @@ -1,95 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Authors: Jeffrey Stedfast <fejj@ximian.com> - * - * Copyright 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 - * 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. - * - */ - -#ifndef CAMEL_IMAP_UTILS_H -#define CAMEL_IMAP_UTILS_H 1 - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus }*/ - -#include <sys/types.h> - -#include "camel-folder-summary.h" -#include "camel-imap-types.h" - -const char *imap_next_word (const char *buf); - -struct _namespace { - struct _namespace *next; - char *prefix; - char delim; -}; - -struct _namespaces { - struct _namespace *personal; - struct _namespace *other; - struct _namespace *shared; -}; - -void imap_namespaces_destroy (struct _namespaces *namespaces); -struct _namespaces *imap_parse_namespace_response (const char *response); - -gboolean imap_parse_list_response (CamelImapStore *store, const char *buf, int *flags, - char *sep, char **folder); - -char **imap_parse_folder_name (CamelImapStore *store, const char *folder_name); - -char *imap_create_flag_list (guint32 flags); -guint32 imap_parse_flag_list (char **flag_list); - - -enum { IMAP_STRING, IMAP_NSTRING, IMAP_ASTRING }; - -char *imap_parse_string_generic (const char **str_p, size_t *len, int type); - -#define imap_parse_string(str_p, len_p) \ - imap_parse_string_generic (str_p, len_p, IMAP_STRING) -#define imap_parse_nstring(str_p, len_p) \ - imap_parse_string_generic (str_p, len_p, IMAP_NSTRING) -#define imap_parse_astring(str_p, len_p) \ - imap_parse_string_generic (str_p, len_p, IMAP_ASTRING) - -void imap_parse_body (const char **body_p, CamelFolder *folder, - CamelMessageContentInfo *ci); - -gboolean imap_is_atom (const char *in); -char *imap_quote_string (const char *str); - -void imap_skip_list (const char **str_p); - -char *imap_uid_array_to_set (CamelFolderSummary *summary, GPtrArray *uids, int uid, ssize_t maxlen, int *lastuid); -GPtrArray *imap_uid_set_to_array (CamelFolderSummary *summary, const char *uids); -void imap_uid_array_free (GPtrArray *arr); - -char *imap_concat (CamelImapStore *imap_store, const char *prefix, const char *suffix); -char *imap_namespace_concat (CamelImapStore *store, const char *name); - -char *imap_mailbox_encode (const unsigned char *in, size_t inlen); -char *imap_mailbox_decode (const unsigned char *in, size_t inlen); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CAMEL_IMAP_UTILS_H */ diff --git a/camel/providers/imap/camel-imap-wrapper.c b/camel/providers/imap/camel-imap-wrapper.c deleted file mode 100644 index 8559203c16..0000000000 --- a/camel/providers/imap/camel-imap-wrapper.c +++ /dev/null @@ -1,226 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; -*- */ -/* camel-imap-wrapper.c: data wrapper for offline IMAP data */ - -/* - * Author: Dan Winship <danw@ximian.com> - * - * Copyright 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 - * 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 <errno.h> -#include <string.h> - -#include "camel-imap-folder.h" -#include "camel-imap-wrapper.h" -#include "camel-imap-private.h" -#include "camel-exception.h" -#include "camel-stream-filter.h" -#include "camel-mime-filter-basic.h" -#include "camel-mime-filter-crlf.h" -#include "camel-mime-filter-charset.h" -#include "camel-mime-part.h" - -static CamelDataWrapperClass *parent_class = NULL; - -/* Returns the class for a CamelDataWrapper */ -#define CDW_CLASS(so) CAMEL_DATA_WRAPPER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) - -static int write_to_stream (CamelDataWrapper *imap_wrapper, CamelStream *stream); - -static void -camel_imap_wrapper_class_init (CamelImapWrapperClass *camel_imap_wrapper_class) -{ - CamelDataWrapperClass *camel_data_wrapper_class = - CAMEL_DATA_WRAPPER_CLASS (camel_imap_wrapper_class); - - parent_class = CAMEL_DATA_WRAPPER_CLASS (camel_type_get_global_classfuncs (camel_data_wrapper_get_type ())); - - /* virtual method override */ - camel_data_wrapper_class->write_to_stream = write_to_stream; -} - -static void -camel_imap_wrapper_finalize (CamelObject *object) -{ - CamelImapWrapper *imap_wrapper = CAMEL_IMAP_WRAPPER (object); - - if (imap_wrapper->folder) - camel_object_unref (CAMEL_OBJECT (imap_wrapper->folder)); - if (imap_wrapper->uid) - g_free (imap_wrapper->uid); - if (imap_wrapper->part) - g_free (imap_wrapper->part_spec); - -#ifdef ENABLE_THREADS - g_mutex_free (imap_wrapper->priv->lock); -#endif - g_free (imap_wrapper->priv); -} - -static void -camel_imap_wrapper_init (gpointer object, gpointer klass) -{ - CamelImapWrapper *imap_wrapper = CAMEL_IMAP_WRAPPER (object); - - imap_wrapper->priv = g_new0 (struct _CamelImapWrapperPrivate, 1); -#ifdef ENABLE_THREADS - imap_wrapper->priv->lock = g_mutex_new (); -#endif -} - -CamelType -camel_imap_wrapper_get_type (void) -{ - static CamelType camel_imap_wrapper_type = CAMEL_INVALID_TYPE; - - if (camel_imap_wrapper_type == CAMEL_INVALID_TYPE) { - camel_imap_wrapper_type = camel_type_register ( - CAMEL_DATA_WRAPPER_TYPE, "CamelImapWrapper", - sizeof (CamelImapWrapper), - sizeof (CamelImapWrapperClass), - (CamelObjectClassInitFunc) camel_imap_wrapper_class_init, - NULL, - (CamelObjectInitFunc) camel_imap_wrapper_init, - (CamelObjectFinalizeFunc) camel_imap_wrapper_finalize); - } - - return camel_imap_wrapper_type; -} - - -static void -imap_wrapper_hydrate (CamelImapWrapper *imap_wrapper, CamelStream *stream) -{ - CamelDataWrapper *data_wrapper = CAMEL_DATA_WRAPPER (imap_wrapper); - CamelStreamFilter *filterstream; - CamelMimeFilter *filter; - CamelContentType *ct; - - filterstream = camel_stream_filter_new_with_stream (stream); - - /* FIXME: lame. We already have code to do all this shit in camel-mime-part-utils.c */ - switch (camel_mime_part_get_encoding (imap_wrapper->part)) { - case CAMEL_MIME_PART_ENCODING_BASE64: - filter = (CamelMimeFilter *)camel_mime_filter_basic_new_type (CAMEL_MIME_FILTER_BASIC_BASE64_DEC); - camel_stream_filter_add (filterstream, filter); - break; - case CAMEL_MIME_PART_ENCODING_QUOTEDPRINTABLE: - filter = (CamelMimeFilter *)camel_mime_filter_basic_new_type (CAMEL_MIME_FILTER_BASIC_QP_DEC); - camel_stream_filter_add (filterstream, filter); - break; - case CAMEL_MIME_PART_ENCODING_UUENCODE: - filter = (CamelMimeFilter *)camel_mime_filter_basic_new_type (CAMEL_MIME_FILTER_BASIC_UU_DEC); - camel_stream_filter_add (filterstream, filter); - break; - default: - filter = NULL; - } - - ct = camel_mime_part_get_content_type (imap_wrapper->part); - if (header_content_type_is (ct, "text", "*")) { - const char *charset; - - /* If we just did B64/QP/UU, need to also do CRLF->LF */ - if (filter) { - filter = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_DECODE, - CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY); - camel_stream_filter_add (filterstream, filter); - } - - charset = header_content_type_param (ct, "charset"); - if (charset && !(strcasecmp (charset, "us-ascii") == 0 - || strcasecmp (charset, "utf-8") == 0)) { - filter = (CamelMimeFilter *)camel_mime_filter_charset_new_convert (charset, "UTF-8"); - if (filter) - camel_stream_filter_add (filterstream, filter); - } - } - - data_wrapper->stream = CAMEL_STREAM (filterstream); - data_wrapper->offline = FALSE; - - camel_object_unref (CAMEL_OBJECT (imap_wrapper->folder)); - imap_wrapper->folder = NULL; - g_free (imap_wrapper->uid); - imap_wrapper->uid = NULL; - g_free (imap_wrapper->part_spec); - imap_wrapper->part = NULL; -} - - -static int -write_to_stream (CamelDataWrapper *data_wrapper, CamelStream *stream) -{ - CamelImapWrapper *imap_wrapper = CAMEL_IMAP_WRAPPER (data_wrapper); - - CAMEL_IMAP_WRAPPER_LOCK (imap_wrapper, lock); - if (data_wrapper->offline) { - CamelStream *datastream; - - datastream = camel_imap_folder_fetch_data ( - imap_wrapper->folder, imap_wrapper->uid, - imap_wrapper->part_spec, FALSE, NULL); - if (!datastream) { - CAMEL_IMAP_WRAPPER_UNLOCK (imap_wrapper, lock); - errno = ENETUNREACH; - return -1; - } - - imap_wrapper_hydrate (imap_wrapper, datastream); - camel_object_unref (CAMEL_OBJECT (datastream)); - } - CAMEL_IMAP_WRAPPER_UNLOCK (imap_wrapper, lock); - - return parent_class->write_to_stream (data_wrapper, stream); -} - - -CamelDataWrapper * -camel_imap_wrapper_new (CamelImapFolder *imap_folder, CamelContentType *type, - const char *uid, const char *part_spec, - CamelMimePart *part) -{ - CamelImapWrapper *imap_wrapper; - CamelStream *stream; - - imap_wrapper = (CamelImapWrapper *)camel_object_new(camel_imap_wrapper_get_type()); - - camel_data_wrapper_set_mime_type_field (CAMEL_DATA_WRAPPER (imap_wrapper), type); - ((CamelDataWrapper *)imap_wrapper)->offline = TRUE; - - imap_wrapper->folder = imap_folder; - camel_object_ref (CAMEL_OBJECT (imap_folder)); - imap_wrapper->uid = g_strdup (uid); - imap_wrapper->part_spec = g_strdup (part_spec); - - /* Don't ref this, it's our parent. */ - imap_wrapper->part = part; - - /* Try the cache. */ - stream = camel_imap_folder_fetch_data (imap_folder, uid, part_spec, - TRUE, NULL); - if (stream) { - imap_wrapper_hydrate (imap_wrapper, stream); - camel_object_unref (CAMEL_OBJECT (stream)); - } - - return (CamelDataWrapper *)imap_wrapper; -} diff --git a/camel/providers/imap/camel-imap-wrapper.h b/camel/providers/imap/camel-imap-wrapper.h deleted file mode 100644 index 4f7ca5097a..0000000000 --- a/camel/providers/imap/camel-imap-wrapper.h +++ /dev/null @@ -1,70 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-imap-wrapper.h: data wrapper for offline IMAP data */ - -/* - * Copyright 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 - * 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 - */ - - -#ifndef CAMEL_IMAP_WRAPPER_H -#define CAMEL_IMAP_WRAPPER_H 1 - - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus }*/ - -#include <camel/camel-data-wrapper.h> -#include "camel-imap-types.h" - -#define CAMEL_IMAP_WRAPPER_TYPE (camel_imap_wrapper_get_type ()) -#define CAMEL_IMAP_WRAPPER(obj) (CAMEL_CHECK_CAST((obj), CAMEL_IMAP_WRAPPER_TYPE, CamelImapWrapper)) -#define CAMEL_IMAP_WRAPPER_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_IMAP_WRAPPER_TYPE, CamelImapWrapperClass)) -#define CAMEL_IS_IMAP_WRAPPER(o) (CAMEL_CHECK_TYPE((o), CAMEL_IMAP_WRAPPER_TYPE)) - -typedef struct -{ - CamelDataWrapper parent_object; - - struct _CamelImapWrapperPrivate *priv; - - CamelImapFolder *folder; - char *uid, *part_spec; - CamelMimePart *part; -} CamelImapWrapper; - -typedef struct { - CamelDataWrapperClass parent_class; - -} CamelImapWrapperClass; - -/* Standard Camel function */ -CamelType camel_imap_wrapper_get_type (void); - -/* Constructor */ -CamelDataWrapper *camel_imap_wrapper_new (CamelImapFolder *imap_folder, - CamelContentType *type, - const char *uid, - const char *part_spec, - CamelMimePart *part); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CAMEL_DATA_WRAPPER_H */ diff --git a/camel/providers/imap/libcamelimap.urls b/camel/providers/imap/libcamelimap.urls deleted file mode 100644 index c301c0ffac..0000000000 --- a/camel/providers/imap/libcamelimap.urls +++ /dev/null @@ -1 +0,0 @@ -imap |