diff options
author | nobody <nobody@localhost> | 2003-12-09 09:57:09 +0800 |
---|---|---|
committer | nobody <nobody@localhost> | 2003-12-09 09:57:09 +0800 |
commit | 40e6fffa5ed18480dc9a4d952d55ebd819a9d953 (patch) | |
tree | 75bb0caf9afd4b94842023406d6a7938c5d8b2b7 /camel/providers | |
parent | 0031a7166cd0f3fc0cec0b60c468ca22a8c45b0b (diff) | |
download | gsoc2013-evolution-40e6fffa5ed18480dc9a4d952d55ebd819a9d953.tar gsoc2013-evolution-40e6fffa5ed18480dc9a4d952d55ebd819a9d953.tar.gz gsoc2013-evolution-40e6fffa5ed18480dc9a4d952d55ebd819a9d953.tar.bz2 gsoc2013-evolution-40e6fffa5ed18480dc9a4d952d55ebd819a9d953.tar.lz gsoc2013-evolution-40e6fffa5ed18480dc9a4d952d55ebd819a9d953.tar.xz gsoc2013-evolution-40e6fffa5ed18480dc9a4d952d55ebd819a9d953.tar.zst gsoc2013-evolution-40e6fffa5ed18480dc9a4d952d55ebd819a9d953.zip |
This commit was manufactured by cvs2svn to create tagRELEASE-2_8_0
'RELEASE-2_8_0'.
svn path=/tags/RELEASE-2_8_0/; revision=23849
Diffstat (limited to 'camel/providers')
132 files changed, 0 insertions, 36056 deletions
diff --git a/camel/providers/.cvsignore b/camel/providers/.cvsignore deleted file mode 100644 index 3dda72986f..0000000000 --- a/camel/providers/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -Makefile.in -Makefile diff --git a/camel/providers/Makefile.am b/camel/providers/Makefile.am deleted file mode 100644 index 119966aacb..0000000000 --- a/camel/providers/Makefile.am +++ /dev/null @@ -1,12 +0,0 @@ -## Process this file with automake to produce Makefile.in - -if ENABLE_NNTP -NNTP_DIR=nntp -endif - -if ENABLE_IMAPP -IMAPP_DIR=imapp -endif - -SUBDIRS = pop3 sendmail smtp imap $(NNTP_DIR) local $(IMAPP_DIR) - 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 1a2f46faf9..0000000000 --- a/camel/providers/imap/Makefile.am +++ /dev/null @@ -1,48 +0,0 @@ -## Process this file with automake to produce Makefile.in - -libcamelimapincludedir = $(privincludedir)/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) \ - $(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 45e5751b87..0000000000 --- a/camel/providers/imap/camel-imap-command.c +++ /dev/null @@ -1,822 +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> -#include <camel/camel-session.h> - - -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 (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); - } - - 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 (!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; - else if (!strncasecmp (respbuf, "* OK [ALERT]", 12)) { - char *msg; - - /* for imap ALERT codes, account user@host */ - msg = g_strdup_printf(_("Alert from IMAP server %s@%s:\n%s"), - ((CamelService *)store)->url->user, ((CamelService *)store)->url->host, respbuf+12); - camel_session_alert_user(((CamelService *)store)->session, CAMEL_SESSION_ALERT_WARNING, msg, FALSE); - g_free(msg); - } - - 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 && !strncasecmp (p, " OK", 3)) - return response; - - /* We should never get BAD, or anything else but +, OK, or NO - * for that matter. - */ - if (!p || 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_SYSTEM, - _("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, ldigits, nread, i; - unsigned int length; - 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 || length >= UINT_MAX - 2) - 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 (!strcasecmp (p, " EXISTS")) { - exists = number; - } else if (!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 (!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 *); - if (*p == 'F') { - /* NB: this is freed during output */ - char *s = camel_imap_store_summary_full_from_path(store->summary, string); - string = s?s:camel_utf8_utf7(string); - } - 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 (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 4db0c7a43f..0000000000 --- a/camel/providers/imap/camel-imap-folder.c +++ /dev/null @@ -1,2729 +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 "e-util/e-time-utils.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 "camel-private.h" -#include "camel-string-utils.h" -#include "camel-file-utils.h" - - -#define d(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 (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) && - !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 (!strncasecmp (resp, "FLAGS ", 6) && - !folder->permanent_flags) { - resp += 6; - folder->permanent_flags = imap_parse_flag_list (&resp); - } else if (!strncasecmp (resp, "OK [PERMANENTFLAGS ", 19)) { - resp += 19; - folder->permanent_flags = imap_parse_flag_list (&resp); - } else if (!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 (!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 (!strcasecmp (resp, " EXISTS")) { - /* Another one?? */ - exists = val; - continue; - } - if (uid != 0 || val != count || 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, ex); - 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_append_printf (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_append_printf (gset, "%s", camel_message_info_uid (info)); - } - - if (range != -1 && range != max - 1) { - info = matches->pdata[matches->len - 1]; - g_string_append_printf (gset, ":%s", camel_message_info_uid (info)); - } - - if (matches->len) { - *set = gset->str; - g_string_free (gset, FALSE); - return matches; - } else { - *set = NULL; - 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); - - /* 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); - if (matches == NULL) - continue; - - /* 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: 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 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_offline (CamelFolder *folder, GPtrArray *uids, CamelException *ex) -{ - CamelFolderChangeInfo *changes; - int i; - - qsort (uids->pdata, uids->len, sizeof (void *), uid_compar); - - 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; - } - } - - qsort (uids->pdata, uids->len, sizeof (void *), uid_compar); - - 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 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, *response2; - CamelStream *memstream; - CamelMimeFilter *crlf_filter; - CamelStreamFilter *streamfilter; - GByteArray *ba; - char *flagstr, *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; - } - - if (*response->status != '+') { - camel_imap_response_free (store, response); - g_byte_array_free (ba, TRUE); - return NULL; - } - - /* send the rest of our data - the mime message */ - response2 = camel_imap_command_continuation (store, ba->data, ba->len, ex); - g_byte_array_free (ba, TRUE); - - /* free it only after message is sent. This may cause more FETCHes. */ - camel_imap_response_free (store, response); - if (!response2) - return response2; - - if (store->capabilities & IMAP_CAPABILITY_UIDPLUS) { - *uid = camel_strstrcase (response2->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 response2; -} - -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 = camel_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); - - qsort (uids->pdata, uids->len, sizeof (void *), uid_compar); - - /* 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; - - qsort (uids->pdata, uids->len, sizeof (void *), uid_compar); - - /* 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 */ - - qsort (uids->pdata, uids->len, sizeof (void *), uid_compar); - - 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 && camel_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 (camel_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), CAMEL_DATA_WRAPPER (part)->mime_type); - - spec = g_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 (camel_content_type_is (ci->type, "multipart", "*")) { - CamelMultipart *body_mp; - char *child_spec; - int speclen, num; - - if (camel_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), CAMEL_DATA_WRAPPER (part)->mime_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 (camel_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"), - g_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); - - 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 char *tm_months[] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" -}; - -static gboolean -decode_time (const unsigned char **in, int *hour, int *min, int *sec) -{ - register const unsigned char *inptr; - int *val, colons = 0; - - *hour = *min = *sec = 0; - - val = hour; - for (inptr = *in; *inptr && !isspace ((int) *inptr); inptr++) { - if (*inptr == ':') { - colons++; - switch (colons) { - case 1: - val = min; - break; - case 2: - val = sec; - break; - default: - return FALSE; - } - } else if (!isdigit ((int) *inptr)) - return FALSE; - else - *val = (*val * 10) + (*inptr - '0'); - } - - *in = inptr; - - return TRUE; -} - -static time_t -decode_internaldate (const unsigned char *in) -{ - const unsigned char *inptr = in; - int hour, min, sec, n; - unsigned char *buf; - struct tm tm; - time_t date; - - memset ((void *) &tm, 0, sizeof (struct tm)); - - tm.tm_mday = strtoul (inptr, (char **) &buf, 10); - if (buf == inptr || *buf != '-') - return (time_t) -1; - - inptr = buf + 1; - if (inptr[3] != '-') - return (time_t) -1; - - for (n = 0; n < 12; n++) { - if (!strncasecmp (inptr, tm_months[n], 3)) - break; - } - - if (n >= 12) - return (time_t) -1; - - tm.tm_mon = n; - - inptr += 4; - - n = strtoul (inptr, (char **) &buf, 10); - if (buf == inptr || *buf != ' ') - return (time_t) -1; - - tm.tm_year = n - 1900; - - inptr = buf + 1; - if (!decode_time (&inptr, &hour, &min, &sec)) - return (time_t) -1; - - tm.tm_hour = hour; - tm.tm_min = min; - tm.tm_sec = sec; - - n = strtol (inptr, NULL, 10); - - date = e_mktime_utc (&tm); - - /* date is now GMT of the time we want, but not offset by the timezone ... */ - - /* this should convert the time to the GMT equiv time */ - date -= ((n / 100) * 60 * 60) + (n % 100) * 60; - - return date; -} - -static void -add_message_from_data (CamelFolder *folder, GPtrArray *messages, - int first, GData *data) -{ - CamelMimeMessage *msg; - CamelStream *stream; - CamelMessageInfo *mi; - const char *idate; - 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)); - - if ((idate = g_datalist_get_data (&data, "INTERNALDATE"))) - mi->date_received = decode_internaldate (idate); - - if (mi->date_received == -1) - mi->date_received = mi->date_sent; - - messages->pdata[seq - first] = mi; -} - - -#define CAMEL_MESSAGE_INFO_HEADERS "DATE FROM TO CC SUBJECT REFERENCES IN-REPLY-TO MESSAGE-ID MIME-VERSION CONTENT-TYPE" - -/* FIXME: this needs to be kept in sync with camel-mime-utils.c's list - of mailing-list headers and so might be best if this were - auto-generated? */ -#define MAILING_LIST_HEADERS "X-MAILING-LIST X-LOOP LIST-ID LIST-POST MAILING-LIST ORIGINATOR X-LIST SENDER RETURN-PATH X-BEENTHERE" - -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; - 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.FIELDS.NOT (RECEIVED)"; - 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 = strtoul(camel_message_info_uid (mi), NULL, 10); - camel_folder_summary_info_free (folder->summary, mi); - } else - uidval = 0; - - size = (exists - seq) * (IMAP_PRETEND_SIZEOF_FLAGS + IMAP_PRETEND_SIZEOF_SIZE + IMAP_PRETEND_SIZEOF_HEADERS); - got = 0; - if (!camel_imap_command_start (store, folder, ex, - "UID FETCH %d:* (FLAGS RFC822.SIZE INTERNALDATE BODY.PEEK[%s])", - uidval + 1, header_spec)) - return; - camel_operation_start (NULL, _("Fetching summary information 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, ex); - if (!stream && (!strcmp (section_text, "HEADER") || !strcmp (section_text, "0"))) { - camel_exception_clear (ex); - stream = camel_imap_message_cache_get (imap_folder->cache, uid, "", ex); - } - - 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; - } - - camel_exception_clear (ex); - 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, *idate = NULL; - gboolean cache_header = TRUE, header = FALSE; - size_t 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 (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 (!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 (!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 (!strncasecmp (response, "BODY[", 5) || - !strncasecmp (response, "RFC822 ", 7)) { - char *p; - - if (*response == 'B') { - response += 5; - - /* HEADER], HEADER.FIELDS (...)], or 0] */ - if (!strncasecmp (response, "HEADER", 6)) { - header = TRUE; - if (!strncasecmp (response + 6, ".FIELDS", 7)) - cache_header = FALSE; - } else if (!strncasecmp (response, "0]", 2)) - header = TRUE; - - p = strchr (response, ']'); - if (!p || *(p + 1) != ' ') - break; - - if (cache_header) - part_spec = g_strndup (response, p - response); - else - part_spec = g_strdup ("HEADER.FIELDS"); - - response = p + 2; - } else { - part_spec = g_strdup (""); - response += 7; - - if (!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 (!strncasecmp (response, "BODY ", 5) || - !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 (!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 if (!strncasecmp (response, "INTERNALDATE ", 13)) { - int len; - - response += 13; - if (*response == '"') { - response++; - len = strcspn (response, "\""); - idate = g_strndup (response, len); - g_datalist_set_data_full (&data, "INTERNALDATE", idate, g_free); - response += len + 1; - } - } 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 (header && !cache_header) { - 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 559c6d2f88..0000000000 --- a/camel/providers/imap/camel-imap-message-cache.c +++ /dev/null @@ -1,527 +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 - * @ex: exception - * - * 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, CamelException *ex) -{ - 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); - } else { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Failed to cache %s: %s"), - part_spec, g_strerror (errno)); - } - - 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; - - if ((stream = camel_imap_message_cache_get (source, source_uid, part, ex))) { - 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 c79195cfa4..0000000000 --- a/camel/providers/imap/camel-imap-message-cache.h +++ /dev/null @@ -1,111 +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, - CamelException *ex); - -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 abda8f89a0..0000000000 --- a/camel/providers/imap/camel-imap-provider.c +++ /dev/null @@ -1,158 +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, "cmdsection", NULL, - N_("Connection to Server") }, - { CAMEL_PROVIDER_CONF_CHECKBOX, "use_command", NULL, - N_("Use custom command to connect to server"), "0" }, - { CAMEL_PROVIDER_CONF_ENTRY, "command", "use_command", - N_("Command:"), "ssh -C -l %u %h exec /usr/sbin/imapd" }, - { CAMEL_PROVIDER_CONF_SECTION_END }, - { 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_CHECKBOX, "offline_sync", NULL, - N_("Automatically synchronize remote mail locally"), "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 eacb839cb2..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) - -/* - 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); - - camel_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_append_printf (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_append_printf (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, GUINT_TO_POINTER(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, GUINT_TO_POINTER(*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 32530d3c3f..0000000000 --- a/camel/providers/imap/camel-imap-store-summary.c +++ /dev/null @@ -1,619 +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. - */ - -#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 "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; - CamelImapStoreNamespace *ns; - - /* 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; - } - - ns = camel_imap_store_summary_namespace_find_path(s, path); - - f = full = alloca(strlen(path)*2+1); - if (si) - p = path + strlen(subpath); - else if (ns) - p = path + strlen(ns->path); - 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; - } else if (ns) { - full = g_strdup_printf("%s%s", ns->full_name, f); - g_free(f); - f = full; - } - - return f; -} - -CamelImapStoreInfo * -camel_imap_store_summary_add_from_full(CamelImapStoreSummary *s, const char *full, char dir_sep) -{ - CamelImapStoreInfo *info; - char *pathu8, *prefix; - int len; - char *full_name; - CamelImapStoreNamespace *ns; - - d(printf("adding full name '%s' '%c'\n", full, dir_sep)); - - len = strlen(full); - full_name = alloca(len+1); - strcpy(full_name, full); - if (full_name[len-1] == dir_sep) - full_name[len-1] = 0; - - 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; - } - - ns = camel_imap_store_summary_namespace_find_full(s, full_name); - if (ns) { - d(printf("(found namespace for '%s' ns '%s') ", full_name, ns->path)); - len = strlen(ns->full_name); - if (len >= strlen(full_name)) { - pathu8 = g_strdup(ns->path); - } else { - if (full_name[len] == ns->sep) - len++; - - prefix = camel_imap_store_summary_full_to_path(s, full_name+len, ns->sep); - if (*ns->path) { - pathu8 = g_strdup_printf ("%s/%s", ns->path, prefix); - g_free (prefix); - } else { - pathu8 = prefix; - } - } - d(printf(" (pathu8 = '%s')", pathu8)); - } else { - d(printf("(Cannot find namespace for '%s')\n", full_name)); - 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? */ -/* TODO: deprecate/merge this function with path_to_full */ -char * -camel_imap_store_summary_full_from_path(CamelImapStoreSummary *s, const char *path) -{ - CamelImapStoreNamespace *ns; - char *name = NULL; - - ns = camel_imap_store_summary_namespace_find_path(s, path); - if (ns) - name = camel_imap_store_summary_path_to_full(s, path, ns->sep); - - d(printf("looking up path %s -> %s\n", path, name?name:"not found")); - - return name; -} - -/* 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; - char *p, *o, c; - int len; - - ns = g_malloc0(sizeof(*ns)); - ns->full_name = g_strdup(full_name); - len = strlen(ns->full_name)-1; - if (len >= 0 && ns->full_name[len] == dir_sep) - ns->full_name[len] = 0; - ns->sep = dir_sep; - - o = p = ns->path = camel_imap_store_summary_full_to_path(s, ns->full_name, dir_sep); - while ((c = *p++)) { - if (c != '#') { - if (c == '/') - c = '.'; - *o++ = c; - } - } - *o = 0; - - return ns; -} - -void camel_imap_store_summary_namespace_set(CamelImapStoreSummary *s, CamelImapStoreNamespace *ns) -{ - static void namespace_clear(CamelStoreSummary *s); - - d(printf("Setting namesapce to '%s' '%c' -> '%s'\n", ns->full_name, ns->sep, ns->path)); - namespace_clear((CamelStoreSummary *)s); - s->namespace = ns; - camel_store_summary_touch((CamelStoreSummary *)s); -} - -CamelImapStoreNamespace * -camel_imap_store_summary_namespace_find_path(CamelImapStoreSummary *s, const char *path) -{ - int len; - CamelImapStoreNamespace *ns; - - /* NB: this currently only compares against 1 namespace, in future compare against others */ - ns = s->namespace; - while (ns) { - len = strlen(ns->path); - if (len == 0 - || (strncmp(ns->path, path, len) == 0 - && (path[len] == '/' || path[len] == 0))) - break; - ns = NULL; - } - - /* have a default? */ - return ns; -} - -CamelImapStoreNamespace * -camel_imap_store_summary_namespace_find_full(CamelImapStoreSummary *s, const char *full) -{ - int len; - CamelImapStoreNamespace *ns; - - /* NB: this currently only compares against 1 namespace, in future compare against others */ - ns = s->namespace; - while (ns) { - len = strlen(ns->full_name); - d(printf("find_full: comparing namespace '%s' to name '%s'\n", ns->full_name, full)); - if (len == 0 - || (strncmp(ns->full_name, full, len) == 0 - && (full[len] == ns->sep || full[len] == 0))) - break; - ns = NULL; - } - - /* have a default? */ - return ns; -} - -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 0fa6be0df3..0000000000 --- a/camel/providers/imap/camel-imap-store-summary.h +++ /dev/null @@ -1,102 +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, needs to support lists */ -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); -CamelImapStoreNamespace *camel_imap_store_summary_namespace_find_path(CamelImapStoreSummary *s, const char *path); -CamelImapStoreNamespace *camel_imap_store_summary_namespace_find_full(CamelImapStoreSummary *s, const char *full_name); - -/* 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 07152eef87..0000000000 --- a/camel/providers/imap/camel-imap-store.c +++ /dev/null @@ -1,2845 +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, 2003 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-stream-process.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 "camel-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->preauthed = 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? */ - break; - } - } - - 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 (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 -}; - -#define SSL_PORT_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3) -#define STARTTLS_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_TLS) - -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; - - if (ssl_mode != USE_SSL_NEVER) { -#ifdef HAVE_SSL - if (try_starttls) { - tcp_stream = camel_tcp_stream_ssl_new_raw (service->session, service->url->host, STARTTLS_FLAGS); - } else { - port = service->url->port ? service->url->port : 993; - tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, SSL_PORT_FLAGS); - } -#else - if (!try_starttls) - port = service->url->port ? service->url->port : 993; - - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Could not connect to %s (port %d): %s"), - service->url->host, port, - _("SSL unavailable")); - - camel_free_host (h); - - return FALSE; -#endif /* HAVE_SSL */ - } else { - tcp_stream = camel_tcp_stream_raw_new (); - } - - 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->preauthed = FALSE; - store->command = 0; - - /* Read the greeting, if any, and 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; - } - if (!strncmp(buf, "* PREAUTH", 9)) - store->preauthed = TRUE; - 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)) { - 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; - } - - return TRUE; - - exception: - - if (clean_quit && store->connected) { - /* try to disconnect cleanly */ - response = camel_imap_command (store, NULL, ex, "LOGOUT"); - if (response) - camel_imap_response_free_without_processing (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; - } - - store->connected = FALSE; - - return FALSE; -#endif /* HAVE_SSL */ -} - -static gboolean -connect_to_server_process (CamelService *service, const char *cmd, CamelException *ex) -{ - CamelImapStore *store = (CamelImapStore *) service; - CamelStream *cmd_stream; - int ret, i = 0; - char *buf; - char *cmd_copy; - char *full_cmd; - char *child_env[7]; - - /* Put full details in the environment, in case the connection - program needs them */ - buf = camel_url_to_string(service->url, 0); - child_env[i++] = g_strdup_printf("URL=%s", buf); - g_free(buf); - - child_env[i++] = g_strdup_printf("URLHOST=%s", service->url->host); - if (service->url->port) - child_env[i++] = g_strdup_printf("URLPORT=%d", service->url->port); - if (service->url->user) - child_env[i++] = g_strdup_printf("URLUSER=%s", service->url->user); - if (service->url->passwd) - child_env[i++] = g_strdup_printf("URLPASSWD=%s", service->url->passwd); - if (service->url->path) - child_env[i++] = g_strdup_printf("URLPATH=%s", service->url->path); - child_env[i] = NULL; - - /* Now do %h, %u, etc. substitution in cmd */ - buf = cmd_copy = g_strdup(cmd); - - full_cmd = g_strdup(""); - - for(;;) { - char *pc; - char *tmp; - char *var; - int len; - - pc = strchr(buf, '%'); - ignore: - if (!pc) { - tmp = g_strdup_printf("%s%s", full_cmd, buf); - g_free(full_cmd); - full_cmd = tmp; - break; - } - - len = pc - buf; - - var = NULL; - - switch(pc[1]) { - case 'h': - var = service->url->host; - break; - case 'u': - var = service->url->user; - break; - } - if (!var) { - /* If there wasn't a valid %-code, with an actual - variable to insert, pretend we didn't see the % */ - pc = strchr(pc + 1, '%'); - goto ignore; - } - tmp = g_strdup_printf("%s%.*s%s", full_cmd, len, buf, var); - g_free(full_cmd); - full_cmd = tmp; - buf = pc + 2; - } - - g_free(cmd_copy); - - cmd_stream = camel_stream_process_new (); - - ret = camel_stream_process_connect (CAMEL_STREAM_PROCESS(cmd_stream), - full_cmd, (const char **)child_env); - - while (i) - g_free(child_env[--i]); - - 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 with command \"%s\": %s"), - full_cmd, g_strerror (errno)); - - camel_object_unref (CAMEL_OBJECT (cmd_stream)); - g_free(full_cmd); - return FALSE; - } - g_free(full_cmd); - - store->ostream = cmd_stream; - store->istream = camel_stream_buffer_new (cmd_stream, CAMEL_STREAM_BUFFER_READ); - - store->connected = TRUE; - store->preauthed = FALSE; - store->command = 0; - - /* Read the greeting, if any, and 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; - } - if (!strncmp(buf, "* PREAUTH", 9)) - store->preauthed = TRUE; - 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; - } - - return TRUE; - -} - -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) -{ - const char *command; -#ifdef HAVE_SSL - const char *use_ssl; - int i, ssl_mode; -#endif - command = camel_url_get_param (service->url, "command"); - if (command) - return connect_to_server_process (service, command, ex); - -#ifdef HAVE_SSL - 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 (cache); - camel_object_unref (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 = response->untagged->len != 0; - - camel_imap_response_free_without_processing (imap_store, response); - - return stillthere; - } - - /* if the command was rejected, there must be some other error, - assume it worked so we dont blow away the folder unecessarily */ - return TRUE; -} - -/* 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 = camel_object_bag_list(CAMEL_STORE (store)->folders); - - 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(folder); - imap_folder_effectively_unsubscribed (store, namedup, ex); - imap_forget_folder (store, namedup, ex); - g_free (namedup); - } else - camel_object_unref(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 (store->preauthed) { - if (camel_verbose_debug) - fprintf(stderr, "Server %s has preauthenticated us.\n", - service->url->host); - return TRUE; - } - - 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, FALSE, 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; - -#if 0 - /* new code... */ - namespaces = imap_parse_namespace_response (result); - imap_namespaces_destroy (namespaces); - /* end new code */ -#endif - - name = camel_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) { - gboolean haveinbox = FALSE; - GPtrArray *folders; - char *pattern; - - /* this pre-fills the summary, and checks that lsub is useful */ - folders = g_ptr_array_new (); - pattern = g_strdup_printf ("%s*", store->namespace); - get_folders_online (store, pattern, folders, TRUE, ex); - g_free (pattern); - - for (i = 0; i < folders->len; i++) { - CamelFolderInfo *fi = folders->pdata[i]; - - haveinbox = haveinbox || !strcasecmp (fi->full_name, "INBOX"); - - if (fi->flags & (CAMEL_IMAP_FOLDER_MARKED | CAMEL_IMAP_FOLDER_UNMARKED)) - store->capabilities |= IMAP_CAPABILITY_useful_lsub; - camel_folder_info_free (fi); - } - - /* if the namespace is under INBOX, check INBOX explicitly */ - if (!strncasecmp (store->namespace, "INBOX", 5) && !camel_exception_is_set (ex)) { - gboolean just_subscribed = FALSE; - gboolean need_subscribe = FALSE; - - recheck: - g_ptr_array_set_size (folders, 0); - get_folders_online (store, "INBOX", folders, TRUE, ex); - - for (i = 0; i < folders->len; i++) { - CamelFolderInfo *fi = folders->pdata[i]; - - /* this should always be TRUE if folders->len > 0 */ - if (!strcasecmp (fi->full_name, "INBOX")) { - haveinbox = TRUE; - - /* if INBOX is marked as \NoSelect then it is probably - because it has not been subscribed to */ - if (!need_subscribe) - need_subscribe = fi->flags & CAMEL_FOLDER_NOSELECT; - } - - camel_folder_info_free (fi); - } - - need_subscribe = !haveinbox || need_subscribe; - if (need_subscribe && !just_subscribed && !camel_exception_is_set (ex)) { - /* in order to avoid user complaints, force a subscription to INBOX */ - response = camel_imap_command (store, NULL, ex, "SUBSCRIBE INBOX"); - if (response != NULL) { - /* force a re-check which will pre-fill the summary and - also get any folder flags present on the INBOX */ - camel_imap_response_free (store, response); - just_subscribed = TRUE; - goto recheck; - } - } - } - - 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. NB: must avoid folder lock */ - ((CamelFolderClass *)((CamelObject *)current_folder)->klass)->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 (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 (strcasecmp (a, "INBOX") == 0) - aname = "INBOX"; - if (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 = camel_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 (!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 (!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; - char sep, *dir; - CamelURL *url; - CamelImapStoreInfo *si; - guint32 newflags; - - 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 */ - - si = camel_imap_store_summary_add_from_full(imap_store->summary, dir, sep?sep:'/'); - newflags = (si->info.flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) | (flags & ~CAMEL_STORE_INFO_FOLDER_SUBSCRIBED); - if (si->info.flags != newflags) { - si->info.flags = newflags; - camel_store_summary_touch((CamelStoreSummary *)imap_store->summary); - } - - fi = g_new0 (CamelFolderInfo, 1); - fi->flags = flags; - fi->name = g_strdup(camel_store_info_name(imap_store->summary, si)); - fi->path = g_strdup_printf("/%s", camel_store_info_path(imap_store->summary, si)); - fi->full_name = g_strdup(fi->path+1); - - url = camel_url_new (imap_store->base_url, NULL); - camel_url_set_path(url, fi->path); - - 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; - int haveinbox = FALSE; - - 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)); - haveinbox = haveinbox || strcasecmp(camel_imap_store_info_full_name(imap_store->summary, si), "INBOX") == 0; - } - camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si); - } - - if (!haveinbox) - 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 0 -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; - CamelFolder *folder; - - /* 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"); - /* if we have this folder open, and the unread count has changed, update */ - folder = camel_object_bag_get(CAMEL_STORE(imap_store)->folders, fi->full_name); - if (folder && fi->unread_message_count != camel_folder_get_unread_message_count(folder)) { - CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(folder))->refresh_info(folder, ex); - fi->unread_message_count = camel_folder_get_unread_message_count(folder); - } - if (folder) - camel_object_unref(folder); - - } - - CAMEL_SERVICE_UNLOCK (imap_store, connect_lock); - } else { - /* since its cheap, get it if they're open */ - folder = camel_object_bag_get(CAMEL_STORE(imap_store)->folders, fi->full_name); - if (folder) { - fi->unread_message_count = camel_folder_get_unread_message_count(folder); - camel_object_unref(folder); - } 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); - CamelFolderInfo *tree; - GPtrArray *folders; - - 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; - - tree = camel_folder_info_build(folders, top, '/', TRUE); - g_ptr_array_free(folders, TRUE); - - if (!(flags & CAMEL_STORE_FOLDER_INFO_FAST)) - get_folder_counts(imap_store, tree, ex); - - d(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); - fi->flags = si->flags; - if (si->flags & CAMEL_FOLDER_NOSELECT) { - CamelURL *url = camel_url_new(fi->url, NULL); - - camel_url_set_param (url, "noselect", "yes"); - g_free(fi->url); - fi->url = camel_url_to_string (url, 0); - camel_url_free (url); - } - 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 b45fb2110e..0000000000 --- a/camel/providers/imap/camel-imap-store.h +++ /dev/null @@ -1,148 +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; - gboolean preauthed; - char tag_prefix; - guint32 command; - CamelFolder *current_folder; - - /* Information about the server */ - CamelImapServerLevel server_level; - guint32 capabilities, parameters; - /* NB: namespace should be handled by summary->namespace */ - 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 879cc23cca..0000000000 --- a/camel/providers/imap/camel-imap-utils.c +++ /dev/null @@ -1,1261 +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> - -#include "camel-imap-utils.h" -#include "camel-imap-summary.h" -#include "camel-imap-store.h" -#include "camel-folder.h" -#include "camel-string-utils.h" -#include "camel-utf8.h" - -#define d(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 (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 (!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; -} - -#if d(!)0 -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"); -} -#endif - -struct _namespaces * -imap_parse_namespace_response (const char *response) -{ - struct _namespaces *namespaces; - const char *inptr; - - d(printf ("parsing: %s\n", response)); - - if (*response != '*') - return NULL; - - inptr = imap_next_word (response); - if (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; - - d(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 (strncasecmp (word, "LIST", 4) && 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 (!strncasecmp (word, "\\NoInferiors", len)) - *flags |= CAMEL_FOLDER_NOINFERIORS; - else if (!strncasecmp (word, "\\NoSelect", len)) - *flags |= CAMEL_FOLDER_NOSELECT; - else if (!strncasecmp (word, "\\Marked", len)) - *flags |= CAMEL_IMAP_FOLDER_MARKED; - else if (!strncasecmp (word, "\\Unmarked", len)) - *flags |= CAMEL_IMAP_FOLDER_UNMARKED; - else if (!strncasecmp (word, "\\HasChildren", len)) - *flags |= CAMEL_FOLDER_CHILDREN; - else if (!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; - - /* get the folder name */ - word = imap_next_word (word); - astring = imap_parse_astring (&word, &len); - if (!astring) - return FALSE; - - *folder = astring; -#if 0 - char *mailbox; - - 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 (!strncasecmp (flag_list, "\\Answered", len)) - flags |= CAMEL_MESSAGE_ANSWERED; - else if (!strncasecmp (flag_list, "\\Deleted", len)) - flags |= CAMEL_MESSAGE_DELETED; - else if (!strncasecmp (flag_list, "\\Draft", len)) - flags |= CAMEL_MESSAGE_DRAFT; - else if (!strncasecmp (flag_list, "\\Flagged", len)) - flags |= CAMEL_MESSAGE_FLAGGED; - else if (!strncasecmp (flag_list, "\\Seen", len)) - flags |= CAMEL_MESSAGE_SEEN; - else if (!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, 0, 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 && !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 int -parse_params (const char **parms_p, CamelContentType *type) -{ - const char *parms = *parms_p; - char *name, *value; - size_t len; - - if (!strncasecmp (parms, "nil", 3)) { - *parms_p += 3; - return 0; - } - - if (*parms++ != '(') - return -1; - - while (parms && *parms != ')') { - name = imap_parse_nstring (&parms, &len); - skip_char (&parms, ' '); - value = imap_parse_nstring (&parms, &len); - - if (name && value) - camel_content_type_set_param (type, name, value); - g_free (name); - g_free (value); - - if (parms && *parms == ' ') - parms++; - } - - if (!parms || *parms++ != ')') - return -1; - - *parms_p = parms; - - return 0; -} - - -static CamelMessageContentInfo * -imap_body_decode (const char **in, CamelMessageContentInfo *ci, CamelFolder *folder, GPtrArray *cis) -{ - const char *inptr = *in; - CamelMessageContentInfo *child = NULL; - char *type, *subtype, *id = NULL; - CamelContentType *ctype = NULL; - char *description = NULL; - char *encoding = NULL; - size_t len; - size_t size; - char *p; - - if (*inptr++ != '(') - return NULL; - - if (ci == NULL) { - ci = camel_folder_summary_content_info_new (folder->summary); - g_ptr_array_add (cis, ci); - } - - if (*inptr == '(') { - /* body_type_mpart */ - CamelMessageContentInfo *tail, *children = NULL; - - tail = (CamelMessageContentInfo *) &children; - - do { - if (!(child = imap_body_decode (&inptr, NULL, folder, cis))) - return NULL; - - child->parent = ci; - tail->next = child; - tail = child; - } while (*inptr == '('); - - if (*inptr++ != ' ') - return NULL; - - if (!strncasecmp (inptr, "nil", 3) != 0) { - subtype = imap_parse_string (&inptr, &len); - } else { - subtype = NULL; - inptr += 3; - } - - ctype = camel_content_type_new ("multipart", subtype ? subtype : "mixed"); - g_free (subtype); - - if (*inptr++ != ')') { - camel_content_type_unref (ctype); - return NULL; - } - - ci->type = ctype; - ci->childs = children; - } else { - /* body_type_1part */ - if (strncasecmp (inptr, "nil", 3) != 0) { - type = imap_parse_string (&inptr, &len); - if (inptr == NULL) - return NULL; - } else { - return NULL; - } - - if (*inptr++ != ' ') { - g_free (type); - return NULL; - } - - if (strncasecmp (inptr, "nil", 3) != 0) { - subtype = imap_parse_string (&inptr, &len); - if (inptr == NULL) { - g_free (type); - return NULL; - } - } else { - if (!strcasecmp (type, "text")) - subtype = g_strdup ("plain"); - else - subtype = NULL; - inptr += 3; - } - - camel_strdown (type); - camel_strdown (subtype); - ctype = camel_content_type_new (type, subtype); - g_free (subtype); - g_free (type); - - if (*inptr++ != ' ') - goto exception; - - /* content-type params */ - if (parse_params (&inptr, ctype) == -1) - goto exception; - - if (*inptr++ != ' ') - goto exception; - - /* content-id */ - if (strncasecmp (inptr, "nil", 3) != 0) { - id = imap_parse_string (&inptr, &len); - if (inptr == NULL) - goto exception; - } else - inptr += 3; - - if (*inptr++ != ' ') - goto exception; - - /* description */ - if (strncasecmp (inptr, "nil", 3) != 0) { - description = imap_parse_string (&inptr, &len); - if (inptr == NULL) - goto exception; - } else - inptr += 3; - - if (*inptr++ != ' ') - goto exception; - - /* encoding */ - if (strncasecmp (inptr, "nil", 3) != 0) { - encoding = imap_parse_string (&inptr, &len); - if (inptr == NULL) - goto exception; - } else - inptr += 3; - - if (*inptr++ != ' ') - goto exception; - - /* size */ - size = strtoul ((const char *) inptr, &p, 10); - inptr = (const unsigned char *) p; - - if (camel_content_type_is (ctype, "message", "rfc822")) { - /* body_type_msg */ - if (*inptr++ != ' ') - goto exception; - - /* envelope */ - imap_skip_list (&inptr); - - if (*inptr++ != ' ') - goto exception; - - /* body */ - if (!(child = imap_body_decode (&inptr, NULL, folder, cis))) - goto exception; - child->parent = ci; - - if (*inptr++ != ' ') - goto exception; - - /* lines */ - strtoul ((const char *) inptr, &p, 10); - inptr = (const unsigned char *) p; - } else if (camel_content_type_is (ctype, "text", "*")) { - if (*inptr++ != ' ') - goto exception; - - /* lines */ - strtoul ((const char *) inptr, &p, 10); - inptr = (const unsigned char *) p; - } else { - /* body_type_basic */ - } - - if (*inptr++ != ')') - goto exception; - - ci->type = ctype; - ci->id = id; - ci->description = description; - ci->encoding = encoding; - ci->size = size; - ci->childs = child; - } - - *in = inptr; - - return ci; - - exception: - - camel_content_type_unref (ctype); - g_free (id); - g_free (description); - g_free (encoding); - - return NULL; -} - - -/** - * 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 *inptr = *body_p; - CamelMessageContentInfo *child; - GPtrArray *children; - int i; - - if (!inptr || *inptr != '(') { - *body_p = NULL; - return; - } - - children = g_ptr_array_new (); - - if (!(imap_body_decode (&inptr, ci, folder, children))) { - for (i = 0; i < children->len; i++) { - child = children->pdata[i]; - - /* content_info_free will free all the child - * nodes, but we don't want that. */ - child->next = NULL; - child->parent = NULL; - child->childs = NULL; - - camel_folder_summary_content_info_free (folder->summary, child); - } - *body_p = NULL; - } else { - *body_p = inptr; - } - - g_ptr_array_free (children, TRUE); -} - - -/** - * 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. - * - * Note: @uids MUST be in sorted order for this code to work properly. - * - * 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_append_printf (gset, ":%lu", last_uid); - range = FALSE; - } - g_string_append_printf (gset, ",%lu", this_uid); - } - - last_uid = this_uid; - } - - if (range) - g_string_append_printf (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 = g_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 = g_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 2cb07b3012..0000000000 --- a/camel/providers/imap/camel-imap-wrapper.c +++ /dev/null @@ -1,185 +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 ssize_t 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 type = CAMEL_INVALID_TYPE; - - if (type == CAMEL_INVALID_TYPE) { - 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 type; -} - - -static void -imap_wrapper_hydrate (CamelImapWrapper *imap_wrapper, CamelStream *stream) -{ - CamelDataWrapper *data_wrapper = (CamelDataWrapper *) imap_wrapper; - - camel_object_ref (stream); - data_wrapper->stream = stream; - data_wrapper->offline = FALSE; - - camel_object_unref (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 ssize_t -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 (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 (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 (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 diff --git a/camel/providers/imapp/.cvsignore b/camel/providers/imapp/.cvsignore deleted file mode 100644 index 3fa8afaa38..0000000000 --- a/camel/providers/imapp/.cvsignore +++ /dev/null @@ -1,11 +0,0 @@ -.deps -Makefile -Makefile.in -.libs -.deps -*.lo -*.la -*.bb -*.bbg -*.da -*.gcov diff --git a/camel/providers/imapp/Makefile.am b/camel/providers/imapp/Makefile.am deleted file mode 100644 index 7ce8c65fcd..0000000000 --- a/camel/providers/imapp/Makefile.am +++ /dev/null @@ -1,45 +0,0 @@ -## Process this file with automake to produce Makefile.in - -libcamelimappincludedir = $(privincludedir)/camel - -camel_provider_LTLIBRARIES = libcamelimapp.la -camel_provider_DATA = libcamelimapp.urls - -INCLUDES = -I.. \ - -I$(srcdir)/.. \ - -I$(top_srcdir)/camel \ - -I$(top_srcdir)/intl \ - -I$(top_srcdir)/e-util \ - -I$(top_srcdir) \ - $(CAMEL_CFLAGS) \ - $(GNOME_INCLUDEDIR) \ - $(GTK_INCLUDEDIR) \ - -DG_LOG_DOMAIN=\"camel-imapp-provider\" - -libcamelimapp_la_SOURCES = \ - camel-imapp-utils.c \ - camel-imapp-engine.c \ - camel-imapp-stream.c \ - camel-imapp-store.c \ - camel-imapp-folder.c \ - camel-imapp-provider.c \ - camel-imapp-store-summary.c \ - camel-imapp-driver.c \ - camel-imapp-summary.c - -libcamelimappinclude_HEADERS = \ - camel-imapp-utils.h \ - camel-imapp-engine.h \ - camel-imapp-stream.h \ - camel-imapp-store.h \ - camel-imapp-folder.h \ - camel-imapp-store-summary.h \ - camel-imapp-driver.h \ - camel-imapp-summary.h - -libcamelimapp_la_LDFLAGS = -avoid-version -module - -#noinst_HEADERS = \ -# camel-imap-private.h - -EXTRA_DIST = libcamelimapp.urls diff --git a/camel/providers/imapp/camel-imapp-driver.c b/camel/providers/imapp/camel-imapp-driver.c deleted file mode 100644 index 106e98fbb3..0000000000 --- a/camel/providers/imapp/camel-imapp-driver.c +++ /dev/null @@ -1,771 +0,0 @@ - - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <ctype.h> - -#include "camel-imapp-driver.h" -#include "camel-imapp-utils.h" -#include "camel-imapp-folder.h" -#include "camel-imapp-engine.h" -#include "camel-imapp-summary.h" -#include "camel-imapp-exception.h" - -#include <camel/camel-stream-mem.h> -#include <camel/camel-stream-null.h> - -#include <camel/camel-folder-summary.h> -#include <camel/camel-store.h> -#include <camel/camel-mime-utils.h> -#include <camel/camel-sasl.h> - -#define d(x) x - -static int driver_resp_fetch(CamelIMAPPEngine *ie, guint32 id, CamelIMAPPDriver *sdata); -static int driver_resp_expunge(CamelIMAPPEngine *ie, guint32 id, CamelIMAPPDriver *sdata); -static int driver_resp_exists(CamelIMAPPEngine *ie, guint32 id, CamelIMAPPDriver *sdata); -static int driver_resp_list(CamelIMAPPEngine *ie, guint32 id, CamelIMAPPDriver *sdata); - -static void driver_status(CamelIMAPPEngine *ie, struct _status_info *sinfo, CamelIMAPPDriver *sdata); - -static void -class_init(CamelIMAPPDriverClass *ieclass) -{ -} - -static void -object_init(CamelIMAPPDriver *ie, CamelIMAPPDriverClass *ieclass) -{ - ie->summary = g_ptr_array_new(); - e_dlist_init(&ie->body_fetch); - e_dlist_init(&ie->body_fetch_done); -} - -static void -object_finalise(CamelIMAPPDriver *ie, CamelIMAPPDriverClass *ieclass) -{ - if (ie->folder) - camel_object_unref((CamelObject *)ie->folder); - if (ie->engine) - camel_object_unref((CamelObject *)ie->engine); - if (ie->summary) - g_ptr_array_free(ie->summary, TRUE); -} - -CamelType -camel_imapp_driver_get_type (void) -{ - static CamelType type = CAMEL_INVALID_TYPE; - - if (type == CAMEL_INVALID_TYPE) { - type = camel_type_register ( - camel_object_get_type (), - "CamelIMAPPDriver", - sizeof (CamelIMAPPDriver), - sizeof (CamelIMAPPDriverClass), - (CamelObjectClassInitFunc) class_init, - NULL, - (CamelObjectInitFunc) object_init, - (CamelObjectFinalizeFunc) object_finalise); - } - - return type; -} - -CamelIMAPPDriver * -camel_imapp_driver_new(CamelIMAPPStream *stream) -{ - CamelIMAPPDriver *driver; - CamelIMAPPEngine *ie; - - driver = CAMEL_IMAPP_DRIVER (camel_object_new (CAMEL_IMAPP_DRIVER_TYPE)); - ie = driver->engine = camel_imapp_engine_new(stream); - - camel_imapp_engine_add_handler(ie, "FETCH", (CamelIMAPPEngineFunc)driver_resp_fetch, driver); - camel_imapp_engine_add_handler(ie, "EXPUNGE", (CamelIMAPPEngineFunc)driver_resp_expunge, driver); - camel_imapp_engine_add_handler(ie, "EXISTS", (CamelIMAPPEngineFunc)driver_resp_exists, driver); - camel_imapp_engine_add_handler(ie, "LIST", (CamelIMAPPEngineFunc)driver_resp_list, driver); - camel_object_hook_event(ie, "status", (CamelObjectEventHookFunc)driver_status, driver); - - return driver; -} - -void -camel_imapp_driver_set_sasl_factory(CamelIMAPPDriver *id, CamelIMAPPSASLFunc get_sasl, void *sasl_data) -{ - id->get_sasl = get_sasl; - id->get_sasl_data = sasl_data; -} - -void -camel_imapp_driver_set_login_query(CamelIMAPPDriver *id, CamelIMAPPLoginFunc get_login, void *login_data) -{ - id->get_login = get_login; - id->get_login_data = login_data; -} - -void -camel_imapp_driver_login(CamelIMAPPDriver *id) -/* throws SERVICE_CANT_AUTHENTICATE, SYSTEM_IO */ -{ - CamelIMAPPCommand * volatile ic = NULL; - - /* connect? */ - /* camel_imapp_engine_connect() */ - /* or above? */ - - CAMEL_TRY { - CamelSasl *sasl; - - if (id->get_sasl - && (sasl = id->get_sasl(id, id->get_sasl_data))) { - ic = camel_imapp_engine_command_new(id->engine, "AUTHENTICATE", NULL, "AUTHENTICATE %A", sasl); - camel_object_unref(sasl); - } else { - char *user, *pass; - - g_assert(id->get_login); - id->get_login(id, &user, &pass, id->get_login_data); - ic = camel_imapp_engine_command_new(id->engine, "LOGIN", NULL, "LOGIN %s %s", user, pass); - g_free(user); - g_free(pass); - } - - camel_imapp_engine_command_queue(id->engine, ic); - while (camel_imapp_engine_iterate(id->engine, ic) > 0) - ; - - if (ic->status->result != IMAP_OK) - camel_exception_throw(CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE, "Login failed: %s", ic->status->text); - camel_imapp_engine_command_free(id->engine, ic); - } CAMEL_CATCH(ex) { - if (ic) - camel_imapp_engine_command_free(id->engine, ic); - camel_exception_throw_ex(ex); - } CAMEL_DONE; -} - -void -camel_imapp_driver_select(CamelIMAPPDriver *id, struct _CamelIMAPPFolder *folder) -{ - CamelIMAPPSelectResponse *sr; - CamelIMAPPCommand * volatile ic = NULL; - CamelIMAPPCommand * volatile ic2 = NULL; - guint32 count; - CamelFolderSummary *summary; - - if (id->folder) { - if (folder == id->folder) - return; - camel_imapp_driver_sync(id, FALSE, id->folder); - if (camel_folder_change_info_changed(id->folder->changes)) { - camel_object_trigger_event(id->folder, "folder_changed", id->folder->changes); - camel_folder_change_info_clear(id->folder->changes); - } - camel_object_unref(id->folder); - id->folder = NULL; - } - - summary = ((CamelFolder *)folder)->summary; - - ic = camel_imapp_engine_command_new(id->engine, "SELECT", NULL, "SELECT %t", folder->raw_name); - camel_imapp_engine_command_queue(id->engine, ic); - while (camel_imapp_engine_iterate(id->engine, ic)>0) - ; - camel_imapp_engine_command_free(id->engine, ic); - - id->folder = folder; - camel_object_ref(folder); - - count = camel_folder_summary_count(summary); - if (count > 0 && count <= id->exists) { - ic = camel_imapp_engine_command_new(id->engine, "FETCH", NULL, - "FETCH 1:%u (UID FLAGS)", count); - camel_imapp_engine_command_queue(id->engine, ic); - if (count < id->exists) { - ic2 = camel_imapp_engine_command_new(id->engine, "FETCH", NULL, - "FETCH %u:* (UID FLAGS ENVELOPE)", count+1); - camel_imapp_engine_command_queue(id->engine, ic2); - } else { - ic2 = NULL; - } - - while (camel_imapp_engine_iterate(id->engine, ic2?ic2:ic)>0) - ; - - camel_imapp_engine_command_free(id->engine, ic); - if (ic2) - camel_imapp_engine_command_free(id->engine, ic2); - } else { - ic = camel_imapp_engine_command_new(id->engine, "FETCH", NULL, - "FETCH 1:* (UID FLAGS ENVELOPE)"); - camel_imapp_engine_command_queue(id->engine, ic); - while (camel_imapp_engine_iterate(id->engine, ic)>0) - ; - camel_imapp_engine_command_free(id->engine, ic); - } - - /* TODO: need to set exists/etc in summary */ - folder->exists = id->exists; - folder->uidvalidity = id->uidvalidity; - - printf("saving summary '%s'\n", summary->summary_path); - camel_folder_summary_save(summary); - - if (camel_folder_change_info_changed(id->folder->changes)) { - camel_object_trigger_event(id->folder, "folder_changed", id->folder->changes); - camel_folder_change_info_clear(id->folder->changes); - } -} - -static void -imapp_driver_check(CamelIMAPPDriver *id) -{ - guint32 count; - CamelIMAPPCommand *ic; - - /* FIXME: exception handling */ - - if (id->folder->exists != id->exists) { - count = camel_folder_summary_count(((CamelFolder *)id->folder)->summary); - if (count < id->exists) { - printf("fetching new messages\n"); - ic = camel_imapp_engine_command_new(id->engine, "FETCH", NULL, - "FETCH %u:* (UID FLAGS ENVELOPE)", count+1); - camel_imapp_engine_command_queue(id->engine, ic); - while (camel_imapp_engine_iterate(id->engine, ic)>0) - ; - camel_imapp_engine_command_free(id->engine, ic); - } else if (count > id->exists) { - printf("folder shrank with no expunge notificaitons!? uh, dunno what to do\n"); - } - } - - printf("checking for change info changes\n"); - if (camel_folder_change_info_changed(id->folder->changes)) { - printf("got somechanges! added=%d changed=%d removed=%d\n", - id->folder->changes->uid_added->len, - id->folder->changes->uid_changed->len, - id->folder->changes->uid_removed->len); - camel_object_trigger_event(id->folder, "folder_changed", id->folder->changes); - camel_folder_change_info_clear(id->folder->changes); - } -} - -void -camel_imapp_driver_update(CamelIMAPPDriver *id, CamelIMAPPFolder *folder) -{ - if (id->folder == folder) { - CamelIMAPPCommand *ic; - - /* this will automagically update flags & expunge items */ - ic = camel_imapp_engine_command_new(id->engine, "NOOP", NULL, "NOOP"); - camel_imapp_engine_command_queue(id->engine, ic); - while (camel_imapp_engine_iterate(id->engine, ic)>0) - ; - camel_imapp_engine_command_free(id->engine, ic); - - imapp_driver_check(id); - } else { - camel_imapp_driver_select(id, folder); - } -} - -/* FIXME: this is basically a copy of the same in camel-imapp-utils.c */ -static struct { - char *name; - guint32 flag; -} flag_table[] = { - { "\\ANSWERED", CAMEL_MESSAGE_ANSWERED }, - { "\\DELETED", CAMEL_MESSAGE_DELETED }, - { "\\DRAFT", CAMEL_MESSAGE_DRAFT }, - { "\\FLAGGED", CAMEL_MESSAGE_FLAGGED }, - { "\\SEEN", CAMEL_MESSAGE_SEEN }, - /* { "\\RECENT", CAMEL_IMAPP_MESSAGE_RECENT }, */ -}; - -/* - flags 00101000 - sflags 01001000 - ^ 01100000 -~flags 11010111 -& 01000000 - -&flags 00100000 -*/ - -static void -imapp_write_flags(CamelIMAPPDriver *id, guint32 orset, gboolean on, CamelFolderSummary *summary) -{ - guint32 i, j, count; - CamelIMAPPMessageInfo *info; - CamelIMAPPCommand *ic = NULL; - struct _uidset_state ss; - GSList *commands = NULL; - - /* FIXME: exception handling */ - - count = camel_folder_summary_count(summary); - for (j=0;j<sizeof(flag_table)/sizeof(flag_table[0]);j++) { - int flush; - - if ((orset & flag_table[j].flag) == 0) - continue; - - printf("checking/storing %s flags '%s'\n", on?"on":"off", flag_table[j].name); - - flush = 0; - imapp_uidset_init(&ss, id->engine); - for (i=0;i<count;i++) { - info = (CamelIMAPPMessageInfo *)camel_folder_summary_index(summary, i); - if (info) { - guint32 flags = info->info.flags & CAMEL_IMAPP_SERVER_FLAGS; - guint32 sflags = info->server_flags & CAMEL_IMAPP_SERVER_FLAGS; - - if ( (on && (((flags ^ sflags) & flags) & flag_table[j].flag)) - || (!on && (((flags ^ sflags) & ~flags) & flag_table[j].flag))) { - if (ic == NULL) - ic = camel_imapp_engine_command_new(id->engine, "STORE", NULL, "UID STORE "); - flush = imapp_uidset_add(&ss, ic, camel_message_info_uid(info)); - } - camel_folder_summary_info_free(summary, (CamelMessageInfo *)info); - } - - if (i == count-1 && ic != NULL) - flush |= imapp_uidset_done(&ss, ic); - - if (flush) { - flush = 0; - camel_imapp_engine_command_add(id->engine, ic, " %tFLAGS.SILENT (%t)", on?"+":"-", flag_table[j].name); - camel_imapp_engine_command_queue(id->engine, ic); - commands = g_slist_prepend(commands, ic); - ic = NULL; - } - } - } - - /* flush off any requests we may have outstanding */ - /* TODO: for max benefit, should have this routine do both on and off flags in one go */ - while (commands) { - GSList *next = commands->next; - - ic = commands->data; - g_slist_free_1(commands); - commands = next; - - while (camel_imapp_engine_iterate(id->engine, ic)>0) - ; - camel_imapp_engine_command_free(id->engine, ic); - } -} - -void -camel_imapp_driver_sync(CamelIMAPPDriver *id, gboolean expunge, CamelIMAPPFolder *folder) -{ - CamelFolderSummary *summary; - guint i, count, on_orset, off_orset; - CamelIMAPPMessageInfo *info; - CamelIMAPPCommand *ic; - - /* FIXME: exception handling */ - - camel_imapp_driver_update(id, folder); - - summary = ((CamelFolder *)folder)->summary; - count = camel_folder_summary_count(summary); - /* find out which flags have turned on, which have tunred off */ - off_orset = on_orset = 0; - for (i=0;i<count;i++) { - guint32 flags, sflags; - - info = (CamelIMAPPMessageInfo *)camel_folder_summary_index(summary, i); - if (info == NULL) - continue; - flags = info->info.flags & CAMEL_IMAPP_SERVER_FLAGS; - sflags = info->server_flags & CAMEL_IMAPP_SERVER_FLAGS; - if (flags != sflags) { - off_orset |= ( flags ^ sflags ) & ~flags; - on_orset |= (flags ^ sflags) & flags; - } - camel_folder_summary_info_free(summary, (CamelMessageInfo *)info); - } - - if (on_orset || off_orset) { - /* turn on or off all messages matching */ - if (on_orset) - imapp_write_flags(id, on_orset, TRUE, summary); - if (off_orset) - imapp_write_flags(id, off_orset, FALSE, summary); - - /* success (no exception), make sure we match what we're supposed to */ - for (i=0;i<count;i++) { - guint32 flags, sflags; - - info = (CamelIMAPPMessageInfo *)camel_folder_summary_index(summary, i); - if (info == NULL) - continue; - info->server_flags = info->info.flags & CAMEL_IMAPP_SERVER_FLAGS; - camel_folder_summary_info_free(summary, (CamelMessageInfo *)info); - } - camel_folder_summary_touch(summary); - /* could save summary here, incase of failure? */ - } - - if (expunge) { - ic = camel_imapp_engine_command_new(id->engine, "EXPUNGE", NULL, "EXPUNGE"); - camel_imapp_engine_command_queue(id->engine, ic); - while (camel_imapp_engine_iterate(id->engine, ic)>0) - ; - camel_imapp_engine_command_free(id->engine, ic); - } - - printf("saving summary '%s'\n", summary->summary_path); - camel_folder_summary_save(summary); - - if (camel_folder_change_info_changed(id->folder->changes)) { - camel_object_trigger_event(id->folder, "folder_changed", id->folder->changes); - camel_folder_change_info_clear(id->folder->changes); - } -} - -struct _fetch_data { - struct _fetch_data *next; - struct _fetch_data *prev; - - CamelStream *data; - const char *uid; - const char *section; -}; - -CamelStream * -camel_imapp_driver_fetch(CamelIMAPPDriver *id, CamelIMAPPFolder *folder, const char *uid, const char *section) -{ - struct _fetch_data fd; - CamelIMAPPCommand *ic; - - fd.data = NULL; - fd.uid = uid; - fd.section = section; - e_dlist_addtail(&id->body_fetch, (EDListNode *)&fd); - - CAMEL_TRY { - camel_imapp_driver_select(id, folder); - - ic = camel_imapp_engine_command_new(id->engine, "FETCH", NULL, "UID FETCH %t (BODY.PEEK[%t])", uid, section); - camel_imapp_engine_command_queue(id->engine, ic); - while (camel_imapp_engine_iterate(id->engine, ic)>0) - ; - camel_imapp_engine_command_free(id->engine, ic); - imapp_driver_check(id); - } CAMEL_CATCH(e) { - /* FIXME: do exception properly */ - } CAMEL_DONE; - - e_dlist_remove((EDListNode *)&fd); - - return fd.data; -} - -GPtrArray * -camel_imapp_driver_list(CamelIMAPPDriver *id, const char *name, guint32 flags) -{ - CamelIMAPPCommand * volatile ic; - GPtrArray *res; - - g_assert(id->list_commands == NULL); - g_assert(id->list_result == NULL); - - /* FIXME: make sure we only have a single list running at a time */ - /* sem_wait(id->list_sem); */ - - /* FIXME: namespace stuff (done in store code?) */ - - /* FIXME: if name != "", we need to also do list "name.%" (. == sep) */ - - id->list_result = g_ptr_array_new(); - id->list_flags = flags; - CAMEL_TRY { - ic = camel_imapp_engine_command_new(id->engine, "LIST", NULL, "LIST \"\" %f", name[0]?name:"%"); - camel_imapp_engine_command_queue(id->engine, ic); - while (ic) { - while (camel_imapp_engine_iterate(id->engine, ic)>0) - ; - camel_imapp_engine_command_free(id->engine, ic); - - if (id->list_commands) { - GSList *top = id->list_commands; - - id->list_commands = top->next; - ic = top->data; - g_slist_free_1(top); - } else { - ic = NULL; - } - } - } CAMEL_CATCH(e) { - GSList *top = id->list_commands; - int i; - - camel_imapp_engine_command_free(id->engine, ic); - - while (top) { - GSList *topn = top->next; - - camel_imapp_engine_command_free(id->engine, ic); - g_slist_free_1(top); - top = topn; - } - id->list_commands = NULL; - - res = id->list_result; - for (i=0;i<res->len;i++) - imap_free_list(res->pdata[i]); - g_ptr_array_free(res, TRUE); - id->list_result = NULL; - - camel_exception_throw_ex(e); - } CAMEL_DONE; - - res = id->list_result; - id->list_result = NULL; - - /* sem_post(id->list_sem); */ - - return res; -} - -static int -driver_resp_list(CamelIMAPPEngine *ie, guint32 idx, CamelIMAPPDriver *id) -{ - struct _list_info *linfo; - - /* FIXME: exceptions */ - - linfo = imap_parse_list(ie->stream); - printf("store list: '%s' ('%c')\n", linfo->name, linfo->separator); - if (id->list_result) { - if ((linfo->flags & CAMEL_FOLDER_NOINFERIORS) == 0 - && (id->list_flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE) - && linfo->separator) { - int depth = 0; - char *p = linfo->name; - char c = linfo->separator; - - /* this is expensive ... but if we've listed this deep we're going slow anyway */ - while (*p && depth < 10) { - if (*p == c) - depth++; - p++; - } - - if (depth < 10 - && (linfo->name[0] == 0 || linfo->name[strlen(linfo->name)-1] != c)) { - CamelIMAPPCommand *ic; - - ic = camel_imapp_engine_command_new(id->engine, "LIST", NULL, "LIST \"\" %t%c%%", linfo->name, c); - id->list_commands = g_slist_prepend(id->list_commands, ic); - camel_imapp_engine_command_queue(id->engine, ic); - } - } - /* FIXME: dont add to list if name ends in separator */ - g_ptr_array_add(id->list_result, linfo); - } else { - g_warning("unexpected list response\n"); - imap_free_list(linfo); - } - - return camel_imapp_engine_skip(ie); -} - -/* ********************************************************************** */ - -static void -driver_status(CamelIMAPPEngine *ie, struct _status_info *sinfo, CamelIMAPPDriver *sdata) -{ - printf("got status response ...\n"); - switch(sinfo->condition) { - case IMAP_READ_WRITE: - printf("folder is read-write\n"); - break; - case IMAP_READ_ONLY: - printf("folder is read-only\n"); - break; - case IMAP_UIDVALIDITY: - sdata->uidvalidity = sinfo->u.uidvalidity; - break; -#if 0 - /* not defined yet ... */ - case IMAP_UIDNEXT: - printf("got uidnext for folder: %d\n", sinfo->u.uidnext); - break; -#endif - case IMAP_UNSEEN: - sdata->unseen = sinfo->u.unseen; - break; - case IMAP_PERMANENTFLAGS: - sdata->permanentflags = sinfo->u.permanentflags; - break; - case IMAP_ALERT: - printf("ALERT!: %s\n", sinfo->text); - break; - case IMAP_PARSE: - printf("PARSE: %s\n", sinfo->text); - break; - default: - break; - } -} - -static int -driver_resp_exists(CamelIMAPPEngine *ie, guint32 id, CamelIMAPPDriver *sdata) -{ - /* should this be an event instead? */ - - sdata->exists = id; - - return camel_imapp_engine_skip(ie); -} - -static int -driver_resp_expunge(CamelIMAPPEngine *ie, guint32 id, CamelIMAPPDriver *sdata) -{ - printf("got expunge response %u\n", id); - if (sdata->folder != NULL) { - CamelMessageInfo *info; - CamelFolderSummary *summary = ((CamelFolder *)sdata->folder)->summary; - - info = camel_folder_summary_index(summary, id-1); - if (info) { - printf("expunging msg %d\n", id); - camel_folder_summary_remove(summary, info); - camel_folder_summary_info_free(summary, info); - camel_folder_change_info_remove_uid(sdata->folder->changes, camel_message_info_uid(info)); - } else { - printf("can not find msg %u from expunge\n", id); - } - } - - return camel_imapp_engine_skip(ie); -} - -static int -driver_resp_fetch(CamelIMAPPEngine *ie, guint32 id, CamelIMAPPDriver *sdata) -{ - struct _fetch_info *finfo = NULL; - CamelMessageInfo *info, *uinfo; - unsigned int i; - CamelFolderSummary *summary; - - printf("got fetch response %d\n", id); - - if (sdata->folder == NULL) - goto done; - - summary = ((CamelFolder *)sdata->folder)->summary; - - finfo = imap_parse_fetch(ie->stream); - imap_dump_fetch(finfo); - - info = camel_folder_summary_index(summary, id-1); - if (info == NULL) { - if (finfo->uid == NULL) { - printf("got fetch response for currently unknown message %u\n", id); - goto done; - } - uinfo = camel_folder_summary_uid(summary, finfo->uid); - if (uinfo) { - /* we have a problem ... index mismatch */ - printf("index mismatch, uid '%s' not at index '%u'\n", - finfo->uid, id); - camel_folder_summary_info_free(summary, uinfo); - } - /* pad out the summary till we have enough indexes */ - for (i=camel_folder_summary_count(summary);i<id;i++) { - info = camel_folder_summary_info_new(summary); - if (i == id-1) { - printf("inserting new info @ %u\n", i); - camel_message_info_set_uid(info, g_strdup(finfo->uid)); - } else { - char uidtmp[32]; - - sprintf(uidtmp, "blank-%u", i); - camel_message_info_set_uid(info, g_strdup(uidtmp)); - printf("inserting empty uid %s\n", uidtmp); - } - - camel_folder_summary_add(summary, info); - } - info = camel_folder_summary_index(summary, id-1); - g_assert(info != NULL); - } else { - if (finfo->uid) { - /* FIXME: need to handle blank-* uids, somehow */ - while (info && strcmp(camel_message_info_uid(info), finfo->uid) != 0) { - printf("index mismatch, uid '%s' not at index '%u', got '%s' instead (removing)\n", - finfo->uid, id, camel_message_info_uid(info)); - - camel_folder_change_info_remove_uid(sdata->folder->changes, camel_message_info_uid(info)); - camel_folder_summary_remove(summary, info); - camel_folder_summary_info_free(summary, info); - info = camel_folder_summary_index(summary, id-1); - } - } else { - printf("got info for unknown message %u\n", id); - } - } - - if (info) { - if (finfo->got & FETCH_MINFO) { - /* if we only use ENVELOPE? */ - camel_message_info_set_subject(info, g_strdup(camel_message_info_subject(finfo->minfo))); - camel_message_info_set_from(info, g_strdup(camel_message_info_from(finfo->minfo))); - camel_message_info_set_to(info, g_strdup(camel_message_info_to(finfo->minfo))); - camel_message_info_set_cc(info, g_strdup(camel_message_info_cc(finfo->minfo))); - info->date_sent = finfo->minfo->date_sent; - camel_folder_change_info_add_uid(sdata->folder->changes, camel_message_info_uid(info)); - printf("adding change info uid '%s'\n", camel_message_info_uid(info)); - } - - if (finfo->got & FETCH_FLAGS) { - if ((info->flags & CAMEL_IMAPP_SERVER_FLAGS) != (finfo->flags & CAMEL_IMAPP_SERVER_FLAGS)) { - camel_folder_change_info_change_uid(sdata->folder->changes, camel_message_info_uid(info)); - info->flags = (info->flags & ~(CAMEL_IMAPP_SERVER_FLAGS)) | (finfo->flags & CAMEL_IMAPP_SERVER_FLAGS); - camel_folder_summary_touch(summary); - } - ((CamelIMAPPMessageInfo *)info)->server_flags = finfo->flags & CAMEL_IMAPP_SERVER_FLAGS; - } - - if ((finfo->got & (FETCH_BODY|FETCH_UID)) == (FETCH_BODY|FETCH_UID)) { - struct _fetch_data *fd, *fn; - - fd = (struct _fetch_data *)sdata->body_fetch.head; - fn = fd->next; - while (fn) { - if (!strcmp(finfo->uid, fd->uid) && !strcmp(finfo->section, fd->section)) { - if (fd->data) - camel_object_unref(fd->data); - fd->data = finfo->body; - camel_object_ref(fd->data); - e_dlist_remove((EDListNode *)fd); - e_dlist_addtail(&sdata->body_fetch_done, (EDListNode *)fd); - break; - } - fd = fn; - fn = fn->next; - } - } - - camel_folder_summary_info_free(summary, info); - } else { - printf("dont know what to do with message\n"); - } - done: - imap_free_fetch(finfo); - - return camel_imapp_engine_skip(ie); -} diff --git a/camel/providers/imapp/camel-imapp-driver.h b/camel/providers/imapp/camel-imapp-driver.h deleted file mode 100644 index 3124700619..0000000000 --- a/camel/providers/imapp/camel-imapp-driver.h +++ /dev/null @@ -1,81 +0,0 @@ - -#ifndef _CAMEL_IMAPP_DRIVER_H -#define _CAMEL_IMAPP_DRIVER_H - -#include <camel/camel-object.h> -#include "camel-imapp-stream.h" -#include <e-util/e-msgport.h> - -#define CAMEL_IMAPP_DRIVER_TYPE (camel_imapp_driver_get_type ()) -#define CAMEL_IMAPP_DRIVER(obj) (CAMEL_CHECK_CAST((obj), CAMEL_IMAPP_DRIVER_TYPE, CamelIMAPPDriver)) -#define CAMEL_IMAPP_DRIVER_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_IMAPP_DRIVER_TYPE, CamelIMAPPDriverClass)) -#define CAMEL_IS_IMAP_DRIVER(o) (CAMEL_CHECK_TYPE((o), CAMEL_IMAPP_DRIVER_TYPE)) - -typedef struct _CamelIMAPPDriver CamelIMAPPDriver; -typedef struct _CamelIMAPPDriverClass CamelIMAPPDriverClass; - -typedef int (*CamelIMAPPDriverFunc)(struct _CamelIMAPPDriver *driver, void *data); -typedef struct _CamelSasl * (*CamelIMAPPSASLFunc)(struct _CamelIMAPPDriver *driver, void *data); -typedef void (*CamelIMAPPLoginFunc)(struct _CamelIMAPPDriver *driver, char **login, char **pass, void *data); - -struct _CamelMimeMessage; - -struct _CamelIMAPPDriver { - CamelObject parent_object; - - struct _CamelIMAPPEngine *engine; - - struct _CamelIMAPPFolder *folder; - - /* current folder stuff */ - GPtrArray *summary; - guint32 uidvalidity; - guint32 exists; - guint32 recent; - guint32 unseen; - guint32 permanentflags; - - /* list stuff */ - GPtrArray *list_result; - GSList *list_commands; - guint32 list_flags; - - /* sem_t list_sem; for controlled access to list variables */ - - /* this is so the node is always in a list - easier exception management */ - EDList body_fetch; - EDList body_fetch_done; - - /* factory to get an appropriate sasl mech */ - CamelIMAPPSASLFunc get_sasl; - void *get_sasl_data; - - /* callbacks, get login username/pass */ - CamelIMAPPLoginFunc get_login; - void *get_login_data; -}; - -struct _CamelIMAPPDriverClass { - CamelObjectClass parent_class; -}; - -CamelType camel_imapp_driver_get_type (void); - -CamelIMAPPDriver * camel_imapp_driver_new(CamelIMAPPStream *stream); - -void camel_imapp_driver_set_sasl_factory(CamelIMAPPDriver *id, CamelIMAPPSASLFunc get_sasl, void *sasl_data); -void camel_imapp_driver_set_login_query(CamelIMAPPDriver *id, CamelIMAPPLoginFunc get_login, void *login_data); - -void camel_imapp_driver_login(CamelIMAPPDriver *id); - -void camel_imapp_driver_select(CamelIMAPPDriver *id, struct _CamelIMAPPFolder *folder); -void camel_imapp_driver_update(CamelIMAPPDriver *id, struct _CamelIMAPPFolder *folder); -void camel_imapp_driver_sync(CamelIMAPPDriver *id, gboolean expunge, struct _CamelIMAPPFolder *folder); - -struct _CamelStream * camel_imapp_driver_fetch(CamelIMAPPDriver *id, struct _CamelIMAPPFolder *folder, const char *uid, const char *body); -GPtrArray * camel_imapp_driver_list(CamelIMAPPDriver *id, const char *name, guint32 flags); - -struct _CamelStream *camel_imapp_driver_get(CamelIMAPPDriver *id, struct _CamelIMAPPFolder *folder, const char *uid); -void camel_imapp_driver_append(CamelIMAPPDriver *id, struct _CamelIMAPPFolder *folder, struct _CamelDataWrapper *); - -#endif diff --git a/camel/providers/imapp/camel-imapp-engine.c b/camel/providers/imapp/camel-imapp-engine.c deleted file mode 100644 index df14903c5a..0000000000 --- a/camel/providers/imapp/camel-imapp-engine.c +++ /dev/null @@ -1,1180 +0,0 @@ - -#include "config.h" - -#include <stdio.h> -#include <string.h> - -#include "camel-imapp-engine.h" -#include "camel-imapp-stream.h" -#include "camel-imapp-utils.h" -#include "camel-imapp-exception.h" - -#include <camel/camel-folder-summary.h> -#include <camel/camel-stream-mem.h> -#include <camel/camel-stream-null.h> -#include <camel/camel-data-wrapper.h> -#include <camel/camel-sasl.h> - -#include <ctype.h> - -#define e(x) -#define c(x) /* command build debug */ - -static void imap_engine_command_addv(CamelIMAPPEngine *imap, CamelIMAPPCommand *ic, const char *fmt, va_list ap); -static void imap_engine_command_complete(CamelIMAPPEngine *imap, CamelIMAPPCommand *ic); - -struct _handler { - CamelIMAPPEngineFunc func; - void *data; - char name[1]; -}; - -static void -class_init(CamelIMAPPEngineClass *ieclass) -{ - ieclass->tagprefix = 'A'; - - camel_object_class_add_event((CamelObjectClass *)ieclass, "status", NULL); -} - -static void -object_init(CamelIMAPPEngine *ie, CamelIMAPPEngineClass *ieclass) -{ - ie->handlers = g_hash_table_new(g_str_hash, g_str_equal); - e_dlist_init(&ie->active); - e_dlist_init(&ie->queue); - e_dlist_init(&ie->done); - - ie->tagprefix = ieclass->tagprefix; - ieclass->tagprefix++; - if (ieclass->tagprefix > 'Z') - ieclass->tagprefix = 'A'; - ie->tagprefix = 'A'; - - ie->state = IMAP_ENGINE_DISCONNECT; -} - -static void -handler_free(void *key, void *mem, void *data) -{ - g_free(mem); -} - -static void -object_finalise(CamelIMAPPEngine *ie, CamelIMAPPEngineClass *ieclass) -{ - /* FIXME: need to free the commands ... */ - while (camel_imapp_engine_iterate(ie, NULL) > 0) - ; - - g_hash_table_foreach(ie->handlers, (GHFunc)handler_free, NULL); - g_hash_table_destroy(ie->handlers); -} - -CamelType -camel_imapp_engine_get_type (void) -{ - static CamelType type = CAMEL_INVALID_TYPE; - - if (type == CAMEL_INVALID_TYPE) { - type = camel_type_register ( - camel_object_get_type (), - "CamelIMAPPEngine", - sizeof (CamelIMAPPEngine), - sizeof (CamelIMAPPEngineClass), - (CamelObjectClassInitFunc) class_init, - NULL, - (CamelObjectInitFunc) object_init, - (CamelObjectFinalizeFunc) object_finalise); - } - - return type; -} - -/* FIXME: check this, just taken from old code, not rfc */ -struct { - char *name; - guint32 flag; -} capa_table[] = { - { "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 }, -}; - - -/* -capability_data ::= "CAPABILITY" SPACE [1#capability SPACE] "IMAP4rev1" - [SPACE 1#capability] - ;; IMAP4rev1 servers which offer RFC 1730 - ;; compatibility MUST list "IMAP4" as the first - ;; capability. -*/ -static int resp_capability(CamelIMAPPEngine *ie, guint32 id, void *data) -{ - int tok, len, i; - unsigned char *token, *p, c; - - /* FIXME: handle auth types */ - - printf("got capability response:\n"); - while (1) { - tok = camel_imapp_stream_token(ie->stream, &token, &len); - switch(tok) { - case IMAP_TOK_TOKEN: - p = token; - while ((c = *p)) - *p++ = toupper(c); - case IMAP_TOK_INT: - printf(" cap: '%s'\n", token); - for (i=0;i<(int)(sizeof(capa_table)/sizeof(capa_table[0]));i++) - if (strcmp(token, capa_table[i].name)) - ie->capa |= capa_table[i].flag; - break; - case '\n': - return 0; - case IMAP_TOK_ERROR: - case IMAP_TOK_PROTOCOL: - camel_imapp_engine_skip(ie); - return -1; - default: - printf("Unknown Response token %02x '%c'\n", tok, isprint(tok)?tok:'.'); - } - } while (tok != '\n'); - - return 0; -} - -/* expunge command, id is expunged seq number */ -/* message_data ::= nz_number SPACE ("EXPUNGE" / - ("FETCH" SPACE msg_att)) */ -static int resp_expunge(CamelIMAPPEngine *ie, guint32 id, void *data) -{ - printf("message expunged: %d\n", id); - - return camel_imapp_engine_skip(ie); -} - -static int resp_flags(CamelIMAPPEngine *ie, guint32 id, void *data) -{ - guint32 flags; - - imap_parse_flags(ie->stream, &flags); - - printf("flags: %08x\n", flags); - - return camel_imapp_engine_skip(ie); -} - -/* exists count */ -static int resp_exists(CamelIMAPPEngine *ie, guint32 id, void *data) -{ - printf("messages exist: %d\n", id); - - if (ie->select_response) - ie->select_response->exists = id; - - return camel_imapp_engine_skip(ie); -} - -static int resp_recent(CamelIMAPPEngine *ie, guint32 id, void *data) -{ - printf("messages recent: %d\n", id); - - if (ie->select_response) - ie->select_response->recent = id; - - return camel_imapp_engine_skip(ie); -} - -static int resp_fetch(CamelIMAPPEngine *ie, guint32 id, void *data) -{ - struct _fetch_info *finfo; - - finfo = imap_parse_fetch(ie->stream); - imap_dump_fetch(finfo); - imap_free_fetch(finfo); - - return camel_imapp_engine_skip(ie); -} - -#if 0 -static int resp_list(CamelIMAPPEngine *ie, guint32 id, void *data) -{ - struct _list_info *linfo; - - linfo = imap_parse_list(ie->stream); - printf("list: '%s' (%c)\n", linfo->name, linfo->separator); - imap_free_list(linfo); - - return camel_imapp_engine_skip(ie); -} -#endif - -CamelIMAPPEngine * -camel_imapp_engine_new(CamelIMAPPStream *stream) -{ - CamelIMAPPEngine * volatile engine; - - engine = CAMEL_IMAPP_ENGINE (camel_object_new (CAMEL_IMAPP_ENGINE_TYPE)); - engine->stream = stream; - camel_object_ref((CamelObject *)stream); - - camel_imapp_engine_add_handler(engine, "CAPABILITY", resp_capability, engine); - - /* mailbox_data */ - camel_imapp_engine_add_handler(engine, "FLAGS", (CamelIMAPPEngineFunc)resp_flags, engine); - camel_imapp_engine_add_handler(engine, "EXISTS", (CamelIMAPPEngineFunc)resp_exists, engine); - camel_imapp_engine_add_handler(engine, "RECENT", (CamelIMAPPEngineFunc)resp_recent, engine); - -#if 0 - camel_imapp_engine_add_handler(engine, "LIST", (CamelIMAPPEngineFunc)resp_list, engine); - camel_imapp_engine_add_handler(engine, "LSUB", (CamelIMAPPEngineFunc)resp_list, engine); -#endif - /* message_data */ - camel_imapp_engine_add_handler(engine, "EXPUNGE", (CamelIMAPPEngineFunc)resp_expunge, engine); - camel_imapp_engine_add_handler(engine, "FETCH", (CamelIMAPPEngineFunc)resp_fetch, engine); - - /* TODO: move this to a driver:connect call? */ - CAMEL_TRY { - unsigned char *token; - unsigned int len; - int tok; - - tok = camel_imapp_stream_token(stream, &token, &len); - if (tok == '*') { - struct _status_info *sinfo = imap_parse_status(stream); - - switch (sinfo->result) { - case IMAP_OK: - engine->state = IMAP_ENGINE_CONNECT; - printf("Server connected ok: %s\n", sinfo->text); - break; - case IMAP_PREAUTH: - printf("pre-authenticated ...\n"); - engine->state = IMAP_ENGINE_AUTH; - break; - default: - imap_free_status(sinfo); - camel_exception_throw(1, "Server refused connection: %s", sinfo->text); - break; - } - imap_free_status(sinfo); - } else { - engine->state = IMAP_ENGINE_CONNECT; - printf("unknwon server greeting, ignored\n"); - camel_imapp_engine_skip(engine); - } - camel_imapp_engine_capabilities(engine); - } CAMEL_CATCH(ex) { - printf("connection failed: %s\n", ex->desc); - camel_object_unref((CamelObject *)engine); - engine = NULL; - } CAMEL_DONE; - - return engine; -} - -void -camel_imapp_engine_add_handler(CamelIMAPPEngine *imap, const char *response, CamelIMAPPEngineFunc func, void *data) -{ - struct _handler *h; - const unsigned char *p; - unsigned char *o, c; - - h = g_malloc0(sizeof(*h) + strlen(response)); - h->func = func; - h->data = data; - - p = response; - o = h->name; - while ((c = *p++)) - *o++ = toupper(c); - *o = 0; - - g_hash_table_insert(imap->handlers, h->name, h); -} - -int -camel_imapp_engine_capabilities(CamelIMAPPEngine *ie) -{ - CamelIMAPPCommand *ic; - - /* reset capabilities */ - ie->capa = 0; - - ic = camel_imapp_engine_command_new(ie, "CAPABILITY", NULL, "CAPABILITY"); - camel_imapp_engine_command_queue(ie, ic); - while (camel_imapp_engine_iterate(ie, ic)>0) - ; - camel_imapp_engine_command_free(ie, ic); - - return 0; -} - -/* skip the rest of the line of tokens */ -int -camel_imapp_engine_skip(CamelIMAPPEngine *imap) -{ - int tok; - unsigned char *token; - unsigned int len; - - do { - tok = camel_imapp_stream_token(imap->stream, &token, &len); - if (tok == IMAP_TOK_LITERAL) { - camel_imapp_stream_set_literal(imap->stream, len); - while ((tok = camel_imapp_stream_getl(imap->stream, &token, &len)) > 0) { - printf("Skip literal data '%.*s'\n", (int)len, token); - } - } - } while (tok != '\n' && tok >= 0); - - if (tok < 0) - return -1; - - return 0; -} - -/* handle any untagged responses */ -static int -iterate_untagged(CamelIMAPPEngine *imap) -{ - unsigned int id, len; - unsigned char *token, *p, c; - int tok; - struct _handler *h; - struct _status_info *sinfo; - - e(printf("got untagged response\n")); - id = 0; - tok = camel_imapp_stream_token(imap->stream, &token, &len); - if (tok == IMAP_TOK_INT) { - id = strtoul(token, NULL, 10); - tok = camel_imapp_stream_token(imap->stream, &token, &len); - } - - if (tok == '\n') - camel_exception_throw(1, "truncated server response"); - - e(printf("Have token '%s' id %d\n", token, id)); - p = token; - while ((c = *p)) - *p++ = toupper(c); - - /* first, check for generic unsolicited response */ - h = g_hash_table_lookup(imap->handlers, token); - if (h) { - tok = h->func(imap, id, h->data); - if (tok < 0) - return tok; - return 1; - } - - /* TODO: apart from bye/preauth, these could be callbacks/events? */ - - /* now, check for status responses */ - switch (imap_tokenise(token, len)) { - case IMAP_BYE: - case IMAP_OK: - case IMAP_NO: - case IMAP_BAD: - case IMAP_PREAUTH: - /* TODO: validate which ones of these can happen as unsolicited responses */ - /* TODO: handle bye/preauth differently */ - /* FIXME: free sinfo */ - camel_imapp_stream_ungettoken(imap->stream, tok, token, len); - sinfo = imap_parse_status(imap->stream); - camel_object_trigger_event(imap, "status", sinfo); - imap_free_status(sinfo); -#if 0 - switch(sinfo->condition) { - case IMAP_READ_WRITE: - printf("folder is read-write\n"); - break; - case IMAP_READ_ONLY: - printf("folder is read-only\n"); - break; - case IMAP_UIDVALIDITY: - if (imap->select_response) - imap->select_response->uidvalidity = sinfo->u.uidvalidity; - break; -#if 0 - /* not defined yet ... */ - case IMAP_UIDNEXT: - printf("got uidnext for folder: %d\n", sinfo->u.uidnext); - break; -#endif - case IMAP_UNSEEN: - if (imap->select_response) - imap->select_response->unseen = sinfo->u.unseen; - break; - case IMAP_PERMANENTFLAGS: - if (imap->select_response) - imap->select_response->permanentflags = sinfo->u.permanentflags; - break; - case IMAP_ALERT: - printf("ALERT!: %s\n", sinfo->text); - break; - case IMAP_PARSE: - printf("PARSE: %s\n", sinfo->text); - break; - default: - break; - } -#endif - break; - default: - printf("unknown token: %s\n", token); - camel_imapp_engine_skip(imap); - /* unknown response, just ignore it */ - } - - return 1; -} - -/* handle any continuation requests - either data continuations, or auth continuation */ -int -iterate_continuation(CamelIMAPPEngine *imap) -{ - CamelIMAPPCommand *ic; - CamelIMAPPCommandPart *cp; - - printf("got continuation response\n"); - - ic = imap->literal; - imap->literal = NULL; - if (ic == NULL) { - camel_imapp_engine_skip(imap); - printf("got continuation response with no outstanding continuation requests?\n"); - return 1; - } - - printf("got continuation response for data\n"); - cp = ic->current; - switch(cp->type & CAMEL_IMAPP_COMMAND_MASK) { - case CAMEL_IMAPP_COMMAND_DATAWRAPPER: - printf("writing data wrapper to literal\n"); - camel_data_wrapper_write_to_stream((CamelDataWrapper *)cp->ob, (CamelStream *)imap->stream); - break; - case CAMEL_IMAPP_COMMAND_STREAM: - printf("writing stream to literal\n"); - camel_stream_write_to_stream((CamelStream *)cp->ob, (CamelStream *)imap->stream); - break; - case CAMEL_IMAPP_COMMAND_AUTH: { - CamelException *ex = camel_exception_new(); - char *resp; - unsigned char *token; - int tok, len; - - tok = camel_imapp_stream_token(imap->stream, &token, &len); - resp = camel_sasl_challenge_base64((CamelSasl *)cp->ob, token, ex); - if (camel_exception_is_set(ex)) - camel_exception_throw_ex(ex); - camel_exception_free(ex); - - printf("got auth continuation, feeding token '%s' back to auth mech\n", resp); - - camel_stream_write((CamelStream *)imap->stream, resp, strlen(resp)); - - /* we want to keep getting called until we get a status reponse from the server - ignore what sasl tells us */ - imap->literal = ic; - - break; } - default: - /* should we just ignore? */ - camel_exception_throw(1, "continuation response for non-continuation request"); - } - - camel_imapp_engine_skip(imap); - - cp = cp->next; - if (cp->next) { - ic->current = cp; - printf("next part of command \"A%05u: %s\"\n", ic->tag, cp->data); - camel_stream_printf((CamelStream *)imap->stream, "%s\r\n", cp->data); - if (cp->type & CAMEL_IMAPP_COMMAND_CONTINUATION) { - imap->literal = ic; - } else { - g_assert(cp->next->next == NULL); - } - } else { - printf("%p: queueing continuation\n", ic); - camel_stream_printf((CamelStream *)imap->stream, "\r\n"); - } - - if (imap->literal == NULL) { - ic = (CamelIMAPPCommand *)e_dlist_remhead(&imap->queue); - if (ic) { - printf("found outstanding op, queueing\n"); - camel_imapp_engine_command_queue(imap, ic); - } - } - - return 1; -} - -/* handle a completion line */ -int -iterate_completion(CamelIMAPPEngine *imap, unsigned char *token) -{ - CamelIMAPPCommand *ic; - unsigned int tag; - - if (token[0] != imap->tagprefix) - camel_exception_throw(1, "Server sent unexpected response: %s", token); - - tag = strtoul(token+1, NULL, 10); - ic = camel_imapp_engine_command_find_tag(imap, tag); - if (ic) { - printf("Got completion response for command %05u '%s'\n", ic->tag, ic->name); - printf("%p: removing command from qwueue, we were at '%s'\n", ic, ic->current->data); - printf("%p: removing command\n", ic); - e_dlist_remove((EDListNode *)ic); - e_dlist_addtail(&imap->done, (EDListNode *)ic); - if (imap->literal == ic) - imap->literal = NULL; - ic->status = imap_parse_status(imap->stream); - printf("got response code: %s\n", ic->status->text); - - /* TODO: remove this stuff and use a completion handler? */ - /* TODO: handle 'SELECT' command cleanup here */ - /* FIXME: have this use tokeniser, have this handle close/logout/select etc as well */ - /* ok response from login/authenticate, then we're in happy land */ - if ((!strcmp(ic->name, "LOGIN") || !strcmp(ic->name, "AUTHENTICATE")) - && ic->status->result == IMAP_OK) - imap->state = IMAP_ENGINE_AUTH; - - if (ic->complete) - ic->complete(imap, ic, ic->complete_data); - } else { - camel_exception_throw(1, "got response tag unexpectedly: %s", token); - } - - if (imap->literal != NULL) { - printf("Warning: continuation command '%s' finished with outstanding continuation\n", imap->literal->name); - ic = imap->literal; - /* set the command complete with a failure code? */ - e_dlist_remove((EDListNode *)ic); - e_dlist_addtail(&imap->done, (EDListNode *)ic); - imap->literal = NULL; - } - - ic = (CamelIMAPPCommand *)e_dlist_remhead(&imap->queue); - if (ic) { - printf("found outstanding op, queueing\n"); - camel_imapp_engine_command_queue(imap, ic); - } - - return 1; -} - - -/* Do work if there's any to do */ -int -camel_imapp_engine_iterate(CamelIMAPPEngine *imap, CamelIMAPPCommand *icwait) -/* throws IO,PARSE exception */ -{ - unsigned int len; - unsigned char *token; - int tok; - - if ((icwait && icwait->status != NULL) || e_dlist_empty(&imap->active)) - return 0; - - /* handle exceptions here? */ - - /* lock here? */ - - tok = camel_imapp_stream_token(imap->stream, &token, &len); - if (tok == '*') - iterate_untagged(imap); - else if (tok == IMAP_TOK_TOKEN) - iterate_completion(imap, token); - else if (tok == '+') - iterate_continuation(imap); - else - camel_exception_throw(1, "unexpected server response: %s", token); - - if (e_dlist_empty(&imap->active)) - return 0; - - return 1; -} - -CamelIMAPPCommand * -camel_imapp_engine_command_new(CamelIMAPPEngine *imap, const char *name, const char *select, const char *fmt, ...) -{ - CamelIMAPPCommand *ic; - va_list ap; - - ic = g_malloc0(sizeof(*ic)); - ic->tag = imap->tag++; - ic->name = name; - ic->mem = (CamelStreamMem *)camel_stream_mem_new(); - ic->select = g_strdup(select); - e_dlist_init(&ic->parts); - - if (fmt && fmt[0]) { - va_start(ap, fmt); - imap_engine_command_addv(imap, ic, fmt, ap); - va_end(ap); - } - - return ic; -} - -void -camel_imapp_engine_command_add(CamelIMAPPEngine *imap, CamelIMAPPCommand *ic, const char *fmt, ...) -{ - va_list ap; - - g_assert(ic->mem); /* gets reset on queue */ - - if (fmt && fmt[0]) { - va_start(ap, fmt); - imap_engine_command_addv(imap, ic, fmt, ap); - va_end(ap); - } -} - -void -camel_imapp_engine_command_complete(CamelIMAPPEngine *imap, struct _CamelIMAPPCommand *ic, CamelIMAPPCommandFunc func, void *data) -{ - ic->complete = func; - ic->complete_data = data; -} - -/* FIXME: make imap command's refcounted */ -void -camel_imapp_engine_command_free (CamelIMAPPEngine *imap, CamelIMAPPCommand *ic) -{ - CamelIMAPPCommandPart *cp, *cn; - - if (ic == NULL) - return; - - /* validity check - we cant' free items still in any queue ... */ - /* maybe we should just have another queue to keep them? */ - { - CamelIMAPPCommand *iw; - int found = 0; - - iw = (CamelIMAPPCommand *)imap->active.head; - while (iw->next) { - if (iw == ic) { - found = 1; - g_warning("command '%s' still in active queue", iw->name); - break; - } - iw = iw->next; - } - iw = (CamelIMAPPCommand *)imap->queue.head; - while (iw->next) { - if (iw == ic) { - found = 1; - g_warning("command '%s' still in waiting queue", iw->name); - break; - } - iw = iw->next; - } - iw = (CamelIMAPPCommand *)imap->done.head; - while (iw->next) { - if (iw == ic) { - found = 1; - break; - } - iw = iw->next; - } - if (!found) { - g_warning("command '%s' not found anywhere", ic->name); - abort(); - } - } - - e_dlist_remove((EDListNode *)ic); - - if (ic->mem) - camel_object_unref((CamelObject *)ic->mem); - imap_free_status(ic->status); - g_free(ic->select); - - cp = (CamelIMAPPCommandPart *)ic->parts.head; - cn = cp->next; - while (cn) { - g_free(cp->data); - if (cp->ob) - camel_object_unref(cp->ob); - g_free(cp); - cp = cn; - cn = cn->next; - } - - g_free(ic); -} - -/* FIXME: error handling */ -void -camel_imapp_engine_command_queue(CamelIMAPPEngine *imap, CamelIMAPPCommand *ic) -{ - CamelIMAPPCommandPart *cp; - - if (ic->mem) - imap_engine_command_complete(imap, ic); - - /* FIXME: remove select stuff */ - - /* see if we need to pre-queue a select command to select the right folder first */ - if (ic->select && (imap->last_select == NULL || strcmp(ic->select, imap->last_select) != 0)) { - CamelIMAPPCommand *select; - - /* of course ... we can't do anything like store/search if we have to select - first, because it'll mess up all the sequence numbers ... hrm ... bugger */ - - select = camel_imapp_engine_command_new(imap, "SELECT", NULL, "SELECT %s", ic->select); - g_free(imap->last_select); - imap->last_select = g_strdup(ic->select); - camel_imapp_engine_command_queue(imap, select); - /* how does it get freed? handle inside engine? */ - } - - /* first, check if command can be sent yet ... queue if not */ - if (imap->literal != NULL) { - printf("%p: queueing while literal active\n", ic); - e_dlist_addtail(&imap->queue, (EDListNode *)ic); - return; - } - - cp = (CamelIMAPPCommandPart *)ic->parts.head; - g_assert(cp); - ic->current = cp; - - /* how to handle exceptions here? */ - - printf("queueing command \"%c%05u %s\"\n", imap->tagprefix, ic->tag, cp->data); - camel_stream_printf((CamelStream *)imap->stream, "%c%05u %s\r\n", imap->tagprefix, ic->tag, cp->data); - - if (cp->type & CAMEL_IMAPP_COMMAND_CONTINUATION) { - printf("%p: active literal\n", ic); - g_assert(cp->next); - imap->literal = ic; - e_dlist_addtail(&imap->active, (EDListNode *)ic); - } else { - printf("%p: active non-literal\n", ic); - g_assert(cp->next && cp->next->next == NULL); - e_dlist_addtail(&imap->active, (EDListNode *)ic); - } -} - -CamelIMAPPCommand * -camel_imapp_engine_command_find (CamelIMAPPEngine *imap, const char *name) -{ - CamelIMAPPCommand *ic, *in; - - ic = imap->literal; - if (ic && strcmp(ic->name, name) == 0) - return ic; - - /* first, try active */ - ic = (CamelIMAPPCommand *)imap->active.head; - in = ic->next; - while (in) { - if (strcmp(ic->name, name) == 0) - return ic; - ic = in; - in = in->next; - } - - return NULL; -} - -CamelIMAPPCommand * -camel_imapp_engine_command_find_tag(CamelIMAPPEngine *imap, unsigned int tag) -{ - CamelIMAPPCommand *ic, *in; - - ic = imap->literal; - if (ic && ic->tag == tag) - return ic; - - ic = (CamelIMAPPCommand *)imap->active.head; - in = ic->next; - while (in) { - if (ic->tag == tag) - return ic; - ic = in; - in = in->next; - } - - return NULL; -} - -/* ********************************************************************** */ - -CamelIMAPPSelectResponse * -camel_imapp_engine_select(CamelIMAPPEngine *imap, const char *name) -{ - CamelIMAPPSelectResponse * volatile resp; - CamelIMAPPCommand * volatile ic = NULL; - - resp = g_malloc0(sizeof(*resp)); - imap->select_response = resp; - - CAMEL_TRY { - ic = camel_imapp_engine_command_new(imap, "SELECT", NULL, "SELECT %s", name); - camel_imapp_engine_command_queue(imap, ic); - while (camel_imapp_engine_iterate(imap, ic) > 0) - ; - - if (ic->status->result != IMAP_OK) - camel_exception_throw(1, "select failed: %s", ic->status->text); - resp->status = ic->status; - ic->status = NULL; - } CAMEL_CATCH (e) { - camel_imapp_engine_command_free(imap, ic); - camel_imapp_engine_select_free(imap, resp); - imap->select_response = NULL; - camel_exception_throw_ex(e); - } CAMEL_DONE; - - camel_imapp_engine_command_free(imap, ic); - imap->select_response = NULL; - - return resp; -} - -void -camel_imapp_engine_select_free(CamelIMAPPEngine *imap, CamelIMAPPSelectResponse *select) -{ - if (select) { - imap_free_status(select->status); - g_free(select); - } -} - -/* ********************************************************************** */ - -static void -imap_engine_command_add_part(CamelIMAPPEngine *imap, CamelIMAPPCommand *ic, camel_imapp_command_part_t type, CamelObject *ob) -{ - CamelIMAPPCommandPart *cp; - CamelStreamNull *null; - unsigned int ob_size = 0; - - switch(type & CAMEL_IMAPP_COMMAND_MASK) { - case CAMEL_IMAPP_COMMAND_DATAWRAPPER: - case CAMEL_IMAPP_COMMAND_STREAM: - null = (CamelStreamNull *)camel_stream_null_new(); - if ( (type & CAMEL_IMAPP_COMMAND_MASK) == CAMEL_IMAPP_COMMAND_DATAWRAPPER) { - camel_data_wrapper_write_to_stream((CamelDataWrapper *)ob, (CamelStream *)null); - } else { - camel_stream_reset((CamelStream *)ob); - camel_stream_write_to_stream((CamelStream *)ob, (CamelStream *)null); - camel_stream_reset((CamelStream *)ob); - } - type |= CAMEL_IMAPP_COMMAND_CONTINUATION; - camel_object_ref(ob); - ob_size = null->written; - camel_object_unref((CamelObject *)null); - camel_stream_printf((CamelStream *)ic->mem, "{%u}", ob_size); - break; - case CAMEL_IMAPP_COMMAND_AUTH: - /* we presume we'll need to get additional data only if we're not authenticated yet */ - camel_object_ref(ob); - camel_stream_printf((CamelStream *)ic->mem, "%s", ((CamelSasl *)ob)->mech); - if (!camel_sasl_authenticated((CamelSasl *)ob)) - type |= CAMEL_IMAPP_COMMAND_CONTINUATION; - break; - default: - ob_size = 0; - } - - cp = g_malloc0(sizeof(*cp)); - cp->type = type; - cp->ob_size = ob_size; - cp->ob = ob; - cp->data_size = ic->mem->buffer->len; - cp->data = g_malloc(cp->data_size+1); - memcpy(cp->data, ic->mem->buffer->data, cp->data_size); - cp->data[cp->data_size] = 0; - - camel_stream_reset((CamelStream *)ic->mem); - /* FIXME: hackish? */ - g_byte_array_set_size(ic->mem->buffer, 0); - - e_dlist_addtail(&ic->parts, (EDListNode *)cp); -} - -static int len(EDList *list) -{ - int count = 0; - EDListNode *n = list->head; - - while (n->next) { - n = n->next; - count++; - } - return count; -} - -static void -imap_engine_command_complete(CamelIMAPPEngine *imap, CamelIMAPPCommand *ic) -{ - c(printf("completing command buffer is [%d] '%.*s'\n", ic->mem->buffer->len, (int)ic->mem->buffer->len, ic->mem->buffer->data)); - c(printf("command has %d parts\n", len(&ic->parts))); - if (ic->mem->buffer->len > 0) - imap_engine_command_add_part(imap, ic, CAMEL_IMAPP_COMMAND_SIMPLE, NULL); - - c(printf("command has %d parts\n", len(&ic->parts))); - - camel_object_unref((CamelObject *)ic->mem); - ic->mem = NULL; -} - -static void -imap_engine_command_addv(CamelIMAPPEngine *imap, CamelIMAPPCommand *ic, const char *fmt, va_list ap) -{ - const unsigned char *p, *ps, *start; - unsigned char c; - unsigned int width; - char ch; - int llong; - int left; - int fill; - int zero; - char *s; - int d; - long int l; - guint32 f; - CamelStream *S; - CamelDataWrapper *D; - CamelSasl *A; - char buffer[16]; - - c(printf("adding command, fmt = '%s'\n", fmt)); - - p = fmt; - ps = fmt; - while ( ( c = *p++ ) ) { - switch(c) { - case '%': - if (*p == '%') { - camel_stream_write((CamelStream *)ic->mem, ps, p-ps); - p++; - ps = p; - } else { - camel_stream_write((CamelStream *)ic->mem, ps, p-ps-1); - start = p-1; - width = 0; - left = FALSE; - fill = FALSE; - zero = FALSE; - llong = FALSE; - - do { - c = *p++; - if (c == '0') - zero = TRUE; - else if ( c== '-') - left = TRUE; - else - break; - } while (c); - - do { - if (isdigit(c)) - width = width * 10 + (c-'0'); - else - break; - } while ((c = *p++)); - - if (c == 'l') { - llong = TRUE; - c = *p++; - } - - switch(c) { - case 'A': /* auth object - sasl auth, treat as special kind of continuation */ - A = va_arg(ap, CamelSasl *); - imap_engine_command_add_part(imap, ic, CAMEL_IMAPP_COMMAND_AUTH, (CamelObject *)A); - break; - case 'S': /* stream */ - S = va_arg(ap, CamelStream *); - c(printf("got stream '%p'\n", S)); - imap_engine_command_add_part(imap, ic, CAMEL_IMAPP_COMMAND_STREAM, (CamelObject *)S); - break; - case 'D': /* datawrapper */ - D = va_arg(ap, CamelDataWrapper *); - c(printf("got data wrapper '%p'\n", D)); - imap_engine_command_add_part(imap, ic, CAMEL_IMAPP_COMMAND_DATAWRAPPER, (CamelObject *)D); - break; - case 't': /* token */ - s = va_arg(ap, char *); - camel_stream_write((CamelStream *)ic->mem, s, strlen(s)); - break; - case 's': /* simple string */ - s = va_arg(ap, char *); - c(printf("got string '%s'\n", s)); - /* FIXME: escpae chars, convert to literal or literal+, etc */ - camel_stream_printf((CamelStream *)ic->mem, "\"%s\"", s); - break; - case 'f': /* imap folder name */ - s = va_arg(ap, char *); - c(printf("got folder '%s'\n", s)); - /* FIXME: encode folder name */ - /* FIXME: namespace? */ - camel_stream_printf((CamelStream *)ic->mem, "\"%s\"", s?s:""); - break; - case 'F': /* IMAP flags set */ - f = va_arg(ap, guint32); - imap_write_flags((CamelStream *)ic->mem, f); - break; - case 'c': - d = va_arg(ap, int); - ch = d; - camel_stream_write((CamelStream *)ic->mem, &ch, 1); - break; - case 'd': /* int/unsigned */ - case 'u': - if (llong) { - l = va_arg(ap, long int); - c(printf("got long int '%d'\n", (int)l)); - memcpy(buffer, start, p-start); - buffer[p-start] = 0; - camel_stream_printf((CamelStream *)ic->mem, buffer, l); - } else { - d = va_arg(ap, int); - c(printf("got int '%d'\n", d)); - memcpy(buffer, start, p-start); - buffer[p-start] = 0; - camel_stream_printf((CamelStream *)ic->mem, buffer, d); - } - break; - } - - ps = p; - } - break; - case '\\': /* only for \\ really, we dont support \n\r etc at all */ - c = *p; - if (c) { - g_assert(c == '\\'); - camel_stream_write((CamelStream *)ic->mem, ps, p-ps); - p++; - ps = p; - } - } - } - - camel_stream_write((CamelStream *)ic->mem, ps, p-ps-1); -} - - -/* here temporarily while its experimental */ - - -#ifdef ENABLE_THREADS -#include <pthread.h> - -static pthread_key_t handler_key = 0; - -void camel_exception_setup(void) -{ - pthread_key_create(&handler_key, NULL); -} - -#else -/* this is per-thread in threaded mode */ -static struct _CamelExceptionEnv *handler = NULL; - -void camel_exception_setup(void) -{ -} -#endif - -void -camel_exception_try(struct _CamelExceptionEnv *env) -{ -#ifdef ENABLE_THREADS - struct _CamelExceptionEnv *handler; - - handler = pthread_getspecific(handler_key); -#endif - env->parent = handler; - handler = env; - env->ex = NULL; - -#ifdef ENABLE_THREADS - pthread_setspecific(handler_key, handler); -#endif -} - -void -camel_exception_throw_ex(CamelException *ex) -{ - struct _CamelExceptionEnv *env; -#ifdef ENABLE_THREADS - struct _CamelExceptionEnv *handler; - - handler = pthread_getspecific(handler_key); -#endif - printf("throwing exception '%s'\n", ex->desc); - - env = handler; - if (env != NULL) { - env->ex = ex; - handler = env->parent; -#ifdef ENABLE_THREADS - pthread_setspecific(handler_key, handler); -#endif - longjmp(env->env, ex->id); - } else { - g_warning("Uncaught exception: %s\n", ex->desc); - /* we just crash and burn, this is a code problem */ - /* we dont use g_assert_not_reached() since its not a noreturn function */ - abort(); - } -} - -void -camel_exception_throw(int id, char *fmt, ...) -{ - CamelException *ex; - va_list ap; - - ex = camel_exception_new(); - ex->id = id; - va_start(ap, fmt); - ex->desc = g_strdup_vprintf(fmt, ap); - va_end(ap); - - camel_exception_throw_ex(ex); -} - -void -camel_exception_drop(struct _CamelExceptionEnv *env) -{ -#ifdef ENABLE_THREADS - pthread_setspecific(handler_key, env->parent); -#else - handler = env->parent; -#endif -} - -void -camel_exception_done(struct _CamelExceptionEnv *env) -{ -#ifdef ENABLE_THREADS - pthread_setspecific(handler_key, env->parent); -#else - handler = env->parent; -#endif - if (env->ex != NULL) { - camel_exception_free(env->ex); - } -} diff --git a/camel/providers/imapp/camel-imapp-engine.h b/camel/providers/imapp/camel-imapp-engine.h deleted file mode 100644 index 5f74d0654a..0000000000 --- a/camel/providers/imapp/camel-imapp-engine.h +++ /dev/null @@ -1,155 +0,0 @@ - -#ifndef _CAMEL_IMAPP_ENGINE_H -#define _CAMEL_IMAPP_ENGINE_H - -#include <camel/camel-object.h> - -#include "camel-imapp-stream.h" -#include <e-util/e-msgport.h> -#include "camel-imapp-folder.h" - -#define CAMEL_IMAPP_ENGINE_TYPE (camel_imapp_engine_get_type ()) -#define CAMEL_IMAPP_ENGINE(obj) (CAMEL_CHECK_CAST((obj), CAMEL_IMAPP_ENGINE_TYPE, CamelIMAPPEngine)) -#define CAMEL_IMAPP_ENGINE_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_IMAPP_ENGINE_TYPE, CamelIMAPPEngineClass)) -#define CAMEL_IS_IMAP_ENGINE(o) (CAMEL_CHECK_TYPE((o), CAMEL_IMAPP_ENGINE_TYPE)) - -typedef struct _CamelIMAPPEngine CamelIMAPPEngine; -typedef struct _CamelIMAPPEngineClass CamelIMAPPEngineClass; - -typedef struct _CamelIMAPPCommandPart CamelIMAPPCommandPart; -typedef struct _CamelIMAPPCommand CamelIMAPPCommand; - -typedef enum { - CAMEL_IMAPP_COMMAND_SIMPLE = 0, - CAMEL_IMAPP_COMMAND_DATAWRAPPER, - CAMEL_IMAPP_COMMAND_STREAM, - CAMEL_IMAPP_COMMAND_AUTH, - CAMEL_IMAPP_COMMAND_MASK = 0xff, - CAMEL_IMAPP_COMMAND_CONTINUATION = 0x8000 /* does this command expect continuation? */ -} camel_imapp_command_part_t; - -struct _CamelIMAPPCommandPart { - struct _CamelIMAPPCommandPart *next; - struct _CamelIMAPPCommandPart *prev; - - struct _CamelIMAPPCommand *parent; - - int data_size; - char *data; - - camel_imapp_command_part_t type; - - int ob_size; - CamelObject *ob; -}; - -typedef int (*CamelIMAPPEngineFunc)(struct _CamelIMAPPEngine *engine, guint32 id, void *data); -typedef void (*CamelIMAPPCommandFunc)(struct _CamelIMAPPEngine *engine, struct _CamelIMAPPCommand *, void *data); - -/* FIXME: make this refcounted */ -struct _CamelIMAPPCommand { - struct _CamelIMAPPCommand *next; - struct _CamelIMAPPCommand *prev; - - const char *name; /* command name/type (e.g. FETCH) */ - - /* FIXME: remove this select stuff */ - char *select; /* if we need to run against a specific folder */ - struct _status_info *status; /* status for command, indicates it is complete if != NULL */ - - unsigned int tag; - - struct _CamelStreamMem *mem; /* for building the part */ - EDList parts; - CamelIMAPPCommandPart *current; - - CamelIMAPPCommandFunc complete; - void *complete_data; -}; - -typedef struct _CamelIMAPPSelectResponse CamelIMAPPSelectResponse; - -struct _CamelIMAPPSelectResponse { - struct _status_info *status; - guint32 exists; - guint32 recent; - guint32 uidvalidity; - guint32 unseen; - guint32 permanentflags; -}; - -enum { - IMAP_CAPABILITY_IMAP4 = (1 << 0), - IMAP_CAPABILITY_IMAP4REV1 = (1 << 1), - IMAP_CAPABILITY_STATUS = (1 << 2), - IMAP_CAPABILITY_NAMESPACE = (1 << 3), - IMAP_CAPABILITY_UIDPLUS = (1 << 4), - IMAP_CAPABILITY_LITERALPLUS = (1 << 5), - IMAP_CAPABILITY_STARTTLS = (1 << 6), -}; - -/* currently selected states */ -typedef enum _camel_imapp_engine_state_t { - IMAP_ENGINE_DISCONNECT, /* only happens during shutdown */ - IMAP_ENGINE_CONNECT, /* connected, not authenticated */ - IMAP_ENGINE_AUTH, /* connected, and authenticated */ - IMAP_ENGINE_SELECT, /* and selected, select holds selected folder */ -} camel_imapp_engine_state_t; - -struct _CamelIMAPPEngine { - CamelObject parent_object; - - CamelIMAPPStream *stream; - - camel_imapp_engine_state_t state; - - guint32 capa; /* capabilities for this server, refresh with :capabilities() */ - - GHashTable *handlers; - - unsigned char tagprefix; /* out tag prefix 'A' 'B' ... 'Z' */ - unsigned int tag; /* next command tag */ - - char *select; /* *currently* selected folder */ - char *last_select; /* last selected or to-be selected folder (e.g. outstanding queued select) */ - CamelIMAPPCommand *literal;/* current literal op */ - EDList active; /* active queue */ - EDList queue; /* outstanding queue */ - EDList done; /* done queue, awaiting reclamation */ - - /* keep track of running a select */ - struct _CamelIMAPPSelectResponse *select_response; -}; - -struct _CamelIMAPPEngineClass { - CamelObjectClass parent_class; - - unsigned char tagprefix; - - /* Events: - status(struct _status_info *); - */ -}; - -CamelType camel_imapp_engine_get_type (void); - -CamelIMAPPEngine *camel_imapp_engine_new(CamelIMAPPStream *stream); - -void camel_imapp_engine_add_handler(CamelIMAPPEngine *imap, const char *response, CamelIMAPPEngineFunc func, void *data); -int camel_imapp_engine_iterate(CamelIMAPPEngine *imap, CamelIMAPPCommand *wait); /* throws PARSE,IO exception */ -int camel_imapp_engine_skip(CamelIMAPPEngine *imap); -int camel_imapp_engine_capabilities(CamelIMAPPEngine *imap); - -CamelIMAPPCommand *camel_imapp_engine_command_new (CamelIMAPPEngine *imap, const char *name, const char *select, const char *fmt, ...); -void camel_imapp_engine_command_complete(CamelIMAPPEngine *imap, struct _CamelIMAPPCommand *, CamelIMAPPCommandFunc func, void *data); -void camel_imapp_engine_command_add (CamelIMAPPEngine *imap, CamelIMAPPCommand *ic, const char *fmt, ...); -void camel_imapp_engine_command_free (CamelIMAPPEngine *imap, CamelIMAPPCommand *ic); -void camel_imapp_engine_command_queue(CamelIMAPPEngine *imap, CamelIMAPPCommand *ic); /* throws IO exception */ -CamelIMAPPCommand *camel_imapp_engine_command_find (CamelIMAPPEngine *imap, const char *name); -CamelIMAPPCommand *camel_imapp_engine_command_find_tag(CamelIMAPPEngine *imap, unsigned int tag); - -/* util functions */ -CamelIMAPPSelectResponse *camel_imapp_engine_select(CamelIMAPPEngine *imap, const char *name); -void camel_imapp_engine_select_free(CamelIMAPPEngine *imap, CamelIMAPPSelectResponse *select); - -#endif diff --git a/camel/providers/imapp/camel-imapp-exception.h b/camel/providers/imapp/camel-imapp-exception.h deleted file mode 100644 index 5e18b6c815..0000000000 --- a/camel/providers/imapp/camel-imapp-exception.h +++ /dev/null @@ -1,35 +0,0 @@ - -/* This implements 'real' exceptions that work a bit like c++/java exceptions */ - -/* Still experimental code */ - -#ifndef __CAMEL_IMAPP_EXCEPTION_H -#define __CAMEL_IMAPP_EXCEPTION_H - -#include <setjmp.h> -#include "camel/camel-exception.h" - -struct _CamelExceptionEnv { - struct _CamelExceptionEnv *parent; - CamelException *ex; - jmp_buf env; -}; - -#define CAMEL_TRY { struct _CamelExceptionEnv __env; camel_exception_try(&__env); if (setjmp(__env.env) == 0) -#define CAMEL_IGNORE camel_exception_done(&__env); } -#define CAMEL_CATCH(x) { CamelException *x; x=__env.ex; if (x != NULL) -#define CAMEL_DONE } camel_exception_done(&__env); } -#define CAMEL_DROP() camel_exception_drop(&__env) - -void camel_exception_setup(void); - -/* internal functions, use macro's above */ -void camel_exception_try(struct _CamelExceptionEnv *env); -void camel_exception_done(struct _CamelExceptionEnv *env); -void camel_exception_drop(struct _CamelExceptionEnv *env); - -/* user functions */ -void camel_exception_throw_ex(CamelException *ex) __attribute__ ((noreturn)); -void camel_exception_throw(int id, char *fmt, ...) __attribute__ ((noreturn)); - -#endif diff --git a/camel/providers/imapp/camel-imapp-fetch-stream.c b/camel/providers/imapp/camel-imapp-fetch-stream.c deleted file mode 100644 index bf18aac57b..0000000000 --- a/camel/providers/imapp/camel-imapp-fetch-stream.c +++ /dev/null @@ -1,183 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*- - * - * Author: - * 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 - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <string.h> -#include <stdio.h> -#include <ctype.h> -#include <errno.h> - -#include <glib.h> - -#include <camel/camel-stream-mem.h> - -#include "camel-imapp-stream.h" -#include "camel-imapp-exception.h" - -#define t(x) -#define io(x) x - -static CamelObjectClass *parent_class = NULL; - -/* Returns the class for a CamelStream */ -#define CS_CLASS(so) CAMEL_IMAPP_FETCH_STREAM_CLASS(CAMEL_OBJECT_GET_CLASS(so)) - -static ssize_t -stream_read(CamelStream *stream, char *buffer, size_t n) -{ - CamelIMAPPFetchStream *is = (CamelIMAPPFetchStream *)stream; - ssize_t max; - - /* make sure we have all the data read in */ - while (camel_imapp_engine_iterate(is->engine, is->command)>0) - ; - - if (is->literal == 0 || n == 0) - return 0; - - max = is->end - is->ptr; - if (max > 0) { - max = MIN(max, is->literal); - max = MIN(max, n); - memcpy(buffer, is->ptr, max); - is->ptr += max; - } else { - max = MIN(is->literal, n); - max = camel_stream_read(is->source, buffer, max); - if (max <= 0) - return max; - } - - is->literal -= max; - - return max; -} - -static ssize_t -stream_write(CamelStream *stream, const char *buffer, size_t n) -{ - CamelIMAPPFetchStream *is = (CamelIMAPPFetchStream *)stream; - - return camel_stream_write(is->source, buffer, n); -} - -static int -stream_close(CamelStream *stream) -{ - /* nop? */ - return 0; -} - -static int -stream_flush(CamelStream *stream) -{ - /* nop? */ - return 0; -} - -static gboolean -stream_eos(CamelStream *stream) -{ - CamelIMAPPFetchStream *is = (CamelIMAPPFetchStream *)stream; - - return is->literal == 0; -} - -static int -stream_reset(CamelStream *stream) -{ - /* nop? reset literal mode? */ - return 0; -} - -static void -camel_imapp_fetch_stream_class_init (CamelStreamClass *camel_imapp_fetch_stream_class) -{ - CamelStreamClass *camel_stream_class = (CamelStreamClass *)camel_imapp_fetch_stream_class; - - parent_class = camel_type_get_global_classfuncs( CAMEL_OBJECT_TYPE ); - - /* virtual method definition */ - camel_stream_class->read = stream_read; - camel_stream_class->write = stream_write; - camel_stream_class->close = stream_close; - camel_stream_class->flush = stream_flush; - camel_stream_class->eos = stream_eos; - camel_stream_class->reset = stream_reset; -} - -static void -camel_imapp_fetch_stream_init(CamelIMAPPFetchStream *is, CamelIMAPPFetchStreamClass *isclass) -{ - ; -} - -static void -camel_imapp_fetch_stream_finalise(CamelIMAPPFetchStream *is) -{ - if (is->engine) - camel_object_unref(is->engine); -} - -CamelType -camel_imapp_fetch_stream_get_type (void) -{ - static CamelType camel_imapp_fetch_stream_type = CAMEL_INVALID_TYPE; - - if (camel_imapp_fetch_stream_type == CAMEL_INVALID_TYPE) { - setup_table(); - camel_imapp_fetch_stream_type = camel_type_register( camel_stream_get_type(), - "CamelIMAPPFetchStream", - sizeof( CamelIMAPPFetchStream ), - sizeof( CamelIMAPPFetchStreamClass ), - (CamelObjectClassInitFunc) camel_imapp_fetch_stream_class_init, - NULL, - (CamelObjectInitFunc) camel_imapp_fetch_stream_init, - (CamelObjectFinalizeFunc) camel_imapp_fetch_stream_finalise ); - } - - return camel_imapp_fetch_stream_type; -} - -/** - * camel_imapp_fetch_stream_new: - * - * Return value: the stream - **/ -CamelStream * -camel_imapp_fetch_stream_new(CamelIMAPPEngine *ie, const char *uid, const char *body) -{ - CamelIMAPPFetchStream *is; - - is = (CamelIMAPPFetchStream *)camel_object_new(camel_imapp_fetch_stream_get_type ()); - is->engine = ie; - camel_object_ref(ie); - - is->command = camel_imapp_engine_command_new(ie, "FETCH", NULL, "FETCH %t (BODY[%t]<0.4096>", uid, body); - camel_imapp_engine_command_queue(ie, command); - - return (CamelStream *)is; -} - diff --git a/camel/providers/imapp/camel-imapp-fetch-stream.h b/camel/providers/imapp/camel-imapp-fetch-stream.h deleted file mode 100644 index c9281ff64f..0000000000 --- a/camel/providers/imapp/camel-imapp-fetch-stream.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2000 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_IMAPP_FETCH_STREAM_H -#define _CAMEL_IMAPP_FETCH_STREAM_H - -#include <camel/camel-stream.h> - -#define CAMEL_IMAPP_FETCH_STREAM(obj) CAMEL_CHECK_CAST (obj, camel_imapp_fetch_stream_get_type (), CamelIMAPPFetchStream) -#define CAMEL_IMAPP_FETCH_STREAM_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_imapp_fetch_stream_get_type (), CamelIMAPPFetchStreamClass) -#define CAMEL_IS_IMAP_FETCH_STREAM(obj) CAMEL_CHECK_TYPE (obj, camel_imapp_fetch_stream_get_type ()) - -typedef struct _CamelIMAPPFetchStreamClass CamelIMAPPFetchStreamClass; -typedef struct _CamelIMAPPFetchStream CamelIMAPPFetchStream; - -struct _CamelIMAPPFetchStream { - CamelStream parent; - - struct _CamelIMAPPEngine *engine; -}; - -struct _CamelIMAPPFetchStreamClass { - CamelStreamClass parent_class; -}; - -CamelType camel_imapp_fetch_stream_get_type (void); - -CamelStream *camel_imapp_fetch_stream_new (struct _CamelIMAPPEngine *src, const char *uid, const char *spec); - -#endif /* ! _CAMEL_IMAPP_FETCH_STREAM_H */ diff --git a/camel/providers/imapp/camel-imapp-folder.c b/camel/providers/imapp/camel-imapp-folder.c deleted file mode 100644 index 967ab541f6..0000000000 --- a/camel/providers/imapp/camel-imapp-folder.c +++ /dev/null @@ -1,269 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-imap-folder.c : class for a imap folder */ - -/* - * Authors: Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 2002 Ximian, Inc. (www.ximian.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> - -#include "camel/camel-exception.h" -#include "camel/camel-stream-mem.h" -#include "camel/camel-stream-filter.h" -#include "camel/camel-mime-message.h" -#include "camel/camel-operation.h" -#include "camel/camel-data-cache.h" -#include "camel/camel-session.h" -#include "camel/camel-file-utils.h" - -#include "camel-imapp-store.h" -#include "camel-imapp-folder.h" -#include "camel-imapp-summary.h" -#include "camel-imapp-exception.h" - -#include <e-util/md5-utils.h> - -#include <stdlib.h> -#include <string.h> - -#define d(x) - -#define CF_CLASS(o) (CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(o))) -static CamelFolderClass *parent_class; - -static void imap_finalize (CamelObject *object); -static void imap_refresh_info (CamelFolder *folder, CamelException *ex); -static void imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex); -static CamelMimeMessage *imap_get_message (CamelFolder *folder, const char *uid, CamelException *ex); - -static void -imap_folder_class_init (CamelIMAPPFolderClass *camel_imapp_folder_class) -{ - CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS(camel_imapp_folder_class); - - parent_class = CAMEL_FOLDER_CLASS(camel_folder_get_type()); - - /* virtual method overload */ - camel_folder_class->refresh_info = imap_refresh_info; - camel_folder_class->sync = imap_sync; - - camel_folder_class->get_message = imap_get_message; - /*camel_folder_class->set_message_flags = imap_set_message_flags;*/ -} - -static void -imap_folder_init(CamelObject *o, CamelObjectClass *klass) -{ - CamelFolder *folder = (CamelFolder *)o; - CamelIMAPPFolder *ifolder = (CamelIMAPPFolder *)o; - - folder->folder_flags |= (CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY | - CAMEL_FOLDER_HAS_SEARCH_CAPABILITY); - - folder->permanent_flags = CAMEL_MESSAGE_ANSWERED | - CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_DRAFT | - CAMEL_MESSAGE_FLAGGED | CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_USER; - - /* FIXME: this is just a skeleton */ - - ifolder->changes = camel_folder_change_info_new(); -} - -CamelType -camel_imapp_folder_get_type (void) -{ - static CamelType camel_imapp_folder_type = CAMEL_INVALID_TYPE; - - if (!camel_imapp_folder_type) { - camel_imapp_folder_type = camel_type_register (CAMEL_FOLDER_TYPE, "CamelIMAPPFolder", - sizeof (CamelIMAPPFolder), - sizeof (CamelIMAPPFolderClass), - (CamelObjectClassInitFunc) imap_folder_class_init, - NULL, - imap_folder_init, - (CamelObjectFinalizeFunc) imap_finalize); - } - - return camel_imapp_folder_type; -} - -void -imap_finalize (CamelObject *object) -{ - CamelIMAPPFolder *folder = (CamelIMAPPFolder *)object; - - camel_folder_change_info_free(folder->changes); -} - -CamelFolder * -camel_imapp_folder_new(CamelStore *store, const char *path) -{ - CamelFolder *folder; - char *root; - - d(printf("opening imap folder '%s'\n", path)); - - folder = CAMEL_FOLDER (camel_object_new (CAMEL_IMAPP_FOLDER_TYPE)); - camel_folder_construct(folder, store, path, path); - - ((CamelIMAPPFolder *)folder)->raw_name = g_strdup(path); - - folder->summary = camel_imapp_summary_new(); - - root = camel_session_get_storage_path(((CamelService *)store)->session, (CamelService *)store, NULL); - if (root) { - char *base = g_build_filename(root, path, NULL); - char *file = g_build_filename(base, ".ev-summary", NULL); - - camel_mkdir(base, 0777); - g_free(base); - - camel_folder_summary_set_filename(folder->summary, file); - printf("loading summary from '%s' (root=%s)\n", file, root); - g_free(file); - camel_folder_summary_load(folder->summary); - g_free(root); - } - - return folder; -} - -void -camel_imapp_folder_open(CamelIMAPPFolder *folder, CamelException *ex) -{ - /* */ -} - -void -camel_imapp_folder_delete(CamelIMAPPFolder *folder, CamelException *ex) -{ -} - -void -camel_imapp_folder_rename(CamelIMAPPFolder *folder, const char *new, CamelException *ex) -{ -} - -void -camel_imapp_folder_close(CamelIMAPPFolder *folder, CamelException *ex) -{ -} - -static void -imap_refresh_info (CamelFolder *folder, CamelException *ex) -{ - printf("imapp refresh info?\n"); -} - -static void -imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex) -{ - camel_imapp_driver_sync(((CamelIMAPPStore *)(folder->parent_store))->driver, expunge, (CamelIMAPPFolder *) folder); -} - -static CamelMimeMessage * -imap_get_message (CamelFolder *folder, const char *uid, CamelException *ex) -{ - CamelMimeMessage * volatile msg = NULL; - CamelStream * volatile stream = NULL; - - printf("get message '%s'\n", uid); - - CAMEL_TRY { - /* simple implementation, just get whole message in 1 go */ - stream = camel_imapp_driver_fetch(((CamelIMAPPStore *)(folder->parent_store))->driver, (CamelIMAPPFolder *)folder, uid, ""); - camel_stream_reset(stream); - msg = camel_mime_message_new(); - if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)msg, stream) != -1) { - /* do we care? */ - } - } CAMEL_CATCH(e) { - if (msg) - camel_object_unref(msg); - msg = NULL; - camel_exception_xfer(ex, e); - } CAMEL_DONE; - - if (stream) - camel_object_unref(stream); - - return msg; -} - - -/* Algorithm for selecting a folder: - - - If uidvalidity == old uidvalidity - and exsists == old exists - and recent == old recent - and unseen == old unseen - Assume our summary is correct - for each summary item - mark the summary item as 'old/not updated' - rof - fetch flags from 1:* - for each fetch response - info = summary[index] - if info.uid != uid - info = summary_by_uid[uid] - fi - if info == NULL - create new info @ index - fi - if got.flags - update flags - fi - if got.header - update based on header - mark as retrieved - else if got.body - update based on imap body - mark as retrieved - fi - - Async fetch response: - info = summary[index] - if info == null - if uid == null - force resync/select? - info = empty @ index - else if uid && info.uid != uid - force a resync? - return - fi - - if got.flags { - info.flags = flags - } - if got.header { - info.init(header) - info.empty = false - } - -info.state - 2 bit field in flags - 0 = empty, nothing set - 1 = uid & flags set - 2 = update required - 3 = up to date -*/ - diff --git a/camel/providers/imapp/camel-imapp-folder.h b/camel/providers/imapp/camel-imapp-folder.h deleted file mode 100644 index 329c66b7fc..0000000000 --- a/camel/providers/imapp/camel-imapp-folder.h +++ /dev/null @@ -1,66 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-imap-folder.h : Class for a IMAP folder */ - -/* - * Authors: Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 2002 Ximian, Inc. (www.ximian.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - */ - -#ifndef CAMEL_IMAPP_FOLDER_H -#define CAMEL_IMAPP_FOLDER_H 1 - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus }*/ - -#include <camel/camel-folder.h> - -#define CAMEL_IMAPP_FOLDER_TYPE (camel_imapp_folder_get_type ()) -#define CAMEL_IMAPP_FOLDER(obj) (CAMEL_CHECK_CAST((obj), CAMEL_IMAPP_FOLDER_TYPE, CamelIMAPPFolder)) -#define CAMEL_IMAPP_FOLDER_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_IMAPP_FOLDER_TYPE, CamelIMAPPFolderClass)) -#define CAMEL_IS_IMAP_FOLDER(o) (CAMEL_CHECK_TYPE((o), CAMEL_IMAPP_FOLDER_TYPE)) - -typedef struct _CamelIMAPPFolder { - CamelFolder parent_object; - - char *raw_name; - CamelFolderChangeInfo *changes; - - guint32 exists; - guint32 recent; - guint32 uidvalidity; - guint32 unseen; - guint32 permanentflags; -} CamelIMAPPFolder; - -typedef struct _CamelIMAPPFolderClass { - CamelFolderClass parent_class; -} CamelIMAPPFolderClass; - -/* Standard Camel function */ -CamelType camel_imapp_folder_get_type (void); - -/* public methods */ -CamelFolder *camel_imapp_folder_new(CamelStore *parent, const char *path); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CAMEL_IMAPP_FOLDER_H */ diff --git a/camel/providers/imapp/camel-imapp-provider.c b/camel/providers/imapp/camel-imapp-provider.c deleted file mode 100644 index 6b0cdd2d43..0000000000 --- a/camel/providers/imapp/camel-imapp-provider.c +++ /dev/null @@ -1,97 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-pop3-provider.c: pop3 provider registration code */ - -/* - * Authors : - * Dan Winship <danw@ximian.com> - * Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 2002 Ximian, Inc. (www.ximian.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "camel/camel-provider.h" -#include "camel/camel-session.h" -#include "camel/camel-url.h" -#include "camel/camel-sasl.h" - -#include "camel-imapp-store.h" - -CamelProviderConfEntry imapp_conf_entries[] = { - { CAMEL_PROVIDER_CONF_SECTION_START, NULL, NULL, - N_("Message storage") }, - { CAMEL_PROVIDER_CONF_SECTION_END }, - { CAMEL_PROVIDER_CONF_END } -}; - -static CamelProvider imapp_provider = { - "imapp", - - N_("IMAP+"), - - N_("Experimental IMAP 4(.1) client\n" - "This is untested and unsupported code, you want to use plain imap instead.\n\n" - " !!! DO NOT USE THIS FOR PRODUCTION EMAIL !!!\n"), - "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, - - imapp_conf_entries, - - /* ... */ -}; - -CamelServiceAuthType camel_imapp_password_authtype = { - N_("Password"), - - N_("This option will connect to the IMAP server using a " - "plaintext password."), - - "", - TRUE -}; - -void -camel_imapp_module_init(CamelSession *session) -{ - extern void camel_exception_setup(void); - - imapp_provider.object_types[CAMEL_PROVIDER_STORE] = camel_imapp_store_get_type(); - imapp_provider.url_hash = camel_url_hash; - imapp_provider.url_equal = camel_url_equal; - - imapp_provider.authtypes = g_list_prepend(imapp_provider.authtypes, camel_sasl_authtype_list(FALSE)); - imapp_provider.authtypes = g_list_prepend(imapp_provider.authtypes, &camel_imapp_password_authtype); - - /* blah ... could just use it in object setup? */ - /* TEMPORARY */ - camel_exception_setup(); - - camel_session_register_provider(session, &imapp_provider); -} - -void -camel_provider_module_init(CamelSession *session) -{ - camel_imapp_module_init(session); -} diff --git a/camel/providers/imapp/camel-imapp-store-summary.c b/camel/providers/imapp/camel-imapp-store-summary.c deleted file mode 100644 index a3ad57fb11..0000000000 --- a/camel/providers/imapp/camel-imapp-store-summary.c +++ /dev/null @@ -1,616 +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-imapp-store-summary.h" - -#include "camel/camel-file-utils.h" - -#include "camel-string-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_IMAPP_STORE_SUMMARY_VERSION_0 (0) - -#define CAMEL_IMAPP_STORE_SUMMARY_VERSION (0) - -#define _PRIVATE(o) (((CamelIMAPPStoreSummary *)(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_imapp_store_summary_class_init (CamelIMAPPStoreSummaryClass *klass); -static void camel_imapp_store_summary_init (CamelIMAPPStoreSummary *obj); -static void camel_imapp_store_summary_finalise (CamelObject *obj); - -static CamelStoreSummaryClass *camel_imapp_store_summary_parent; - -static void -camel_imapp_store_summary_class_init (CamelIMAPPStoreSummaryClass *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_imapp_store_summary_init (CamelIMAPPStoreSummary *s) -{ - /*struct _CamelIMAPPStoreSummaryPrivate *p; - - p = _PRIVATE(s) = g_malloc0(sizeof(*p));*/ - - ((CamelStoreSummary *)s)->store_info_size = sizeof(CamelIMAPPStoreInfo); - s->version = CAMEL_IMAPP_STORE_SUMMARY_VERSION; -} - -static void -camel_imapp_store_summary_finalise (CamelObject *obj) -{ - /*struct _CamelIMAPPStoreSummaryPrivate *p;*/ - /*CamelIMAPPStoreSummary *s = (CamelIMAPPStoreSummary *)obj;*/ - - /*p = _PRIVATE(obj); - g_free(p);*/ -} - -CamelType -camel_imapp_store_summary_get_type (void) -{ - static CamelType type = CAMEL_INVALID_TYPE; - - if (type == CAMEL_INVALID_TYPE) { - camel_imapp_store_summary_parent = (CamelStoreSummaryClass *)camel_store_summary_get_type(); - type = camel_type_register((CamelType)camel_imapp_store_summary_parent, "CamelIMAPPStoreSummary", - sizeof (CamelIMAPPStoreSummary), - sizeof (CamelIMAPPStoreSummaryClass), - (CamelObjectClassInitFunc) camel_imapp_store_summary_class_init, - NULL, - (CamelObjectInitFunc) camel_imapp_store_summary_init, - (CamelObjectFinalizeFunc) camel_imapp_store_summary_finalise); - } - - return type; -} - -/** - * camel_imapp_store_summary_new: - * - * Create a new CamelIMAPPStoreSummary object. - * - * Return value: A new CamelIMAPPStoreSummary widget. - **/ -CamelIMAPPStoreSummary * -camel_imapp_store_summary_new (void) -{ - CamelIMAPPStoreSummary *new = CAMEL_IMAPP_STORE_SUMMARY ( camel_object_new (camel_imapp_store_summary_get_type ())); - - return new; -} - -/** - * camel_imapp_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(). - **/ -CamelIMAPPStoreInfo * -camel_imapp_store_summary_full_name(CamelIMAPPStoreSummary *s, const char *full_name) -{ - int count, i; - CamelIMAPPStoreInfo *info; - - count = camel_store_summary_count((CamelStoreSummary *)s); - for (i=0;i<count;i++) { - info = (CamelIMAPPStoreInfo *)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_imapp_store_summary_full_to_path(CamelIMAPPStoreSummary *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_imapp_store_summary_path_to_full(CamelIMAPPStoreSummary *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; - CamelIMAPPStoreNamespace *ns; - - /* 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_imapp_store_info_full_name(s, si)); - camel_store_summary_info_free((CamelStoreSummary *)s, si); - return f; - } - - ns = camel_imapp_store_summary_namespace_find_path(s, path); - - f = full = alloca(strlen(path)*2+1); - if (si) - p = path + strlen(subpath); - else if (ns) - p = path + strlen(ns->path); - 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_imapp_store_info_full_name(s, si), f); - g_free(f); - camel_store_summary_info_free((CamelStoreSummary *)s, si); - f = full; - } else if (ns) { - full = g_strdup_printf("%s%s", ns->full_name, f); - g_free(f); - f = full; - } - - return f; -} - -CamelIMAPPStoreInfo * -camel_imapp_store_summary_add_from_full(CamelIMAPPStoreSummary *s, const char *full, char dir_sep) -{ - CamelIMAPPStoreInfo *info; - char *pathu8, *prefix; - int len; - char *full_name; - CamelIMAPPStoreNamespace *ns; - - d(printf("adding full name '%s' '%c'\n", full, dir_sep)); - - len = strlen(full); - full_name = alloca(len+1); - strcpy(full_name, full); - if (full_name[len-1] == dir_sep) - full_name[len-1] = 0; - - info = camel_imapp_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; - } - - ns = camel_imapp_store_summary_namespace_find_full(s, full_name); - if (ns) { - d(printf("(found namespace for '%s' ns '%s') ", full_name, ns->path)); - len = strlen(ns->full_name); - if (len >= strlen(full_name)) { - pathu8 = g_strdup(ns->path); - } else { - if (full_name[len] == ns->sep) - len++; - - prefix = camel_imapp_store_summary_full_to_path(s, full_name+len, ns->sep); - if (*ns->path) { - pathu8 = g_strdup_printf ("%s/%s", ns->path, prefix); - g_free (prefix); - } else { - pathu8 = prefix; - } - } - d(printf(" (pathu8 = '%s')", pathu8)); - } else { - d(printf("(Cannot find namespace for '%s')\n", full_name)); - pathu8 = camel_imapp_store_summary_full_to_path(s, full_name, dir_sep); - } - - info = (CamelIMAPPStoreInfo *)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_IMAPP_STORE_INFO_FULL_NAME, full_name); - } else - d(printf(" failed\n")); - - return info; -} - -/* should this be const? */ -/* TODO: deprecate/merge this function with path_to_full */ -char * -camel_imapp_store_summary_full_from_path(CamelIMAPPStoreSummary *s, const char *path) -{ - CamelIMAPPStoreNamespace *ns; - char *name = NULL; - - ns = camel_imapp_store_summary_namespace_find_path(s, path); - if (ns) - name = camel_imapp_store_summary_path_to_full(s, path, ns->sep); - - d(printf("looking up path %s -> %s\n", path, name?name:"not found")); - - return name; -} - -/* TODO: this api needs some more work */ -CamelIMAPPStoreNamespace *camel_imapp_store_summary_namespace_new(CamelIMAPPStoreSummary *s, const char *full_name, char dir_sep) -{ - CamelIMAPPStoreNamespace *ns; - char *p; - int len; - - ns = g_malloc0(sizeof(*ns)); - ns->full_name = g_strdup(full_name); - len = strlen(ns->full_name)-1; - if (len >= 0 && ns->full_name[len] == dir_sep) - ns->full_name[len] = 0; - ns->sep = dir_sep; - - p = ns->path = camel_imapp_store_summary_full_to_path(s, ns->full_name, dir_sep); - while (*p) { - if (*p == '/') - *p = '.'; - p++; - } - - return ns; -} - -void camel_imapp_store_summary_namespace_set(CamelIMAPPStoreSummary *s, CamelIMAPPStoreNamespace *ns) -{ - static void namespace_clear(CamelStoreSummary *s); - - d(printf("Setting namesapce to '%s' '%c' -> '%s'\n", ns->full_name, ns->sep, ns->path)); - namespace_clear((CamelStoreSummary *)s); - s->namespace = ns; - camel_store_summary_touch((CamelStoreSummary *)s); -} - -CamelIMAPPStoreNamespace * -camel_imapp_store_summary_namespace_find_path(CamelIMAPPStoreSummary *s, const char *path) -{ - int len; - CamelIMAPPStoreNamespace *ns; - - /* NB: this currently only compares against 1 namespace, in future compare against others */ - ns = s->namespace; - while (ns) { - len = strlen(ns->path); - if (len == 0 - || (strncmp(ns->path, path, len) == 0 - && (path[len] == '/' || path[len] == 0))) - break; - ns = NULL; - } - - /* have a default? */ - return ns; -} - -CamelIMAPPStoreNamespace * -camel_imapp_store_summary_namespace_find_full(CamelIMAPPStoreSummary *s, const char *full) -{ - int len; - CamelIMAPPStoreNamespace *ns; - - /* NB: this currently only compares against 1 namespace, in future compare against others */ - ns = s->namespace; - while (ns) { - len = strlen(ns->full_name); - d(printf("find_full: comparing namespace '%s' to name '%s'\n", ns->full_name, full)); - if (len == 0 - || (strncmp(ns->full_name, full, len) == 0 - && (full[len] == ns->sep || full[len] == 0))) - break; - ns = NULL; - } - - /* have a default? */ - return ns; -} - -static void -namespace_free(CamelStoreSummary *s, CamelIMAPPStoreNamespace *ns) -{ - g_free(ns->path); - g_free(ns->full_name); - g_free(ns); -} - -static void -namespace_clear(CamelStoreSummary *s) -{ - CamelIMAPPStoreSummary *is = (CamelIMAPPStoreSummary *)s; - - if (is->namespace) - namespace_free(s, is->namespace); - is->namespace = NULL; -} - -static CamelIMAPPStoreNamespace * -namespace_load(CamelStoreSummary *s, FILE *in) -{ - CamelIMAPPStoreNamespace *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, CamelIMAPPStoreNamespace *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) -{ - CamelIMAPPStoreSummary *is = (CamelIMAPPStoreSummary *)s; - gint32 version, capabilities, count; - - namespace_clear(s); - - if (camel_imapp_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_IMAPP_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) -{ - CamelIMAPPStoreSummary *is = (CamelIMAPPStoreSummary *)s; - guint32 count; - - count = is->namespace?1:0; - - /* always write as latest version */ - if (camel_imapp_store_summary_parent->summary_header_save((CamelStoreSummary *)s, out) == -1 - || camel_file_util_encode_fixed_int32(out, CAMEL_IMAPP_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) -{ - CamelIMAPPStoreInfo *mi; - - mi = (CamelIMAPPStoreInfo *)camel_imapp_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) -{ - CamelIMAPPStoreInfo *isi = (CamelIMAPPStoreInfo *)mi; - - if (camel_imapp_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) -{ - CamelIMAPPStoreInfo *isi = (CamelIMAPPStoreInfo *)mi; - - g_free(isi->full_name); - camel_imapp_store_summary_parent->store_info_free(s, mi); -} - -static const char * -store_info_string(CamelStoreSummary *s, const CamelStoreInfo *mi, int type) -{ - CamelIMAPPStoreInfo *isi = (CamelIMAPPStoreInfo *)mi; - - /* FIXME: Locks? */ - - g_assert (mi != NULL); - - switch (type) { - case CAMEL_IMAPP_STORE_INFO_FULL_NAME: - return isi->full_name; - default: - return camel_imapp_store_summary_parent->store_info_string(s, mi, type); - } -} - -static void -store_info_set_string(CamelStoreSummary *s, CamelStoreInfo *mi, int type, const char *str) -{ - CamelIMAPPStoreInfo *isi = (CamelIMAPPStoreInfo *)mi; - - g_assert(mi != NULL); - - switch(type) { - case CAMEL_IMAPP_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_imapp_store_summary_parent->store_info_set_string(s, mi, type, str); - break; - } -} diff --git a/camel/providers/imapp/camel-imapp-store-summary.h b/camel/providers/imapp/camel-imapp-store-summary.h deleted file mode 100644 index 154fe8798e..0000000000 --- a/camel/providers/imapp/camel-imapp-store-summary.h +++ /dev/null @@ -1,102 +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_IMAPP_STORE_SUMMARY_H -#define _CAMEL_IMAPP_STORE_SUMMARY_H - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus */ - -#include <camel/camel-object.h> -#include <camel/camel-store-summary.h> - -#define CAMEL_IMAPP_STORE_SUMMARY(obj) CAMEL_CHECK_CAST (obj, camel_imapp_store_summary_get_type (), CamelIMAPPStoreSummary) -#define CAMEL_IMAPP_STORE_SUMMARY_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_imapp_store_summary_get_type (), CamelIMAPPStoreSummaryClass) -#define CAMEL_IS_IMAP_STORE_SUMMARY(obj) CAMEL_CHECK_TYPE (obj, camel_imapp_store_summary_get_type ()) - -typedef struct _CamelIMAPPStoreSummary CamelIMAPPStoreSummary; -typedef struct _CamelIMAPPStoreSummaryClass CamelIMAPPStoreSummaryClass; - -typedef struct _CamelIMAPPStoreInfo CamelIMAPPStoreInfo; - -enum { - CAMEL_IMAPP_STORE_INFO_FULL_NAME = CAMEL_STORE_INFO_LAST, - CAMEL_IMAPP_STORE_INFO_LAST, -}; - -struct _CamelIMAPPStoreInfo { - CamelStoreInfo info; - char *full_name; -}; - -typedef struct _CamelIMAPPStoreNamespace CamelIMAPPStoreNamespace; - -struct _CamelIMAPPStoreNamespace { - char *path; /* display path */ - char *full_name; /* real name */ - char sep; /* directory separator */ -}; - -struct _CamelIMAPPStoreSummary { - CamelStoreSummary summary; - - struct _CamelIMAPPStoreSummaryPrivate *priv; - - /* header info */ - guint32 version; /* version of base part of file */ - guint32 capabilities; - CamelIMAPPStoreNamespace *namespace; /* eventually to be a list */ -}; - -struct _CamelIMAPPStoreSummaryClass { - CamelStoreSummaryClass summary_class; -}; - -CamelType camel_imapp_store_summary_get_type (void); -CamelIMAPPStoreSummary *camel_imapp_store_summary_new (void); - -/* TODO: this api needs some more work, needs to support lists */ -CamelIMAPPStoreNamespace *camel_imapp_store_summary_namespace_new(CamelIMAPPStoreSummary *s, const char *full_name, char dir_sep); -void camel_imapp_store_summary_namespace_set(CamelIMAPPStoreSummary *s, CamelIMAPPStoreNamespace *ns); -CamelIMAPPStoreNamespace *camel_imapp_store_summary_namespace_find_path(CamelIMAPPStoreSummary *s, const char *path); -CamelIMAPPStoreNamespace *camel_imapp_store_summary_namespace_find_full(CamelIMAPPStoreSummary *s, const char *full_name); - -/* converts to/from utf8 canonical nasmes */ -char *camel_imapp_store_summary_full_to_path(CamelIMAPPStoreSummary *s, const char *full_name, char dir_sep); -char *camel_imapp_store_summary_path_to_full(CamelIMAPPStoreSummary *s, const char *path, char dir_sep); - -CamelIMAPPStoreInfo *camel_imapp_store_summary_full_name(CamelIMAPPStoreSummary *s, const char *full_name); -CamelIMAPPStoreInfo *camel_imapp_store_summary_add_from_full(CamelIMAPPStoreSummary *s, const char *full_name, char dir_sep); - -/* a convenience lookup function. always use this if path known */ -char *camel_imapp_store_summary_full_from_path(CamelIMAPPStoreSummary *s, const char *path); - -/* helper macro's */ -#define camel_imapp_store_info_full_name(s, i) (camel_store_info_string((CamelStoreSummary *)s, (const CamelStoreInfo *)i, CAMEL_IMAPP_STORE_INFO_FULL_NAME)) - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* ! _CAMEL_IMAPP_STORE_SUMMARY_H */ diff --git a/camel/providers/imapp/camel-imapp-store.c b/camel/providers/imapp/camel-imapp-store.c deleted file mode 100644 index 9123102a03..0000000000 --- a/camel/providers/imapp/camel-imapp-store.c +++ /dev/null @@ -1,1006 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-imap-store.c : class for a imap store */ - -/* - * Authors: Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 2000-2002 Ximian, Inc. (www.ximian.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> - -#include "camel/camel-operation.h" - -#include "camel/camel-stream-buffer.h" -#include "camel/camel-session.h" -#include "camel/camel-exception.h" -#include "camel/camel-url.h" -#include "camel/camel-sasl.h" -#include "camel/camel-data-cache.h" -#include "camel/camel-tcp-stream.h" -#include "camel/camel-tcp-stream-raw.h" -#ifdef HAVE_SSL -#include "camel/camel-tcp-stream-ssl.h" -#endif - -#include "camel-imapp-store-summary.h" -#include "camel-imapp-store.h" -#include "camel-imapp-folder.h" -#include "camel-imapp-engine.h" -#include "camel-imapp-exception.h" -#include "camel-imapp-utils.h" -#include "camel-imapp-driver.h" - -/* Specified in RFC 2060 section 2.1 */ -#define IMAP_PORT 143 - -static CamelStoreClass *parent_class = NULL; - -static void finalize (CamelObject *object); - -static void imap_construct(CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, CamelException *ex); -/* static char *imap_get_name(CamelService *service, gboolean brief);*/ -static gboolean imap_connect (CamelService *service, CamelException *ex); -static gboolean imap_disconnect (CamelService *service, gboolean clean, CamelException *ex); -static GList *imap_query_auth_types (CamelService *service, CamelException *ex); - -static void imap_init_trash (CamelStore *store); -static CamelFolder *imap_get_trash (CamelStore *store, CamelException *ex); - -static CamelFolder *imap_get_folder(CamelStore * store, const char *folder_name, guint32 flags, CamelException * ex); -static CamelFolder *imap_get_inbox (CamelStore *store, CamelException *ex); -static void imap_rename_folder(CamelStore *store, const char *old_name, const char *new_name, CamelException *ex); -static CamelFolderInfo *imap_get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex); -static void imap_delete_folder(CamelStore *store, const char *folder_name, CamelException *ex); -static void imap_rename_folder(CamelStore *store, const char *old, const char *new, CamelException *ex); -static CamelFolderInfo *imap_create_folder(CamelStore *store, const char *parent_name, const char *folder_name, CamelException *ex); - -static int store_resp_list(CamelIMAPPEngine *ie, guint32 id, void *data); - -/* yet to see if this should go global or not */ -void camel_imapp_store_folder_selected(CamelIMAPPStore *store, CamelIMAPPFolder *folder, CamelIMAPPSelectResponse *select); - -static void -camel_imapp_store_class_init (CamelIMAPPStoreClass *camel_imapp_store_class) -{ - CamelServiceClass *camel_service_class = CAMEL_SERVICE_CLASS(camel_imapp_store_class); - CamelStoreClass *camel_store_class = CAMEL_STORE_CLASS(camel_imapp_store_class); - - parent_class = CAMEL_STORE_CLASS(camel_type_get_global_classfuncs(camel_store_get_type())); - - /* virtual method overload */ - camel_service_class->construct = imap_construct; - /*camel_service_class->get_name = imap_get_name;*/ - camel_service_class->query_auth_types = imap_query_auth_types; - camel_service_class->connect = imap_connect; - camel_service_class->disconnect = imap_disconnect; - - camel_store_class->init_trash = imap_init_trash; - camel_store_class->get_trash = imap_get_trash; - - camel_store_class->get_folder = imap_get_folder; - camel_store_class->get_inbox = imap_get_inbox; - - camel_store_class->create_folder = imap_create_folder; - camel_store_class->rename_folder = imap_rename_folder; - camel_store_class->delete_folder = imap_delete_folder; - camel_store_class->get_folder_info = imap_get_folder_info; -} - -static void -camel_imapp_store_init (gpointer object, gpointer klass) -{ - CamelIMAPPStore *istore = object; -} - -CamelType -camel_imapp_store_get_type (void) -{ - static CamelType camel_imapp_store_type = CAMEL_INVALID_TYPE; - - if (!camel_imapp_store_type) { - camel_imapp_store_type = camel_type_register(CAMEL_STORE_TYPE, - "CamelIMAPPStore", - sizeof (CamelIMAPPStore), - sizeof (CamelIMAPPStoreClass), - (CamelObjectClassInitFunc) camel_imapp_store_class_init, - NULL, - (CamelObjectInitFunc) camel_imapp_store_init, - finalize); - } - - return camel_imapp_store_type; -} - -static void -finalize (CamelObject *object) -{ - CamelIMAPPStore *imap_store = CAMEL_IMAPP_STORE (object); - - /* force disconnect so we dont have it run later, after we've cleaned up some stuff */ - /* SIGH */ - - camel_service_disconnect((CamelService *)imap_store, TRUE, NULL); - - if (imap_store->driver) - camel_object_unref(imap_store->driver); - if (imap_store->cache) - camel_object_unref(imap_store->cache); -} - -static void imap_construct(CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, CamelException *ex) -{ - char *root, *summary; - CamelIMAPPStore *store = (CamelIMAPPStore *)service; - - CAMEL_SERVICE_CLASS (parent_class)->construct (service, session, provider, url, ex); - if (camel_exception_is_set(ex)) - return; - - CAMEL_TRY { - store->summary = camel_imapp_store_summary_new(); - root = camel_session_get_storage_path(service->session, service, ex); - if (root) { - summary = g_build_filename(root, ".ev-store-summary", NULL); - camel_store_summary_set_filename((CamelStoreSummary *)store->summary, summary); - /* FIXME: need to remove params, passwords, etc */ - camel_store_summary_set_uri_base((CamelStoreSummary *)store->summary, service->url); - camel_store_summary_load((CamelStoreSummary *)store->summary); - } - } CAMEL_CATCH(e) { - camel_exception_xfer(ex, e); - } CAMEL_DONE; -} - -enum { - USE_SSL_NEVER, - USE_SSL_ALWAYS, - USE_SSL_WHEN_POSSIBLE -}; - -#define SSL_PORT_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3) -#define STARTTLS_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_TLS) - -static void -connect_to_server (CamelService *service, int ssl_mode, int try_starttls) -/* throws IO exception */ -{ - CamelIMAPPStore *store = CAMEL_IMAPP_STORE (service); - CamelStream * volatile tcp_stream = NULL; - CamelIMAPPStream * volatile imap_stream = NULL; - struct hostent *h = NULL; - int ret, port; - CamelException *ex; - - ex = camel_exception_new(); - CAMEL_TRY { - /* parent class connect initialization */ - CAMEL_SERVICE_CLASS (parent_class)->connect (service, ex); - if (ex->id) - camel_exception_throw_ex(ex); - - h = camel_service_gethost(service, ex); - if (ex->id) - camel_exception_throw_ex(ex); - - port = service->url->port ? service->url->port : IMAP_PORT; - -#ifdef HAVE_SSL - if (camel_url_get_param (service->url, "use_ssl")) { - if (try_starttls) - tcp_stream = camel_tcp_stream_ssl_new_raw (service->session, service->url->host, STARTTLS_FLAGS); - else { - port = service->url->port ? service->url->port : 995; - tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, SSL_PORT_FLAGS); - } - } 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_throw(CAMEL_EXCEPTION_USER_CANCEL, _("Connection cancelled")); - else - camel_exception_throw(CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Could not connect to %s (port %d): %s"), - service->url->host, port, strerror(errno)); - } - - imap_stream = (CamelIMAPPStream *)camel_imapp_stream_new(tcp_stream); - store->driver = camel_imapp_driver_new(imap_stream); - - camel_object_unref(imap_stream); - camel_object_unref(tcp_stream); - } CAMEL_CATCH(e) { - if (tcp_stream) - camel_object_unref(tcp_stream); - if (imap_stream) - camel_object_unref((CamelObject *)imap_stream); - camel_exception_throw_ex(e); - } CAMEL_DONE; - - camel_exception_free(ex); -} - -#if 0 - -/* leave this stuff out for now */ - - -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 -} -#endif - -extern CamelServiceAuthType camel_imapp_password_authtype; -extern CamelServiceAuthType camel_imapp_apop_authtype; - -static GList * -imap_query_auth_types (CamelService *service, CamelException *ex) -{ - /*CamelIMAPPStore *store = CAMEL_IMAPP_STORE (service);*/ - GList *types = NULL; - - types = CAMEL_SERVICE_CLASS (parent_class)->query_auth_types (service, ex); - if (types == NULL) - return NULL; - -#if 0 - if (connect_to_server_wrapper (service, NULL)) { - types = g_list_concat(types, g_list_copy(store->engine->auth)); - imap_disconnect (service, TRUE, NULL); - } else { - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Could not connect to POP server on %s"), - service->url->host); - } -#endif - return types; -} - -static void -store_get_pass(CamelIMAPPStore *store) -{ - if (((CamelService *)store)->url->passwd == NULL) { - char *prompt; - CamelException ex; - - camel_exception_init(&ex); - - prompt = g_strdup_printf (_("%sPlease enter the IMAP password for %s@%s"), - store->login_error?store->login_error:"", - ((CamelService *)store)->url->user, - ((CamelService *)store)->url->host); - ((CamelService *)store)->url->passwd = camel_session_get_password(camel_service_get_session((CamelService *)store), - prompt, FALSE, TRUE, (CamelService*)store, "password", &ex); - g_free (prompt); - if (camel_exception_is_set(&ex)) - camel_exception_throw_ex(&ex); - } -} - -static struct _CamelSasl * -store_get_sasl(struct _CamelIMAPPDriver *driver, CamelIMAPPStore *store) -{ - store_get_pass(store); - - if (((CamelService *)store)->url->authmech) - return camel_sasl_new("imap", ((CamelService *)store)->url->authmech, (CamelService *)store); - - return NULL; -} - -static void -store_get_login(struct _CamelIMAPPDriver *driver, char **login, char **pass, CamelIMAPPStore *store) -{ - store_get_pass(store); - - *login = g_strdup(((CamelService *)store)->url->user); - *pass = g_strdup(((CamelService *)store)->url->passwd); -} - -static gboolean -imap_connect (CamelService *service, CamelException *ex) -{ - CamelIMAPPStore *store = (CamelIMAPPStore *)service; - volatile int ret = FALSE; - - CAMEL_TRY { - volatile int retry = TRUE; - - if (store->cache == NULL) { - char *root; - - root = camel_session_get_storage_path(service->session, service, ex); - if (root) { - store->cache = camel_data_cache_new(root, 0, ex); - g_free(root); - if (store->cache) { - /* Default cache expiry - 1 week or not visited in a day */ - camel_data_cache_set_expire_age(store->cache, 60*60*24*7); - camel_data_cache_set_expire_access(store->cache, 60*60*24); - } - } - if (camel_exception_is_set(ex)) - camel_exception_throw_ex(ex); - } - - connect_to_server(service, USE_SSL_NEVER, FALSE); - - camel_imapp_driver_set_sasl_factory(store->driver, (CamelIMAPPSASLFunc)store_get_sasl, store); - camel_imapp_driver_set_login_query(store->driver, (CamelIMAPPLoginFunc)store_get_login, store); - store->login_error = NULL; - - do { - CAMEL_TRY { - if (store->driver->engine->state != IMAP_ENGINE_AUTH) - camel_imapp_driver_login(store->driver); - ret = TRUE; - retry = FALSE; - } CAMEL_CATCH(e) { - g_free(store->login_error); - store->login_error = NULL; - switch (e->id) { - case CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE: - store->login_error = g_strdup_printf("%s\n\n", e->desc); - camel_session_forget_password(service->session, service, "password", ex); - camel_url_set_passwd(service->url, NULL); - break; - default: - camel_exception_throw_ex(e); - break; - } - } CAMEL_DONE; - } while (retry); - } CAMEL_CATCH(e) { - camel_exception_xfer(ex, e); - camel_service_disconnect(service, TRUE, NULL); - ret = FALSE; - } CAMEL_DONE; - - g_free(store->login_error); - store->login_error = NULL; - - return ret; -} - -static gboolean -imap_disconnect (CamelService *service, gboolean clean, CamelException *ex) -{ - CamelIMAPPStore *store = CAMEL_IMAPP_STORE (service); - - /* FIXME: logout */ - - if (!CAMEL_SERVICE_CLASS (parent_class)->disconnect (service, clean, ex)) - return FALSE; - - /* logout/disconnect */ - if (store->driver) { - camel_object_unref(store->driver); - store->driver = NULL; - } - - return TRUE; -} - -static void -imap_init_trash (CamelStore *store) -{ - /* no-op */ - ; -} - -static CamelFolder * -imap_get_trash (CamelStore *store, CamelException *ex) -{ - /* no-op */ - return NULL; -} - -static CamelFolder * -imap_get_folder (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex) -{ - CamelIMAPPStore *istore = (CamelIMAPPStore *)store; - CamelIMAPPFolder * volatile folder = NULL; - - /* ??? */ - - /* 1. create the folder */ - /* 2. run select? */ - /* 3. update the folder */ - - CAMEL_TRY { - folder = (CamelIMAPPFolder *)camel_imapp_folder_new(store, folder_name); - camel_imapp_driver_select(istore->driver, folder); - } CAMEL_CATCH (e) { - if (folder) { - camel_object_unref(folder); - folder = NULL; - } - camel_exception_xfer(ex, e); - } CAMEL_DONE; - - return (CamelFolder *)folder; -} - -static CamelFolder * -imap_get_inbox(CamelStore *store, CamelException *ex) -{ - camel_exception_setv(ex, 1, "get_inbox::unimplemented"); - - return NULL; -} - -/* 8 bit, string compare */ -static int folders_build_cmp(const void *app, const void *bpp) -{ - struct _list_info *a = *((struct _list_info **)app); - struct _list_info *b = *((struct _list_info **)bpp); - unsigned char *ap = (unsigned char *)(a->name); - unsigned char *bp = (unsigned char *)(b->name); - - printf("qsort, cmp '%s' <> '%s'\n", ap, bp); - - while (*ap && *ap == *bp) { - ap++; - bp++; - } - - if (*ap < *bp) - return -1; - else if (*ap > *bp) - return 1; - return 0; -} - -/* FIXME: this should go via storesummary? */ -static CamelFolderInfo * -folders_build_info(CamelURL *base, struct _list_info *li) -{ - char *path, *full_name, *name; - CamelFolderInfo *fi; - - full_name = imapp_list_get_path(li); - name = strrchr(full_name, '/'); - if (name) - name++; - else - name = full_name; - - path = alloca(strlen(full_name)+2); - sprintf(path, "/%s", full_name); - camel_url_set_path(base, path); - - fi = g_malloc0(sizeof(*fi)); - fi->url = camel_url_to_string(base, CAMEL_URL_HIDE_ALL); - fi->name = g_strdup(name); - fi->full_name = full_name; - fi->path = g_strdup(path); - fi->unread_message_count = -1; - fi->flags = li->flags; - - /* TODO: could look up count here ... */ - /* ?? */ - /*folder = camel_object_bag_get(store->folders, "INBOX");*/ - - return fi; -} - -/* - a - a/b - a/b/c - a/d - b - c/d - -*/ - -/* note, pname is the raw name, not the folderinfo name */ -/* note also this free's as we go, since we never go 'backwards' */ -static CamelFolderInfo * -folders_build_rec(CamelURL *base, GPtrArray *folders, int *ip, CamelFolderInfo *pfi, char *pname) -{ - int plen = 0; - CamelFolderInfo *last = NULL, *first = NULL; - - if (pfi) - plen = strlen(pname); - - for(;(*ip)<(int)folders->len;) { - CamelFolderInfo *fi; - struct _list_info *li; - - li = folders->pdata[*ip]; - printf("checking '%s' is child of '%s'\n", li->name, pname); - - /* is this a child of the parent? */ - if (pfi != NULL - && (strncmp(pname, li->name, strlen(pname)) != 0 - || li->name[plen] != li->separator)) { - printf(" nope\n"); - break; - } - printf(" yep\n"); - - /* is this not an immediate child of the parent? */ -#if 0 - char *p; - if (pfi != NULL - && li->separator != 0 - && (p = strchr(li->name + plen + 1, li->separator)) != NULL) { - if (last == NULL) { - struct _list_info tli; - - tli.flags = CAMEL_FOLDER_NOSELECT|CAMEL_FOLDER_CHILDREN; - tli.separator = li->separator; - tli.name = g_strndup(li->name, p-li->name+1); - fi = folders_build_info(base, &tli); - fi->parent = pfi; - if (pfi && pfi->child == NULL) - pfi->child = fi; - i = folders_build_rec(folders, i, fi, tli.name); - break; - } - } -#endif - - fi = folders_build_info(base, li); - fi->parent = pfi; - if (last != NULL) - last->sibling = fi; - last = fi; - if (first == NULL) - first = fi; - - (*ip)++; - fi->child = folders_build_rec(base, folders, ip, fi, li->name); - imap_free_list(li); - } - - return first; -} - -static void -folder_info_dump(CamelFolderInfo *fi, int depth) -{ - char *s; - - s = alloca(depth+1); - memset(s, ' ', depth); - s[depth] = 0; - while (fi) { - printf("%s%s (%s)\n", s, fi->name, fi->url); - if (fi->child) - folder_info_dump(fi->child, depth+2); - fi = fi->sibling; - } - -} - -static CamelFolderInfo * -imap_get_folder_info(CamelStore *store, const char *top, guint32 flags, CamelException *ex) -{ - CamelIMAPPStore *istore = (CamelIMAPPStore *)store; - CamelFolderInfo * fi= NULL; - char *name; - - /* FIXME: temporary, since this is not a disco store */ - if (istore->driver == NULL - && !camel_service_connect((CamelService *)store, ex)) - return NULL; - - name = (char *)top; - if (name == NULL || name[0] == 0) { - /* namespace? */ - name = ""; - } - - name = ""; - - CAMEL_TRY { - CamelURL *base; - int i; - GPtrArray *folders; - - /* FIXME: subscriptions? lsub? */ - folders = camel_imapp_driver_list(istore->driver, name, flags); - - /* this greatly simplifies the tree algorithm ... but it might - be faster just to use a hashtable to find parents? */ - qsort(folders->pdata, folders->len, sizeof(folders->pdata[0]), folders_build_cmp); - - i = 0; - base = camel_url_copy(((CamelService *)store)->url); - fi = folders_build_rec(base, folders, &i, NULL, NULL); - camel_url_free(base); - g_ptr_array_free(folders, TRUE); - } CAMEL_CATCH(e) { - camel_exception_xfer(ex, e); - } CAMEL_DONE; - - printf("built folder info:\n"); - folder_info_dump(fi, 2); - - return fi; - -#if 0 - if (top == NULL || !g_ascii_strcasecmp(top, "inbox")) { - CamelURL *uri = camel_url_copy(((CamelService *)store)->url); - - camel_url_set_path(uri, "/INBOX"); - fi = g_malloc0(sizeof(*fi)); - fi->url = camel_url_to_string(uri, CAMEL_URL_HIDE_ALL); - camel_url_free(uri); - fi->name = g_strdup("INBOX"); - fi->full_name = g_strdup("INBOX"); - fi->path = g_strdup("/INBOX"); - fi->unread_message_count = -1; - fi->flags = 0; - - folder = camel_object_bag_get(store->folders, "INBOX"); - if (folder) { - /*if (!cflags & FAST)*/ - camel_imapp_driver_update(istore->driver, (CamelIMAPPFolder *)folder); - fi->unread_message_count = camel_folder_get_unread_message_count(folder); - camel_object_unref(folder); - } - } else { - camel_exception_setv(ex, 1, "not implemented"); - } -#endif - return fi; - -#if 0 - istore->pending_list = g_ptr_array_new(); - - CAMEL_TRY { - ic = camel_imapp_engine_command_new(istore->driver->engine, "LIST", NULL, "LIST \"\" %f", top); - camel_imapp_engine_command_queue(istore->driver->engine, ic); - while (camel_imapp_engine_iterate(istore->driver->engine, ic) > 0) - ; - - if (ic->status->result != IMAP_OK) - camel_exception_throw(1, "list failed: %s", ic->status->text); - } CAMEL_CATCH (e) { - camel_exception_xfer(ex, e); - } CAMEL_DONE; - - camel_imapp_engine_command_free(istore->driver->engine, ic); - - printf("got folder list:\n"); - for (i=0;i<(int)istore->pending_list->len;i++) { - struct _list_info *linfo = istore->pending_list->pdata[i]; - - printf("%s (%c)\n", linfo->name, linfo->separator); - imap_free_list(linfo); - } - istore->pending_list = NULL; - - return NULL; -#endif -} - -static void -imap_delete_folder(CamelStore *store, const char *folder_name, CamelException *ex) -{ - camel_exception_setv(ex, 1, "delete_folder::unimplemented"); -} - -static void -imap_rename_folder(CamelStore *store, const char *old, const char *new, CamelException *ex) -{ - camel_exception_setv(ex, 1, "rename_folder::unimplemented"); -} - -static CamelFolderInfo * -imap_create_folder(CamelStore *store, const char *parent_name, const char *folder_name, CamelException *ex) -{ - camel_exception_setv(ex, 1, "create_folder::unimplemented"); - return NULL; -} - -/* ********************************************************************** */ -#if 0 -static int store_resp_fetch(CamelIMAPPEngine *ie, guint32 id, void *data) -{ - struct _fetch_info *finfo; - CamelIMAPPStore *istore = data; - CamelMessageInfo *info; - struct _pending_fetch *pending; - - finfo = imap_parse_fetch(ie->stream); - if (istore->selected) { - if ((finfo->got & FETCH_UID) == 0) { - printf("didn't get uid in fetch response?\n"); - } else { - info = camel_folder_summary_index(((CamelFolder *)istore->selected)->summary, id-1); - /* exists, check/update */ - if (info) { - if (strcmp(finfo->uid, camel_message_info_uid(info)) != 0) { - printf("summary at index %d has uid %s expected %s\n", id, camel_message_info_uid(info), finfo->uid); - /* uid mismatch??? try do it based on uid instead? try to reorder? i dont know? */ - camel_folder_summary_info_free(((CamelFolder *)istore->selected)->summary, info); - info = camel_folder_summary_uid(((CamelFolder *)istore->selected)->summary, finfo->uid); - } - } - - if (info) { - if (finfo->got & (FETCH_FLAGS)) { - printf("updating flags for uid '%s'\n", finfo->uid); - info->flags = finfo->flags; - camel_folder_change_info_change_uid(istore->selected->changes, finfo->uid); - } - if (finfo->got & FETCH_MINFO) { - printf("got envelope unexpectedly?\n"); - } - /* other things go here, like body fetches */ - } else { - pending = g_hash_table_lookup(istore->pending_fetch_table, finfo->uid); - - /* we need to create a new info, we only care about flags and minfo */ - - if (pending) - info = pending->info; - else { - info = camel_folder_summary_info_new(((CamelFolder *)istore->selected)->summary); - camel_message_info_set_uid(info, g_strdup(finfo->uid)); - } - - if (finfo->got & FETCH_FLAGS) - info->flags = finfo->flags; - - if (finfo->got & FETCH_MINFO) { - /* if we only use ENVELOPE? */ - camel_message_info_set_subject(info, g_strdup(camel_message_info_subject(finfo->minfo))); - camel_message_info_set_from(info, g_strdup(camel_message_info_from(finfo->minfo))); - camel_message_info_set_to(info, g_strdup(camel_message_info_to(finfo->minfo))); - camel_message_info_set_cc(info, g_strdup(camel_message_info_cc(finfo->minfo))); - info->date_sent = finfo->minfo->date_sent; - camel_folder_summary_add(((CamelFolder *)istore->selected)->summary, info); - camel_folder_change_info_add_uid(istore->selected->changes, finfo->uid); - if (pending) { - e_dlist_remove((EDListNode *)pending); - g_hash_table_remove(istore->pending_fetch_table, finfo->uid); - /*e_memchunk_free(istore->pending_fetch_chunks, pending);*/ - } - } else if (finfo->got & FETCH_HEADER) { - /* if we only use HEADER? */ - CamelMimeParser *mp; - - if (pending == NULL) - camel_folder_summary_info_free(((CamelFolder *)istore->selected)->summary, info); - mp = camel_mime_parser_new(); - camel_mime_parser_init_with_stream(mp, finfo->header); - info = camel_folder_summary_info_new_from_parser(((CamelFolder *)istore->selected)->summary, mp); - camel_object_unref(mp); - camel_message_info_set_uid(info, g_strdup(finfo->uid)); - - camel_folder_summary_add(((CamelFolder *)istore->selected)->summary, info); - camel_folder_change_info_add_uid(istore->selected->changes, finfo->uid); - if (pending) { - /* FIXME: use a dlist */ - e_dlist_remove((EDListNode *)pending); - g_hash_table_remove(istore->pending_fetch_table, camel_message_info_uid(pending->info)); - camel_folder_summary_info_free(((CamelFolder *)istore->selected)->summary, pending->info); - /*e_memchunk_free(istore->pending_fetch_chunks, pending);*/ - } - } else if (finfo->got & FETCH_FLAGS) { - if (pending == NULL) { - pending = e_memchunk_alloc(istore->pending_fetch_chunks); - pending->info = info; - g_hash_table_insert(istore->pending_fetch_table, (char *)camel_message_info_uid(info), pending); - e_dlist_addtail(&istore->pending_fetch_list, (EDListNode *)pending); - } - } else { - if (pending == NULL) - camel_folder_summary_info_free(((CamelFolder *)istore->selected)->summary, info); - printf("got unexpected fetch response?\n"); - imap_dump_fetch(finfo); - } - } - } - } else { - printf("unexpected fetch response, no folder selected?\n"); - } - /*imap_dump_fetch(finfo);*/ - imap_free_fetch(finfo); - - return camel_imapp_engine_skip(ie); -} -#endif - -/* ********************************************************************** */ - -/* should be moved to imapp-utils? - stuff in imapp-utils should be moved to imapp-parse? */ - -/* ********************************************************************** */ - -#if 0 -void -camel_imapp_store_folder_selected(CamelIMAPPStore *store, CamelIMAPPFolder *folder, CamelIMAPPSelectResponse *select) -{ - CamelIMAPPCommand * volatile ic = NULL; - CamelIMAPPStore *istore = (CamelIMAPPStore *)store; - int i; - struct _uidset_state ss; - GPtrArray *fetch; - CamelMessageInfo *info; - struct _pending_fetch *fw, *fn; - - printf("imap folder selected\n"); - - if (select->uidvalidity == folder->uidvalidity - && select->exists == folder->exists - && select->recent == folder->recent - && select->unseen == folder->unseen) { - /* no work to do? */ - return; - } - - istore->pending_fetch_table = g_hash_table_new(g_str_hash, g_str_equal); - istore->pending_fetch_chunks = e_memchunk_new(256, sizeof(struct _pending_fetch)); - - /* perform an update - flags first (and see what we have) */ - CAMEL_TRY { - ic = camel_imapp_engine_command_new(istore->engine, "FETCH", NULL, "FETCH 1:%d (UID FLAGS)", select->exists); - camel_imapp_engine_command_queue(istore->engine, ic); - while (camel_imapp_engine_iterate(istore->engine, ic) > 0) - ; - - if (ic->status->result != IMAP_OK) - camel_exception_throw(1, "fetch failed: %s", ic->status->text); - - /* pending_fetch_list now contains any new messages */ - /* FIXME: how do we work out no-longer present messages? */ - printf("now fetching info for messages?\n"); - uidset_init(&ss, store->engine); - ic = camel_imapp_engine_command_new(istore->engine, "FETCH", NULL, "UID FETCH "); - fw = (struct _pending_fetch *)istore->pending_fetch_list.head; - fn = fw->next; - while (fn) { - info = fw->info; - /* if the uid set fills, then flush the command out */ - if (uidset_add(&ss, ic, camel_message_info_uid(info)) - || (fn->next == NULL && uidset_done(&ss, ic))) { - camel_imapp_engine_command_add(istore->engine, ic, " (FLAGS RFC822.HEADER)"); - camel_imapp_engine_command_queue(istore->engine, ic); - while (camel_imapp_engine_iterate(istore->engine, ic) > 0) - ; - if (ic->status->result != IMAP_OK) - camel_exception_throw(1, "fetch failed: %s", ic->status->text); - /* if not end ... */ - camel_imapp_engine_command_free(istore->engine, ic); - ic = camel_imapp_engine_command_new(istore->engine, "FETCH", NULL, "UID FETCH "); - } - fw = fn; - fn = fn->next; - } - - printf("The pending list should now be empty: %s\n", e_dlist_empty(&istore->pending_fetch_list)?"TRUE":"FALSE"); - for (i=0;i<10;i++) { - info = camel_folder_summary_index(((CamelFolder *)istore->selected)->summary, i); - if (info) { - printf("message info [%d] =\n", i); - camel_message_info_dump(info); - camel_folder_summary_info_free(((CamelFolder *)istore->selected)->summary, info); - } - } - } CAMEL_CATCH (e) { - /* FIXME: cleanup */ - camel_exception_throw_ex(e); - } CAMEL_DONE; - - g_hash_table_destroy(istore->pending_fetch_table); - istore->pending_fetch_table = NULL; - e_memchunk_destroy(istore->pending_fetch_chunks); - - camel_imapp_engine_command_free(istore->engine, ic); -} -#endif - -#if 0 -/*char *uids[] = {"1", "2", "4", "5", "6", "7", "9", "11", "12", 0};*/ -/*char *uids[] = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", 0};*/ -char *uids[] = {"1", "3", "5", "7", "9", "11", "12", "13", "14", "15", "20", "21", "24", "25", "26", 0}; - -void -uidset_test(CamelIMAPPEngine *ie) -{ - struct _uidset_state ss; - CamelIMAPPCommand *ic; - int i; - - /*ic = camel_imapp_engine_command_new(ie, 0, "FETCH", NULL, "FETCH ");*/ - uidset_init(&ss, 0, 0); - for (i=0;uids[i];i++) { - if (uidset_add(&ss, uids[i])) { - printf("\n[%d] flushing uids\n", i); - } - } - - if (uidset_done(&ss)) { - printf("\nflushing uids\n"); - } -} -#endif diff --git a/camel/providers/imapp/camel-imapp-store.h b/camel/providers/imapp/camel-imapp-store.h deleted file mode 100644 index 97b7afd1d1..0000000000 --- a/camel/providers/imapp/camel-imapp-store.h +++ /dev/null @@ -1,77 +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: Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 2002 Ximian, Inc. (www.ximian.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - */ - - -#ifndef CAMEL_IMAPP_STORE_H -#define CAMEL_IMAPP_STORE_H 1 - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus }*/ - -#include <camel/camel-types.h> -#include <camel/camel-store.h> -#include "camel-imapp-driver.h" -#include "e-util/e-memory.h" - -#define CAMEL_IMAPP_STORE_TYPE (camel_imapp_store_get_type ()) -#define CAMEL_IMAPP_STORE(obj) (CAMEL_CHECK_CAST((obj), CAMEL_IMAPP_STORE_TYPE, CamelIMAPPStore)) -#define CAMEL_IMAPP_STORE_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_IMAPP_STORE_TYPE, CamelIMAPPStoreClass)) -#define CAMEL_IS_IMAP_STORE(o) (CAMEL_CHECK_TYPE((o), CAMEL_IMAPP_STORE_TYPE)) - -struct _pending_fetch { - struct _pending_fetch *next; - struct _pending_fetch *prev; - - CamelMessageInfo *info; -}; - -typedef struct { - CamelStore parent_object; - - struct _CamelIMAPPStoreSummary *summary; /* in-memory list of folders */ - struct _CamelIMAPPDriver *driver; /* IMAP processing engine */ - struct _CamelDataCache *cache; - - /* if we had a login error, what to show to user */ - char *login_error; - - GPtrArray *pending_list; -} CamelIMAPPStore; - -typedef struct { - CamelStoreClass parent_class; - -} CamelIMAPPStoreClass; - -/* Standard Camel function */ -CamelType camel_imapp_store_get_type (void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CAMEL_IMAPP_STORE_H */ - - diff --git a/camel/providers/imapp/camel-imapp-stream.c b/camel/providers/imapp/camel-imapp-stream.c deleted file mode 100644 index 20876beae2..0000000000 --- a/camel/providers/imapp/camel-imapp-stream.c +++ /dev/null @@ -1,761 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*- - * - * Author: - * 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 - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <string.h> -#include <stdio.h> -#include <ctype.h> -#include <errno.h> - -#include <glib.h> - -#include <camel/camel-stream-mem.h> - -#include "camel-imapp-stream.h" -#include "camel-imapp-exception.h" - -#define t(x) -#define io(x) x - -static void setup_table(void); - -static CamelObjectClass *parent_class = NULL; - -/* Returns the class for a CamelStream */ -#define CS_CLASS(so) CAMEL_IMAPP_STREAM_CLASS(CAMEL_OBJECT_GET_CLASS(so)) - -#define CAMEL_IMAPP_STREAM_SIZE (4096) -#define CAMEL_IMAPP_STREAM_TOKEN (4096) /* maximum token size */ - -static int -stream_fill(CamelIMAPPStream *is) -{ - int left = 0; - - if (is->source) { - left = is->end - is->ptr; - memcpy(is->buf, is->ptr, left); - is->end = is->buf + left; - is->ptr = is->buf; - left = camel_stream_read(is->source, is->end, CAMEL_IMAPP_STREAM_SIZE - (is->end - is->buf)); - if (left > 0) { - is->end += left; - io(printf("camel_imapp_read: buffer is '%.*s'\n", is->end - is->ptr, is->ptr)); - return is->end - is->ptr; - } else { - io(printf("camel_imapp_read: -1\n")); - return -1; - } - } - - printf("camel_imapp_read: -1\n"); - - return -1; -} - -static ssize_t -stream_read(CamelStream *stream, char *buffer, size_t n) -{ - CamelIMAPPStream *is = (CamelIMAPPStream *)stream; - ssize_t max; - - if (is->literal == 0 || n == 0) - return 0; - - max = is->end - is->ptr; - if (max > 0) { - max = MIN(max, is->literal); - max = MIN(max, n); - memcpy(buffer, is->ptr, max); - is->ptr += max; - } else { - max = MIN(is->literal, n); - max = camel_stream_read(is->source, buffer, max); - if (max <= 0) - return max; - } - - is->literal -= max; - - return max; -} - -static ssize_t -stream_write(CamelStream *stream, const char *buffer, size_t n) -{ - CamelIMAPPStream *is = (CamelIMAPPStream *)stream; - - return camel_stream_write(is->source, buffer, n); -} - -static int -stream_close(CamelStream *stream) -{ - /* nop? */ - return 0; -} - -static int -stream_flush(CamelStream *stream) -{ - /* nop? */ - return 0; -} - -static gboolean -stream_eos(CamelStream *stream) -{ - CamelIMAPPStream *is = (CamelIMAPPStream *)stream; - - return is->literal == 0; -} - -static int -stream_reset(CamelStream *stream) -{ - /* nop? reset literal mode? */ - return 0; -} - -static void -camel_imapp_stream_class_init (CamelStreamClass *camel_imapp_stream_class) -{ - CamelStreamClass *camel_stream_class = (CamelStreamClass *)camel_imapp_stream_class; - - parent_class = camel_type_get_global_classfuncs( CAMEL_OBJECT_TYPE ); - - /* virtual method definition */ - camel_stream_class->read = stream_read; - camel_stream_class->write = stream_write; - camel_stream_class->close = stream_close; - camel_stream_class->flush = stream_flush; - camel_stream_class->eos = stream_eos; - camel_stream_class->reset = stream_reset; -} - -static void -camel_imapp_stream_init(CamelIMAPPStream *is, CamelIMAPPStreamClass *isclass) -{ - /* +1 is room for appending a 0 if we need to for a token */ - is->ptr = is->end = is->buf = g_malloc(CAMEL_IMAPP_STREAM_SIZE+1); - is->tokenptr = is->tokenbuf = g_malloc(CAMEL_IMAPP_STREAM_SIZE+1); - is->tokenend = is->tokenbuf + CAMEL_IMAPP_STREAM_SIZE; -} - -static void -camel_imapp_stream_finalise(CamelIMAPPStream *is) -{ - g_free(is->buf); - if (is->source) - camel_object_unref((CamelObject *)is->source); -} - -CamelType -camel_imapp_stream_get_type (void) -{ - static CamelType camel_imapp_stream_type = CAMEL_INVALID_TYPE; - - if (camel_imapp_stream_type == CAMEL_INVALID_TYPE) { - setup_table(); - camel_imapp_stream_type = camel_type_register( camel_stream_get_type(), - "CamelIMAPPStream", - sizeof( CamelIMAPPStream ), - sizeof( CamelIMAPPStreamClass ), - (CamelObjectClassInitFunc) camel_imapp_stream_class_init, - NULL, - (CamelObjectInitFunc) camel_imapp_stream_init, - (CamelObjectFinalizeFunc) camel_imapp_stream_finalise ); - } - - return camel_imapp_stream_type; -} - -/** - * camel_imapp_stream_new: - * - * Returns a NULL stream. A null stream is always at eof, and - * always returns success for all reads and writes. - * - * Return value: the stream - **/ -CamelStream * -camel_imapp_stream_new(CamelStream *source) -{ - CamelIMAPPStream *is; - - is = (CamelIMAPPStream *)camel_object_new(camel_imapp_stream_get_type ()); - camel_object_ref((CamelObject *)source); - is->source = source; - - return (CamelStream *)is; -} - - -/* - 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_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(c) ((imap_specials[(c)&0xff] & 0x01) != 0) -#define imap_is_simple(c) ((imap_specials[(c)&0xff] & 0x02) != 0) -#define imap_not_id(c) ((imap_specials[(c)&0xff] & 0x04) != 0) - -/* could be pregenerated, but this is cheap */ -static struct { - unsigned char *chars; - unsigned char mask; -} is_masks[] = { - { "\n*()[]+", 2 }, - { " \r\n()[]+", 4 }, -}; - -static void setup_table(void) -{ - int i; - unsigned char *p, c; - - for (i=0;i<(int)(sizeof(is_masks)/sizeof(is_masks[0]));i++) { - p = is_masks[i].chars; - while ((c = *p++)) - imap_specials[c] |= is_masks[i].mask; - } -} - -#if 0 - -static int -skip_ws(CamelIMAPPStream *is, unsigned char *pp, unsigned char *pe) -{ - register unsigned char c, *p; - unsigned char *e; - - p = is->ptr; - e = is->end; - - do { - while (p >= e ) { - is->ptr = p; - if (stream_fill(is) == IMAP_TOK_ERROR) - return IMAP_TOK_ERROR; - p = is->ptr; - e = is->end; - } - c = *p++; - } while (c == ' ' || c == '\r'); - - is->ptr = p; - is->end = e; - - return c; -} -#endif - -/* FIXME: these should probably handle it themselves, - and get rid of the token interface? */ -int -camel_imapp_stream_atom(CamelIMAPPStream *is, unsigned char **data, unsigned int *lenp) -{ - unsigned char *p, c; - - /* this is only 'approximate' atom */ - switch(camel_imapp_stream_token(is, data, lenp)) { - case IMAP_TOK_TOKEN: - p = *data; - while ((c = *p)) - *p++ = toupper(c); - case IMAP_TOK_INT: - return 0; - case IMAP_TOK_ERROR: - return IMAP_TOK_ERROR; - default: - camel_exception_throw(1, "expecting atom"); - printf("expecting atom!\n"); - return IMAP_TOK_PROTOCOL; - } -} - -/* gets an atom, a quoted_string, or a literal */ -int -camel_imapp_stream_astring(CamelIMAPPStream *is, unsigned char **data) -{ - unsigned char *p, *start; - unsigned int len, inlen; - - switch(camel_imapp_stream_token(is, data, &len)) { - case IMAP_TOK_TOKEN: - case IMAP_TOK_INT: - case IMAP_TOK_STRING: - return 0; - case IMAP_TOK_LITERAL: - /* FIXME: just grow buffer */ - if (len >= CAMEL_IMAPP_STREAM_TOKEN) { - camel_exception_throw(1, "astring: literal too long"); - printf("astring too long\n"); - return IMAP_TOK_PROTOCOL; - } - p = is->tokenptr; - camel_imapp_stream_set_literal(is, len); - do { - len = camel_imapp_stream_getl(is, &start, &inlen); - if (len < 0) - return len; - memcpy(p, start, inlen); - p += inlen; - } while (len > 0); - *data = is->tokenptr; - return 0; - case IMAP_TOK_ERROR: - /* wont get unless no exception hanlder*/ - return IMAP_TOK_ERROR; - default: - camel_exception_throw(1, "expecting astring"); - printf("expecting astring!\n"); - return IMAP_TOK_PROTOCOL; - } -} - -/* check for NIL or (small) quoted_string or literal */ -int -camel_imapp_stream_nstring(CamelIMAPPStream *is, unsigned char **data) -{ - unsigned char *p, *start; - unsigned int len, inlen; - - switch(camel_imapp_stream_token(is, data, &len)) { - case IMAP_TOK_STRING: - return 0; - case IMAP_TOK_LITERAL: - /* FIXME: just grow buffer */ - if (len >= CAMEL_IMAPP_STREAM_TOKEN) { - camel_exception_throw(1, "nstring: literal too long"); - return IMAP_TOK_PROTOCOL; - } - p = is->tokenptr; - camel_imapp_stream_set_literal(is, len); - do { - len = camel_imapp_stream_getl(is, &start, &inlen); - if (len < 0) - return len; - memcpy(p, start, inlen); - p += inlen; - } while (len > 0); - *data = is->tokenptr; - return 0; - case IMAP_TOK_TOKEN: - p = *data; - if (toupper(p[0]) == 'N' && toupper(p[1]) == 'I' && toupper(p[2]) == 'L' && p[3] == 0) { - *data = NULL; - return 0; - } - default: - camel_exception_throw(1, "expecting nstring"); - return IMAP_TOK_PROTOCOL; - case IMAP_TOK_ERROR: - /* we'll never get this unless there are no exception handlers anyway */ - return IMAP_TOK_ERROR; - - } -} - -/* parse an nstring as a stream */ -int -camel_imapp_stream_nstring_stream(CamelIMAPPStream *is, CamelStream **stream) -/* throws IO,PARSE exception */ -{ - unsigned char *token; - unsigned int len; - int ret = 0; - CamelStream * volatile mem = NULL; - - *stream = NULL; - - CAMEL_TRY { - switch(camel_imapp_stream_token(is, &token, &len)) { - case IMAP_TOK_STRING: - mem = camel_stream_mem_new_with_buffer(token, len); - *stream = mem; - break; - case IMAP_TOK_LITERAL: - /* if len is big, we could automatically use a file backing */ - camel_imapp_stream_set_literal(is, len); - mem = camel_stream_mem_new(); - if (camel_stream_write_to_stream((CamelStream *)is, mem) == -1) - camel_exception_throw(1, "nstring: io error: %s", strerror(errno)); - camel_stream_reset(mem); - *stream = mem; - break; - case IMAP_TOK_TOKEN: - if (toupper(token[0]) == 'N' && toupper(token[1]) == 'I' && toupper(token[2]) == 'L' && token[3] == 0) { - *stream = NULL; - break; - } - default: - ret = -1; - camel_exception_throw(1, "nstring: token not string"); - } - } CAMEL_CATCH(ex) { - if (mem) - camel_object_unref((CamelObject *)mem); - camel_exception_throw_ex(ex); - } CAMEL_DONE; - - /* never reaches here anyway */ - return ret; -} - -guint32 -camel_imapp_stream_number(CamelIMAPPStream *is) -{ - unsigned char *token; - unsigned int len; - - if (camel_imapp_stream_token(is, &token, &len) != IMAP_TOK_INT) { - camel_exception_throw(1, "expecting number"); - return 0; - } - - return strtoul(token, 0, 10); -} - -int -camel_imapp_stream_text(CamelIMAPPStream *is, unsigned char **text) -{ - GByteArray *build = g_byte_array_new(); - unsigned char *token; - unsigned int len; - int tok; - - CAMEL_TRY { - while (is->unget > 0) { - switch (is->unget_tok) { - case IMAP_TOK_TOKEN: - case IMAP_TOK_STRING: - case IMAP_TOK_INT: - g_byte_array_append(build, is->unget_token, is->unget_len); - g_byte_array_append(build, " ", 1); - default: /* invalid, but we'll ignore */ - break; - } - is->unget--; - } - - do { - tok = camel_imapp_stream_gets(is, &token, &len); - if (tok < 0) - camel_exception_throw(1, "io error: %s", strerror(errno)); - if (len) - g_byte_array_append(build, token, len); - } while (tok > 0); - } CAMEL_CATCH(ex) { - *text = NULL; - g_byte_array_free(build, TRUE); - camel_exception_throw_ex(ex); - } CAMEL_DONE; - - g_byte_array_append(build, "", 1); - *text = build->data; - g_byte_array_free(build, FALSE); - - return 0; -} - -/* Get one token from the imap stream */ -camel_imapp_token_t -/* throws IO,PARSE exception */ -camel_imapp_stream_token(CamelIMAPPStream *is, unsigned char **data, unsigned int *len) -{ - register unsigned char c, *p, *o, *oe; - unsigned char *e; - unsigned int literal; - int digits; - - if (is->unget > 0) { - is->unget--; - *data = is->unget_token; - *len = is->unget_len; - /*printf("token UNGET '%c' %s\n", is->unget_tok, is->unget_token);*/ - return is->unget_tok; - } - - if (is->literal > 0) - g_warning("stream_token called with literal %d", is->literal); - - p = is->ptr; - e = is->end; - - /* skip whitespace/prefill buffer */ - do { - while (p >= e ) { - is->ptr = p; - if (stream_fill(is) == IMAP_TOK_ERROR) - goto io_error; - p = is->ptr; - e = is->end; - } - c = *p++; - } while (c == ' ' || c == '\r'); - - /*strchr("\n*()[]+", c)*/ - if (imap_is_simple(c)) { - is->ptr = p; - t(printf("token '%c'\n", c)); - return c; - } else if (c == '{') { - literal = 0; - *data = p; - while (1) { - while (p < e) { - c = *p++; - if (isdigit(c) && literal < (UINT_MAX/10)) { - literal = literal * 10 + (c - '0'); - } else if (c == '}') { - while (1) { - while (p < e) { - c = *p++; - if (c == '\n') { - *len = literal; - is->ptr = p; - is->literal = literal; - t(printf("token LITERAL %d\n", literal)); - return IMAP_TOK_LITERAL; - } - } - is->ptr = p; - if (stream_fill(is) == IMAP_TOK_ERROR) - goto io_error; - p = is->ptr; - e = is->end; - } - } else { - if (isdigit(c)) - printf("Protocol error: literal too big\n"); - else - printf("Protocol error: literal contains invalid char %02x '%c'\n", c, isprint(c)?c:c); - goto protocol_error; - } - } - is->ptr = p; - if (stream_fill(is) == IMAP_TOK_ERROR) - goto io_error; - p = is->ptr; - e = is->end; - } - } else if (c == '"') { - o = is->tokenptr; - oe = is->tokenptr + CAMEL_IMAPP_STREAM_TOKEN - 1; - while (1) { - while (p < e) { - c = *p++; - if (c == '\\') { - while (p >= e) { - is->ptr = p; - if (stream_fill(is) == IMAP_TOK_ERROR) - goto io_error; - p = is->ptr; - e = is->end; - } - c = *p++; - } else if (c == '\"') { - is->ptr = p; - *o = 0; - *data = is->tokenbuf; - *len = o - is->tokenbuf; - t(printf("token STRING '%s'\n", is->tokenbuf)); - return IMAP_TOK_STRING; - } - - if (c == '\n' || c == '\r' || o>=oe) { - if (o >= oe) - printf("Protocol error: string too long\n"); - else - printf("Protocol error: truncated string\n"); - goto protocol_error; - } else { - *o++ = c; - } - } - is->ptr = p; - if (stream_fill(is) == IMAP_TOK_ERROR) - goto io_error; - p = is->ptr; - e = is->end; - } - } else { - o = is->tokenptr; - oe = is->tokenptr + CAMEL_IMAPP_STREAM_TOKEN - 1; - digits = isdigit(c); - *o++ = c; - while (1) { - while (p < e) { - c = *p++; - /*if (strchr(" \r\n*()[]+", c) != NULL) {*/ - if (imap_not_id(c)) { - if (c == ' ' || c == '\r') - is->ptr = p; - else - is->ptr = p-1; - *o = 0; - *data = is->tokenbuf; - *len = o - is->tokenbuf; - t(printf("token TOKEN '%s'\n", is->tokenbuf)); - return digits?IMAP_TOK_INT:IMAP_TOK_TOKEN; - } else if (o < oe) { - digits &= isdigit(c); - *o++ = c; - } else { - printf("Protocol error: token too long\n"); - goto protocol_error; - } - } - is->ptr = p; - if (stream_fill(is) == IMAP_TOK_ERROR) - goto io_error; - p = is->ptr; - e = is->end; - } - } - - /* Had an i/o erorr */ -io_error: - printf("Got io error\n"); - camel_exception_throw(1, "io error"); - return IMAP_TOK_ERROR; - - /* Protocol error, skip until next lf? */ -protocol_error: - printf("Got protocol error\n"); - - if (c == '\n') - is->ptr = p-1; - else - is->ptr = p; - - camel_exception_throw(1, "protocol error"); - return IMAP_TOK_PROTOCOL; -} - -void -camel_imapp_stream_ungettoken(CamelIMAPPStream *is, camel_imapp_token_t tok, unsigned char *token, unsigned int len) -{ - /*printf("ungettoken: '%c' '%s'\n", tok, token);*/ - is->unget_tok = tok; - is->unget_token = token; - is->unget_len = len; - is->unget++; -} - -/* returns -1 on error, 0 if last lot of data, >0 if more remaining */ -int camel_imapp_stream_gets(CamelIMAPPStream *is, unsigned char **start, unsigned int *len) -{ - int max; - unsigned char *end; - - *len = 0; - - max = is->end - is->ptr; - if (max == 0) { - max = stream_fill(is); - if (max <= 0) - return max; - } - - *start = is->ptr; - end = memchr(is->ptr, '\n', max); - if (end) - max = (end - is->ptr) + 1; - *start = is->ptr; - *len = max; - is->ptr += max; - - return end == NULL?1:0; -} - -void camel_imapp_stream_set_literal(CamelIMAPPStream *is, unsigned int literal) -{ - is->literal = literal; -} - -/* returns -1 on erorr, 0 if last data, >0 if more data left */ -int camel_imapp_stream_getl(CamelIMAPPStream *is, unsigned char **start, unsigned int *len) -{ - int max; - - *len = 0; - - if (is->literal > 0) { - max = is->end - is->ptr; - if (max == 0) { - max = stream_fill(is); - if (max <= 0) - return max; - } - - max = MIN(max, is->literal); - *start = is->ptr; - *len = max; - is->ptr += max; - is->literal -= max; - } - - if (is->literal > 0) - return 1; - - return 0; -} diff --git a/camel/providers/imapp/camel-imapp-stream.h b/camel/providers/imapp/camel-imapp-stream.h deleted file mode 100644 index 802c018672..0000000000 --- a/camel/providers/imapp/camel-imapp-stream.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2000 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_IMAPP_STREAM_H -#define _CAMEL_IMAPP_STREAM_H - -#include <camel/camel-stream.h> - -#define CAMEL_IMAPP_STREAM(obj) CAMEL_CHECK_CAST (obj, camel_imapp_stream_get_type (), CamelIMAPPStream) -#define CAMEL_IMAPP_STREAM_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_imapp_stream_get_type (), CamelIMAPPStreamClass) -#define CAMEL_IS_IMAP_STREAM(obj) CAMEL_CHECK_TYPE (obj, camel_imapp_stream_get_type ()) - -typedef struct _CamelIMAPPStreamClass CamelIMAPPStreamClass; -typedef struct _CamelIMAPPStream CamelIMAPPStream; - -typedef enum { - IMAP_TOK_PROTOCOL = -2, - IMAP_TOK_ERROR = -1, - IMAP_TOK_TOKEN = 256, - IMAP_TOK_STRING, - IMAP_TOK_INT, - IMAP_TOK_LITERAL, -} camel_imapp_token_t; - -struct _CamelIMAPPStream { - CamelStream parent; - - CamelStream *source; - - /*int state;*/ - unsigned char *buf, *ptr, *end; - unsigned int literal; - - unsigned int unget; - camel_imapp_token_t unget_tok; - unsigned char *unget_token; - unsigned int unget_len; - - unsigned char *tokenbuf, *tokenptr, *tokenend; -}; - -struct _CamelIMAPPStreamClass { - CamelStreamClass parent_class; -}; - -CamelType camel_imapp_stream_get_type (void); - -CamelStream *camel_imapp_stream_new (CamelStream *source); - -camel_imapp_token_t camel_imapp_stream_token (CamelIMAPPStream *is, unsigned char **start, unsigned int *len); /* throws IO,PARSE exception */ -void camel_imapp_stream_ungettoken (CamelIMAPPStream *is, camel_imapp_token_t tok, unsigned char *token, unsigned int len); - -void camel_imapp_stream_set_literal (CamelIMAPPStream *is, unsigned int literal); -int camel_imapp_stream_gets (CamelIMAPPStream *is, unsigned char **start, unsigned int *len); -int camel_imapp_stream_getl (CamelIMAPPStream *is, unsigned char **start, unsigned int *len); - -/* all throw IO,PARSE exceptions */ - -/* gets an atom, upper-cases */ -int camel_imapp_stream_atom (CamelIMAPPStream *is, unsigned char **start, unsigned int *len); -/* gets an atom or string */ -int camel_imapp_stream_astring (CamelIMAPPStream *is, unsigned char **start); -/* gets a NIL or a string, start==NULL if NIL */ -int camel_imapp_stream_nstring (CamelIMAPPStream *is, unsigned char **start); -/* gets a NIL or string into a stream, stream==NULL if NIL */ -int camel_imapp_stream_nstring_stream(CamelIMAPPStream *is, CamelStream **stream); -/* gets 'text' */ -int camel_imapp_stream_text (CamelIMAPPStream *is, unsigned char **text); - -/* gets a 'number' */ -guint32 camel_imapp_stream_number(CamelIMAPPStream *is); - -#endif /* ! _CAMEL_IMAPP_STREAM_H */ diff --git a/camel/providers/imapp/camel-imapp-summary.c b/camel/providers/imapp/camel-imapp-summary.c deleted file mode 100644 index a0df21bcb0..0000000000 --- a/camel/providers/imapp/camel-imapp-summary.c +++ /dev/null @@ -1,166 +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-imapp-summary.h" -#include <camel/camel-file-utils.h> - -#define CAMEL_IMAPP_SUMMARY_VERSION (0x1000) - -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 void camel_imapp_summary_class_init(CamelIMAPPSummaryClass *klass); -static void camel_imapp_summary_init (CamelIMAPPSummary *obj); - -static CamelFolderSummaryClass *camel_imapp_summary_parent; - -CamelType -camel_imapp_summary_get_type(void) -{ - static CamelType type = CAMEL_INVALID_TYPE; - - if (type == CAMEL_INVALID_TYPE) { - type = camel_type_register( - camel_folder_summary_get_type(), "CamelIMAPPSummary", - sizeof(CamelIMAPPSummary), - sizeof(CamelIMAPPSummaryClass), - (CamelObjectClassInitFunc) camel_imapp_summary_class_init, - NULL, - (CamelObjectInitFunc) camel_imapp_summary_init, - NULL); - } - - return type; -} - -static void -camel_imapp_summary_class_init(CamelIMAPPSummaryClass *klass) -{ - CamelFolderSummaryClass *cfs_class =(CamelFolderSummaryClass *) klass; - - camel_imapp_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; -} - -static void -camel_imapp_summary_init(CamelIMAPPSummary *obj) -{ - CamelFolderSummary *s =(CamelFolderSummary *)obj; - - /* subclasses need to set the right instance data sizes */ - s->message_info_size = sizeof(CamelIMAPPMessageInfo); - s->content_info_size = sizeof(CamelMessageContentInfo); - - /* and a unique file version */ - s->version += CAMEL_IMAPP_SUMMARY_VERSION; -} - -/** - * camel_imapp_summary_new: - * @filename: the file to store the summary in. - * - * This will create a new CamelIMAPPSummary object and read in the - * summary data from disk, if it exists. - * - * Return value: A new CamelIMAPPSummary object. - **/ -CamelFolderSummary * -camel_imapp_summary_new(void) -{ - CamelFolderSummary *summary = CAMEL_FOLDER_SUMMARY(camel_object_new(camel_imapp_summary_get_type())); - - return summary; -} - - -static int -summary_header_load(CamelFolderSummary *s, FILE *in) -{ - CamelIMAPPSummary *ims = CAMEL_IMAPP_SUMMARY(s); - - if (camel_imapp_summary_parent->summary_header_load(s, in) == -1) - return -1; - - return camel_file_util_decode_uint32(in, &ims->uidvalidity); -} - -static int -summary_header_save(CamelFolderSummary *s, FILE *out) -{ - CamelIMAPPSummary *ims = CAMEL_IMAPP_SUMMARY(s); - - if (camel_imapp_summary_parent->summary_header_save(s, out) == -1) - return -1; - - return camel_file_util_encode_uint32(out, ims->uidvalidity); -} - - -static CamelMessageInfo * -message_info_load(CamelFolderSummary *s, FILE *in) -{ - CamelMessageInfo *info; - CamelIMAPPMessageInfo *iinfo; - - info = camel_imapp_summary_parent->message_info_load(s, in); - if (info) { - iinfo =(CamelIMAPPMessageInfo *)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) -{ - CamelIMAPPMessageInfo *iinfo =(CamelIMAPPMessageInfo *)info; - - if (camel_imapp_summary_parent->message_info_save(s, out, info) == -1) - return -1; - - return camel_file_util_encode_uint32(out, iinfo->server_flags); -} diff --git a/camel/providers/imapp/camel-imapp-summary.h b/camel/providers/imapp/camel-imapp-summary.h deleted file mode 100644 index e9783625f4..0000000000 --- a/camel/providers/imapp/camel-imapp-summary.h +++ /dev/null @@ -1,65 +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_IMAPP_SUMMARY_H -#define _CAMEL_IMAPP_SUMMARY_H - -#include <camel/camel-folder-summary.h> -#include <camel/camel-exception.h> - -#define CAMEL_IMAPP_SUMMARY(obj) CAMEL_CHECK_CAST (obj, camel_imapp_summary_get_type (), CamelIMAPPSummary) -#define CAMEL_IMAPP_SUMMARY_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_imapp_summary_get_type (), CamelIMAPPSummaryClass) -#define CAMEL_IS_IMAPP_SUMMARY(obj) CAMEL_CHECK_TYPE (obj, camel_imapp_summary_get_type ()) - -#define CAMEL_IMAPP_SERVER_FLAGS (CAMEL_MESSAGE_ANSWERED | \ - CAMEL_MESSAGE_DELETED | \ - CAMEL_MESSAGE_DRAFT | \ - CAMEL_MESSAGE_FLAGGED | \ - CAMEL_MESSAGE_SEEN) - -#define CAMEL_IMAPP_MESSAGE_RECENT (1 << 8) - -typedef struct _CamelIMAPPSummaryClass CamelIMAPPSummaryClass; -typedef struct _CamelIMAPPSummary CamelIMAPPSummary; - -typedef struct _CamelIMAPPMessageInfo { - CamelMessageInfo info; - - guint32 server_flags; -} CamelIMAPPMessageInfo; - -struct _CamelIMAPPSummary { - CamelFolderSummary parent; - - guint32 uidvalidity; -}; - -struct _CamelIMAPPSummaryClass { - CamelFolderSummaryClass parent_class; - -}; - -CamelType camel_imapp_summary_get_type (void); -CamelFolderSummary *camel_imapp_summary_new (void); - -#endif /* ! _CAMEL_IMAPP_SUMMARY_H */ - diff --git a/camel/providers/imapp/camel-imapp-utils.c b/camel/providers/imapp/camel-imapp-utils.c deleted file mode 100644 index e20499689d..0000000000 --- a/camel/providers/imapp/camel-imapp-utils.c +++ /dev/null @@ -1,1339 +0,0 @@ - -#include <ctype.h> -#include <errno.h> -#include <string.h> - -#include <camel/camel-folder-summary.h> -#include <camel/camel-store.h> -#include <camel/camel-utf8.h> - -#include "camel-imapp-folder.h" -#include "camel-imapp-stream.h" -#include "camel-imapp-utils.h" -#include "camel-imapp-exception.h" -#include "camel-imapp-engine.h" -#include "e-util/e-memory.h" - -/* high-level parser state */ -#define p(x) -/* debug */ -#define d(x) - -/* ANSI-C code produced by gperf version 2.7 */ -/* Command-line: gperf -H imap_hash -N imap_tokenise -L ANSI-C -o -t -k1,$ imap-tokens.txt */ -struct _imap_keyword { char *name; enum _imap_id id; }; -/* - gperf input file - best hash generated using: gperf -o -s-2 -k1,'$' -t -H imap_hash -N imap_tokenise -L ANSI-C -*/ - -#define TOTAL_KEYWORDS 23 -#define MIN_WORD_LENGTH 2 -#define MAX_WORD_LENGTH 14 -#define MIN_HASH_VALUE 2 -#define MAX_HASH_VALUE 38 -/* maximum key range = 37, duplicates = 0 */ - -#ifdef __GNUC__ -__inline -#endif -static unsigned int -imap_hash (register const char *str, register unsigned int len) -{ - static unsigned char asso_values[] = - { - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 10, 15, 39, 20, 0, - 0, 39, 0, 10, 39, 0, 39, 39, 10, 0, - 0, 39, 0, 10, 5, 10, 39, 39, 39, 0, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39 - }; - return len + asso_values[(unsigned char)str[len - 1]] + asso_values[(unsigned char)str[0]]; -} - -#ifdef __GNUC__ -__inline -#endif -enum _imap_id -imap_tokenise (register const char *str, register unsigned int len) -{ - static struct _imap_keyword wordlist[] = - { - {""}, {""}, - {"OK", IMAP_OK}, - {""}, {""}, - {"PARSE", IMAP_PARSE}, - {""}, - {"PREAUTH", IMAP_PREAUTH}, - {"ENVELOPE", IMAP_ENVELOPE}, - {"READ-ONLY", IMAP_READ_ONLY}, - {"READ-WRITE", IMAP_READ_WRITE}, - {"RFC822.SIZE", IMAP_RFC822_SIZE}, - {"NO", IMAP_NO}, - {"RFC822.HEADER", IMAP_RFC822_HEADER}, - {"TRYCREATE", IMAP_TRYCREATE}, - {"FLAGS", IMAP_FLAGS}, - {"RFC822.TEXT", IMAP_RFC822_TEXT}, - {"NEWNAME", IMAP_NEWNAME}, - {"BYE", IMAP_BYE}, - {"BODY", IMAP_BODY}, - {"ALERT", IMAP_ALERT}, - {"UIDVALIDITY", IMAP_UIDVALIDITY}, - {"INTERNALDATE", IMAP_INTERNALDATE}, - {""}, - {"PERMANENTFLAGS", IMAP_PERMANENTFLAGS}, - {""}, - {"UNSEEN", IMAP_UNSEEN}, - {""}, - {"BODYSTRUCTURE", IMAP_BODYSTRUCTURE}, - {""}, {""}, {""}, {""}, - {"UID", IMAP_UID}, - {""}, {""}, {""}, {""}, - {"BAD", IMAP_BAD} - }; - - if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) - { - register int key = imap_hash (str, len); - - if (key <= MAX_HASH_VALUE && key >= 0) - { - register const char *s = wordlist[key].name; - - if (*str == *s && !strcmp (str + 1, s + 1)) - return wordlist[key].id; - } - } - return 0; -} - -/* flag table */ -static struct { - char *name; - guint32 flag; -} flag_table[] = { - { "\\ANSWERED", CAMEL_MESSAGE_ANSWERED }, - { "\\DELETED", CAMEL_MESSAGE_DELETED }, - { "\\DRAFT", CAMEL_MESSAGE_DRAFT }, - { "\\FLAGGED", CAMEL_MESSAGE_FLAGGED }, - { "\\SEEN", CAMEL_MESSAGE_SEEN }, - { "\\RECENT", CAMEL_IMAPP_MESSAGE_RECENT }, - { "\\*", CAMEL_MESSAGE_USER }, -}; - -/* utility functions - shoudl this be part of imapp-driver? */ -/* mabye this should be a stream op? */ -void -imap_parse_flags(CamelIMAPPStream *stream, guint32 *flagsp) -/* throws IO,PARSE exception */ -{ - int tok, len, i; - unsigned char *token, *p, c; - guint32 flags = 0; - - *flagsp = flags; - - tok = camel_imapp_stream_token(stream, &token, &len); - if (tok == '(') { - do { - tok = camel_imapp_stream_token(stream, &token, &len); - if (tok == IMAP_TOK_TOKEN) { - p = token; - while ((c=*p)) - *p++ = toupper(c); - for (i=0;i<(int)(sizeof(flag_table)/sizeof(flag_table[0]));i++) - if (!strcmp(token, flag_table[i].name)) - flags |= flag_table[i].flag; - } else if (tok != ')') { - camel_exception_throw(1, "expecting flag"); - } - } while (tok != ')'); - } else { - camel_exception_throw(1, "expecting flag list"); - } - - *flagsp = flags; -} - -void -imap_write_flags(CamelStream *stream, guint32 flags) -/* throws IO exception */ -{ - int i; - - /* all this ugly exception throwing goes away once camel streams throw their own? */ - if (camel_stream_write(stream, "(", 1) == -1) - camel_exception_throw(1, "io error: %s", strerror(errno)); - - for (i=0;flags!=0 && i<(int)(sizeof(flag_table)/sizeof(flag_table[0]));i++) { - if (flag_table[i].flag & flags) { - if (camel_stream_write(stream, flag_table[i].name, strlen(flag_table[i].name)) == -1) - camel_exception_throw(1, "io error: %s", strerror(errno)); - flags &= ~flag_table[i].flag; - if (flags != 0) - if (camel_stream_write(stream, " ", 1) == -1) - camel_exception_throw(1, "io error: %s", strerror(errno)); - } - } - - if (camel_stream_write(stream, ")", 1) == -1) - camel_exception_throw(1, "io error: %s", strerror(errno)); -} - -/* -body ::= "(" body_type_1part / body_type_mpart ")" - -body_extension ::= nstring / number / "(" 1#body_extension ")" - ;; Future expansion. Client implementations - ;; MUST accept body_extension fields. Server - ;; implementations MUST NOT generate - ;; body_extension fields except as defined by - ;; future standard or standards-track - ;; revisions of this specification. - -body_ext_1part ::= body_fld_md5 [SPACE body_fld_dsp - [SPACE body_fld_lang - [SPACE 1#body_extension]]] - ;; MUST NOT be returned on non-extensible - ;; "BODY" fetch - -body_ext_mpart ::= body_fld_param - [SPACE body_fld_dsp SPACE body_fld_lang - [SPACE 1#body_extension]] - ;; MUST NOT be returned on non-extensible - ;; "BODY" fetch - -body_fields ::= body_fld_param SPACE body_fld_id SPACE - body_fld_desc SPACE body_fld_enc SPACE - body_fld_octets - -body_fld_desc ::= nstring - -body_fld_dsp ::= "(" string SPACE body_fld_param ")" / nil - -body_fld_enc ::= (<"> ("7BIT" / "8BIT" / "BINARY" / "BASE64"/ - "QUOTED-PRINTABLE") <">) / string - -body_fld_id ::= nstring - -body_fld_lang ::= nstring / "(" 1#string ")" - -body_fld_lines ::= number - -body_fld_md5 ::= nstring - -body_fld_octets ::= number - -body_fld_param ::= "(" 1#(string SPACE string) ")" / nil - -body_type_1part ::= (body_type_basic / body_type_msg / body_type_text) - [SPACE body_ext_1part] - -body_type_basic ::= media_basic SPACE body_fields - ;; MESSAGE subtype MUST NOT be "RFC822" - -body_type_mpart ::= 1*body SPACE media_subtype - [SPACE body_ext_mpart] - -body_type_msg ::= media_message SPACE body_fields SPACE envelope - SPACE body SPACE body_fld_lines - -body_type_text ::= media_text SPACE body_fields SPACE body_fld_lines - -envelope ::= "(" env_date SPACE env_subject SPACE env_from - SPACE env_sender SPACE env_reply_to SPACE env_to - SPACE env_cc SPACE env_bcc SPACE env_in_reply_to - SPACE env_message_id ")" - -env_bcc ::= "(" 1*address ")" / nil - -env_cc ::= "(" 1*address ")" / nil - -env_date ::= nstring - -env_from ::= "(" 1*address ")" / nil - -env_in_reply_to ::= nstring - -env_message_id ::= nstring - -env_reply_to ::= "(" 1*address ")" / nil - -env_sender ::= "(" 1*address ")" / nil - -env_subject ::= nstring - -env_to ::= "(" 1*address ")" / nil - -media_basic ::= (<"> ("APPLICATION" / "AUDIO" / "IMAGE" / - "MESSAGE" / "VIDEO") <">) / string) - SPACE media_subtype - ;; Defined in [MIME-IMT] - -media_message ::= <"> "MESSAGE" <"> SPACE <"> "RFC822" <"> - ;; Defined in [MIME-IMT] - -media_subtype ::= string - ;; Defined in [MIME-IMT] - -media_text ::= <"> "TEXT" <"> SPACE media_subtype - ;; Defined in [MIME-IMT] - - - - ( "type" "subtype" body_fields [envelope body body_fld_lines] - [body_fld_lines] - - - - (("TEXT" "PLAIN" ("CHARSET" - "US-ASCII") NIL NIL "7BIT" 1152 23)("TEXT" "PLAIN" - ("CHARSET" "US-ASCII" "NAME" "cc.diff") - "<960723163407.20117h@cac.washington.edu>" - "Compiler diff" "BASE64" 4554 73) "MIXED")) - -*/ - -/* -struct _body_fields { - CamelContentType *ct; - char *msgid, *desc; - CamelTransferEncoding encoding; - guint32 size; - };*/ - -void -imap_free_body(struct _CamelMessageContentInfo *cinfo) -{ - struct _CamelMessageContentInfo *list, *next; - - list = cinfo->childs; - while (list) { - next = list->next; - imap_free_body(list); - list = next; - } - - if (cinfo->type) - camel_content_type_unref(cinfo->type); - g_free(cinfo->id); - g_free(cinfo->description); - g_free(cinfo->encoding); - g_free(cinfo); -} - -void -imap_parse_param_list(CamelIMAPPStream *is, struct _camel_header_param **plist) -{ - int tok, len; - unsigned char *token, *param; - - p(printf("body_fld_param\n")); - - /* body_fld_param ::= "(" 1#(string SPACE string) ")" / nil */ - tok = camel_imapp_stream_token(is, &token, &len); - if (tok == '(') { - while (1) { - tok = camel_imapp_stream_token(is, &token, &len); - if (tok == ')') - break; - camel_imapp_stream_ungettoken(is, tok, token, len); - - camel_imapp_stream_astring(is, &token); - param = alloca(strlen(token)+1); - strcpy(param, token); - camel_imapp_stream_astring(is, &token); - camel_header_set_param(plist, param, token); - } - } /* else check nil? no need */ -} - -struct _CamelContentDisposition * -imap_parse_ext_optional(CamelIMAPPStream *is) -{ - int tok, len; - unsigned char *token; - struct _CamelContentDisposition * volatile dinfo = NULL; - - /* this parses both extension types, from the body_fld_dsp onwards */ - /* although the grammars are different, they can be parsed the same way */ - - /* body_ext_1part ::= body_fld_md5 [SPACE body_fld_dsp - [SPACE body_fld_lang - [SPACE 1#body_extension]]] - ;; MUST NOT be returned on non-extensible - ;; "BODY" fetch */ - - /* body_ext_mpart ::= body_fld_param - [SPACE body_fld_dsp SPACE body_fld_lang - [SPACE 1#body_extension]] - ;; MUST NOT be returned on non-extensible - ;; "BODY" fetch */ - - CAMEL_TRY { - /* body_fld_dsp ::= "(" string SPACE body_fld_param ")" / nil */ - - tok = camel_imapp_stream_token(is, &token, &len); - switch (tok) { - case '(': - dinfo = g_malloc0(sizeof(*dinfo)); - dinfo->refcount = 1; - /* should be string */ - camel_imapp_stream_astring(is, &token); - - dinfo->disposition = g_strdup(token); - imap_parse_param_list(is, &dinfo->params); - case IMAP_TOK_TOKEN: - d(printf("body_fld_dsp: NIL\n")); - break; - default: - camel_exception_throw(1, "body_fld_disp: expecting nil or list"); - } - - p(printf("body_fld_lang\n")); - - /* body_fld_lang ::= nstring / "(" 1#string ")" */ - - /* we just drop the lang string/list, save it somewhere? */ - - tok = camel_imapp_stream_token(is, &token, &len); - switch (tok) { - case '(': - while (1) { - tok = camel_imapp_stream_token(is, &token, &len); - if (tok == ')') { - break; - } else if (tok != IMAP_TOK_STRING) { - camel_exception_throw(1, "expecting string"); - } - } - break; - case IMAP_TOK_TOKEN: - d(printf("body_fld_lang = nil\n")); - /* treat as 'nil' */ - break; - case IMAP_TOK_STRING: - /* we have a string */ - break; - case IMAP_TOK_LITERAL: - /* we have a literal string */ - camel_imapp_stream_set_literal(is, len); - while ((tok = camel_imapp_stream_getl(is, &token, &len)) > 0) { - d(printf("Skip literal data '%.*s'\n", (int)len, token)); - } - break; - - } - } CAMEL_CATCH(ex) { - if (dinfo) - camel_content_disposition_unref(dinfo); - camel_exception_throw_ex(ex); - } CAMEL_DONE; - - return dinfo; -} - -struct _CamelMessageContentInfo * -imap_parse_body_fields(CamelIMAPPStream *is) -{ - unsigned char *token, *type; - struct _CamelMessageContentInfo *cinfo; - - /* body_fields ::= body_fld_param SPACE body_fld_id SPACE - body_fld_desc SPACE body_fld_enc SPACE - body_fld_octets */ - - p(printf("body_fields\n")); - - cinfo = g_malloc0(sizeof(*cinfo)); - - CAMEL_TRY { - /* this should be string not astring */ - camel_imapp_stream_astring(is, &token); - type = alloca(strlen(token)+1); - strcpy(type, token); - camel_imapp_stream_astring(is, &token); - cinfo->type = camel_content_type_new(type, token); - imap_parse_param_list(is, &cinfo->type->params); - - /* body_fld_id ::= nstring */ - camel_imapp_stream_nstring(is, &token); - cinfo->id = g_strdup(token); - - /* body_fld_desc ::= nstring */ - camel_imapp_stream_nstring(is, &token); - cinfo->description = g_strdup(token); - - /* body_fld_enc ::= (<"> ("7BIT" / "8BIT" / "BINARY" / "BASE64"/ - "QUOTED-PRINTABLE") <">) / string */ - camel_imapp_stream_astring(is, &token); - cinfo->encoding = g_strdup(token); - - /* body_fld_octets ::= number */ - cinfo->size = camel_imapp_stream_number(is); - } CAMEL_CATCH(ex) { - imap_free_body(cinfo); - camel_exception_throw_ex(ex); - } CAMEL_DONE; - - return cinfo; -} - -struct _camel_header_address * -imap_parse_address_list(CamelIMAPPStream *is) -/* throws PARSE,IO exception */ -{ - int tok, len; - unsigned char *token, *host, *mbox; - struct _camel_header_address *list = NULL; - - /* "(" 1*address ")" / nil */ - - CAMEL_TRY { - tok = camel_imapp_stream_token(is, &token, &len); - if (tok == '(') { - while (1) { - struct _camel_header_address *addr, *group = NULL; - - /* address ::= "(" addr_name SPACE addr_adl SPACE addr_mailbox - SPACE addr_host ")" */ - tok = camel_imapp_stream_token(is, &token, &len); - if (tok == ')') - break; - if (tok != '(') - camel_exception_throw(1, "missing '(' for address"); - - addr = camel_header_address_new(); - addr->type = HEADER_ADDRESS_NAME; - tok = camel_imapp_stream_nstring(is, &token); - addr->name = g_strdup(token); - /* we ignore the route, nobody uses it in the real world */ - tok = camel_imapp_stream_nstring(is, &token); - - /* [RFC-822] group syntax is indicated by a special - form of address structure in which the host name - field is NIL. If the mailbox name field is also - NIL, this is an end of group marker (semi-colon in - RFC 822 syntax). If the mailbox name field is - non-NIL, this is a start of group marker, and the - mailbox name field holds the group name phrase. */ - - tok = camel_imapp_stream_nstring(is, &mbox); - mbox = g_strdup(mbox); - tok = camel_imapp_stream_nstring(is, &host); - if (host == NULL) { - if (mbox == NULL) { - group = NULL; - } else { - d(printf("adding group '%s'\n", mbox)); - g_free(addr->name); - addr->name = mbox; - addr->type = HEADER_ADDRESS_GROUP; - camel_header_address_list_append(&list, addr); - group = addr; - } - } else { - addr->v.addr = g_strdup_printf("%s%s%s", mbox?(char *)mbox:"", host?"@":"", host?(char *)host:""); - g_free(mbox); - d(printf("adding address '%s'\n", addr->v.addr)); - if (group != NULL) - camel_header_address_add_member(group, addr); - else - camel_header_address_list_append(&list, addr); - } - do { - tok = camel_imapp_stream_token(is, &token, &len); - } while (tok != ')'); - } - } else { - d(printf("empty, nil '%s'\n", token)); - } - } CAMEL_CATCH(ex) { - camel_header_address_list_clear(&list); - camel_exception_throw_ex(ex); - } CAMEL_DONE; - - return list; -} - -struct _CamelMessageInfo * -imap_parse_envelope(CamelIMAPPStream *is) -{ - int tok, len; - unsigned char *token; - struct _camel_header_address *addr, *addr_from; - char *addrstr; - struct _CamelMessageInfo *minfo; - - /* envelope ::= "(" env_date SPACE env_subject SPACE env_from - SPACE env_sender SPACE env_reply_to SPACE env_to - SPACE env_cc SPACE env_bcc SPACE env_in_reply_to - SPACE env_message_id ")" */ - - p(printf("envelope\n")); - - minfo = camel_message_info_new(); - - CAMEL_TRY { - tok = camel_imapp_stream_token(is, &token, &len); - if (tok != '(') - camel_exception_throw(1, "envelope: expecting '('"); - - /* env_date ::= nstring */ - camel_imapp_stream_nstring(is, &token); - minfo->date_sent = camel_header_decode_date(token, NULL); - - /* env_subject ::= nstring */ - tok = camel_imapp_stream_nstring(is, &token); - /* DUH: this free's it!: camel_message_info_set_subject(minfo, token); */ - e_poolv_set(minfo->strings, CAMEL_MESSAGE_INFO_SUBJECT, token, FALSE); - - /* we merge from/sender into from, append should probably merge more smartly? */ - - /* env_from ::= "(" 1*address ")" / nil */ - addr_from = imap_parse_address_list(is); - - /* env_sender ::= "(" 1*address ")" / nil */ - addr = imap_parse_address_list(is); - if (addr_from) { - camel_header_address_list_clear(&addr); -#if 0 - if (addr) - camel_header_address_list_append_list(&addr_from, &addr); -#endif - } else { - if (addr) - addr_from = addr; - } - - if (addr_from) { - addrstr = camel_header_address_list_format(addr_from); - camel_message_info_set_from(minfo, addrstr); - camel_header_address_list_clear(&addr_from); - } - - /* we dont keep reply_to */ - - /* env_reply_to ::= "(" 1*address ")" / nil */ - addr = imap_parse_address_list(is); - camel_header_address_list_clear(&addr); - - /* env_to ::= "(" 1*address ")" / nil */ - addr = imap_parse_address_list(is); - if (addr) { - addrstr = camel_header_address_list_format(addr); - camel_message_info_set_to(minfo, addrstr); - camel_header_address_list_clear(&addr); - } - - /* env_cc ::= "(" 1*address ")" / nil */ - addr = imap_parse_address_list(is); - if (addr) { - addrstr = camel_header_address_list_format(addr); - camel_message_info_set_cc(minfo, addrstr); - camel_header_address_list_clear(&addr); - } - - /* we dont keep bcc either */ - - /* env_bcc ::= "(" 1*address ")" / nil */ - addr = imap_parse_address_list(is); - camel_header_address_list_clear(&addr); - - /* FIXME: need to put in-reply-to into references hash list */ - - /* env_in_reply_to ::= nstring */ - tok = camel_imapp_stream_nstring(is, &token); - - /* FIXME: need to put message-id into message-id hash */ - - /* env_message_id ::= nstring */ - tok = camel_imapp_stream_nstring(is, &token); - - tok = camel_imapp_stream_token(is, &token, &len); - if (tok != ')') - camel_exception_throw(1, "expecting ')'"); - } CAMEL_CATCH(ex) { - camel_message_info_free(minfo); - camel_exception_throw_ex(ex); - } CAMEL_DONE; - - return minfo; -} - -struct _CamelMessageContentInfo * -imap_parse_body(CamelIMAPPStream *is) -{ - int tok, len; - unsigned char *token; - struct _CamelMessageContentInfo * volatile cinfo = NULL; - struct _CamelMessageContentInfo *subinfo, *last; - struct _CamelContentDisposition * volatile dinfo = NULL; - struct _CamelMessageInfo * volatile minfo = NULL; - - /* body ::= "(" body_type_1part / body_type_mpart ")" */ - - p(printf("body\n")); - - CAMEL_TRY { - tok = camel_imapp_stream_token(is, &token, &len); - if (tok != '(') - camel_exception_throw(1, "body: expecting '('"); - - /* 1*body (optional for multiparts) */ - tok = camel_imapp_stream_token(is, &token, &len); - camel_imapp_stream_ungettoken(is, tok, token, len); - if (tok == '(') { - /* body_type_mpart ::= 1*body SPACE media_subtype - [SPACE body_ext_mpart] */ - - cinfo = g_malloc0(sizeof(*cinfo)); - last = (struct _CamelMessageContentInfo *)&cinfo->childs; - do { - subinfo = imap_parse_body(is); - last->next = subinfo; - last = subinfo; - subinfo->parent = cinfo; - tok = camel_imapp_stream_token(is, &token, &len); - camel_imapp_stream_ungettoken(is, tok, token, len); - } while (tok == '('); - - d(printf("media_subtype\n")); - - camel_imapp_stream_astring(is, &token); - cinfo->type = camel_content_type_new("multipart", token); - - /* body_ext_mpart ::= body_fld_param - [SPACE body_fld_dsp SPACE body_fld_lang - [SPACE 1#body_extension]] - ;; MUST NOT be returned on non-extensible - ;; "BODY" fetch */ - - d(printf("body_ext_mpart\n")); - - tok = camel_imapp_stream_token(is, &token, &len); - camel_imapp_stream_ungettoken(is, tok, token, len); - if (tok == '(') { - imap_parse_param_list(is, &cinfo->type->params); - - /* body_fld_dsp ::= "(" string SPACE body_fld_param ")" / nil */ - - tok = camel_imapp_stream_token(is, &token, &len); - camel_imapp_stream_ungettoken(is, tok, token, len); - if (tok == '(' || tok == IMAP_TOK_TOKEN) { - dinfo = imap_parse_ext_optional(is); - /* other extension fields?, soaked up below */ - } else { - camel_imapp_stream_ungettoken(is, tok, token, len); - } - } - } else { - /* body_type_1part ::= (body_type_basic / body_type_msg / body_type_text) - [SPACE body_ext_1part] - - body_type_basic ::= media_basic SPACE body_fields - body_type_text ::= media_text SPACE body_fields SPACE body_fld_lines - body_type_msg ::= media_message SPACE body_fields SPACE envelope - SPACE body SPACE body_fld_lines */ - - d(printf("Single part body\n")); - - cinfo = imap_parse_body_fields(is); - - d(printf("envelope?\n")); - - /* do we have an envelope following */ - tok = camel_imapp_stream_token(is, &token, &len); - camel_imapp_stream_ungettoken(is, tok, token, len); - if (tok == '(') { - /* what do we do with the envelope?? */ - minfo = imap_parse_envelope(is); - /* what do we do with the message content info?? */ - minfo->content = imap_parse_body(is); - camel_message_info_free(minfo); - minfo = NULL; - d(printf("Scanned envelope - what do i do with it?\n")); - } - - d(printf("fld_lines?\n")); - - /* do we have fld_lines following? */ - tok = camel_imapp_stream_token(is, &token, &len); - if (tok == IMAP_TOK_INT) { - d(printf("field lines: %s\n", token)); - tok = camel_imapp_stream_token(is, &token, &len); - } - camel_imapp_stream_ungettoken(is, tok, token, len); - - /* body_ext_1part ::= body_fld_md5 [SPACE body_fld_dsp - [SPACE body_fld_lang - [SPACE 1#body_extension]]] - ;; MUST NOT be returned on non-extensible - ;; "BODY" fetch */ - - d(printf("extension data?\n")); - - if (tok != ')') { - camel_imapp_stream_nstring(is, &token); - - d(printf("md5: %s\n", token?(char *)token:"NIL")); - - /* body_fld_dsp ::= "(" string SPACE body_fld_param ")" / nil */ - - tok = camel_imapp_stream_token(is, &token, &len); - camel_imapp_stream_ungettoken(is, tok, token, len); - if (tok == '(' || tok == IMAP_TOK_TOKEN) { - dinfo = imap_parse_ext_optional(is); - /* then other extension fields, soaked up below */ - } - } - } - - /* soak up any other extension fields that may be present */ - /* there should only be simple tokens, no lists */ - do { - tok = camel_imapp_stream_token(is, &token, &len); - if (tok != ')') - d(printf("Dropping extension data '%s'\n", token)); - } while (tok != ')'); - } CAMEL_CATCH(ex) { - if (cinfo) - imap_free_body(cinfo); - if (dinfo) - camel_content_disposition_unref(dinfo); - if (minfo) - camel_message_info_free(minfo); - camel_exception_throw_ex(ex); - } CAMEL_DONE; - - /* FIXME: do something with the disposition, currently we have no way to pass it out? */ - if (dinfo) - camel_content_disposition_unref(dinfo); - - return cinfo; -} - -char * -imap_parse_section(CamelIMAPPStream *is) -{ - int tok, len; - unsigned char *token; - char * volatile section = NULL; - - /* currently we only return the part within the [section] specifier - any header fields are parsed, but dropped */ - - /* - section ::= "[" [section_text / - (nz_number *["." nz_number] ["." (section_text / "MIME")])] "]" - - section_text ::= "HEADER" / "HEADER.FIELDS" [".NOT"] - SPACE header_list / "TEXT" - */ - - CAMEL_TRY { - tok = camel_imapp_stream_token(is, &token, &len); - if (tok != '[') - camel_exception_throw(1, "section: expecting '['"); - - tok = camel_imapp_stream_token(is, &token, &len); - if (tok == IMAP_TOK_INT || tok == IMAP_TOK_TOKEN) - section = g_strdup(token); - else if (tok == ']') { - section = g_strdup(""); - camel_imapp_stream_ungettoken(is, tok, token, len); - } else - camel_exception_throw(1, "section: expecting token"); - - /* header_list ::= "(" 1#header_fld_name ")" - header_fld_name ::= astring */ - - /* we dont need the header specifiers */ - tok = camel_imapp_stream_token(is, &token, &len); - if (tok == '(') { - do { - tok = camel_imapp_stream_token(is, &token, &len); - if (tok == IMAP_TOK_STRING || tok == IMAP_TOK_TOKEN || tok == IMAP_TOK_INT) { - /* ?do something? */ - } else if (tok != ')') - camel_exception_throw(1, "section: header fields: expecting string"); - } while (tok != ')'); - tok = camel_imapp_stream_token(is, &token, &len); - } - - if (tok != ']') - camel_exception_throw(1, "section: expecting ']'"); - } CAMEL_CATCH(ex) { - g_free(section); - camel_exception_throw_ex(ex); - } CAMEL_DONE; - - return section; -} - -void -imap_free_fetch(struct _fetch_info *finfo) -{ - if (finfo == NULL) - return; - - if (finfo->body) - camel_object_unref((CamelObject *)finfo->body); - if (finfo->text) - camel_object_unref((CamelObject *)finfo->text); - if (finfo->header) - camel_object_unref((CamelObject *)finfo->header); - if (finfo->minfo) - camel_message_info_free(finfo->minfo); - if (finfo->cinfo) - imap_free_body(finfo->cinfo); - g_free(finfo->date); - g_free(finfo->section); - g_free(finfo->uid); - g_free(finfo); -} - -extern void camel_content_info_dump(CamelMessageContentInfo *ci, int depth); -extern void camel_message_info_dump(CamelMessageInfo *mi); - -#include <camel/camel-stream-fs.h> - -/* debug, dump one out */ -void -imap_dump_fetch(struct _fetch_info *finfo) -{ - CamelStream *sout; - int fd; - - printf("Fetch info:\n"); - if (finfo == NULL) { - printf("Empty\n"); - return; - } - - fd = dup(1); - sout = camel_stream_fs_new_with_fd(fd); - if (finfo->body) { - camel_stream_printf(sout, "Body content:\n"); - camel_stream_write_to_stream(finfo->body, sout); - } - if (finfo->text) { - camel_stream_printf(sout, "Text content:\n"); - camel_stream_write_to_stream(finfo->text, sout); - } - if (finfo->header) { - camel_stream_printf(sout, "Header content:\n"); - camel_stream_write_to_stream(finfo->header, sout); - } - if (finfo->minfo) { - camel_stream_printf(sout, "Message Info:\n"); - camel_message_info_dump(finfo->minfo); - } - if (finfo->cinfo) { - camel_stream_printf(sout, "Content Info:\n"); - camel_content_info_dump(finfo->cinfo, 0); - } - if (finfo->got & FETCH_SIZE) - camel_stream_printf(sout, "Size: %d\n", (int)finfo->size); - if (finfo->got & FETCH_BODY) - camel_stream_printf(sout, "Offset: %d\n", (int)finfo->offset); - if (finfo->got & FETCH_FLAGS) - camel_stream_printf(sout, "Flags: %08x\n", (int)finfo->flags); - if (finfo->date) - camel_stream_printf(sout, "Date: '%s'\n", finfo->date); - if (finfo->section) - camel_stream_printf(sout, "Section: '%s'\n", finfo->section); - if (finfo->date) - camel_stream_printf(sout, "UID: '%s'\n", finfo->uid); - camel_object_unref((CamelObject *)sout); -} - -struct _fetch_info * -imap_parse_fetch(CamelIMAPPStream *is) -{ - int tok, len; - unsigned char *token, *p, c; - struct _fetch_info *finfo; - - finfo = g_malloc0(sizeof(*finfo)); - - CAMEL_TRY { - tok = camel_imapp_stream_token(is, &token, &len); - if (tok != '(') - camel_exception_throw(1, "fetch: expecting '('"); - - while ( (tok = camel_imapp_stream_token(is, &token, &len)) == IMAP_TOK_TOKEN ) { - - p = token; - while ((c=*p)) - *p++ = toupper(c); - - switch(imap_tokenise(token, len)) { - case IMAP_ENVELOPE: - finfo->minfo = imap_parse_envelope(is); - finfo->got |= FETCH_MINFO; - break; - case IMAP_FLAGS: - imap_parse_flags(is, &finfo->flags); - finfo->got |= FETCH_FLAGS; - break; - case IMAP_INTERNALDATE: - camel_imapp_stream_nstring(is, &token); - /* TODO: convert to camel format? */ - finfo->date = g_strdup(token); - finfo->got |= FETCH_DATE; - break; - case IMAP_RFC822_HEADER: - camel_imapp_stream_nstring_stream(is, &finfo->header); - finfo->got |= FETCH_HEADER; - break; - case IMAP_RFC822_TEXT: - camel_imapp_stream_nstring_stream(is, &finfo->text); - finfo->got |= FETCH_TEXT; - break; - case IMAP_RFC822_SIZE: - finfo->size = camel_imapp_stream_number(is); - finfo->got |= FETCH_SIZE; - break; - case IMAP_BODYSTRUCTURE: - finfo->cinfo = imap_parse_body(is); - finfo->got |= FETCH_CINFO; - break; - case IMAP_BODY: - tok = camel_imapp_stream_token(is, &token, &len); - camel_imapp_stream_ungettoken(is, tok, token, len); - if (tok == '(') { - finfo->cinfo = imap_parse_body(is); - finfo->got |= FETCH_CINFO; - } else if (tok == '[') { - finfo->section = imap_parse_section(is); - finfo->got |= FETCH_SECTION; - tok = camel_imapp_stream_token(is, &token, &len); - if (token[0] == '<') { - finfo->offset = strtoul(token+1, NULL, 10); - } else { - camel_imapp_stream_ungettoken(is, tok, token, len); - } - camel_imapp_stream_nstring_stream(is, &finfo->body); - finfo->got |= FETCH_BODY; - } else { - camel_exception_throw(1, "unknown body response"); - } - break; - case IMAP_UID: - tok = camel_imapp_stream_token(is, &token, &len); - if (tok != IMAP_TOK_INT) - camel_exception_throw(1, "uid not integer"); - finfo->uid = g_strdup(token); - finfo->got |= FETCH_UID; - break; - default: - camel_exception_throw(1, "unknown body response"); - } - } - - if (tok != ')') - camel_exception_throw(1, "missing closing ')' on fetch response"); - } CAMEL_CATCH(ex) { - imap_free_fetch(finfo); - camel_exception_throw_ex(ex); - } CAMEL_DONE; - - return finfo; -} - -/* rfc 2060 section 7.1 Status Responses */ -/* shoudl this start after [ or before the [? token_unget anyone? */ -struct _status_info * -imap_parse_status(CamelIMAPPStream *is) -{ - int tok, len; - unsigned char *token; - struct _status_info *sinfo; - - sinfo = g_malloc0(sizeof(*sinfo)); - - CAMEL_TRY { - camel_imapp_stream_atom(is, &token, &len); - - /* - resp_cond_auth ::= ("OK" / "PREAUTH") SPACE resp_text - ;; Authentication condition - - resp_cond_bye ::= "BYE" SPACE resp_text - - resp_cond_state ::= ("OK" / "NO" / "BAD") SPACE resp_text - ;; Status condition - */ - - sinfo->result = imap_tokenise(token, len); - switch (sinfo->result) { - case IMAP_OK: - case IMAP_NO: - case IMAP_BAD: - case IMAP_PREAUTH: - case IMAP_BYE: - break; - default: - camel_exception_throw(1, "expecting OK/NO/BAD"); - } - - tok = camel_imapp_stream_token(is, &token, &len); - if (tok == '[') { - camel_imapp_stream_atom(is, &token, &len); - sinfo->condition = imap_tokenise(token, len); - - /* parse any details */ - switch (sinfo->condition) { - case IMAP_READ_ONLY: - case IMAP_READ_WRITE: - case IMAP_ALERT: - case IMAP_PARSE: - case IMAP_TRYCREATE: - break; - case IMAP_NEWNAME: - /* the rfc doesn't specify the bnf for this */ - camel_imapp_stream_astring(is, &token); - sinfo->u.newname.oldname = g_strdup(token); - camel_imapp_stream_astring(is, &token); - sinfo->u.newname.newname = g_strdup(token); - break; - case IMAP_PERMANENTFLAGS: - imap_parse_flags(is, &sinfo->u.permanentflags); - break; - case IMAP_UIDVALIDITY: - sinfo->u.uidvalidity = camel_imapp_stream_number(is); - break; - case IMAP_UNSEEN: - sinfo->u.unseen = camel_imapp_stream_number(is); - break; - default: - sinfo->condition = IMAP_UNKNOWN; - printf("Got unknown response code: %s: ignored\n", token); - } - - /* ignore anything we dont know about */ - do { - tok = camel_imapp_stream_token(is, &token, &len); - if (tok == '\n') - camel_exception_throw(1, "server response truncated"); - } while (tok != ']'); - } else { - camel_imapp_stream_ungettoken(is, tok, token, len); - } - - /* and take the human readable response */ - camel_imapp_stream_text(is, (unsigned char **)&sinfo->text); - } CAMEL_CATCH(ex) { - imap_free_status(sinfo); - camel_exception_throw_ex(ex); - } CAMEL_DONE; - - return sinfo; -} - -void -imap_free_status(struct _status_info *sinfo) -{ - if (sinfo == NULL) - return; - - switch (sinfo->condition) { - case IMAP_NEWNAME: - g_free(sinfo->u.newname.oldname); - g_free(sinfo->u.newname.newname); - default: - break; - } - - g_free(sinfo->text); - g_free(sinfo); -} - -/* FIXME: use tokeniser? */ -/* FIXME: real flags */ -static struct { - char *name; - guint32 flag; -} list_flag_table[] = { - { "\\NOINFERIORS", CAMEL_FOLDER_NOINFERIORS }, - { "\\NOSELECT", CAMEL_FOLDER_NOSELECT }, - { "\\MARKED", 1<<8 }, - { "\\UNMARKED", 1<<9 }, -}; - -struct _list_info * -imap_parse_list(CamelIMAPPStream *is) -/* throws io, parse */ -{ - int tok, len, i; - unsigned char *token, *p, c; - struct _list_info * volatile linfo; - - linfo = g_malloc0(sizeof(*linfo)); - - CAMEL_TRY { - /* mailbox_list ::= "(" #("\Marked" / "\Noinferiors" / - "\Noselect" / "\Unmarked" / flag_extension) ")" - SPACE (<"> QUOTED_CHAR <"> / nil) SPACE mailbox */ - - tok = camel_imapp_stream_token(is, &token, &len); - if (tok != '(') - camel_exception_throw(1, "list: expecting '('"); - - while ( (tok = camel_imapp_stream_token(is, &token, &len)) != ')' ) { - if (tok == IMAP_TOK_STRING || tok == IMAP_TOK_TOKEN) { - p = token; - while ((c=*p)) - *p++ = toupper(c); - for (i=0;i<(int)(sizeof(list_flag_table)/sizeof(list_flag_table[0]));i++) - if (!strcmp(token, list_flag_table[i].name)) - linfo->flags |= list_flag_table[i].flag; - } else { - camel_exception_throw(1, "list: expecting flag or ')'"); - } - } - - camel_imapp_stream_nstring(is, &token); - linfo->separator = token?*token:0; - camel_imapp_stream_astring(is, &token); - linfo->name = g_strdup(token); - } CAMEL_CATCH(ex) { - imap_free_list(linfo); - camel_exception_throw_ex(ex); - } CAMEL_DONE; - - return linfo; -} - -char * -imapp_list_get_path(struct _list_info *li) -{ - char *path, *p; - int c; - const char *f; - - if (li->separator != 0 && li->separator != '/') { - p = path = alloca(strlen(li->name)*3+1); - f = li->name; - while ( (c = *f++ & 0xff) ) { - if (c == li->separator) - *p++ = '/'; - else if (c == '/' || c == '%') - p += sprintf(p, "%%%02X", c); - else - *p++ = c; - } - *p = 0; - } else - path = li->name; - - return camel_utf7_utf8(path); -} - -void -imap_free_list(struct _list_info *linfo) -{ - if (linfo) { - g_free(linfo->name); - g_free(linfo); - } -} - - -/* ********************************************************************** */ -/* utility functions */ - -/* should the rest of imapp-utils go into imapp-parse? */ - -/* this creates a uid (or sequence number) set directly into the command, - optionally breaking it into smaller chunks */ - -void -imapp_uidset_init(struct _uidset_state *ss, CamelIMAPPEngine *ie) -{ - ss->ie = ie; - ss->len = 0; - ss->start = 0; - ss->last = 0; -} - -int -imapp_uidset_done(struct _uidset_state *ss, CamelIMAPPCommand *ic) -{ - int ret = 0; - - if (ss->last != 0 && ss->last != ss->start) { - camel_imapp_engine_command_add(ss->ie, ic, ":%d", ss->last); - printf(":%d", ss->last); - } - - ret = ss->last != 0; - - ss->start = 0; - ss->last = 0; - ss->len = 0; - - return ret; -} - -int -imapp_uidset_add(struct _uidset_state *ss, CamelIMAPPCommand *ic, const char *uid) -{ - guint32 uidn; - - uidn = strtoul(uid, NULL, 10); - if (uidn == 0) - return -1; - - if (ss->last == 0) { - camel_imapp_engine_command_add(ss->ie, ic, "%d", uidn); - printf("%d", uidn); - ss->len ++; - ss->start = uidn; - } else { - if (ss->last != uidn-1) { - if (ss->last == ss->start) { - camel_imapp_engine_command_add(ss->ie, ic, ",%d", uidn); - printf(",%d", uidn); - ss->len ++; - } else { - camel_imapp_engine_command_add(ss->ie, ic, ":%d,%d", ss->last, uidn); - printf(":%d,%d", ss->last, uidn); - ss->len+=2; - } - ss->start = uidn; - } - } - - ss->last = uidn; - - if (ss->len > 10) { - imapp_uidset_done(ss, ic); - return 1; - } - - return 0; -} diff --git a/camel/providers/imapp/camel-imapp-utils.h b/camel/providers/imapp/camel-imapp-utils.h deleted file mode 100644 index e0974bdc96..0000000000 --- a/camel/providers/imapp/camel-imapp-utils.h +++ /dev/null @@ -1,145 +0,0 @@ - -#ifndef _CAMEL_IMAPP_UTILS_H -#define _CAMEL_IMAPP_UTILS_H - -#include <camel/camel-mime-utils.h> - -/* FIXME: the enum should be split up into logical groups, so that testing - can be done more accurately? */ - -/* list of strings we know about that can be *quickly* tokenised */ -enum _imap_id { - IMAP_UNKNOWN = 0, - IMAP_ALERT, - IMAP_BYE, - IMAP_BAD, - IMAP_NO, - IMAP_OK, - IMAP_PREAUTH, - IMAP_NEWNAME, - IMAP_PARSE, - IMAP_PERMANENTFLAGS, - IMAP_READ_ONLY, - IMAP_READ_WRITE, - IMAP_TRYCREATE, - IMAP_UIDVALIDITY, - IMAP_UNSEEN, - IMAP_ENVELOPE, - IMAP_FLAGS, - IMAP_INTERNALDATE, - IMAP_RFC822_HEADER, - IMAP_RFC822_TEXT, - IMAP_RFC822_SIZE, - IMAP_BODYSTRUCTURE, - IMAP_BODY, - IMAP_UID, -}; - -/* str MUST be in upper case, tokenised using gperf function */ -enum _imap_id imap_tokenise(register const char *str, register unsigned int len); - -/* this flag should be part of imapfoldersummary */ -enum { - CAMEL_IMAPP_MESSAGE_RECENT = (1<<8), -}; - -/* ********************************************************************** */ -void imap_parse_flags(CamelIMAPPStream *stream, guint32 *flagsp) /* IO,PARSE */; -void imap_write_flags(CamelStream *stream, guint32 flags) /* IO */; - -/* ********************************************************************** */ -void imap_parse_param_list(CamelIMAPPStream *is, struct _camel_header_param **plist) /* IO,PARSE */; -struct _CamelContentDisposition *imap_parse_ext_optional(CamelIMAPPStream *is) /* IO,PARSE */; -struct _CamelMessageContentInfo *imap_parse_body_fields(CamelIMAPPStream *is) /* IO,PARSE */; -struct _camel_header_address *imap_parse_address_list(CamelIMAPPStream *is) /* IO,PARSE */; -struct _CamelMessageInfo *imap_parse_envelope(CamelIMAPPStream *is) /* IO, PARSE */; -struct _CamelMessageContentInfo *imap_parse_body(CamelIMAPPStream *is) /* IO,PARSE */; -char *imap_parse_section(CamelIMAPPStream *is) /* IO,PARSE */; -void imap_free_body(struct _CamelMessageContentInfo *cinfo); - -/* ********************************************************************** */ -/* all the possible stuff we might get from a fetch request */ -/* this assumes the caller/server doesn't send any one of these types twice */ -struct _fetch_info { - guint32 got; /* what we got, see below */ - CamelStream *body; /* BODY[.*](<.*>)? */ - CamelStream *text; /* RFC822.TEXT */ - CamelStream *header; /* RFC822.HEADER */ - CamelMessageInfo *minfo; /* ENVELOPE */ - CamelMessageContentInfo *cinfo; /* BODYSTRUCTURE,BODY */ - guint32 size; /* RFC822.SIZE */ - guint32 offset; /* start offset of a BODY[]<offset.length> request */ - guint32 flags; /* FLAGS */ - char *date; /* INTERNALDATE */ - char *section; /* section for a BODY[section] request */ - char *uid; /* UID */ -}; - -#define FETCH_BODY (1<<0) -#define FETCH_TEXT (1<<1) -#define FETCH_HEADER (1<<2) -#define FETCH_MINFO (1<<3) -#define FETCH_CINFO (1<<4) -#define FETCH_SIZE (1<<5) -#define FETCH_OFFSET (1<<6) -#define FETCH_FLAGS (1<<7) -#define FETCH_DATE (1<<8) -#define FETCH_SECTION (1<<9) -#define FETCH_UID (1<<10) - -struct _fetch_info *imap_parse_fetch(CamelIMAPPStream *is); -void imap_free_fetch(struct _fetch_info *finfo); -void imap_dump_fetch(struct _fetch_info *finfo); - -/* ********************************************************************** */ - -struct _status_info { - enum _imap_id result; /* ok/no/bad/preauth only */ - enum _imap_id condition; /* read-only/read-write/alert/parse/trycreate/newname/permanentflags/uidvalidity/unseen */ - - union { - struct { - char *oldname; - char *newname; - } newname; - guint32 permanentflags; - guint32 uidvalidity; - guint32 unseen; - } u; - - char *text; -}; - -struct _status_info *imap_parse_status(CamelIMAPPStream *is); -void imap_free_status(struct _status_info *sinfo); - -/* ********************************************************************** */ - -/* should this just return a FolderInfo? - should this just return the name & flags & separator by reference? */ -struct _list_info { - guint32 flags:24; - char separator; - char *name; -}; - -struct _list_info *imap_parse_list(CamelIMAPPStream *is); -char *imapp_list_get_path(struct _list_info *li); -void imap_free_list(struct _list_info *linfo); - -/* ********************************************************************** */ - -struct _uidset_state { - struct _CamelIMAPPEngine *ie; - int len; - guint32 start; - guint32 last; -}; - -struct _CamelIMAPPEngine; -struct _CamelIMAPPCommand; -void imapp_uidset_init(struct _uidset_state *ss, struct _CamelIMAPPEngine *ie); -int imapp_uidset_done(struct _uidset_state *ss, struct _CamelIMAPPCommand *ic); -int imapp_uidset_add(struct _uidset_state *ss, struct _CamelIMAPPCommand *ic, const char *uid); - -#endif diff --git a/camel/providers/imapp/libcamelimapp.urls b/camel/providers/imapp/libcamelimapp.urls deleted file mode 100644 index aad1347834..0000000000 --- a/camel/providers/imapp/libcamelimapp.urls +++ /dev/null @@ -1 +0,0 @@ -imapp diff --git a/camel/providers/local/.cvsignore b/camel/providers/local/.cvsignore deleted file mode 100644 index 3fa8afaa38..0000000000 --- a/camel/providers/local/.cvsignore +++ /dev/null @@ -1,11 +0,0 @@ -.deps -Makefile -Makefile.in -.libs -.deps -*.lo -*.la -*.bb -*.bbg -*.da -*.gcov diff --git a/camel/providers/local/Makefile.am b/camel/providers/local/Makefile.am deleted file mode 100644 index ad07472e85..0000000000 --- a/camel/providers/local/Makefile.am +++ /dev/null @@ -1,61 +0,0 @@ -## Process this file with automake to produce Makefile.in - -libcamellocalincludedir = $(privincludedir)/camel - -camel_provider_LTLIBRARIES = libcamellocal.la -camel_provider_DATA = libcamellocal.urls - -INCLUDES = -I.. \ - -I$(srcdir)/.. \ - -I$(top_srcdir)/camel \ - -I$(top_srcdir)/intl \ - -I$(top_srcdir)/e-util \ - -I$(top_srcdir) \ - $(CAMEL_CFLAGS) \ - $(GNOME_INCLUDEDIR) \ - $(GTK_INCLUDEDIR) \ - -DG_LOG_DOMAIN=\"camel-local-provider\" - -libcamellocal_la_SOURCES = \ - camel-local-folder.c \ - camel-local-store.c \ - camel-local-summary.c \ - camel-local-provider.c \ - camel-mh-folder.c \ - camel-mh-store.c \ - camel-mh-summary.c \ - camel-mbox-folder.c \ - camel-mbox-store.c \ - camel-mbox-summary.c \ - camel-maildir-folder.c \ - camel-maildir-store.c \ - camel-maildir-summary.c \ - camel-spool-folder.c \ - camel-spool-store.c \ - camel-spool-summary.c - -libcamellocalinclude_HEADERS = \ - camel-local-folder.h \ - camel-local-store.h \ - camel-local-summary.h \ - camel-mh-folder.h \ - camel-mh-store.h \ - camel-mh-summary.h \ - camel-mbox-folder.h \ - camel-mbox-store.h \ - camel-mbox-summary.h \ - camel-maildir-folder.h \ - camel-maildir-store.h \ - camel-maildir-summary.h \ - camel-spool-folder.h \ - camel-spool-store.h \ - camel-spool-summary.h - -noinst_HEADERS = \ - camel-local-private.h - -libcamellocal_la_LDFLAGS = -avoid-version -module - -libcamellocal_la_LIBADD = $(top_builddir)/e-util/libeutil.la - -EXTRA_DIST = libcamellocal.urls diff --git a/camel/providers/local/camel-local-folder.c b/camel/providers/local/camel-local-folder.c deleted file mode 100644 index 5bf2142f35..0000000000 --- a/camel/providers/local/camel-local-folder.c +++ /dev/null @@ -1,646 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Authors: Michael Zucchi <notzed@ximian.com> - * - * Copyright 1999-2003 Ximian, Inc. (www.ximian.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. - * - */ - - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdlib.h> -#include <limits.h> -#include <sys/types.h> -#include <dirent.h> -#include <sys/stat.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <fcntl.h> - -#ifndef _POSIX_PATH_MAX -#include <posix1_lim.h> -#endif - -#include "camel-local-folder.h" -#include "camel-local-store.h" -#include "camel-stream-fs.h" -#include "camel-local-summary.h" -#include "camel-data-wrapper.h" -#include "camel-mime-message.h" -#include "camel-stream-filter.h" -#include "camel-mime-filter-from.h" -#include "camel-exception.h" - -#include "camel-local-private.h" - -#include "camel-text-index.h" - -#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/ - -#ifndef PATH_MAX -#define PATH_MAX _POSIX_PATH_MAX -#endif - -static CamelFolderClass *parent_class; -static GSList *local_folder_properties; - -/* Returns the class for a CamelLocalFolder */ -#define CLOCALF_CLASS(so) CAMEL_LOCAL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -#define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -#define CLOCALS_CLASS(so) CAMEL_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so)) - -static int local_getv(CamelObject *object, CamelException *ex, CamelArgGetV *args); -static int local_setv(CamelObject *object, CamelException *ex, CamelArgV *args); - -static int local_lock(CamelLocalFolder *lf, CamelLockType type, CamelException *ex); -static void local_unlock(CamelLocalFolder *lf); - -static char *local_get_full_path (const char *toplevel_dir, const char *full_name); -static char *local_get_meta_path (const char *toplevel_dir, const char *full_name, const char *ext); - -static void local_refresh_info(CamelFolder *folder, CamelException *ex); - -static void local_sync(CamelFolder *folder, gboolean expunge, CamelException *ex); -static void local_expunge(CamelFolder *folder, CamelException *ex); - -static GPtrArray *local_search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex); -static GPtrArray *local_search_by_uids(CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex); -static void local_search_free(CamelFolder *folder, GPtrArray * result); - -static void local_delete(CamelFolder *folder); -static void local_rename(CamelFolder *folder, const char *newname); - -static void local_finalize(CamelObject * object); - -static void -camel_local_folder_class_init(CamelLocalFolderClass * camel_local_folder_class) -{ - CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS(camel_local_folder_class); - CamelObjectClass *oklass = (CamelObjectClass *)camel_local_folder_class; - - /* virtual method definition */ - - /* virtual method overload */ - oklass->getv = local_getv; - oklass->setv = local_setv; - - camel_folder_class->refresh_info = local_refresh_info; - camel_folder_class->sync = local_sync; - camel_folder_class->expunge = local_expunge; - - camel_folder_class->search_by_expression = local_search_by_expression; - camel_folder_class->search_by_uids = local_search_by_uids; - camel_folder_class->search_free = local_search_free; - - camel_folder_class->delete = local_delete; - camel_folder_class->rename = local_rename; - - camel_local_folder_class->get_full_path = local_get_full_path; - camel_local_folder_class->get_meta_path = local_get_meta_path; - - camel_local_folder_class->lock = local_lock; - camel_local_folder_class->unlock = local_unlock; -} - -static void -local_init(gpointer object, gpointer klass) -{ - CamelFolder *folder = object; - CamelLocalFolder *local_folder = object; - - folder->folder_flags |= (CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY | - CAMEL_FOLDER_HAS_SEARCH_CAPABILITY); - - folder->permanent_flags = CAMEL_MESSAGE_ANSWERED | - CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_DRAFT | - CAMEL_MESSAGE_FLAGGED | CAMEL_MESSAGE_SEEN | - CAMEL_MESSAGE_ANSWERED_ALL | CAMEL_MESSAGE_USER; - - folder->summary = NULL; - local_folder->search = NULL; - - local_folder->priv = g_malloc0(sizeof(*local_folder->priv)); - local_folder->priv->search_lock = g_mutex_new(); -} - -static void -local_finalize(CamelObject * object) -{ - CamelLocalFolder *local_folder = CAMEL_LOCAL_FOLDER(object); - CamelFolder *folder = (CamelFolder *)object; - - if (folder->summary) { - camel_local_summary_sync((CamelLocalSummary *)folder->summary, FALSE, local_folder->changes, NULL); - camel_object_unref((CamelObject *)folder->summary); - folder->summary = NULL; - } - - if (local_folder->search) { - camel_object_unref((CamelObject *)local_folder->search); - } - - if (local_folder->index) - camel_object_unref((CamelObject *)local_folder->index); - - while (local_folder->locked> 0) - camel_local_folder_unlock(local_folder); - - g_free(local_folder->base_path); - g_free(local_folder->folder_path); - g_free(local_folder->summary_path); - g_free(local_folder->index_path); - - camel_folder_change_info_free(local_folder->changes); - - g_mutex_free(local_folder->priv->search_lock); - - g_free(local_folder->priv); -} - -static CamelProperty local_property_list[] = { - { CAMEL_LOCAL_FOLDER_INDEX_BODY, "index_body", N_("Index message body data") }, -}; - -CamelType -camel_local_folder_get_type(void) -{ - static CamelType camel_local_folder_type = CAMEL_INVALID_TYPE; - - if (camel_local_folder_type == CAMEL_INVALID_TYPE) { - int i; - - parent_class = (CamelFolderClass *)camel_folder_get_type(); - camel_local_folder_type = camel_type_register(camel_folder_get_type(), "CamelLocalFolder", - sizeof(CamelLocalFolder), - sizeof(CamelLocalFolderClass), - (CamelObjectClassInitFunc) camel_local_folder_class_init, - NULL, - (CamelObjectInitFunc) local_init, - (CamelObjectFinalizeFunc) local_finalize); - - for (i=0;i<sizeof(local_property_list)/sizeof(local_property_list[0]);i++) { - local_property_list[i].description = _(local_property_list[i].description); - local_folder_properties = g_slist_prepend(local_folder_properties, &local_property_list[i]); - } - } - - return camel_local_folder_type; -} - -CamelLocalFolder * -camel_local_folder_construct(CamelLocalFolder *lf, CamelStore *parent_store, const char *full_name, guint32 flags, CamelException *ex) -{ - CamelFolderInfo *fi; - CamelFolder *folder; - const char *root_dir_path, *name; - char *tmp, *statepath; - char folder_path[PATH_MAX]; - struct stat st; - int forceindex, len; - - folder = (CamelFolder *)lf; - - name = strrchr(full_name, '/'); - if (name) - name++; - else - name = full_name; - - camel_folder_construct(folder, parent_store, full_name, name); - - root_dir_path = camel_local_store_get_toplevel_dir(CAMEL_LOCAL_STORE(folder->parent_store)); - /* strip the trailing '/' which is always present */ - len = strlen (root_dir_path); - tmp = g_alloca (len + 1); - strcpy (tmp, root_dir_path); - if (len>1 && tmp[len-1] == '/') - tmp[len-1] = 0; - - lf->base_path = g_strdup(root_dir_path); - - /* if the base store points to a file, then use that */ - if (stat(tmp, &st) != -1 && S_ISREG(st.st_mode)) { - lf->folder_path = g_strdup(tmp); - /* not really sure to do with these for now? */ - lf->summary_path = g_strdup_printf("%s.ev-summary", tmp); - lf->index_path = g_strdup_printf("%s.ibex", tmp); - statepath = g_strdup_printf ("%s.cmeta", tmp); - } else { - lf->folder_path = CLOCALF_CLASS (lf)->get_full_path (root_dir_path, full_name); - lf->summary_path = CLOCALF_CLASS (lf)->get_meta_path (root_dir_path, full_name, ".ev-summary"); - lf->index_path = CLOCALF_CLASS (lf)->get_meta_path (root_dir_path, full_name, ".ibex"); - statepath = CLOCALF_CLASS (lf)->get_meta_path (root_dir_path, full_name, ".cmeta"); - } - camel_object_set(lf, NULL, CAMEL_OBJECT_STATE_FILE, statepath, NULL); - g_free (statepath); - - lf->flags = flags; - - if (camel_object_state_read(lf) == -1) { - /* FIXME: load defaults? */ - } - - /* follow any symlinks to the mailbox */ - if (lstat (lf->folder_path, &st) != -1 && S_ISLNK (st.st_mode) && - realpath (lf->folder_path, folder_path) != NULL) { - g_free (lf->folder_path); - lf->folder_path = g_strdup (folder_path); - } - - lf->changes = camel_folder_change_info_new(); - - /* TODO: Remove the following line, it is a temporary workaround to remove - the old-format 'ibex' files that might be lying around */ - unlink(lf->index_path); - - /* FIXME: Need to run indexing off of the setv method */ -#if 1 - forceindex = FALSE; -#else - /* if we have no/invalid index file, force it */ - forceindex = camel_text_index_check(lf->index_path) == -1; - if (flags & CAMEL_STORE_FOLDER_BODY_INDEX) { - int flag = O_RDWR|O_CREAT; - if (forceindex) - flag |= O_TRUNC; - lf->index = (CamelIndex *)camel_text_index_new(lf->index_path, flag); - if (lf->index == NULL) { - /* yes, this isn't fatal at all */ - g_warning("Could not open/create index file: %s: indexing not performed", strerror (errno)); - forceindex = FALSE; - /* record that we dont have an index afterall */ - flags &= ~CAMEL_STORE_FOLDER_BODY_INDEX; - } - } else { - /* if we do have an index file, remove it (?) */ - if (forceindex == FALSE) - camel_text_index_remove(lf->index_path); - forceindex = FALSE; - } - lf->flags = flags; -#endif - - folder->summary = (CamelFolderSummary *)CLOCALF_CLASS(lf)->create_summary(lf->summary_path, lf->folder_path, lf->index); - if (camel_local_summary_load((CamelLocalSummary *)folder->summary, forceindex, ex) == -1) { - camel_exception_clear(ex); - } - - /*if (camel_local_summary_check((CamelLocalSummary *)folder->summary, lf->changes, ex) == -1) {*/ - /* we sync here so that any hard work setting up the folder isn't lost */ - if (camel_local_summary_sync((CamelLocalSummary *)folder->summary, FALSE, lf->changes, ex) == -1) { - camel_object_unref (CAMEL_OBJECT (folder)); - return NULL; - } - - fi = g_new0 (CamelFolderInfo, 1); - fi->full_name = g_strdup (full_name); - fi->name = g_strdup (name); - fi->url = g_strdup_printf("%s:%s#%s", ((CamelService *)parent_store)->url->protocol, ((CamelService *)parent_store)->url->path, full_name); - fi->unread_message_count = camel_folder_get_unread_message_count(folder); - camel_folder_info_build_path(fi, '/'); - - camel_object_trigger_event(CAMEL_OBJECT (parent_store), "folder_created", fi); - camel_folder_info_free(fi); - - return lf; -} - -/* lock the folder, may be called repeatedly (with matching unlock calls), - with type the same or less than the first call */ -int camel_local_folder_lock(CamelLocalFolder *lf, CamelLockType type, CamelException *ex) -{ - if (lf->locked > 0) { - /* lets be anal here - its important the code knows what its doing */ - g_assert(lf->locktype == type || lf->locktype == CAMEL_LOCK_WRITE); - } else { - if (CLOCALF_CLASS(lf)->lock(lf, type, ex) == -1) - return -1; - lf->locktype = type; - } - - lf->locked++; - - return 0; -} - -/* unlock folder */ -int camel_local_folder_unlock(CamelLocalFolder *lf) -{ - g_assert(lf->locked>0); - lf->locked--; - if (lf->locked == 0) - CLOCALF_CLASS(lf)->unlock(lf); - - return 0; -} - -static int -local_getv(CamelObject *object, CamelException *ex, CamelArgGetV *args) -{ - CamelFolder *folder = (CamelFolder *)object; - int i; - guint32 tag; - - for (i=0;i<args->argc;i++) { - CamelArgGet *arg = &args->argv[i]; - - tag = arg->tag; - - switch (tag & CAMEL_ARG_TAG) { - case CAMEL_OBJECT_ARG_DESCRIPTION: - if (folder->description == NULL) { - char *tmp, *path; - - /* check some common prefixes to shorten the name */ - tmp = ((CamelService *)folder->parent_store)->url->path; - if (tmp == NULL) - goto skip; - - path = g_alloca (strlen (tmp) + strlen (folder->full_name) + 1); - sprintf (path, "%s/%s", tmp, folder->full_name); - - if ((tmp = getenv("HOME")) && strncmp(tmp, path, strlen(tmp)) == 0) - /* $HOME relative path + protocol string */ - folder->description = g_strdup_printf(_("~%s (%s)"), path+strlen(tmp), - ((CamelService *)folder->parent_store)->url->protocol); - else if ((tmp = "/var/spool/mail") && strncmp(tmp, path, strlen(tmp)) == 0) - /* /var/spool/mail relative path + protocol */ - folder->description = g_strdup_printf(_("mailbox:%s (%s)"), path+strlen(tmp), - ((CamelService *)folder->parent_store)->url->protocol); - else if ((tmp = "/var/mail") && strncmp(tmp, path, strlen(tmp)) == 0) - folder->description = g_strdup_printf(_("mailbox:%s (%s)"), path+strlen(tmp), - ((CamelService *)folder->parent_store)->url->protocol); - else - /* a full path + protocol */ - folder->description = g_strdup_printf(_("%s (%s)"), path, - ((CamelService *)folder->parent_store)->url->protocol); - } - *arg->ca_str = folder->description; - break; - - case CAMEL_OBJECT_ARG_PERSISTENT_PROPERTIES: - case CAMEL_FOLDER_ARG_PROPERTIES: { - CamelArgGetV props; - - props.argc = 1; - props.argv[0] = *arg; - ((CamelObjectClass *)parent_class)->getv(object, ex, &props); - *arg->ca_ptr = g_slist_concat(*arg->ca_ptr, g_slist_copy(local_folder_properties)); - - break; } - - case CAMEL_LOCAL_FOLDER_ARG_INDEX_BODY: - printf("getv:'%s' flags %08x\n", ((CamelFolder *)object)->full_name, ((CamelLocalFolder *)object)->flags); - - /* FIXME: remove this from sotre flags */ - *arg->ca_int = (((CamelLocalFolder *)folder)->flags & CAMEL_STORE_FOLDER_BODY_INDEX) != 0; - break; - - default: skip: - continue; - } - - arg->tag = (tag & CAMEL_ARG_TYPE) | CAMEL_ARG_IGNORE; - } - - return ((CamelObjectClass *)parent_class)->getv(object, ex, args); -} - -static int -local_setv(CamelObject *object, CamelException *ex, CamelArgV *args) -{ - int i; - guint32 tag; - - for (i=0;i<args->argc;i++) { - CamelArg *arg = &args->argv[i]; - - tag = arg->tag; - - switch (tag & CAMEL_ARG_TAG) { - case CAMEL_LOCAL_FOLDER_ARG_INDEX_BODY: - /* FIXME: implement */ - /* TODO: When turning on (off?) the index, we want to launch a task for it, - and make sure we dont have multiple tasks doing the same job */ - if (arg->ca_int) - ((CamelLocalFolder *)object)->flags |= CAMEL_STORE_FOLDER_BODY_INDEX; - else - ((CamelLocalFolder *)object)->flags &= ~CAMEL_STORE_FOLDER_BODY_INDEX; - break; - default: - continue; - } - - arg->tag = (tag & CAMEL_ARG_TYPE) | CAMEL_ARG_IGNORE; - } - - return ((CamelObjectClass *)parent_class)->setv(object, ex, args); -} - -static char * -local_get_full_path (const char *toplevel_dir, const char *full_name) -{ - return g_strdup_printf ("%s/%s", toplevel_dir, full_name); -} - -static char * -local_get_meta_path (const char *toplevel_dir, const char *full_name, const char *ext) -{ - return g_strdup_printf ("%s/%s%s", toplevel_dir, full_name, ext); -} - -static int -local_lock(CamelLocalFolder *lf, CamelLockType type, CamelException *ex) -{ - return 0; -} - -static void -local_unlock(CamelLocalFolder *lf) -{ - /* nothing */ -} - -/* for auto-check to work */ -static void -local_refresh_info(CamelFolder *folder, CamelException *ex) -{ - CamelLocalFolder *lf = (CamelLocalFolder *)folder; - - if (camel_local_summary_check((CamelLocalSummary *)folder->summary, lf->changes, ex) == -1) - return; - - if (camel_folder_change_info_changed(lf->changes)) { - camel_object_trigger_event((CamelObject *)folder, "folder_changed", lf->changes); - camel_folder_change_info_clear(lf->changes); - } -} - -static void -local_sync(CamelFolder *folder, gboolean expunge, CamelException *ex) -{ - CamelLocalFolder *lf = CAMEL_LOCAL_FOLDER(folder); - - d(printf("local sync, expunge=%s\n", expunge?"true":"false")); - - if (camel_local_folder_lock(lf, CAMEL_LOCK_WRITE, ex) == -1) - return; - - camel_object_state_write(lf); - - /* if sync fails, we'll pass it up on exit through ex */ - camel_local_summary_sync((CamelLocalSummary *)folder->summary, expunge, lf->changes, ex); - camel_local_folder_unlock(lf); - - if (camel_folder_change_info_changed(lf->changes)) { - camel_object_trigger_event(CAMEL_OBJECT(folder), "folder_changed", lf->changes); - camel_folder_change_info_clear(lf->changes); - } -} - -static void -local_expunge(CamelFolder *folder, CamelException *ex) -{ - d(printf("expunge\n")); - - /* Just do a sync with expunge, serves the same purpose */ - /* call the callback directly, to avoid locking problems */ - CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(folder))->sync(folder, TRUE, ex); -} - -static void -local_delete(CamelFolder *folder) -{ - CamelLocalFolder *lf = (CamelLocalFolder *)folder; - - if (lf->index) - camel_index_delete(lf->index); - - parent_class->delete(folder); -} - -static void -local_rename(CamelFolder *folder, const char *newname) -{ - CamelLocalFolder *lf = (CamelLocalFolder *)folder; - - d(printf("renaming local folder paths to '%s'\n", newname)); - - /* Sync? */ - - g_free(lf->folder_path); - g_free(lf->summary_path); - g_free(lf->index_path); - lf->folder_path = g_strdup_printf("%s/%s", lf->base_path, newname); - lf->summary_path = g_strdup_printf("%s/%s.ev-summary", lf->base_path, newname); - lf->index_path = g_strdup_printf("%s/%s.ibex", lf->base_path, newname); - - /* FIXME: Poke some internals, sigh */ - camel_folder_summary_set_filename(folder->summary, lf->summary_path); - g_free(((CamelLocalSummary *)folder->summary)->folder_path); - ((CamelLocalSummary *)folder->summary)->folder_path = g_strdup(lf->folder_path); - - parent_class->rename(folder, newname); -} - -static GPtrArray * -local_search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex) -{ - CamelLocalFolder *local_folder = CAMEL_LOCAL_FOLDER(folder); - GPtrArray *summary, *matches; - - /* NOTE: could get away without the search lock by creating a new - search object each time */ - - CAMEL_LOCAL_FOLDER_LOCK(folder, search_lock); - - if (local_folder->search == NULL) - local_folder->search = camel_folder_search_new(); - - camel_folder_search_set_folder(local_folder->search, folder); - camel_folder_search_set_body_index(local_folder->search, local_folder->index); - summary = camel_folder_get_summary(folder); - camel_folder_search_set_summary(local_folder->search, summary); - - matches = camel_folder_search_execute_expression(local_folder->search, expression, ex); - - CAMEL_LOCAL_FOLDER_UNLOCK(folder, search_lock); - - camel_folder_free_summary(folder, summary); - - return matches; -} - -static GPtrArray * -local_search_by_uids(CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex) -{ - CamelLocalFolder *local_folder = CAMEL_LOCAL_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_LOCAL_FOLDER_LOCK(folder, search_lock); - - if (local_folder->search == NULL) - local_folder->search = camel_folder_search_new(); - - camel_folder_search_set_folder(local_folder->search, folder); - camel_folder_search_set_body_index(local_folder->search, local_folder->index); - camel_folder_search_set_summary(local_folder->search, summary); - - matches = camel_folder_search_execute_expression(local_folder->search, expression, ex); - - CAMEL_LOCAL_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 -local_search_free(CamelFolder *folder, GPtrArray * result) -{ - CamelLocalFolder *local_folder = CAMEL_LOCAL_FOLDER(folder); - - /* we need to lock this free because of the way search_free_result works */ - /* FIXME: put the lock inside search_free_result */ - CAMEL_LOCAL_FOLDER_LOCK(folder, search_lock); - - camel_folder_search_free_result(local_folder->search, result); - - CAMEL_LOCAL_FOLDER_UNLOCK(folder, search_lock); -} diff --git a/camel/providers/local/camel-local-folder.h b/camel/providers/local/camel-local-folder.h deleted file mode 100644 index 73059f03b3..0000000000 --- a/camel/providers/local/camel-local-folder.h +++ /dev/null @@ -1,109 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Author: Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 1999 Ximian (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_LOCAL_FOLDER_H -#define CAMEL_LOCAL_FOLDER_H 1 - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus }*/ - -#include <camel/camel-folder.h> -#include <camel/camel-folder-search.h> -#include <camel/camel-index.h> -#include "camel-local-summary.h" -#include "camel-lock.h" - -/* #include "camel-store.h" */ - -#define CAMEL_LOCAL_FOLDER_TYPE (camel_local_folder_get_type ()) -#define CAMEL_LOCAL_FOLDER(obj) (CAMEL_CHECK_CAST((obj), CAMEL_LOCAL_FOLDER_TYPE, CamelLocalFolder)) -#define CAMEL_LOCAL_FOLDER_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_LOCAL_FOLDER_TYPE, CamelLocalFolderClass)) -#define CAMEL_IS_LOCAL_FOLDER(o) (CAMEL_CHECK_TYPE((o), CAMEL_LOCAL_FOLDER_TYPE)) - -enum { - CAMEL_LOCAL_FOLDER_ARG_INDEX_BODY = CAMEL_FOLDER_ARG_LAST, - - CAMEL_LOCAL_FOLDER_ARG_LAST = CAMEL_FOLDER_ARG_LAST + 0x100 -}; - -enum { - CAMEL_LOCAL_FOLDER_INDEX_BODY = CAMEL_LOCAL_FOLDER_ARG_INDEX_BODY | CAMEL_ARG_BOO, -}; - -typedef struct { - CamelFolder parent_object; - struct _CamelLocalFolderPrivate *priv; - - guint32 flags; /* open mode flags */ - - int locked; /* lock counter */ - CamelLockType locktype; /* what type of lock we have */ - - char *base_path; /* base path of the local folder */ - char *folder_path; /* the path to the folder itself */ - char *summary_path; /* where the summary lives */ - char *index_path; /* where the index file lives */ - - CamelIndex *index; /* index for this folder */ - CamelFolderSearch *search; /* used to run searches, we just use the real thing (tm) */ - CamelFolderChangeInfo *changes; /* used to store changes to the folder during processing */ -} CamelLocalFolder; - -typedef struct { - CamelFolderClass parent_class; - - /* Virtual methods */ - - /* path construction, only used at init */ - char * (* get_full_path) (const char *toplevel_dir, const char *full_name); - char * (* get_meta_path) (const char *toplevel_dir, const char *full_name, const char *ext); - - /* summary factory, only used at init */ - CamelLocalSummary *(*create_summary)(const char *path, const char *folder, CamelIndex *index); - - /* Lock the folder for my operations */ - int (*lock)(CamelLocalFolder *, CamelLockType type, CamelException *ex); - - /* Unlock the folder for my operations */ - void (*unlock)(CamelLocalFolder *); -} CamelLocalFolderClass; - - -/* public methods */ -/* flags are taken from CAMEL_STORE_FOLDER_* flags */ -CamelLocalFolder *camel_local_folder_construct(CamelLocalFolder *lf, CamelStore *parent_store, - const char *full_name, guint32 flags, CamelException *ex); - -/* Standard Camel function */ -CamelType camel_local_folder_get_type(void); - -/* Lock the folder for internal use. May be called repeatedly */ -/* UNIMPLEMENTED */ -int camel_local_folder_lock(CamelLocalFolder *lf, CamelLockType type, CamelException *ex); -int camel_local_folder_unlock(CamelLocalFolder *lf); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CAMEL_LOCAL_FOLDER_H */ diff --git a/camel/providers/local/camel-local-private.h b/camel/providers/local/camel-local-private.h deleted file mode 100644 index e8e5061fae..0000000000 --- a/camel/providers/local/camel-local-private.h +++ /dev/null @@ -1,53 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Authors: Michael Zucchi <notzed@ximian.com> - * - * Copyright 1999-2003 Ximian, Inc. (www.ximian.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. - * - */ - - -#ifndef CAMEL_LOCAL_PRIVATE_H -#define CAMEL_LOCAL_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 - -#include <pthread.h> - -struct _CamelLocalFolderPrivate { - GMutex *search_lock; /* for locking the search object */ -}; - -#define CAMEL_LOCAL_FOLDER_LOCK(f, l) (g_mutex_lock(((CamelLocalFolder *)f)->priv->l)) -#define CAMEL_LOCAL_FOLDER_UNLOCK(f, l) (g_mutex_unlock(((CamelLocalFolder *)f)->priv->l)) - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CAMEL_LOCAL_PRIVATE_H */ - diff --git a/camel/providers/local/camel-local-provider.c b/camel/providers/local/camel-local-provider.c deleted file mode 100644 index a52dfbde5f..0000000000 --- a/camel/providers/local/camel-local-provider.c +++ /dev/null @@ -1,222 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Authors: Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 2000 Ximian (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 <stdio.h> -#include <string.h> - -#include "camel-provider.h" -#include "camel-session.h" -#include "camel-url.h" - -#include "camel-mh-store.h" -#include "camel-mbox-store.h" -#include "camel-maildir-store.h" -#include "camel-spool-store.h" - -#define d(x) - -static CamelProviderConfEntry mh_conf_entries[] = { - CAMEL_PROVIDER_CONF_DEFAULT_PATH, - { CAMEL_PROVIDER_CONF_CHECKBOX, "dotfolders", NULL, - N_("Use the `.folders' folder summary file (exmh)"), "0" }, - { CAMEL_PROVIDER_CONF_END } -}; - -static CamelProvider mh_provider = { - "mh", - N_("MH-format mail directories"), - N_("For storing local mail in MH-like mail directories."), - "mail", - CAMEL_PROVIDER_IS_SOURCE | CAMEL_PROVIDER_IS_STORAGE | CAMEL_PROVIDER_IS_LOCAL, - CAMEL_URL_NEED_PATH | CAMEL_URL_PATH_IS_ABSOLUTE | CAMEL_URL_FRAGMENT_IS_PATH, - mh_conf_entries, - /* ... */ -}; - -static CamelProviderConfEntry mbox_conf_entries[] = { - CAMEL_PROVIDER_CONF_DEFAULT_PATH, - { CAMEL_PROVIDER_CONF_END } -}; - -static CamelProvider mbox_provider = { - "mbox", - N_("Local delivery"), - N_("For retrieving (moving) local mail from standard mbox formated spools into folders managed by Evolution."), - "mail", - CAMEL_PROVIDER_IS_SOURCE | CAMEL_PROVIDER_IS_STORAGE | CAMEL_PROVIDER_IS_LOCAL, - CAMEL_URL_NEED_PATH | CAMEL_URL_PATH_IS_ABSOLUTE | CAMEL_URL_FRAGMENT_IS_PATH, - mbox_conf_entries, - /* ... */ -}; - -static CamelProviderConfEntry maildir_conf_entries[] = { - CAMEL_PROVIDER_CONF_DEFAULT_PATH, - { CAMEL_PROVIDER_CONF_CHECKBOX, "filter", NULL, - N_("Apply filters to new messages in INBOX"), "0" }, - { CAMEL_PROVIDER_CONF_END } -}; - -static CamelProvider maildir_provider = { - "maildir", - N_("Maildir-format mail directories"), - N_("For storing local mail in maildir directories."), - "mail", - CAMEL_PROVIDER_IS_SOURCE | CAMEL_PROVIDER_IS_STORAGE | CAMEL_PROVIDER_IS_LOCAL, - CAMEL_URL_NEED_PATH | CAMEL_URL_PATH_IS_ABSOLUTE | CAMEL_URL_FRAGMENT_IS_PATH, - maildir_conf_entries, - /* ... */ -}; - -static CamelProviderConfEntry spool_conf_entries[] = { - CAMEL_PROVIDER_CONF_DEFAULT_PATH, - { CAMEL_PROVIDER_CONF_CHECKBOX, "filter", NULL, N_("Apply filters to new messages in INBOX"), "0" }, - { CAMEL_PROVIDER_CONF_CHECKBOX, "xstatus", NULL, N_("Store status headers in Elm/Pine/Mutt format"), "0" }, - { CAMEL_PROVIDER_CONF_END } -}; - -static CamelProvider spool_provider = { - "spool", - N_("Standard Unix mbox spool or directory"), - N_("For reading and storing local mail in external standard mbox spool files.\nMay also be used to read a tree of Elm, Pine, or Mutt style folders."), - "mail", - CAMEL_PROVIDER_IS_SOURCE | CAMEL_PROVIDER_IS_STORAGE, - CAMEL_URL_NEED_PATH | CAMEL_URL_PATH_IS_ABSOLUTE | CAMEL_URL_FRAGMENT_IS_PATH, - spool_conf_entries, - /* ... */ -}; - -/* build a canonical 'path' */ -static char * -make_can_path(char *p, char *o) -{ - char c, last, *start = o; - - d(printf("canonical '%s' = ", p)); - - last = 0; - while ((c = *p++)) { - if (c!='/' - || (c=='/' && last != '/')) - *o++ = c; - last = c; - } - if (o>start && o[-1] == '/') - o[-1] = 0; - else - *o = 0; - - d(printf("'%s'\n", start)); - - return start; -} - -/* 'helper' function for it */ -#define get_can_path(p) ((p == NULL) ? NULL : (make_can_path ((p), g_alloca (strlen (p) + 1)))) - -static guint -local_url_hash (const void *v) -{ - const CamelURL *u = v; - guint hash = 0; - -#define ADD_HASH(s) if (s) hash ^= g_str_hash (s); - - ADD_HASH (u->protocol); - ADD_HASH (u->user); - ADD_HASH (u->authmech); - ADD_HASH (u->host); - if (u->path) - hash ^= g_str_hash(get_can_path(u->path)); - ADD_HASH (u->path); - ADD_HASH (u->query); - hash ^= u->port; - - return hash; -} - -static int -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 int -local_url_equal(const void *v, const void *v2) -{ - const CamelURL *u1 = v, *u2 = v2; - char *p1, *p2; - - p1 = get_can_path(u1->path); - p2 = get_can_path(u2->path); - return check_equal(p1, p2) - && check_equal(u1->protocol, u2->protocol) - && check_equal(u1->user, u2->user) - && check_equal(u1->authmech, u2->authmech) - && check_equal(u1->host, u2->host) - && check_equal(u1->query, u2->query) - && u1->port == u2->port; -} - -void camel_provider_module_init(CamelSession * session) -{ - char *path; - - mh_conf_entries[0].value = ""; /* default path */ - mh_provider.object_types[CAMEL_PROVIDER_STORE] = camel_mh_store_get_type (); - mh_provider.url_hash = local_url_hash; - mh_provider.url_equal = local_url_equal; - camel_session_register_provider(session, &mh_provider); - - if (!(path = getenv ("MAIL"))) - path = g_strdup_printf (SYSTEM_MAIL_DIR "/%s", g_get_user_name ()); - mbox_conf_entries[0].value = path; /* default path */ - mbox_provider.object_types[CAMEL_PROVIDER_STORE] = camel_mbox_store_get_type (); - mbox_provider.url_hash = local_url_hash; - mbox_provider.url_equal = local_url_equal; - camel_session_register_provider(session, &mbox_provider); - - spool_conf_entries[0].value = path; /* default path - same as mbox */ - spool_provider.object_types[CAMEL_PROVIDER_STORE] = camel_spool_store_get_type (); - spool_provider.url_hash = local_url_hash; - spool_provider.url_equal = local_url_equal; - camel_session_register_provider(session, &spool_provider); - - path = getenv ("MAILDIR"); - maildir_conf_entries[0].value = path ? path : ""; /* default path */ - maildir_provider.object_types[CAMEL_PROVIDER_STORE] = camel_maildir_store_get_type (); - maildir_provider.url_hash = local_url_hash; - maildir_provider.url_equal = local_url_equal; - camel_session_register_provider(session, &maildir_provider); -} diff --git a/camel/providers/local/camel-local-store.c b/camel/providers/local/camel-local-store.c deleted file mode 100644 index a0eaf9d68f..0000000000 --- a/camel/providers/local/camel-local-store.c +++ /dev/null @@ -1,442 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Authors: Michael Zucchi <notzed@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 - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <sys/stat.h> -#include <errno.h> -#include <string.h> -#include <unistd.h> -#include <stdio.h> - -#include <glib.h> - -#include "camel-private.h" - -#include "camel-local-store.h" -#include "camel-exception.h" -#include "camel-url.h" - -#include "camel-local-folder.h" -#include <camel/camel-text-index.h> - -#define d(x) - -/* Returns the class for a CamelLocalStore */ -#define CLOCALS_CLASS(so) CAMEL_LOCAL_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -#define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) - -static void construct (CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, CamelException *ex); -static CamelFolder *get_folder(CamelStore * store, const char *folder_name, guint32 flags, CamelException * ex); -static char *get_name(CamelService *service, gboolean brief); -static CamelFolder *get_inbox (CamelStore *store, CamelException *ex); -static CamelFolderInfo *get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex); -static void delete_folder(CamelStore *store, const char *folder_name, CamelException *ex); -static void rename_folder(CamelStore *store, const char *old, const char *new, CamelException *ex); -static CamelFolderInfo *create_folder(CamelStore *store, const char *parent_name, const char *folder_name, CamelException *ex); - -static CamelStoreClass *parent_class = NULL; - -static void -camel_local_store_class_init (CamelLocalStoreClass *camel_local_store_class) -{ - CamelStoreClass *camel_store_class = CAMEL_STORE_CLASS (camel_local_store_class); - CamelServiceClass *camel_service_class = CAMEL_SERVICE_CLASS (camel_local_store_class); - - parent_class = CAMEL_STORE_CLASS (camel_type_get_global_classfuncs (camel_store_get_type ())); - - /* virtual method overload */ - camel_service_class->construct = construct; - camel_service_class->get_name = get_name; - camel_store_class->get_folder = get_folder; - camel_store_class->get_inbox = get_inbox; - camel_store_class->get_folder_info = get_folder_info; - camel_store_class->free_folder_info = camel_store_free_folder_info_full; - - camel_store_class->create_folder = create_folder; - camel_store_class->delete_folder = delete_folder; - camel_store_class->rename_folder = rename_folder; -} - -static void -camel_local_store_finalize (CamelLocalStore *local_store) -{ - if (local_store->toplevel_dir) - g_free (local_store->toplevel_dir); -} - -CamelType -camel_local_store_get_type (void) -{ - static CamelType camel_local_store_type = CAMEL_INVALID_TYPE; - - if (camel_local_store_type == CAMEL_INVALID_TYPE) { - camel_local_store_type = camel_type_register (CAMEL_STORE_TYPE, "CamelLocalStore", - sizeof (CamelLocalStore), - sizeof (CamelLocalStoreClass), - (CamelObjectClassInitFunc) camel_local_store_class_init, - NULL, - NULL, - (CamelObjectFinalizeFunc) camel_local_store_finalize); - } - - return camel_local_store_type; -} - -static void -construct (CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, CamelException *ex) -{ - CamelLocalStore *local_store = CAMEL_LOCAL_STORE (service); - int len; - - CAMEL_SERVICE_CLASS (parent_class)->construct (service, session, provider, url, ex); - if (camel_exception_is_set (ex)) - return; - - len = strlen (service->url->path); - if (service->url->path[len - 1] != '/') - local_store->toplevel_dir = g_strdup_printf ("%s/", service->url->path); - else - local_store->toplevel_dir = g_strdup (service->url->path); -} - -const char * -camel_local_store_get_toplevel_dir (CamelLocalStore *store) -{ - return store->toplevel_dir; -} - -static CamelFolder * -get_folder(CamelStore * store, const char *folder_name, guint32 flags, CamelException * ex) -{ - struct stat st; - char *path = ((CamelLocalStore *)store)->toplevel_dir; - char *sub, *slash; - - if (path[0] != '/') { - camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("Store root %s is not an absolute path"), path); - return NULL; - } - - if (stat(path, &st) == 0) { - if (!S_ISDIR(st.st_mode)) { - camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("Store root %s is not a regular directory"), path); - return NULL; - } - return (CamelFolder *) 0xdeadbeef; - } - - if (errno != ENOENT - || (flags & CAMEL_STORE_FOLDER_CREATE) == 0) { - camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("Cannot get folder: %s: %s"), - path, g_strerror (errno)); - return NULL; - } - - /* need to create the dir heirarchy */ - sub = g_alloca (strlen (path) + 1); - strcpy (sub, path); - slash = sub; - do { - slash = strchr (slash + 1, '/'); - if (slash) - *slash = 0; - if (stat (sub, &st) == -1) { - if (errno != ENOENT || mkdir (sub, 0700) == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("Cannot get folder: %s: %s"), - path, g_strerror (errno)); - return NULL; - } - } - if (slash) - *slash = '/'; - } while (slash); - - return (CamelFolder *) 0xdeadbeef; -} - -static CamelFolder * -get_inbox(CamelStore *store, CamelException *ex) -{ - camel_exception_set(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("Local stores do not have an inbox")); - return NULL; -} - -static char * -get_name (CamelService *service, gboolean brief) -{ - char *dir = ((CamelLocalStore*)service)->toplevel_dir; - - if (brief) - return g_strdup (dir); - else - return g_strdup_printf (_("Local mail file %s"), dir); -} - -static CamelFolderInfo * -get_folder_info (CamelStore *store, const char *top, - guint32 flags, CamelException *ex) -{ - /* FIXME: This is broken, but it corresponds to what was - * there before. - */ - - d(printf("-- LOCAL STORE -- get folder info: %s\n", top)); - - return NULL; -} - -static CamelFolderInfo * -create_folder(CamelStore *store, const char *parent_name, const char *folder_name, CamelException *ex) -{ - char *path = ((CamelLocalStore *)store)->toplevel_dir; - char *name; - CamelFolder *folder; - CamelFolderInfo *info = NULL; - struct stat st; - - /* This is a pretty hacky version of create folder, but should basically work */ - - if (path[0] != '/') { - camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("Store root %s is not an absolute path"), path); - return NULL; - } - - if (parent_name) - name = g_strdup_printf("%s/%s/%s", path, parent_name, folder_name); - else - name = g_strdup_printf("%s/%s", path, folder_name); - - if (stat(name, &st) == 0 || errno != ENOENT) { - camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("Cannot get folder: %s: %s"), - name, g_strerror (errno)); - g_free(name); - return NULL; - } - - g_free(name); - - if (parent_name) - name = g_strdup_printf("%s/%s", parent_name, folder_name); - else - name = g_strdup_printf("%s", folder_name); - - folder = ((CamelStoreClass *)((CamelObject *)store)->klass)->get_folder(store, name, CAMEL_STORE_FOLDER_CREATE, ex); - if (folder) { - camel_object_unref((CamelObject *)folder); - info = ((CamelStoreClass *)((CamelObject *)store)->klass)->get_folder_info(store, name, 0, ex); - - /* get_folder(CREATE) will emit a folder_created event for us */ - /*if (info) - camel_object_trigger_event((CamelObject *)store, "folder_created", info);*/ - } - - g_free(name); - - return info; -} - -static int xrename(const char *oldp, const char *newp, const char *prefix, const char *suffix, int missingok, CamelException *ex) -{ - struct stat st; - char *old = g_strconcat(prefix, oldp, suffix, 0); - char *new = g_strconcat(prefix, newp, suffix, 0); - int ret = -1; - int err = 0; - - d(printf("renaming %s%s to %s%s\n", oldp, suffix, newp, suffix)); - - if (stat(old, &st) == -1) { - if (missingok && errno == ENOENT) { - ret = 0; - } else { - err = errno; - ret = -1; - } - } else if (S_ISDIR(st.st_mode)) { /* use rename for dirs */ - if (rename(old, new) == 0 - || stat(new, &st) == 0) { - ret = 0; - } else { - err = errno; - ret = -1; - } - } else if (link(old, new) == 0 /* and link for files */ - || (stat(new, &st) == 0 && st.st_nlink == 2)) { - if (unlink(old) == 0) { - ret = 0; - } else { - err = errno; - unlink(new); - ret = -1; - } - } else { - err = errno; - ret = -1; - } - - if (ret == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not rename folder %s to %s: %s"), - old, new, g_strerror (err)); - } - - g_free(old); - g_free(new); - return ret; -} - -/* default implementation, rename all */ -static void -rename_folder(CamelStore *store, const char *old, const char *new, CamelException *ex) -{ - char *path = CAMEL_LOCAL_STORE (store)->toplevel_dir; - CamelLocalFolder *folder = NULL; - char *newibex = g_strdup_printf("%s%s.ibex", path, new); - char *oldibex = g_strdup_printf("%s%s.ibex", path, old); - - /* try to rollback failures, has obvious races */ - - d(printf("local rename folder '%s' '%s'\n", old, new)); - - folder = camel_object_bag_get(store->folders, old); - if (folder && folder->index) { - if (camel_index_rename(folder->index, newibex) == -1) - goto ibex_failed; - } else { - /* TODO: camel_text_index_rename should find out if we have an active index itself? */ - if (camel_text_index_rename(oldibex, newibex) == -1) - goto ibex_failed; - } - - if (xrename(old, new, path, ".ev-summary", TRUE, ex)) - goto summary_failed; - - if (xrename(old, new, path, "", FALSE, ex)) - goto base_failed; - - g_free(newibex); - g_free(oldibex); - - if (folder) - camel_object_unref(folder); - - return; - -base_failed: - xrename(new, old, path, ".ev-summary", TRUE, ex); - -summary_failed: - if (folder) { - if (folder->index) - camel_index_rename(folder->index, oldibex); - } else - camel_text_index_rename(newibex, oldibex); -ibex_failed: - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not rename '%s': %s"), - old, g_strerror (errno)); - - g_free(newibex); - g_free(oldibex); - - if (folder) - camel_object_unref(folder); -} - -/* default implementation, only delete metadata */ -static void -delete_folder(CamelStore *store, const char *folder_name, CamelException *ex) -{ - CamelFolderInfo *fi; - CamelException lex; - CamelFolder *lf; - char *name; - char *str; - - /* remove metadata only */ - name = g_strdup_printf("%s%s", CAMEL_LOCAL_STORE(store)->toplevel_dir, folder_name); - str = g_strdup_printf("%s.ev-summary", name); - if (unlink(str) == -1 && errno != ENOENT) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not delete folder summary file `%s': %s"), - str, g_strerror (errno)); - g_free(str); - g_free (name); - return; - } - g_free(str); - str = g_strdup_printf("%s.ibex", name); - if (camel_text_index_remove(str) == -1 && errno != ENOENT) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not delete folder index file `%s': %s"), - str, g_strerror (errno)); - g_free(str); - g_free (name); - return; - } - g_free(str); - - camel_exception_init (&lex); - if ((lf = camel_store_get_folder (store, folder_name, 0, &lex))) { - camel_object_get (lf, NULL, CAMEL_OBJECT_STATE_FILE, &str, NULL); - camel_object_set (lf, NULL, CAMEL_OBJECT_STATE_FILE, NULL, NULL); - camel_object_unref (lf); - } else { - camel_exception_clear (&lex); - } - - if (str == NULL) - str = g_strdup_printf ("%s.cmeta", name); - - if (unlink (str) == -1 && errno != ENOENT) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not delete folder meta file `%s': %s"), - str, g_strerror (errno)); - g_free (name); - g_free (str); - return; - } - - g_free (str); - g_free (name); - - fi = g_new0 (CamelFolderInfo, 1); - fi->full_name = g_strdup (folder_name); - fi->name = g_path_get_basename (folder_name); - fi->url = g_strdup_printf ("%s:%s#%s", ((CamelService *) store)->url->protocol, - CAMEL_LOCAL_STORE(store)->toplevel_dir, folder_name); - fi->unread_message_count = -1; - camel_folder_info_build_path(fi, '/'); - - camel_object_trigger_event (store, "folder_deleted", fi); - - camel_folder_info_free (fi); -} diff --git a/camel/providers/local/camel-local-store.h b/camel/providers/local/camel-local-store.h deleted file mode 100644 index 21d854c562..0000000000 --- a/camel/providers/local/camel-local-store.h +++ /dev/null @@ -1,68 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-mbox-store.h : class for an mbox store */ - -/* - * - * Copyright (C) 2000 Ximian, Inc. <bertrand@helixcode.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_LOCAL_STORE_H -#define CAMEL_LOCAL_STORE_H 1 - - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus }*/ - -#include "camel-store.h" - -#define CAMEL_LOCAL_STORE_TYPE (camel_local_store_get_type ()) -#define CAMEL_LOCAL_STORE(obj) (CAMEL_CHECK_CAST((obj), CAMEL_LOCAL_STORE_TYPE, CamelLocalStore)) -#define CAMEL_LOCAL_STORE_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_LOCAL_STORE_TYPE, CamelLocalStoreClass)) -#define CAMEL_IS_LOCAL_STORE(o) (CAMEL_CHECK_TYPE((o), CAMEL_LOCAL_STORE_TYPE)) - - -typedef struct { - CamelStore parent_object; - char *toplevel_dir; - -} CamelLocalStore; - - - -typedef struct { - CamelStoreClass parent_class; - -} CamelLocalStoreClass; - - -/* public methods */ - -/* Standard Camel function */ -CamelType camel_local_store_get_type (void); - -const gchar *camel_local_store_get_toplevel_dir (CamelLocalStore *store); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CAMEL_LOCAL_STORE_H */ - - diff --git a/camel/providers/local/camel-local-summary.c b/camel/providers/local/camel-local-summary.c deleted file mode 100644 index 42534b361d..0000000000 --- a/camel/providers/local/camel-local-summary.c +++ /dev/null @@ -1,614 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*- */ -/* - * Copyright (C) 2000 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 <ctype.h> -#include <sys/stat.h> -#include <sys/uio.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <stdlib.h> - -#include "camel-local-summary.h" -#include "camel/camel-mime-message.h" -#include "camel/camel-stream-null.h" - -#define w(x) -#define io(x) -#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/ - -#define CAMEL_LOCAL_SUMMARY_VERSION (0x200) - -static CamelMessageInfo * message_info_new (CamelFolderSummary *, struct _camel_header_raw *); - -static int local_summary_decode_x_evolution(CamelLocalSummary *cls, const char *xev, CamelMessageInfo *mi); -static char *local_summary_encode_x_evolution(CamelLocalSummary *cls, const CamelMessageInfo *mi); - -static int local_summary_load(CamelLocalSummary *cls, int forceindex, CamelException *ex); -static int local_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changeinfo, CamelException *ex); -static int local_summary_sync(CamelLocalSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex); -static CamelMessageInfo *local_summary_add(CamelLocalSummary *cls, CamelMimeMessage *msg, const CamelMessageInfo *info, CamelFolderChangeInfo *, CamelException *ex); - -static void camel_local_summary_class_init (CamelLocalSummaryClass *klass); -static void camel_local_summary_init (CamelLocalSummary *obj); -static void camel_local_summary_finalise (CamelObject *obj); -static CamelFolderSummaryClass *camel_local_summary_parent; - -CamelType -camel_local_summary_get_type(void) -{ - static CamelType type = CAMEL_INVALID_TYPE; - - if (type == CAMEL_INVALID_TYPE) { - type = camel_type_register(camel_folder_summary_get_type(), "CamelLocalSummary", - sizeof (CamelLocalSummary), - sizeof (CamelLocalSummaryClass), - (CamelObjectClassInitFunc) camel_local_summary_class_init, - NULL, - (CamelObjectInitFunc) camel_local_summary_init, - (CamelObjectFinalizeFunc) camel_local_summary_finalise); - } - - return type; -} - -static void -camel_local_summary_class_init(CamelLocalSummaryClass *klass) -{ - CamelFolderSummaryClass *sklass = (CamelFolderSummaryClass *) klass; - - camel_local_summary_parent = CAMEL_FOLDER_SUMMARY_CLASS(camel_type_get_global_classfuncs(camel_folder_summary_get_type())); - - sklass->message_info_new = message_info_new; - - klass->load = local_summary_load; - klass->check = local_summary_check; - klass->sync = local_summary_sync; - klass->add = local_summary_add; - - klass->encode_x_evolution = local_summary_encode_x_evolution; - klass->decode_x_evolution = local_summary_decode_x_evolution; -} - -static void -camel_local_summary_init(CamelLocalSummary *obj) -{ - struct _CamelFolderSummary *s = (CamelFolderSummary *)obj; - - /* subclasses need to set the right instance data sizes */ - s->message_info_size = sizeof(CamelMessageInfo); - s->content_info_size = sizeof(CamelMessageContentInfo); - - /* and a unique file version */ - s->version += CAMEL_LOCAL_SUMMARY_VERSION; -} - -static void -camel_local_summary_finalise(CamelObject *obj) -{ - CamelLocalSummary *mbs = CAMEL_LOCAL_SUMMARY(obj); - - if (mbs->index) - camel_object_unref((CamelObject *)mbs->index); - g_free(mbs->folder_path); -} - -void -camel_local_summary_construct(CamelLocalSummary *new, const char *filename, const char *local_name, CamelIndex *index) -{ - camel_folder_summary_set_build_content(CAMEL_FOLDER_SUMMARY(new), FALSE); - camel_folder_summary_set_filename(CAMEL_FOLDER_SUMMARY(new), filename); - new->folder_path = g_strdup(local_name); - new->index = index; - if (index) - camel_object_ref((CamelObject *)index); -} - -static int -local_summary_load(CamelLocalSummary *cls, int forceindex, CamelException *ex) -{ - return camel_folder_summary_load((CamelFolderSummary *)cls); -} - -/* load/check the summary */ -int -camel_local_summary_load(CamelLocalSummary *cls, int forceindex, CamelException *ex) -{ - struct stat st; - CamelFolderSummary *s = (CamelFolderSummary *)cls; - - d(printf("Loading summary ...\n")); - - if (forceindex - || stat(s->summary_path, &st) == -1 - || ((CamelLocalSummaryClass *)(CAMEL_OBJECT_GET_CLASS(cls)))->load(cls, forceindex, ex) == -1) { - w(g_warning("Could not load summary: flags may be reset")); - camel_folder_summary_clear((CamelFolderSummary *)cls); - return -1; - } - - return 0; -} - -void camel_local_summary_check_force(CamelLocalSummary *cls) -{ - cls->check_force = 1; -} - -char * -camel_local_summary_encode_x_evolution(CamelLocalSummary *cls, const CamelMessageInfo *info) -{ - return ((CamelLocalSummaryClass *)(CAMEL_OBJECT_GET_CLASS(cls)))->encode_x_evolution(cls, info); -} - -int -camel_local_summary_decode_x_evolution(CamelLocalSummary *cls, const char *xev, CamelMessageInfo *info) -{ - return ((CamelLocalSummaryClass *)(CAMEL_OBJECT_GET_CLASS(cls)))->decode_x_evolution(cls, xev, info); -} - -/*#define DOSTATS*/ -#ifdef DOSTATS -struct _stat_info { - int mitotal; - int micount; - int citotal; - int cicount; - int msgid; - int msgcount; -}; - -static void -do_stat_ci(CamelLocalSummary *cls, struct _stat_info *info, CamelMessageContentInfo *ci) -{ - info->cicount++; - info->citotal += ((CamelFolderSummary *)cls)->content_info_size /*+ 4 memchunks are 1/4 byte overhead per mi */; - if (ci->id) - info->citotal += strlen(ci->id) + 4; - if (ci->description) - info->citotal += strlen(ci->description) + 4; - if (ci->encoding) - info->citotal += strlen(ci->encoding) + 4; - if (ci->type) { - CamelContentType *ct = ci->type; - struct _camel_header_param *param; - - info->citotal += sizeof(*ct) + 4; - if (ct->type) - info->citotal += strlen(ct->type) + 4; - if (ct->subtype) - info->citotal += strlen(ct->subtype) + 4; - param = ct->params; - while (param) { - info->citotal += sizeof(*param) + 4; - if (param->name) - info->citotal += strlen(param->name)+4; - if (param->value) - info->citotal += strlen(param->value)+4; - param = param->next; - } - } - ci = ci->childs; - while (ci) { - do_stat_ci(cls, info, ci); - ci = ci->next; - } -} - -static void -do_stat_mi(CamelLocalSummary *cls, struct _stat_info *info, CamelMessageInfo *mi) -{ - info->micount++; - info->mitotal += ((CamelFolderSummary *)cls)->content_info_size /*+ 4*/; - - if (mi->subject) - info->mitotal += strlen(mi->subject) + 4; - if (mi->to) - info->mitotal += strlen(mi->to) + 4; - if (mi->from) - info->mitotal += strlen(mi->from) + 4; - if (mi->cc) - info->mitotal += strlen(mi->cc) + 4; - if (mi->uid) - info->mitotal += strlen(mi->uid) + 4; - - if (mi->references) { - info->mitotal += (mi->references->size-1) * sizeof(CamelSummaryMessageID) + sizeof(CamelSummaryReferences) + 4; - info->msgid += (mi->references->size) * sizeof(CamelSummaryMessageID); - info->msgcount += mi->references->size; - } - - /* dont have any user flags yet */ - - if (mi->content) { - do_stat_ci(cls, info, mi->content); - } -} - -#endif - -int -camel_local_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changeinfo, CamelException *ex) -{ - int ret; - - ret = ((CamelLocalSummaryClass *)(CAMEL_OBJECT_GET_CLASS(cls)))->check(cls, changeinfo, ex); - -#ifdef DOSTATS - if (ret != -1) { - int i; - CamelFolderSummary *s = (CamelFolderSummary *)cls; - struct _stat_info stats = { 0 }; - - for (i=0;i<camel_folder_summary_count(s);i++) { - CamelMessageInfo *info = camel_folder_summary_index(s, i); - do_stat_mi(cls, &stats, info); - camel_folder_summary_info_free(s, info); - } - - printf("\nMemory used by summary:\n\n"); - printf("Total of %d messages\n", camel_folder_summary_count(s)); - printf("Total: %d bytes (ave %f)\n", stats.citotal + stats.mitotal, - (double)(stats.citotal+stats.mitotal)/(double)camel_folder_summary_count(s)); - printf("Message Info: %d (ave %f)\n", stats.mitotal, (double)stats.mitotal/(double)stats.micount); - printf("Content Info; %d (ave %f) count %d\n", stats.citotal, (double)stats.citotal/(double)stats.cicount, stats.cicount); - printf("message id's: %d (ave %f) count %d\n", stats.msgid, (double)stats.msgid/(double)stats.msgcount, stats.msgcount); - } -#endif - return ret; -} - -int -camel_local_summary_sync(CamelLocalSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex) -{ - return ((CamelLocalSummaryClass *)(CAMEL_OBJECT_GET_CLASS(cls)))->sync(cls, expunge, changeinfo, ex); -} - -CamelMessageInfo * -camel_local_summary_add(CamelLocalSummary *cls, CamelMimeMessage *msg, const CamelMessageInfo *info, CamelFolderChangeInfo *ci, CamelException *ex) -{ - return ((CamelLocalSummaryClass *)(CAMEL_OBJECT_GET_CLASS(cls)))->add(cls, msg, info, ci, ex); -} - -/** - * camel_local_summary_write_headers: - * @fd: - * @header: - * @xevline: - * @status: - * @xstatus: - * - * Write a bunch of headers to the file @fd. IF xevline is non NULL, then - * an X-Evolution header line is created at the end of all of the headers. - * If @status is non NULL, then a Status header line is also written. - * The headers written are termianted with a blank line. - * - * Return value: -1 on error, otherwise the number of bytes written. - **/ -int -camel_local_summary_write_headers(int fd, struct _camel_header_raw *header, const char *xevline, const char *status, const char *xstatus) -{ - int outlen = 0, len; - int newfd; - FILE *out; - - /* dum de dum, maybe the whole sync function should just use stdio for output */ - newfd = dup(fd); - if (newfd == -1) - return -1; - - out = fdopen(newfd, "w"); - if (out == NULL) { - close(newfd); - errno = EINVAL; - return -1; - } - - while (header) { - if (strcmp(header->name, "X-Evolution") != 0 - && (status == NULL || strcmp(header->name, "Status") != 0) - && (xstatus == NULL || strcmp(header->name, "X-Status") != 0)) { - len = fprintf(out, "%s:%s\n", header->name, header->value); - if (len == -1) { - fclose(out); - return -1; - } - outlen += len; - } - header = header->next; - } - - if (status) { - len = fprintf(out, "Status: %s\n", status); - if (len == -1) { - fclose(out); - return -1; - } - outlen += len; - } - - if (xstatus) { - len = fprintf(out, "X-Status: %s\n", xstatus); - if (len == -1) { - fclose(out); - return -1; - } - outlen += len; - } - - if (xevline) { - len = fprintf(out, "X-Evolution: %s\n", xevline); - if (len == -1) { - fclose(out); - return -1; - } - outlen += len; - } - - len = fprintf(out, "\n"); - if (len == -1) { - fclose(out); - return -1; - } - outlen += len; - - if (fclose(out) == -1) - return -1; - - return outlen; -} - -static int -local_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changeinfo, CamelException *ex) -{ - /* FIXME: sync index here ? */ - return 0; -} - -static int -local_summary_sync(CamelLocalSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex) -{ - int ret = 0; - - ret = camel_folder_summary_save((CamelFolderSummary *)cls); - if (ret == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not save summary: %s: %s"), - cls->folder_path, g_strerror (errno)); - - g_warning ("Could not save summary for %s: %s", cls->folder_path, strerror (errno)); - } - - if (cls->index && camel_index_sync(cls->index) == -1) - g_warning ("Could not sync index for %s: %s", cls->folder_path, strerror (errno)); - - return ret; -} - -static CamelMessageInfo * -local_summary_add(CamelLocalSummary *cls, CamelMimeMessage *msg, const CamelMessageInfo *info, CamelFolderChangeInfo *ci, CamelException *ex) -{ - CamelMessageInfo *mi; - char *xev; - - d(printf("Adding message to summary\n")); - - mi = camel_folder_summary_add_from_message((CamelFolderSummary *)cls, msg); - if (mi) { - d(printf("Added, uid = %s\n", mi->uid)); - if (info) { - CamelTag *tag = info->user_tags; - CamelFlag *flag = info->user_flags; - - while (flag) { - camel_flag_set(&mi->user_flags, flag->name, TRUE); - flag = flag->next; - } - - while (tag) { - camel_tag_set(&mi->user_tags, tag->name, tag->value); - tag = tag->next; - } - - mi->flags = mi->flags | (info->flags & 0xffff); - if (info->size) - mi->size = info->size; - } - - /* we need to calculate the size ourselves */ - if (mi->size == 0) { - CamelStreamNull *sn = (CamelStreamNull *)camel_stream_null_new(); - - camel_data_wrapper_write_to_stream((CamelDataWrapper *)msg, (CamelStream *)sn); - mi->size = sn->written; - camel_object_unref((CamelObject *)sn); - } - - mi->flags &= ~(CAMEL_MESSAGE_FOLDER_NOXEV|CAMEL_MESSAGE_FOLDER_FLAGGED); - xev = camel_local_summary_encode_x_evolution(cls, mi); - camel_medium_set_header((CamelMedium *)msg, "X-Evolution", xev); - g_free(xev); - camel_folder_change_info_add_uid(ci, camel_message_info_uid(mi)); - } else { - d(printf("Failed!\n")); - camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, - _("Unable to add message to summary: unknown reason")); - } - return mi; -} - -static char * -local_summary_encode_x_evolution(CamelLocalSummary *cls, const CamelMessageInfo *mi) -{ - GString *out = g_string_new(""); - struct _camel_header_param *params = NULL; - GString *val = g_string_new(""); - CamelFlag *flag = mi->user_flags; - CamelTag *tag = mi->user_tags; - char *ret; - const char *p, *uidstr; - guint32 uid; - - /* FIXME: work out what to do with uid's that aren't stored here? */ - /* FIXME: perhaps make that a mbox folder only issue?? */ - p = uidstr = camel_message_info_uid(mi); - while (*p && isdigit(*p)) - p++; - if (*p == 0 && sscanf (uidstr, "%u", &uid) == 1) { - g_string_printf (out, "%08x-%04x", uid, mi->flags & 0xffff); - } else { - g_string_printf (out, "%s-%04x", uidstr, mi->flags & 0xffff); - } - - if (flag || tag) { - val = g_string_new (""); - - if (flag) { - while (flag) { - g_string_append (val, flag->name); - if (flag->next) - g_string_append_c (val, ','); - flag = flag->next; - } - camel_header_set_param (¶ms, "flags", val->str); - g_string_truncate (val, 0); - } - if (tag) { - while (tag) { - g_string_append (val, tag->name); - g_string_append_c (val, '='); - g_string_append (val, tag->value); - if (tag->next) - g_string_append_c (val, ','); - tag = tag->next; - } - camel_header_set_param (¶ms, "tags", val->str); - } - g_string_free (val, TRUE); - camel_header_param_list_format_append (out, params); - camel_header_param_list_free (params); - } - ret = out->str; - g_string_free (out, FALSE); - - return ret; -} - -static int -local_summary_decode_x_evolution(CamelLocalSummary *cls, const char *xev, CamelMessageInfo *mi) -{ - struct _camel_header_param *params, *scan; - guint32 uid, flags; - char *header; - int i; - - /* check for uid/flags */ - header = camel_header_token_decode(xev); - if (header && strlen(header) == strlen("00000000-0000") - && sscanf(header, "%08x-%04x", &uid, &flags) == 2) { - char uidstr[20]; - if (mi) { - sprintf(uidstr, "%u", uid); - camel_message_info_set_uid(mi, g_strdup(uidstr)); - mi->flags = flags; - } - } else { - g_free(header); - return -1; - } - g_free(header); - - if (mi == NULL) - return 0; - - /* check for additional data */ - header = strchr(xev, ';'); - if (header) { - params = camel_header_param_list_decode(header+1); - scan = params; - while (scan) { - if (!strcasecmp(scan->name, "flags")) { - char **flagv = g_strsplit(scan->value, ",", 1000); - - for (i=0;flagv[i];i++) { - camel_flag_set(&mi->user_flags, flagv[i], TRUE); - } - g_strfreev(flagv); - } else if (!strcasecmp(scan->name, "tags")) { - char **tagv = g_strsplit(scan->value, ",", 10000); - char *val; - - for (i=0;tagv[i];i++) { - val = strchr(tagv[i], '='); - if (val) { - *val++ = 0; - camel_tag_set(&mi->user_tags, tagv[i], val); - val[-1]='='; - } - } - g_strfreev(tagv); - } - scan = scan->next; - } - camel_header_param_list_free(params); - } - return 0; -} - -static CamelMessageInfo * -message_info_new(CamelFolderSummary *s, struct _camel_header_raw *h) -{ - CamelMessageInfo *mi; - CamelLocalSummary *cls = (CamelLocalSummary *)s; - - mi = ((CamelFolderSummaryClass *)camel_local_summary_parent)->message_info_new(s, h); - if (mi) { - const char *xev; - int doindex = FALSE; - - xev = camel_header_raw_find(&h, "X-Evolution", NULL); - if (xev==NULL || camel_local_summary_decode_x_evolution(cls, xev, mi) == -1) { - /* to indicate it has no xev header */ - mi->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED | CAMEL_MESSAGE_FOLDER_NOXEV; - camel_message_info_set_uid(mi, camel_folder_summary_next_uid_string(s)); - - /* shortcut, no need to look it up in the index library */ - doindex = TRUE; - } - - if (cls->index - && (doindex - || cls->index_force - || !camel_index_has_name(cls->index, camel_message_info_uid(mi)))) { - d(printf("Am indexing message %s\n", camel_message_info_uid(mi))); - camel_folder_summary_set_index(s, cls->index); - } else { - d(printf("Not indexing message %s\n", camel_message_info_uid(mi))); - camel_folder_summary_set_index(s, NULL); - } - } - - return mi; -} diff --git a/camel/providers/local/camel-local-summary.h b/camel/providers/local/camel-local-summary.h deleted file mode 100644 index 25d77e62c3..0000000000 --- a/camel/providers/local/camel-local-summary.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2000 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_LOCAL_SUMMARY_H -#define _CAMEL_LOCAL_SUMMARY_H - -#include <camel/camel-folder-summary.h> -#include <camel/camel-folder.h> -#include <camel/camel-exception.h> -#include <camel/camel-index.h> - -#define CAMEL_LOCAL_SUMMARY(obj) CAMEL_CHECK_CAST (obj, camel_local_summary_get_type (), CamelLocalSummary) -#define CAMEL_LOCAL_SUMMARY_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_local_summary_get_type (), CamelLocalSummaryClass) -#define CAMEL_IS_LOCAL_SUMMARY(obj) CAMEL_CHECK_TYPE (obj, camel_local_summary_get_type ()) - -typedef struct _CamelLocalSummary CamelLocalSummary; -typedef struct _CamelLocalSummaryClass CamelLocalSummaryClass; - -/* extra summary flags */ -enum { - CAMEL_MESSAGE_FOLDER_NOXEV = 1<<17, - CAMEL_MESSAGE_FOLDER_XEVCHANGE = 1<<18, - CAMEL_MESSAGE_FOLDER_NOTSEEN = 1<<19, /* have we seen this in processing this loop? */ -}; - -struct _CamelLocalSummary { - CamelFolderSummary parent; - - char *folder_path; /* name of matching folder */ - - CamelIndex *index; - unsigned int index_force:1; /* do we force index during creation? */ - unsigned int check_force:1; /* does a check force a full check? */ -}; - -struct _CamelLocalSummaryClass { - CamelFolderSummaryClass parent_class; - - int (*load)(CamelLocalSummary *cls, int forceindex, CamelException *ex); - int (*check)(CamelLocalSummary *cls, CamelFolderChangeInfo *changeinfo, CamelException *ex); - int (*sync)(CamelLocalSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex); - CamelMessageInfo *(*add)(CamelLocalSummary *cls, CamelMimeMessage *msg, const CamelMessageInfo *info, CamelFolderChangeInfo *, CamelException *ex); - - char *(*encode_x_evolution)(CamelLocalSummary *cls, const CamelMessageInfo *info); - int (*decode_x_evolution)(CamelLocalSummary *cls, const char *xev, CamelMessageInfo *info); -}; - -CamelType camel_local_summary_get_type (void); -void camel_local_summary_construct (CamelLocalSummary *new, const char *filename, const char *local_name, CamelIndex *index); - -/* load/check the summary */ -int camel_local_summary_load(CamelLocalSummary *cls, int forceindex, CamelException *ex); -/* check for new/removed messages */ -int camel_local_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *, CamelException *ex); -/* perform a folder sync or expunge, if needed */ -int camel_local_summary_sync(CamelLocalSummary *cls, gboolean expunge, CamelFolderChangeInfo *, CamelException *ex); -/* add a new message to the summary */ -CamelMessageInfo *camel_local_summary_add(CamelLocalSummary *cls, CamelMimeMessage *msg, const CamelMessageInfo *info, CamelFolderChangeInfo *, CamelException *ex); - -/* force the next check to be a full check/rebuild */ -void camel_local_summary_check_force(CamelLocalSummary *cls); - -/* generate an X-Evolution header line */ -char *camel_local_summary_encode_x_evolution(CamelLocalSummary *cls, const CamelMessageInfo *info); -int camel_local_summary_decode_x_evolution(CamelLocalSummary *cls, const char *xev, CamelMessageInfo *info); - -/* utility functions - write headers to a file with optional X-Evolution header and/or status header */ -int camel_local_summary_write_headers(int fd, struct _camel_header_raw *header, const char *xevline, const char *status, const char *xstatus); - -#endif /* ! _CAMEL_LOCAL_SUMMARY_H */ - diff --git a/camel/providers/local/camel-maildir-folder.c b/camel/providers/local/camel-maildir-folder.c deleted file mode 100644 index eca07efbef..0000000000 --- a/camel/providers/local/camel-maildir-folder.c +++ /dev/null @@ -1,245 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*- - * - * Authors: Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 1999, 2003 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 "camel-maildir-folder.h" -#include "camel-maildir-store.h" -#include "camel-stream-fs.h" -#include "camel-maildir-summary.h" -#include "camel-data-wrapper.h" -#include "camel-mime-message.h" -#include "camel-exception.h" - -#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/ - -static CamelLocalFolderClass *parent_class = NULL; - -/* Returns the class for a CamelMaildirFolder */ -#define CMAILDIRF_CLASS(so) CAMEL_MAILDIR_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -#define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -#define CMAILDIRS_CLASS(so) CAMEL_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so)) - -static CamelLocalSummary *maildir_create_summary(const char *path, const char *folder, CamelIndex *index); - -static void maildir_append_message(CamelFolder * folder, CamelMimeMessage * message, const CamelMessageInfo *info, char **appended_uid, CamelException * ex); -static CamelMimeMessage *maildir_get_message(CamelFolder * folder, const gchar * uid, CamelException * ex); - -static void maildir_finalize(CamelObject * object); - -static void camel_maildir_folder_class_init(CamelObjectClass * camel_maildir_folder_class) -{ - CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS(camel_maildir_folder_class); - CamelLocalFolderClass *lclass = (CamelLocalFolderClass *)camel_maildir_folder_class; - - parent_class = CAMEL_LOCAL_FOLDER_CLASS (camel_type_get_global_classfuncs(camel_local_folder_get_type())); - - /* virtual method definition */ - - /* virtual method overload */ - camel_folder_class->append_message = maildir_append_message; - camel_folder_class->get_message = maildir_get_message; - - lclass->create_summary = maildir_create_summary; -} - -static void maildir_init(gpointer object, gpointer klass) -{ - /*CamelFolder *folder = object; - CamelMaildirFolder *maildir_folder = object;*/ -} - -static void maildir_finalize(CamelObject * object) -{ - /*CamelMaildirFolder *maildir_folder = CAMEL_MAILDIR_FOLDER(object);*/ -} - -CamelType camel_maildir_folder_get_type(void) -{ - static CamelType camel_maildir_folder_type = CAMEL_INVALID_TYPE; - - if (camel_maildir_folder_type == CAMEL_INVALID_TYPE) { - camel_maildir_folder_type = camel_type_register(CAMEL_LOCAL_FOLDER_TYPE, "CamelMaildirFolder", - sizeof(CamelMaildirFolder), - sizeof(CamelMaildirFolderClass), - (CamelObjectClassInitFunc) camel_maildir_folder_class_init, - NULL, - (CamelObjectInitFunc) maildir_init, - (CamelObjectFinalizeFunc) maildir_finalize); - } - - return camel_maildir_folder_type; -} - -CamelFolder * -camel_maildir_folder_new(CamelStore *parent_store, const char *full_name, guint32 flags, CamelException *ex) -{ - CamelFolder *folder; - - d(printf("Creating maildir folder: %s\n", full_name)); - - folder = (CamelFolder *)camel_object_new(CAMEL_MAILDIR_FOLDER_TYPE); - - if (parent_store->flags & CAMEL_STORE_FILTER_INBOX - && strcmp(full_name, ".") == 0) - folder->folder_flags |= CAMEL_FOLDER_FILTER_RECENT; - - folder = (CamelFolder *)camel_local_folder_construct((CamelLocalFolder *)folder, - parent_store, full_name, flags, ex); - - return folder; -} - -static CamelLocalSummary *maildir_create_summary(const char *path, const char *folder, CamelIndex *index) -{ - return (CamelLocalSummary *)camel_maildir_summary_new(path, folder, index); -} - -static void -maildir_append_message (CamelFolder *folder, CamelMimeMessage *message, const CamelMessageInfo *info, char **appended_uid, CamelException *ex) -{ - CamelMaildirFolder *maildir_folder = (CamelMaildirFolder *)folder; - CamelLocalFolder *lf = (CamelLocalFolder *)folder; - CamelStream *output_stream; - CamelMessageInfo *mi; - CamelMaildirMessageInfo *mdi; - char *name, *dest = NULL; - - d(printf("Appending message\n")); - - /* add it to the summary/assign the uid, etc */ - mi = camel_local_summary_add((CamelLocalSummary *)folder->summary, message, info, lf->changes, ex); - if (camel_exception_is_set (ex)) - return; - - mdi = (CamelMaildirMessageInfo *)mi; - - d(printf("Appending message: uid is %s filename is %s\n", camel_message_info_uid(mi), mdi->filename)); - - /* write it out to tmp, use the uid we got from the summary */ - name = g_strdup_printf ("%s/tmp/%s", lf->folder_path, camel_message_info_uid(mi)); - output_stream = camel_stream_fs_new_with_name (name, O_WRONLY|O_CREAT, 0600); - if (output_stream == NULL) - goto fail_write; - - if (camel_data_wrapper_write_to_stream ((CamelDataWrapper *)message, output_stream) == -1 - || camel_stream_close (output_stream) == -1) - goto fail_write; - - /* now move from tmp to cur (bypass new, does it matter?) */ - dest = g_strdup_printf("%s/cur/%s", lf->folder_path, camel_maildir_info_filename (mdi)); - if (rename (name, dest) == 1) - goto fail_write; - - g_free (dest); - g_free (name); - - camel_object_trigger_event (CAMEL_OBJECT (folder), "folder_changed", - ((CamelLocalFolder *)maildir_folder)->changes); - camel_folder_change_info_clear (((CamelLocalFolder *)maildir_folder)->changes); - - if (appended_uid) - *appended_uid = g_strdup(camel_message_info_uid(mi)); - - return; - - fail_write: - - /* remove the summary info so we are not out-of-sync with the mh folder */ - camel_folder_summary_remove_uid (CAMEL_FOLDER_SUMMARY (folder->summary), - camel_message_info_uid (mi)); - - if (errno == EINTR) - camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, - _("Maildir append message cancelled")); - else - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot append message to maildir folder: %s: %s"), - name, g_strerror (errno)); - - if (output_stream) { - camel_object_unref (CAMEL_OBJECT (output_stream)); - unlink (name); - } - - g_free (name); - g_free (dest); -} - -static CamelMimeMessage *maildir_get_message(CamelFolder * folder, const gchar * uid, CamelException * ex) -{ - CamelLocalFolder *lf = (CamelLocalFolder *)folder; - CamelStream *message_stream = NULL; - CamelMimeMessage *message = NULL; - CamelMessageInfo *info; - char *name; - CamelMaildirMessageInfo *mdi; - - d(printf("getting message: %s\n", uid)); - - /* get the message summary info */ - if ((info = camel_folder_summary_uid(folder->summary, uid)) == NULL) { - camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID, _("Cannot get message: %s\n %s"), uid, _("No such message")); - return NULL; - } - - mdi = (CamelMaildirMessageInfo *)info; - - /* what do we do if the message flags (and :info data) changes? filename mismatch - need to recheck I guess */ - name = g_strdup_printf("%s/cur/%s", lf->folder_path, camel_maildir_info_filename(mdi)); - - camel_folder_summary_info_free(folder->summary, info); - - if ((message_stream = camel_stream_fs_new_with_name(name, O_RDONLY, 0)) == NULL) { - camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID, - _("Cannot get message: %s\n %s"), - name, g_strerror (errno)); - g_free(name); - return NULL; - } - - message = camel_mime_message_new(); - if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)message, message_stream) == -1) { - camel_exception_setv(ex, (errno==EINTR)?CAMEL_EXCEPTION_USER_CANCEL:CAMEL_EXCEPTION_FOLDER_INVALID_UID, - _("Cannot get message: %s\n %s"), - name, _("Invalid message contents")); - g_free(name); - camel_object_unref((CamelObject *)message_stream); - camel_object_unref((CamelObject *)message); - return NULL; - - } - camel_object_unref((CamelObject *)message_stream); - g_free(name); - - return message; -} diff --git a/camel/providers/local/camel-maildir-folder.h b/camel/providers/local/camel-maildir-folder.h deleted file mode 100644 index c495d9b14d..0000000000 --- a/camel/providers/local/camel-maildir-folder.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Authors: - * Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 1999 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_MAILDIR_FOLDER_H -#define CAMEL_MAILDIR_FOLDER_H 1 - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus } */ -#include "camel-local-folder.h" - -#define CAMEL_MAILDIR_FOLDER_TYPE (camel_maildir_folder_get_type ()) -#define CAMEL_MAILDIR_FOLDER(obj) (CAMEL_CHECK_CAST((obj), CAMEL_MAILDIR_FOLDER_TYPE, CamelMaildirFolder)) -#define CAMEL_MAILDIR_FOLDER_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_MAILDIR_FOLDER_TYPE, CamelMaildirFolderClass)) -#define CAMEL_IS_MAILDIR_FOLDER(o) (CAMEL_CHECK_TYPE((o), CAMEL_MAILDIR_FOLDER_TYPE)) - -typedef struct { - CamelLocalFolder parent_object; - -} CamelMaildirFolder; - -typedef struct { - CamelLocalFolderClass parent_class; - - /* Virtual methods */ - -} CamelMaildirFolderClass; - -/* public methods */ -CamelFolder *camel_maildir_folder_new(CamelStore *parent_store, const char *full_name, guint32 flags, CamelException *ex); - -/* Standard Camel function */ -CamelType camel_maildir_folder_get_type(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* CAMEL_MAILDIR_FOLDER_H */ diff --git a/camel/providers/local/camel-maildir-store.c b/camel/providers/local/camel-maildir-store.c deleted file mode 100644 index c84c37158c..0000000000 --- a/camel/providers/local/camel-maildir-store.c +++ /dev/null @@ -1,416 +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> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <sys/types.h> -#include <sys/stat.h> -#include <errno.h> -#include <string.h> -#include <unistd.h> - -#include <dirent.h> - -#include "camel-maildir-store.h" -#include "camel-maildir-folder.h" -#include "camel-exception.h" -#include "camel-url.h" -#include "camel-private.h" - -#define d(x) - -static CamelLocalStoreClass *parent_class = NULL; - -/* Returns the class for a CamelMaildirStore */ -#define CMAILDIRS_CLASS(so) CAMEL_MAILDIR_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -#define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -#define CMAILDIRF_CLASS(so) CAMEL_MAILDIR_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) - -static CamelFolder *get_folder(CamelStore * store, const char *folder_name, guint32 flags, CamelException * ex); -static CamelFolder *get_inbox (CamelStore *store, CamelException *ex); -static void delete_folder(CamelStore * store, const char *folder_name, CamelException * ex); - -static CamelFolderInfo * get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex); - -static void camel_maildir_store_class_init(CamelObjectClass * camel_maildir_store_class) -{ - CamelStoreClass *camel_store_class = CAMEL_STORE_CLASS(camel_maildir_store_class); - /*CamelServiceClass *camel_service_class = CAMEL_SERVICE_CLASS(camel_maildir_store_class);*/ - - parent_class = (CamelLocalStoreClass *)camel_type_get_global_classfuncs(camel_local_store_get_type()); - - /* virtual method overload, use defaults for most */ - camel_store_class->get_folder = get_folder; - camel_store_class->get_inbox = get_inbox; - camel_store_class->delete_folder = delete_folder; - - camel_store_class->get_folder_info = get_folder_info; - camel_store_class->free_folder_info = camel_store_free_folder_info_full; -} - -CamelType camel_maildir_store_get_type(void) -{ - static CamelType camel_maildir_store_type = CAMEL_INVALID_TYPE; - - if (camel_maildir_store_type == CAMEL_INVALID_TYPE) { - camel_maildir_store_type = camel_type_register(CAMEL_LOCAL_STORE_TYPE, "CamelMaildirStore", - sizeof(CamelMaildirStore), - sizeof(CamelMaildirStoreClass), - (CamelObjectClassInitFunc) camel_maildir_store_class_init, - NULL, - NULL, - NULL); - } - - return camel_maildir_store_type; -} - -static CamelFolder * -get_folder(CamelStore * store, const char *folder_name, guint32 flags, CamelException * ex) -{ - char *name, *tmp, *cur, *new; - struct stat st; - CamelFolder *folder = NULL; - - if (!((CamelStoreClass *)parent_class)->get_folder(store, folder_name, flags, ex)) - return NULL; - - name = g_strdup_printf("%s%s", CAMEL_LOCAL_STORE(store)->toplevel_dir, folder_name); - tmp = g_strdup_printf("%s/tmp", name); - cur = g_strdup_printf("%s/cur", name); - new = g_strdup_printf("%s/new", name); - - if (stat(name, &st) == -1) { - if (errno != ENOENT) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not open folder `%s':\n%s"), - folder_name, g_strerror (errno)); - } else if ((flags & CAMEL_STORE_FOLDER_CREATE) == 0) { - camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("Folder `%s' does not exist."), folder_name); - } else { - if (mkdir(name, 0700) != 0 - || mkdir(tmp, 0700) != 0 - || mkdir(cur, 0700) != 0 - || mkdir(new, 0700) != 0) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not create folder `%s':\n%s"), - folder_name, g_strerror (errno)); - rmdir(tmp); - rmdir(cur); - rmdir(new); - rmdir(name); - } else { - folder = camel_maildir_folder_new(store, folder_name, flags, ex); - } - } - } else if (!S_ISDIR(st.st_mode) - || stat(tmp, &st) != 0 || !S_ISDIR(st.st_mode) - || stat(cur, &st) != 0 || !S_ISDIR(st.st_mode) - || stat(new, &st) != 0 || !S_ISDIR(st.st_mode)) { - camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("`%s' is not a maildir directory."), name); - } else { - folder = camel_maildir_folder_new(store, folder_name, flags, ex); - } - - g_free(name); - g_free(tmp); - g_free(cur); - g_free(new); - - return folder; -} - -static CamelFolder * -get_inbox (CamelStore *store, CamelException *ex) -{ - return get_folder (store, ".", 0, ex); -} - -static void delete_folder(CamelStore * store, const char *folder_name, CamelException * ex) -{ - char *name, *tmp, *cur, *new; - struct stat st; - - name = g_strdup_printf("%s%s", CAMEL_LOCAL_STORE(store)->toplevel_dir, folder_name); - - tmp = g_strdup_printf("%s/tmp", name); - cur = g_strdup_printf("%s/cur", name); - new = g_strdup_printf("%s/new", name); - - if (stat(name, &st) == -1 || !S_ISDIR(st.st_mode) - || stat(tmp, &st) == -1 || !S_ISDIR(st.st_mode) - || stat(cur, &st) == -1 || !S_ISDIR(st.st_mode) - || stat(new, &st) == -1 || !S_ISDIR(st.st_mode)) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not delete folder `%s': %s"), - folder_name, errno ? g_strerror (errno) : - _("not a maildir directory")); - } else { - int err = 0; - - /* remove subdirs first - will fail if not empty */ - if (rmdir(cur) == -1 || rmdir(new) == -1) { - err = errno; - } else { - DIR *dir; - struct dirent *d; - - /* for tmp (only), its contents is irrelevant */ - dir = opendir(tmp); - if (dir) { - while ( (d=readdir(dir)) ) { - char *name = d->d_name, *file; - - if (!strcmp(name, ".") || !strcmp(name, "..")) - continue; - file = g_strdup_printf("%s/%s", tmp, name); - unlink(file); - g_free(file); - } - closedir(dir); - } - if (rmdir(tmp) == -1 || rmdir(name) == -1) - err = errno; - } - - if (err != 0) { - /* easier just to mkdir all (and let them fail), than remember what we got to */ - mkdir(name, 0700); - mkdir(cur, 0700); - mkdir(new, 0700); - mkdir(tmp, 0700); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not delete folder `%s': %s"), - folder_name, g_strerror (err)); - } else { - /* and remove metadata */ - ((CamelStoreClass *)parent_class)->delete_folder(store, folder_name, ex); - } - } - - g_free(name); - g_free(tmp); - g_free(cur); - g_free(new); -} - -static CamelFolderInfo *camel_folder_info_new(const char *url, const char *full, const char *name, int unread) -{ - CamelFolderInfo *fi; - - fi = g_malloc0(sizeof(*fi)); - fi->url = g_strdup(url); - fi->full_name = g_strdup(full); - fi->name = g_strdup(name); - fi->unread_message_count = unread; - camel_folder_info_build_path(fi, '/'); - - d(printf("Adding maildir info: '%s' '%s' '%s' '%s'\n", fi->path, fi->name, fi->full_name, fi->url)); - - return fi; -} - -/* used to find out where we've visited already */ -struct _inode { - dev_t dnode; - ino_t inode; -}; - -/* returns number of records found at or below this level */ -static int scan_dir(CamelStore *store, GHashTable *visited, char *root, const char *path, guint32 flags, CamelFolderInfo *parent, CamelFolderInfo **fip, CamelException *ex) -{ - DIR *dir; - struct dirent *d; - char *name, *uri, *tmp, *cur, *new; - const char *base; - CamelFolderInfo *fi = NULL; - struct stat st; - CamelFolder *folder; - int unread; - - /* look for folders matching the right structure, recursively */ - name = g_strdup_printf("%s/%s", root, path); - - d(printf("checking dir '%s' part '%s' for maildir content\n", root, path)); - - tmp = g_strdup_printf("%s/tmp", name); - cur = g_strdup_printf("%s/cur", name); - new = g_strdup_printf("%s/new", name); - - if (stat(tmp, &st) == 0 && S_ISDIR(st.st_mode) - && stat(cur, &st) == 0 && S_ISDIR(st.st_mode) - && stat(new, &st) == 0 && S_ISDIR(st.st_mode)) { - uri = g_strdup_printf("maildir:%s#%s", root, path); - } else - uri = g_strdup_printf("maildir:%s;noselect=yes#%s", root, path); - - base = strrchr(path, '/'); - if (base) - base++; - else - base = path; - - /* if we have this folder open, get the real unread count */ - folder = camel_object_bag_get(store->folders, path); - if (folder) { - if ((flags & CAMEL_STORE_FOLDER_INFO_FAST) == 0) - camel_folder_refresh_info(folder, NULL); - unread = camel_folder_get_unread_message_count(folder); - camel_object_unref(folder); - } else { - unread = -1; - } - - /* if we dont have a folder, then scan the directory and get the unread - count from there, which is reasonably cheap (on decent filesystem) */ - /* Well we could get this from the summary, but this is more accurate */ - if (folder == NULL - && (flags & CAMEL_STORE_FOLDER_INFO_FAST) == 0) { - unread = 0; - dir = opendir(new); - if (dir) { - /* we assume that all files here are unread ones */ - while ( (d = readdir(dir)) ) { - if (d->d_name[0] != '.') - unread++; - } - closedir(dir); - } - dir = opendir(cur); - if (dir) { - /* any files with flags but not the 'S' (seen) flag are unread */ - while ( (d = readdir(dir)) ) { - char *p = strstr(d->d_name, ":2,"); - - if (p && strchr(p, 'S') == NULL) - unread++; - } - closedir(dir); - } - } - - fi = camel_folder_info_new(uri, path, base, unread); - - d(printf("found! uri = %s\n", fi->url)); - d(printf(" full_name = %s\n name = '%s'\n", fi->full_name, fi->name)); - - fi->parent = parent; - fi->sibling = *fip; - *fip = fi; - g_free(uri); - - g_free(tmp); - g_free(cur); - g_free(new); - - unread = 0; - - /* always look further if asked */ - if (((flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE) || parent == NULL)) { - dir = opendir(name); - if (dir == NULL) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not scan folder `%s': %s"), - root, g_strerror (errno)); - g_free(name); - return -1; - } - - while ( (d = readdir(dir)) ) { - if (strcmp(d->d_name, "tmp") == 0 - || strcmp(d->d_name, "cur") == 0 - || strcmp(d->d_name, "new") == 0 - || strcmp(d->d_name, ".") == 0 - || strcmp(d->d_name, "..") == 0) - continue; - - tmp = g_strdup_printf("%s/%s", name, d->d_name); - if (stat(tmp, &st) == 0 && S_ISDIR(st.st_mode)) { - struct _inode in = { st.st_dev, st.st_ino }; - - /* see if we've visited already */ - if (g_hash_table_lookup(visited, &in) == NULL) { - struct _inode *inew = g_malloc(sizeof(*inew)); - - *inew = in; - g_hash_table_insert(visited, inew, inew); - new = g_strdup_printf("%s/%s", path, d->d_name); - if (scan_dir(store, visited, root, new, flags, fi, &fi->child, ex) == -1) { - g_free(tmp); - g_free(new); - closedir(dir); - return -1; - } - g_free(new); - } - } - g_free(tmp); - } - closedir(dir); - } - - g_free(name); - - return 0; -} - -static guint inode_hash(const void *d) -{ - const struct _inode *v = d; - - return v->inode ^ v->dnode; -} - -static gboolean inode_equal(const void *a, const void *b) -{ - const struct _inode *v1 = a, *v2 = b; - - return v1->inode == v2->inode && v1->dnode == v2->dnode; -} - -static void inode_free(void *k, void *v, void *d) -{ - g_free(k); -} - -static CamelFolderInfo * -get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex) -{ - CamelFolderInfo *fi = NULL; - CamelLocalStore *local_store = (CamelLocalStore *)store; - GHashTable *visited; - - visited = g_hash_table_new(inode_hash, inode_equal); - - if (scan_dir(store, visited, ((CamelService *)local_store)->url->path, top?top:".", flags, NULL, &fi, ex) == -1 && fi != NULL) { - camel_store_free_folder_info_full(store, fi); - fi = NULL; - } - - g_hash_table_foreach(visited, inode_free, NULL); - g_hash_table_destroy(visited); - - return fi; -} diff --git a/camel/providers/local/camel-maildir-store.h b/camel/providers/local/camel-maildir-store.h deleted file mode 100644 index f7725bc189..0000000000 --- a/camel/providers/local/camel-maildir-store.h +++ /dev/null @@ -1,55 +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> - * - * 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_MAILDIR_STORE_H -#define CAMEL_MAILDIR_STORE_H 1 - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus } */ - -#include "camel-local-store.h" - -#define CAMEL_MAILDIR_STORE_TYPE (camel_maildir_store_get_type ()) -#define CAMEL_MAILDIR_STORE(obj) (CAMEL_CHECK_CAST((obj), CAMEL_MAILDIR_STORE_TYPE, CamelMaildirStore)) -#define CAMEL_MAILDIR_STORE_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_MAILDIR_STORE_TYPE, CamelMaildirStoreClass)) -#define CAMEL_IS_MAILDIR_STORE(o) (CAMEL_CHECK_TYPE((o), CAMEL_MAILDIR_STORE_TYPE)) - -typedef struct { - CamelLocalStore parent_object; - -} CamelMaildirStore; - -typedef struct { - CamelLocalStoreClass parent_class; - -} CamelMaildirStoreClass; - -/* public methods */ - -/* Standard Camel function */ -CamelType camel_maildir_store_get_type(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* CAMEL_MAILDIR_STORE_H */ diff --git a/camel/providers/local/camel-maildir-summary.c b/camel/providers/local/camel-maildir-summary.c deleted file mode 100644 index 37e1ac2ce7..0000000000 --- a/camel/providers/local/camel-maildir-summary.c +++ /dev/null @@ -1,807 +0,0 @@ -/* - * Copyright (C) 2000 Ximian Inc. - * - * Authors: Not Zed <notzed@lostzed.mmc.com.au> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/uio.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <stdlib.h> - -#include <sys/types.h> -#include <dirent.h> - -#include <ctype.h> - -#include "camel-maildir-summary.h" -#include <camel/camel-mime-message.h> -#include <camel/camel-operation.h> - -#include "camel-private.h" -#include "e-util/e-memory.h" - -#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/ - -#define CAMEL_MAILDIR_SUMMARY_VERSION (0x2000) - -static CamelMessageInfo *message_info_load(CamelFolderSummary *s, FILE *in); -static CamelMessageInfo *message_info_new(CamelFolderSummary *, struct _camel_header_raw *); -static void message_info_free(CamelFolderSummary *, CamelMessageInfo *mi); - -static int maildir_summary_load(CamelLocalSummary *cls, int forceindex, CamelException *ex); -static int maildir_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changeinfo, CamelException *ex); -static int maildir_summary_sync(CamelLocalSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex); -static CamelMessageInfo *maildir_summary_add(CamelLocalSummary *cls, CamelMimeMessage *msg, const CamelMessageInfo *info, CamelFolderChangeInfo *, CamelException *ex); - -static char *maildir_summary_next_uid_string(CamelFolderSummary *s); -static int maildir_summary_decode_x_evolution(CamelLocalSummary *cls, const char *xev, CamelMessageInfo *mi); -static char *maildir_summary_encode_x_evolution(CamelLocalSummary *cls, const CamelMessageInfo *mi); - -static void camel_maildir_summary_class_init (CamelMaildirSummaryClass *class); -static void camel_maildir_summary_init (CamelMaildirSummary *gspaper); -static void camel_maildir_summary_finalise (CamelObject *obj); - -#define _PRIVATE(x) (((CamelMaildirSummary *)(x))->priv) - -struct _CamelMaildirSummaryPrivate { - char *current_file; - char *hostname; - - GHashTable *load_map; -}; - -static CamelLocalSummaryClass *parent_class; - -CamelType -camel_maildir_summary_get_type (void) -{ - static CamelType type = CAMEL_INVALID_TYPE; - - if (type == CAMEL_INVALID_TYPE) { - type = camel_type_register(camel_local_summary_get_type (), "CamelMaildirSummary", - sizeof(CamelMaildirSummary), - sizeof(CamelMaildirSummaryClass), - (CamelObjectClassInitFunc)camel_maildir_summary_class_init, - NULL, - (CamelObjectInitFunc)camel_maildir_summary_init, - (CamelObjectFinalizeFunc)camel_maildir_summary_finalise); - } - - return type; -} - -static void -camel_maildir_summary_class_init (CamelMaildirSummaryClass *class) -{ - CamelFolderSummaryClass *sklass = (CamelFolderSummaryClass *) class; - CamelLocalSummaryClass *lklass = (CamelLocalSummaryClass *)class; - - parent_class = (CamelLocalSummaryClass *)camel_type_get_global_classfuncs(camel_local_summary_get_type ()); - - /* override methods */ - sklass->message_info_load = message_info_load; - sklass->message_info_new = message_info_new; - sklass->message_info_free = message_info_free; - sklass->next_uid_string = maildir_summary_next_uid_string; - - lklass->load = maildir_summary_load; - lklass->check = maildir_summary_check; - lklass->sync = maildir_summary_sync; - lklass->add = maildir_summary_add; - lklass->encode_x_evolution = maildir_summary_encode_x_evolution; - lklass->decode_x_evolution = maildir_summary_decode_x_evolution; -} - -static void -camel_maildir_summary_init (CamelMaildirSummary *o) -{ - struct _CamelFolderSummary *s = (CamelFolderSummary *) o; - char hostname[256]; - - o->priv = g_malloc0(sizeof(*o->priv)); - /* set unique file version */ - s->version += CAMEL_MAILDIR_SUMMARY_VERSION; - - s->message_info_size = sizeof(CamelMaildirMessageInfo); - s->content_info_size = sizeof(CamelMaildirMessageContentInfo); - -#if defined (DOEPOOLV) || defined (DOESTRV) - s->message_info_strings = CAMEL_MAILDIR_INFO_LAST; -#endif - - if (gethostname(hostname, 256) == 0) { - o->priv->hostname = g_strdup(hostname); - } else { - o->priv->hostname = g_strdup("localhost"); - } -} - -static void -camel_maildir_summary_finalise(CamelObject *obj) -{ - CamelMaildirSummary *o = (CamelMaildirSummary *)obj; - - g_free(o->priv->hostname); - g_free(o->priv); -} - -/** - * camel_maildir_summary_new: - * - * Create a new CamelMaildirSummary object. - * - * Return value: A new #CamelMaildirSummary object. - **/ -CamelMaildirSummary *camel_maildir_summary_new (const char *filename, const char *maildirdir, CamelIndex *index) -{ - CamelMaildirSummary *o = (CamelMaildirSummary *)camel_object_new(camel_maildir_summary_get_type ()); - - camel_local_summary_construct((CamelLocalSummary *)o, filename, maildirdir, index); - return o; -} - -/* the 'standard' maildir flags. should be defined in sorted order. */ -static struct { - char flag; - guint32 flagbit; -} flagbits[] = { - { 'F', CAMEL_MESSAGE_FLAGGED }, - { 'R', CAMEL_MESSAGE_ANSWERED }, - { 'S', CAMEL_MESSAGE_SEEN }, - { 'T', CAMEL_MESSAGE_DELETED }, -}; - -/* convert the uid + flags into a unique:info maildir format */ -char *camel_maildir_summary_info_to_name(const CamelMessageInfo *info) -{ - const char *uid; - char *p, *buf; - int i; - - uid = camel_message_info_uid (info); - buf = g_alloca (strlen (uid) + strlen (":2,") + (sizeof (flagbits) / sizeof (flagbits[0])) + 1); - p = buf + sprintf (buf, "%s:2,", uid); - for (i = 0; i < sizeof (flagbits) / sizeof (flagbits[0]); i++) { - if (info->flags & flagbits[i].flagbit) - *p++ = flagbits[i].flag; - } - *p = 0; - - return g_strdup(buf); -} - -/* returns 0 if the info matches (or there was none), otherwise we changed it */ -int camel_maildir_summary_name_to_info(CamelMessageInfo *info, const char *name) -{ - char *p, c; - guint32 set = 0; /* what we set */ - /*guint32 all = 0;*/ /* all flags */ - int i; - - p = strstr(name, ":2,"); - if (p) { - p+=3; - while ((c = *p++)) { - /* we could assume that the flags are in order, but its just as easy not to require */ - for (i=0;i<sizeof(flagbits)/sizeof(flagbits[0]);i++) { - if (flagbits[i].flag == c && (info->flags & flagbits[i].flagbit) == 0) { - set |= flagbits[i].flagbit; - } - /*all |= flagbits[i].flagbit;*/ - } - } - - /* changed? */ - /*if ((info->flags & all) != set) {*/ - if ((info->flags & set) != set) { - /* ok, they did change, only add the new flags ('merge flags'?) */ - /*info->flags &= all; if we wanted to set only the new flags, which we probably dont */ - info->flags |= set; - return 1; - } - } - - return 0; -} - -/* for maildir, x-evolution isn't used, so dont try and get anything out of it */ -static int maildir_summary_decode_x_evolution(CamelLocalSummary *cls, const char *xev, CamelMessageInfo *mi) -{ - return -1; -} - -static char *maildir_summary_encode_x_evolution(CamelLocalSummary *cls, const CamelMessageInfo *mi) -{ - return NULL; -} - -/* FIXME: - both 'new' and 'add' will try and set the filename, this is not ideal ... -*/ -static CamelMessageInfo *maildir_summary_add(CamelLocalSummary *cls, CamelMimeMessage *msg, const CamelMessageInfo *info, CamelFolderChangeInfo *changes, CamelException *ex) -{ - CamelMessageInfo *mi; - - mi = ((CamelLocalSummaryClass *) parent_class)->add(cls, msg, info, changes, ex); - if (mi) { - if (info) { - camel_maildir_info_set_filename(mi, camel_maildir_summary_info_to_name(mi)); - d(printf("Setting filename to %s\n", camel_maildir_info_filename(mi))); - } - } - - return mi; -} - -static CamelMessageInfo *message_info_new(CamelFolderSummary * s, struct _camel_header_raw *h) -{ - CamelMessageInfo *mi, *info; - CamelMaildirSummary *mds = (CamelMaildirSummary *)s; - CamelMaildirMessageInfo *mdi; - const char *uid; - - mi = ((CamelFolderSummaryClass *) parent_class)->message_info_new(s, h); - /* assign the uid and new filename */ - if (mi) { - mdi = (CamelMaildirMessageInfo *)mi; - - uid = camel_message_info_uid(mi); - if (uid==NULL || uid[0] == 0) - camel_message_info_set_uid(mi, camel_folder_summary_next_uid_string(s)); - - /* handle 'duplicates' */ - info = camel_folder_summary_uid(s, uid); - if (info) { - d(printf("already seen uid '%s', just summarising instead\n", uid)); - camel_folder_summary_info_free(s, mi); - mdi = (CamelMaildirMessageInfo *)mi = info; - } - - /* with maildir we know the real received date, from the filename */ - mi->date_received = strtoul(camel_message_info_uid(mi), NULL, 10); - - if (mds->priv->current_file) { -#if 0 - char *p1, *p2, *p3; - unsigned long uid; -#endif - /* if setting from a file, grab the flags from it */ - camel_maildir_info_set_filename(mi, g_strdup(mds->priv->current_file)); - camel_maildir_summary_name_to_info(mi, mds->priv->current_file); - -#if 0 - /* Actually, I dont think all this effort is worth it at all ... */ - - /* also, see if we can extract the next-id from tne name, and safe-if-fy ourselves against collisions */ - /* we check for something.something_number.something */ - p1 = strchr(mdi->filename, '.'); - if (p1) { - p2 = strchr(p1+1, '.'); - p3 = strchr(p1+1, '_'); - if (p2 && p3 && p3<p2) { - uid = strtoul(p3+1, &p1, 10); - if (p1 == p2 && uid>0) - camel_folder_summary_set_uid(s, uid); - } - } -#endif - } else { - /* if creating a file, set its name from the flags we have */ - camel_maildir_info_set_filename(mdi, camel_maildir_summary_info_to_name(mi)); - d(printf("Setting filename to %s\n", camel_maildir_info_filename(mi))); - } - } - - return mi; -} - - -static void message_info_free(CamelFolderSummary *s, CamelMessageInfo *mi) -{ -#if !defined (DOEPOOLV) && !defined (DOESTRV) - CamelMaildirMessageInfo *mdi = (CamelMaildirMessageInfo *)mi; - - g_free(mdi->filename); -#endif - ((CamelFolderSummaryClass *) parent_class)->message_info_free(s, mi); -} - - -static char *maildir_summary_next_uid_string(CamelFolderSummary *s) -{ - CamelMaildirSummary *mds = (CamelMaildirSummary *)s; - - d(printf("next uid string called?\n")); - - /* if we have a current file, then use that to get the uid */ - if (mds->priv->current_file) { - char *cln; - - cln = strchr(mds->priv->current_file, ':'); - if (cln) - return g_strndup(mds->priv->current_file, cln-mds->priv->current_file); - else - return g_strdup(mds->priv->current_file); - } else { - /* the first would probably work, but just to be safe, check for collisions */ -#if 0 - return g_strdup_printf("%ld.%d_%u.%s", time(0), getpid(), camel_folder_summary_next_uid(s), mds->priv->hostname); -#else - CamelLocalSummary *cls = (CamelLocalSummary *)s; - char *name = NULL, *uid = NULL; - struct stat st; - int retry = 0; - guint32 nextuid = camel_folder_summary_next_uid(s); - - /* we use time.pid_count.hostname */ - do { - if (retry > 0) { - g_free(name); - g_free(uid); - sleep(2); - } - uid = g_strdup_printf("%ld.%d_%u.%s", time(0), getpid(), nextuid, mds->priv->hostname); - name = g_strdup_printf("%s/tmp/%s", cls->folder_path, uid); - retry++; - } while (stat(name, &st) == 0 && retry<3); - - /* I dont know what we're supposed to do if it fails to find a unique name?? */ - - g_free(name); - return uid; -#endif - } -} - -static CamelMessageInfo * -message_info_load(CamelFolderSummary *s, FILE *in) -{ - CamelMessageInfo *mi; - CamelMaildirSummary *mds = (CamelMaildirSummary *)s; - - mi = ((CamelFolderSummaryClass *) parent_class)->message_info_load(s, in); - if (mi) { - char *name; - - if (mds->priv->load_map - && (name = g_hash_table_lookup(mds->priv->load_map, camel_message_info_uid(mi)))) { - d(printf("Setting filename of %s to %s\n", camel_message_info_uid(mi), name)); - camel_maildir_info_set_filename(mi, g_strdup(name)); - camel_maildir_summary_name_to_info(mi, name); - } - } - - return mi; -} - -static int maildir_summary_load(CamelLocalSummary *cls, int forceindex, CamelException *ex) -{ - char *cur; - DIR *dir; - struct dirent *d; - CamelMaildirSummary *mds = (CamelMaildirSummary *)cls; - char *uid; - EMemPool *pool; - int ret; - - cur = g_strdup_printf("%s/cur", cls->folder_path); - - d(printf("pre-loading uid <> filename map\n")); - - dir = opendir(cur); - if (dir == NULL) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot open maildir directory path: %s: %s"), - cls->folder_path, g_strerror (errno)); - g_free(cur); - return -1; - } - - mds->priv->load_map = g_hash_table_new(g_str_hash, g_str_equal); - pool = e_mempool_new(1024, 512, E_MEMPOOL_ALIGN_BYTE); - - while ( (d = readdir(dir)) ) { - if (d->d_name[0] == '.') - continue; - - /* map the filename -> uid */ - uid = strchr(d->d_name, ':'); - if (uid) { - int len = uid-d->d_name; - uid = e_mempool_alloc(pool, len+1); - memcpy(uid, d->d_name, len); - uid[len] = 0; - g_hash_table_insert(mds->priv->load_map, uid, e_mempool_strdup(pool, d->d_name)); - } else { - uid = e_mempool_strdup(pool, d->d_name); - g_hash_table_insert(mds->priv->load_map, uid, uid); - } - } - closedir(dir); - g_free(cur); - - ret = ((CamelLocalSummaryClass *) parent_class)->load(cls, forceindex, ex); - - g_hash_table_destroy(mds->priv->load_map); - mds->priv->load_map = NULL; - e_mempool_destroy(pool); - - return ret; -} - -static int camel_maildir_summary_add(CamelLocalSummary *cls, const char *name, int forceindex) -{ - CamelMaildirSummary *maildirs = (CamelMaildirSummary *)cls; - char *filename = g_strdup_printf("%s/cur/%s", cls->folder_path, name); - int fd; - CamelMimeParser *mp; - - d(printf("summarising: %s\n", name)); - - fd = open(filename, O_RDONLY); - if (fd == -1) { - g_warning ("Cannot summarise/index: %s: %s", filename, strerror (errno)); - g_free(filename); - return -1; - } - mp = camel_mime_parser_new(); - camel_mime_parser_scan_from(mp, FALSE); - camel_mime_parser_init_with_fd(mp, fd); - if (cls->index && (forceindex || !camel_index_has_name(cls->index, name))) { - d(printf("forcing indexing of message content\n")); - camel_folder_summary_set_index((CamelFolderSummary *)maildirs, cls->index); - } else { - camel_folder_summary_set_index((CamelFolderSummary *)maildirs, NULL); - } - maildirs->priv->current_file = (char *)name; - camel_folder_summary_add_from_parser((CamelFolderSummary *)maildirs, mp); - camel_object_unref((CamelObject *)mp); - maildirs->priv->current_file = NULL; - camel_folder_summary_set_index((CamelFolderSummary *)maildirs, NULL); - g_free(filename); - return 0; -} - -struct _remove_data { - CamelLocalSummary *cls; - CamelFolderChangeInfo *changes; -}; - -static void -remove_summary(char *key, CamelMessageInfo *info, struct _remove_data *rd) -{ - d(printf("removing message %s from summary\n", key)); - if (rd->cls->index) - camel_index_delete_name(rd->cls->index, camel_message_info_uid(info)); - if (rd->changes) - camel_folder_change_info_remove_uid(rd->changes, key); - camel_folder_summary_remove((CamelFolderSummary *)rd->cls, info); - camel_folder_summary_info_free((CamelFolderSummary *)rd->cls, info); -} - -static int -sort_receive_cmp(const void *ap, const void *bp) -{ - const CamelMessageInfo - *a = *((CamelMessageInfo **)ap), - *b = *((CamelMessageInfo **)bp); - - if (a->date_received < b->date_received) - return -1; - else if (a->date_received > b->date_received) - return 1; - - return 0; -} - -static int -maildir_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changes, CamelException *ex) -{ - DIR *dir; - struct dirent *d; - char *p; - CamelMessageInfo *info; - CamelMaildirMessageInfo *mdi; - CamelFolderSummary *s = (CamelFolderSummary *)cls; - GHashTable *left; - int i, count, total; - int forceindex; - char *new, *cur; - char *uid; - struct _remove_data rd = { cls, changes }; - - new = g_strdup_printf("%s/new", cls->folder_path); - cur = g_strdup_printf("%s/cur", cls->folder_path); - - d(printf("checking summary ...\n")); - - camel_operation_start(NULL, _("Checking folder consistency")); - - /* scan the directory, check for mail files not in the index, or index entries that - no longer exist */ - dir = opendir(cur); - if (dir == NULL) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot open maildir directory path: %s: %s"), - cls->folder_path, g_strerror (errno)); - g_free(cur); - g_free(new); - camel_operation_end(NULL); - return -1; - } - - /* keeps track of all uid's that have not been processed */ - left = g_hash_table_new(g_str_hash, g_str_equal); - count = camel_folder_summary_count((CamelFolderSummary *)cls); - forceindex = count == 0; - for (i=0;i<count;i++) { - info = camel_folder_summary_index((CamelFolderSummary *)cls, i); - if (info) { - g_hash_table_insert(left, (char *)camel_message_info_uid(info), info); - } - } - - /* joy, use this to pre-count the total, so we can report progress meaningfully */ - total = 0; - count = 0; - while ( (d = readdir(dir)) ) - total++; - rewinddir(dir); - - while ( (d = readdir(dir)) ) { - int pc = count * 100 / total; - - camel_operation_progress(NULL, pc); - count++; - - /* FIXME: also run stat to check for regular file */ - p = d->d_name; - if (p[0] == '.') - continue; - - /* map the filename -> uid */ - uid = strchr(d->d_name, ':'); - if (uid) - uid = g_strndup(d->d_name, uid-d->d_name); - else - uid = g_strdup(d->d_name); - - info = g_hash_table_lookup(left, uid); - if (info) { - camel_folder_summary_info_free((CamelFolderSummary *)cls, info); - g_hash_table_remove(left, uid); - } - - info = camel_folder_summary_uid((CamelFolderSummary *)cls, uid); - if (info == NULL) { - /* must be a message incorporated by another client, this is not a 'recent' uid */ - if (camel_maildir_summary_add(cls, d->d_name, forceindex) == 0) - if (changes) - camel_folder_change_info_add_uid(changes, uid); - } else { - const char *filename; - - if (cls->index && (!camel_index_has_name(cls->index, uid))) { - /* message_info_new will handle duplicates */ - camel_maildir_summary_add(cls, d->d_name, forceindex); - } - - mdi = (CamelMaildirMessageInfo *)info; - filename = camel_maildir_info_filename(mdi); - /* TODO: only store the extension in the mdi->filename struct, not the whole lot */ - if (filename == NULL || strcmp(filename, d->d_name) != 0) { -#ifdef DOESTRV -#warning "cannot modify the estrv after its been setup, for mt-safe code" - CAMEL_SUMMARY_LOCK(s, summary_lock); - /* need to update the summary hash ref */ - g_hash_table_remove(s->messages_uid, camel_message_info_uid(info)); - info->strings = e_strv_set_ref(info->strings, CAMEL_MAILDIR_INFO_FILENAME, d->d_name); - info->strings = e_strv_pack(info->strings); - g_hash_table_insert(s->messages_uid, (char *)camel_message_info_uid(info), info); - CAMEL_SUMMARY_UNLOCK(s, summary_lock); -#else -# ifdef DOEPOOLV - info->strings = e_poolv_set(info->strings, CAMEL_MAILDIR_INFO_FILENAME, d->d_name, FALSE); -# else - g_free(mdi->filename); - mdi->filename = g_strdup(d->d_name); -# endif -#endif - } - camel_folder_summary_info_free((CamelFolderSummary *)cls, info); - } - g_free(uid); - } - closedir(dir); - g_hash_table_foreach(left, (GHFunc)remove_summary, &rd); - g_hash_table_destroy(left); - - camel_operation_end(NULL); - - camel_operation_start(NULL, _("Checking for new messages")); - - /* now, scan new for new messages, and copy them to cur, and so forth */ - dir = opendir(new); - if (dir != NULL) { - total = 0; - count = 0; - while ( (d = readdir(dir)) ) - total++; - rewinddir(dir); - - while ( (d = readdir(dir)) ) { - char *name, *newname, *destname, *destfilename; - char *src, *dest; - int pc = count * 100 / total; - - camel_operation_progress(NULL, pc); - count++; - - name = d->d_name; - if (name[0] == '.') - continue; - - /* already in summary? shouldn't happen, but just incase ... */ - if ((info = camel_folder_summary_uid((CamelFolderSummary *)cls, name))) { - camel_folder_summary_info_free((CamelFolderSummary *)cls, info); - newname = destname = camel_folder_summary_next_uid_string(s); - } else { - newname = NULL; - destname = name; - } - - /* copy this to the destination folder, use 'standard' semantics for maildir info field */ - src = g_strdup_printf("%s/%s", new, name); - destfilename = g_strdup_printf("%s:2,", destname); - dest = g_strdup_printf("%s/%s", cur, destfilename); - - /* FIXME: This should probably use link/unlink */ - - if (rename(src, dest) == 0) { - camel_maildir_summary_add(cls, destfilename, forceindex); - if (changes) { - camel_folder_change_info_add_uid(changes, destname); - camel_folder_change_info_recent_uid(changes, destname); - } - } else { - /* else? we should probably care about failures, but wont */ - g_warning("Failed to move new maildir message %s to cur %s", src, dest); - } - - /* c strings are painful to work with ... */ - g_free(destfilename); - g_free(newname); - g_free(src); - g_free(dest); - } - camel_operation_end(NULL); - } - closedir(dir); - - g_free(new); - g_free(cur); - - /* sort the summary based on receive time, since the directory order is not useful */ - CAMEL_SUMMARY_LOCK(s, summary_lock); - qsort(s->messages->pdata, s->messages->len, sizeof(CamelMessageInfo *), sort_receive_cmp); - CAMEL_SUMMARY_UNLOCK(s, summary_lock); - - return 0; -} - -/* sync the summary with the ondisk files. */ -static int -maildir_summary_sync(CamelLocalSummary *cls, gboolean expunge, CamelFolderChangeInfo *changes, CamelException *ex) -{ - int count, i; - CamelMessageInfo *info; - CamelMaildirMessageInfo *mdi; -#ifdef DOESTRV - CamelFolderSummary *s = (CamelFolderSummary *)cls; -#endif - char *name; - struct stat st; - - d(printf("summary_sync(expunge=%s)\n", expunge?"true":"false")); - - if (camel_local_summary_check(cls, changes, ex) == -1) - return -1; - - camel_operation_start(NULL, _("Storing folder")); - - count = camel_folder_summary_count((CamelFolderSummary *)cls); - for (i=count-1;i>=0;i--) { - camel_operation_progress(NULL, (count-i)*100/count); - - info = camel_folder_summary_index((CamelFolderSummary *)cls, i); - mdi = (CamelMaildirMessageInfo *)info; - if (info && (info->flags & CAMEL_MESSAGE_DELETED) && expunge) { - name = g_strdup_printf("%s/cur/%s", cls->folder_path, camel_maildir_info_filename(mdi)); - d(printf("deleting %s\n", name)); - if (unlink(name) == 0 || errno==ENOENT) { - - /* FIXME: put this in folder_summary::remove()? */ - if (cls->index) - camel_index_delete_name(cls->index, camel_message_info_uid(info)); - - camel_folder_change_info_remove_uid(changes, camel_message_info_uid(info)); - camel_folder_summary_remove((CamelFolderSummary *)cls, info); - } - g_free(name); - } else if (info && (info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED)) { - char *newname = camel_maildir_summary_info_to_name(info); - char *dest; - - /* do we care about additional metainfo stored inside the message? */ - /* probably should all go in the filename? */ - - /* have our flags/ i.e. name changed? */ - if (strcmp(newname, camel_maildir_info_filename(mdi))) { - name = g_strdup_printf("%s/cur/%s", cls->folder_path, camel_maildir_info_filename(mdi)); - dest = g_strdup_printf("%s/cur/%s", cls->folder_path, newname); - rename(name, dest); - if (stat(dest, &st) == -1) { - /* we'll assume it didn't work, but dont change anything else */ - g_free(newname); - } else { - /* TODO: If this is made mt-safe, then this code could be a problem, since - the estrv is being modified. - Sigh, this may mean the maildir name has to be cached another way */ -#ifdef DOESTRV -#warning "cannot modify the estrv after its been setup, for mt-safe code" - CAMEL_SUMMARY_LOCK(s, summary_lock); - /* need to update the summary hash ref */ - g_hash_table_remove(s->messages_uid, camel_message_info_uid(info)); - info->strings = e_strv_set_ref_free(info->strings, CAMEL_MAILDIR_INFO_FILENAME, newname); - info->strings = e_strv_pack(info->strings); - g_hash_table_insert(s->messages_uid, (char *)camel_message_info_uid(info), info); - CAMEL_SUMMARY_UNLOCK(s, summary_lock); -#else -# ifdef DOEPOOLV - info->strings = e_poolv_set(info->strings, CAMEL_MAILDIR_INFO_FILENAME, newname, TRUE); -# else - g_free(mdi->filename); - mdi->filename = newname; -# endif -#endif - } - g_free(name); - g_free(dest); - } else { - g_free(newname); - } - - /* strip FOLDER_MESSAGE_FLAGED, etc */ - info->flags &= 0xffff; - } - camel_folder_summary_info_free((CamelFolderSummary *)cls, info); - } - - camel_operation_end(NULL); - - return ((CamelLocalSummaryClass *)parent_class)->sync(cls, expunge, changes, ex); -} - diff --git a/camel/providers/local/camel-maildir-summary.h b/camel/providers/local/camel-maildir-summary.h deleted file mode 100644 index 0cae785c6c..0000000000 --- a/camel/providers/local/camel-maildir-summary.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2000 Ximian Inc. - * - * Authors: Not Zed <notzed@lostzed.mmc.com.au> - * - * 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_MAILDIR_SUMMARY_H -#define _CAMEL_MAILDIR_SUMMARY_H - -#include "camel-local-summary.h" -#include <camel/camel-folder.h> -#include <camel/camel-exception.h> -#include <camel/camel-index.h> - -#define CAMEL_MAILDIR_SUMMARY(obj) CAMEL_CHECK_CAST (obj, camel_maildir_summary_get_type (), CamelMaildirSummary) -#define CAMEL_MAILDIR_SUMMARY_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_maildir_summary_get_type (), CamelMaildirSummaryClass) -#define CAMEL_IS_MAILDIR_SUMMARY(obj) CAMEL_CHECK_TYPE (obj, camel_maildir_summary_get_type ()) - -typedef struct _CamelMaildirSummary CamelMaildirSummary; -typedef struct _CamelMaildirSummaryClass CamelMaildirSummaryClass; - -typedef struct _CamelMaildirMessageContentInfo { - CamelMessageContentInfo info; -} CamelMaildirMessageContentInfo; - -#if defined (DOEPOOLV) || defined (DOESTRV) -enum { - CAMEL_MAILDIR_INFO_FILENAME = CAMEL_MESSAGE_INFO_LAST, - CAMEL_MAILDIR_INFO_LAST, -}; -#endif - -typedef struct _CamelMaildirMessageInfo { - CamelMessageInfo info; - -#if !defined (DOEPOOLV) && !defined (DOESTRV) - char *filename; /* maildir has this annoying status shit on the end of the filename, use this to get the real message id */ -#endif -} CamelMaildirMessageInfo; - -struct _CamelMaildirSummary { - CamelLocalSummary parent; - struct _CamelMaildirSummaryPrivate *priv; -}; - -struct _CamelMaildirSummaryClass { - CamelLocalSummaryClass parent_class; - - /* virtual methods */ - - /* signals */ -}; - -CamelType camel_maildir_summary_get_type (void); -CamelMaildirSummary *camel_maildir_summary_new (const char *filename, const char *maildirdir, CamelIndex *index); - -/* convert some info->flags to/from the messageinfo */ -char *camel_maildir_summary_info_to_name(const CamelMessageInfo *info); -int camel_maildir_summary_name_to_info(CamelMessageInfo *info, const char *name); - -#if defined (DOEPOOLV) || defined (DOESTRV) -#define camel_maildir_info_filename(x) camel_message_info_string((const CamelMessageInfo *)(x), CAMEL_MAILDIR_INFO_FILENAME) -#define camel_maildir_info_set_filename(x, s) camel_message_info_set_string((CamelMessageInfo *)(x), CAMEL_MAILDIR_INFO_FILENAME, s) -#else -#define camel_maildir_info_filename(x) (((CamelMaildirMessageInfo *)x)->filename) -#define camel_maildir_info_set_filename(x, s) (g_free(((CamelMaildirMessageInfo *)x)->filename),((CamelMaildirMessageInfo *)x)->filename = s) -#endif - -#endif /* ! _CAMEL_MAILDIR_SUMMARY_H */ - diff --git a/camel/providers/local/camel-mbox-folder.c b/camel/providers/local/camel-mbox-folder.c deleted file mode 100644 index 9c3a7036f2..0000000000 --- a/camel/providers/local/camel-mbox-folder.c +++ /dev/null @@ -1,549 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*- - * - * Authors: Michael Zucchi <notzed@ximian.com> - * Jeffrey Stedfast <fejj@ximian.com> - * - * Copyright (C) 1999, 2003 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 "camel-mbox-folder.h" -#include "camel-mbox-store.h" -#include "camel-stream-fs.h" -#include "camel-mbox-summary.h" -#include "camel-data-wrapper.h" -#include "camel-mime-message.h" -#include "camel-stream-filter.h" -#include "camel-mime-filter-from.h" -#include "camel-exception.h" - -#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/ - -static CamelLocalFolderClass *parent_class = NULL; - -/* Returns the class for a CamelMboxFolder */ -#define CMBOXF_CLASS(so) CAMEL_MBOX_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -#define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -#define CMBOXS_CLASS(so) CAMEL_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so)) - -char *camel_mbox_folder_get_full_path (const char *toplevel_dir, const char *full_name); -char *camel_mbox_folder_get_meta_path (const char *toplevel_dir, const char *full_name, const char *ext); - -static int mbox_lock(CamelLocalFolder *lf, CamelLockType type, CamelException *ex); -static void mbox_unlock(CamelLocalFolder *lf); - -#ifdef STATUS_PINE -static void mbox_set_message_flags(CamelFolder *folder, const char *uid, guint32 flags, guint32 set); -#endif - -static void mbox_set_message_user_flag(CamelFolder *folder, const char *uid, const char *name, gboolean value); -static void mbox_set_message_user_tag(CamelFolder *folder, const char *uid, const char *name, const char *value); - -static void mbox_append_message(CamelFolder *folder, CamelMimeMessage * message, const CamelMessageInfo * info, char **appended_uid, CamelException *ex); -static CamelMimeMessage *mbox_get_message(CamelFolder *folder, const gchar * uid, CamelException *ex); -static CamelLocalSummary *mbox_create_summary(const char *path, const char *folder, CamelIndex *index); - -static void mbox_finalise(CamelObject * object); - -static void -camel_mbox_folder_class_init(CamelMboxFolderClass * camel_mbox_folder_class) -{ - CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS(camel_mbox_folder_class); - CamelLocalFolderClass *lclass = (CamelLocalFolderClass *)camel_mbox_folder_class; - - parent_class = (CamelLocalFolderClass *)camel_type_get_global_classfuncs(camel_local_folder_get_type()); - - /* virtual method definition */ - - /* virtual method overload */ - camel_folder_class->append_message = mbox_append_message; - camel_folder_class->get_message = mbox_get_message; - -#ifdef STATUS_PINE - camel_folder_class->set_message_flags = mbox_set_message_flags; -#endif - camel_folder_class->set_message_user_flag = mbox_set_message_user_flag; - camel_folder_class->set_message_user_tag = mbox_set_message_user_tag; - - lclass->get_full_path = camel_mbox_folder_get_full_path; - lclass->get_meta_path = camel_mbox_folder_get_meta_path; - lclass->create_summary = mbox_create_summary; - lclass->lock = mbox_lock; - lclass->unlock = mbox_unlock; -} - -static void -mbox_init(gpointer object, gpointer klass) -{ - /*CamelFolder *folder = object;*/ - CamelMboxFolder *mbox_folder = object; - - mbox_folder->lockfd = -1; -} - -static void -mbox_finalise(CamelObject * object) -{ - CamelMboxFolder *mbox_folder = (CamelMboxFolder *)object; - - g_assert(mbox_folder->lockfd == -1); -} - -CamelType camel_mbox_folder_get_type(void) -{ - static CamelType camel_mbox_folder_type = CAMEL_INVALID_TYPE; - - if (camel_mbox_folder_type == CAMEL_INVALID_TYPE) { - camel_mbox_folder_type = camel_type_register(CAMEL_LOCAL_FOLDER_TYPE, "CamelMboxFolder", - sizeof(CamelMboxFolder), - sizeof(CamelMboxFolderClass), - (CamelObjectClassInitFunc) camel_mbox_folder_class_init, - NULL, - (CamelObjectInitFunc) mbox_init, - (CamelObjectFinalizeFunc) mbox_finalise); - } - - return camel_mbox_folder_type; -} - -CamelFolder * -camel_mbox_folder_new(CamelStore *parent_store, const char *full_name, guint32 flags, CamelException *ex) -{ - CamelFolder *folder; - - d(printf("Creating mbox folder: %s in %s\n", full_name, camel_local_store_get_toplevel_dir((CamelLocalStore *)parent_store))); - - folder = (CamelFolder *)camel_object_new(CAMEL_MBOX_FOLDER_TYPE); - folder = (CamelFolder *)camel_local_folder_construct((CamelLocalFolder *)folder, - parent_store, full_name, flags, ex); - - return folder; -} - -char * -camel_mbox_folder_get_full_path (const char *toplevel_dir, const char *full_name) -{ - const char *inptr = full_name; - int subdirs = 0; - char *path, *p; - - while (*inptr != '\0') { - if (*inptr == '/') - subdirs++; - inptr++; - } - - path = g_malloc (strlen (toplevel_dir) + (inptr - full_name) + (4 * subdirs) + 1); - p = g_stpcpy (path, toplevel_dir); - - inptr = full_name; - while (*inptr != '\0') { - while (*inptr != '/' && *inptr != '\0') - *p++ = *inptr++; - - if (*inptr == '/') { - p = g_stpcpy (p, ".sbd/"); - inptr++; - - /* strip extranaeous '/'s */ - while (*inptr == '/') - inptr++; - } - } - - *p = '\0'; - - return path; -} - -char * -camel_mbox_folder_get_meta_path (const char *toplevel_dir, const char *full_name, const char *ext) -{ -/*#define USE_HIDDEN_META_FILES*/ -#ifdef USE_HIDDEN_META_FILES - char *name, *slash; - - name = g_alloca (strlen (full_name) + strlen (ext) + 2); - if ((slash = strrchr (full_name, '/'))) - sprintf (name, "%.*s.%s%s", slash - full_name + 1, full_name, slash + 1, ext); - else - sprintf (name, ".%s%s", full_name, ext); - - return camel_mbox_folder_get_full_path (toplevel_dir, name); -#else - char *full_path, *path; - - full_path = camel_mbox_folder_get_full_path (toplevel_dir, full_name); - path = g_strdup_printf ("%s%s", full_path, ext); - g_free (full_path); - - return path; -#endif -} - -static CamelLocalSummary *mbox_create_summary(const char *path, const char *folder, CamelIndex *index) -{ - return (CamelLocalSummary *)camel_mbox_summary_new(path, folder, index); -} - -static int mbox_lock(CamelLocalFolder *lf, CamelLockType type, CamelException *ex) -{ - CamelMboxFolder *mf = (CamelMboxFolder *)lf; - - /* make sure we have matching unlocks for locks, camel-local-folder class should enforce this */ - g_assert(mf->lockfd == -1); - - mf->lockfd = open(lf->folder_path, O_RDWR, 0); - if (mf->lockfd == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot create folder lock on %s: %s"), - lf->folder_path, g_strerror (errno)); - return -1; - } - - if (camel_lock_folder(lf->folder_path, mf->lockfd, type, ex) == -1) { - close(mf->lockfd); - mf->lockfd = -1; - return -1; - } - - return 0; -} - -static void mbox_unlock(CamelLocalFolder *lf) -{ - CamelMboxFolder *mf = (CamelMboxFolder *)lf; - - g_assert(mf->lockfd != -1); - camel_unlock_folder(lf->folder_path, mf->lockfd); - close(mf->lockfd); - mf->lockfd = -1; -} - -static void -mbox_append_message(CamelFolder *folder, CamelMimeMessage * message, const CamelMessageInfo * info, char **appended_uid, CamelException *ex) -{ - CamelLocalFolder *lf = (CamelLocalFolder *)folder; - CamelStream *output_stream = NULL, *filter_stream = NULL; - CamelMimeFilter *filter_from = NULL; - CamelMboxSummary *mbs = (CamelMboxSummary *)folder->summary; - CamelMessageInfo *mi; - char *fromline = NULL; - int fd, retval; - struct stat st; -#if 0 - char *xev; -#endif - /* If we can't lock, dont do anything */ - if (camel_local_folder_lock(lf, CAMEL_LOCK_WRITE, ex) == -1) - return; - - d(printf("Appending message\n")); - - /* first, check the summary is correct (updates folder_size too) */ - retval = camel_local_summary_check ((CamelLocalSummary *)folder->summary, lf->changes, ex); - if (retval == -1) - goto fail; - - /* add it to the summary/assign the uid, etc */ - mi = camel_local_summary_add((CamelLocalSummary *)folder->summary, message, info, lf->changes, ex); - if (mi == NULL) - goto fail; - - d(printf("Appending message: uid is %s\n", camel_message_info_uid(mi))); - - output_stream = camel_stream_fs_new_with_name(lf->folder_path, O_WRONLY|O_APPEND, 0600); - if (output_stream == NULL) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot open mailbox: %s: %s\n"), - lf->folder_path, g_strerror (errno)); - goto fail; - } - - /* and we need to set the frompos/XEV explicitly */ - ((CamelMboxMessageInfo *)mi)->frompos = mbs->folder_size; -#if 0 - xev = camel_local_summary_encode_x_evolution((CamelLocalSummary *)folder->summary, mi); - if (xev) { - /* the x-ev header should match the 'current' flags, no problem, so store as much */ - camel_medium_set_header((CamelMedium *)message, "X-Evolution", xev); - mi->flags &= ~ CAMEL_MESSAGE_FOLDER_NOXEV|CAMEL_MESSAGE_FOLDER_FLAGGED; - g_free(xev); - } -#endif - - /* we must write this to the non-filtered stream ... */ - fromline = camel_mime_message_build_mbox_from(message); - if (camel_stream_write(output_stream, fromline, strlen(fromline)) == -1) - goto fail_write; - - /* and write the content to the filtering stream, that translates '\nFrom' into '\n>From' */ - filter_stream = (CamelStream *) camel_stream_filter_new_with_stream(output_stream); - filter_from = (CamelMimeFilter *) camel_mime_filter_from_new(); - camel_stream_filter_add((CamelStreamFilter *) filter_stream, filter_from); - if (camel_data_wrapper_write_to_stream((CamelDataWrapper *)message, filter_stream) == -1 - || camel_stream_write(filter_stream, "\n", 1) == -1 - || camel_stream_close(filter_stream) == -1) - goto fail_write; - - /* filter stream ref's the output stream itself, so we need to unref it too */ - camel_object_unref((CamelObject *)filter_from); - camel_object_unref((CamelObject *)filter_stream); - camel_object_unref((CamelObject *)output_stream); - g_free(fromline); - - /* now we 'fudge' the summary to tell it its uptodate, because its idea of uptodate has just changed */ - /* the stat really shouldn't fail, we just wrote to it */ - if (stat(lf->folder_path, &st) == 0) { - mbs->folder_size = st.st_size; - ((CamelFolderSummary *)mbs)->time = st.st_mtime; - } - - /* unlock as soon as we can */ - camel_local_folder_unlock(lf); - - if (camel_folder_change_info_changed(lf->changes)) { - camel_object_trigger_event((CamelObject *)folder, "folder_changed", lf->changes); - camel_folder_change_info_clear(lf->changes); - } - - if (appended_uid) - *appended_uid = g_strdup(camel_message_info_uid(mi)); - - return; - -fail_write: - if (errno == EINTR) - camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, - _("Mail append cancelled")); - else - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot append message to mbox file: %s: %s"), - lf->folder_path, g_strerror (errno)); - - if (filter_stream) - camel_object_unref(CAMEL_OBJECT(filter_stream)); - - if (output_stream) - camel_object_unref(CAMEL_OBJECT(output_stream)); - - if (filter_from) - camel_object_unref(CAMEL_OBJECT(filter_from)); - - g_free(fromline); - - /* reset the file to original size */ - fd = open(lf->folder_path, O_WRONLY, 0600); - if (fd != -1) { - ftruncate(fd, mbs->folder_size); - close(fd); - } - - /* remove the summary info so we are not out-of-sync with the mbox */ - camel_folder_summary_remove_uid (CAMEL_FOLDER_SUMMARY (mbs), camel_message_info_uid (mi)); - - /* and tell the summary its uptodate */ - if (stat(lf->folder_path, &st) == 0) { - mbs->folder_size = st.st_size; - ((CamelFolderSummary *)mbs)->time = st.st_mtime; - } - -fail: - /* make sure we unlock the folder - before we start triggering events into appland */ - camel_local_folder_unlock(lf); - - /* cascade the changes through, anyway, if there are any outstanding */ - if (camel_folder_change_info_changed(lf->changes)) { - camel_object_trigger_event((CamelObject *)folder, "folder_changed", lf->changes); - camel_folder_change_info_clear(lf->changes); - } -} - -static CamelMimeMessage * -mbox_get_message(CamelFolder *folder, const gchar * uid, CamelException *ex) -{ - CamelLocalFolder *lf = (CamelLocalFolder *)folder; - CamelMimeMessage *message = NULL; - CamelMboxMessageInfo *info; - CamelMimeParser *parser = NULL; - int fd, retval; - int retried = FALSE; - off_t frompos; - - d(printf("Getting message %s\n", uid)); - - /* lock the folder first, burn if we can't, need write lock for summary check */ - if (camel_local_folder_lock(lf, CAMEL_LOCK_WRITE, ex) == -1) - return NULL; - - /* check for new messages always */ - if (camel_local_summary_check((CamelLocalSummary *)folder->summary, lf->changes, ex) == -1) { - camel_local_folder_unlock(lf); - return NULL; - } - -retry: - /* get the message summary info */ - info = (CamelMboxMessageInfo *) camel_folder_summary_uid(folder->summary, uid); - - if (info == NULL) { - camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID, - _("Cannot get message: %s\n %s"), uid, _("No such message")); - goto fail; - } - - /* no frompos, its an error in the library (and we can't do anything with it) */ - g_assert(info->frompos != -1); - - frompos = info->frompos; - camel_folder_summary_info_free(folder->summary, (CamelMessageInfo *)info); - - /* we use an fd instead of a normal stream here - the reason is subtle, camel_mime_part will cache - the whole message in memory if the stream is non-seekable (which it is when built from a parser - with no stream). This means we dont have to lock the mbox for the life of the message, but only - while it is being created. */ - - fd = open(lf->folder_path, O_RDONLY); - if (fd == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID, - _("Cannot get message: %s from folder %s\n %s"), - uid, lf->folder_path, g_strerror (errno)); - goto fail; - } - - /* we use a parser to verify the message is correct, and in the correct position */ - parser = camel_mime_parser_new(); - camel_mime_parser_init_with_fd(parser, fd); - camel_mime_parser_scan_from(parser, TRUE); - - camel_mime_parser_seek(parser, frompos, SEEK_SET); - if (camel_mime_parser_step(parser, NULL, NULL) != CAMEL_MIME_PARSER_STATE_FROM - || camel_mime_parser_tell_start_from(parser) != frompos) { - - g_warning("Summary doesn't match the folder contents! eek!\n" - " expecting offset %ld got %ld, state = %d", (long int)frompos, - (long int)camel_mime_parser_tell_start_from(parser), - camel_mime_parser_state(parser)); - - camel_object_unref((CamelObject *)parser); - parser = NULL; - - if (!retried) { - retried = TRUE; - camel_local_summary_check_force((CamelLocalSummary *)folder->summary); - retval = camel_local_summary_check((CamelLocalSummary *)folder->summary, lf->changes, ex); - if (retval != -1) - goto retry; - } - - camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID, - _("Cannot get message: %s from folder %s\n %s"), uid, lf->folder_path, - _("The folder appears to be irrecoverably corrupted.")); - goto fail; - } - - message = camel_mime_message_new(); - if (camel_mime_part_construct_from_parser((CamelMimePart *)message, parser) == -1) { - camel_exception_setv(ex, errno==EINTR?CAMEL_EXCEPTION_USER_CANCEL:CAMEL_EXCEPTION_FOLDER_INVALID_UID, - _("Cannot get message: %s from folder %s\n %s"), uid, lf->folder_path, - _("Message construction failed: Corrupt mailbox?")); - camel_object_unref((CamelObject *)message); - message = NULL; - goto fail; - } - - camel_medium_remove_header((CamelMedium *)message, "X-Evolution"); -fail: - /* and unlock now we're finished with it */ - camel_local_folder_unlock(lf); - - if (parser) - camel_object_unref((CamelObject *)parser); - - /* use the opportunity to notify of changes (particularly if we had a rebuild) */ - if (camel_folder_change_info_changed(lf->changes)) { - camel_object_trigger_event((CamelObject *)folder, "folder_changed", lf->changes); - camel_folder_change_info_clear(lf->changes); - } - - return message; -} - -#ifdef STATUS_PINE -static void -mbox_set_message_flags(CamelFolder *folder, const char *uid, guint32 flags, guint32 set) -{ - /* Basically, if anything could change the Status line, presume it does */ - if (((CamelMboxSummary *)folder->summary)->xstatus - && (flags & (CAMEL_MESSAGE_SEEN|CAMEL_MESSAGE_FLAGGED|CAMEL_MESSAGE_ANSWERED|CAMEL_MESSAGE_DELETED))) { - flags |= CAMEL_MESSAGE_FOLDER_XEVCHANGE|CAMEL_MESSAGE_FOLDER_FLAGGED; - set |= CAMEL_MESSAGE_FOLDER_XEVCHANGE|CAMEL_MESSAGE_FOLDER_FLAGGED; - } - - ((CamelFolderClass *)parent_class)->set_message_flags(folder, uid, flags, set); -} -#endif - -static void -mbox_set_message_user_flag(CamelFolder *folder, const char *uid, const char *name, gboolean value) -{ - CamelMessageInfo *info; - - g_return_if_fail(folder->summary != NULL); - - info = camel_folder_summary_uid(folder->summary, uid); - if (info == NULL) - return; - - if (camel_flag_set(&info->user_flags, name, value)) { - info->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED|CAMEL_MESSAGE_FOLDER_XEVCHANGE; - camel_folder_summary_touch(folder->summary); - camel_object_trigger_event(CAMEL_OBJECT(folder), "message_changed", (char *) uid); - } - camel_folder_summary_info_free(folder->summary, info); -} - -static void -mbox_set_message_user_tag(CamelFolder *folder, const char *uid, const char *name, const char *value) -{ - CamelMessageInfo *info; - - g_return_if_fail(folder->summary != NULL); - - info = camel_folder_summary_uid(folder->summary, uid); - if (info == NULL) - return; - - if (camel_tag_set(&info->user_tags, name, value)) { - info->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED|CAMEL_MESSAGE_FOLDER_XEVCHANGE; - camel_folder_summary_touch(folder->summary); - camel_object_trigger_event(CAMEL_OBJECT(folder), "message_changed", (char *) uid); - } - camel_folder_summary_info_free(folder->summary, info); -} diff --git a/camel/providers/local/camel-mbox-folder.h b/camel/providers/local/camel-mbox-folder.h deleted file mode 100644 index aa0b67201f..0000000000 --- a/camel/providers/local/camel-mbox-folder.h +++ /dev/null @@ -1,62 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Authors: Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 1999 Ximian . - * - * 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_MBOX_FOLDER_H -#define CAMEL_MBOX_FOLDER_H 1 - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus }*/ - -#include "camel-local-folder.h" -#include "camel-mbox-summary.h" - -#define CAMEL_MBOX_FOLDER_TYPE (camel_mbox_folder_get_type ()) -#define CAMEL_MBOX_FOLDER(obj) (CAMEL_CHECK_CAST((obj), CAMEL_MBOX_FOLDER_TYPE, CamelMboxFolder)) -#define CAMEL_MBOX_FOLDER_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_MBOX_FOLDER_TYPE, CamelMboxFolderClass)) -#define CAMEL_IS_MBOX_FOLDER(o) (CAMEL_CHECK_TYPE((o), CAMEL_MBOX_FOLDER_TYPE)) - -typedef struct { - CamelLocalFolder parent_object; - - int lockfd; /* for when we have a lock on the folder */ -} CamelMboxFolder; - -typedef struct { - CamelLocalFolderClass parent_class; - - /* Virtual methods */ - -} CamelMboxFolderClass; - -/* public methods */ -/* flags are taken from CAMEL_STORE_FOLDER_* flags */ -CamelFolder *camel_mbox_folder_new(CamelStore *parent_store, const char *full_name, guint32 flags, CamelException *ex); - -/* Standard Camel function */ -CamelType camel_mbox_folder_get_type(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CAMEL_MBOX_FOLDER_H */ diff --git a/camel/providers/local/camel-mbox-store.c b/camel/providers/local/camel-mbox-store.c deleted file mode 100644 index ffce19171f..0000000000 --- a/camel/providers/local/camel-mbox-store.c +++ /dev/null @@ -1,753 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Authors: Michael Zucchi <notzed@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 - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <string.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <dirent.h> -#include <fcntl.h> -#include <errno.h> - -#include "camel-mbox-store.h" -#include "camel-mbox-folder.h" -#include "camel-file-utils.h" -#include "camel-text-index.h" -#include "camel-exception.h" -#include "camel-url.h" - -#define d(x) - -static CamelLocalStoreClass *parent_class = NULL; - -/* Returns the class for a CamelMboxStore */ -#define CMBOXS_CLASS(so) CAMEL_MBOX_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -#define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -#define CMBOXF_CLASS(so) CAMEL_MBOX_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) - -extern char *camel_mbox_folder_get_full_path (const char *toplevel_dir, const char *full_name); -extern char *camel_mbox_folder_get_meta_path (const char *toplevel_dir, const char *full_name, const char *ext); - -static CamelFolder *get_folder(CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex); -static void delete_folder(CamelStore *store, const char *folder_name, CamelException *ex); -static void rename_folder (CamelStore *store, const char *old, const char *new, CamelException *ex); -static CamelFolderInfo *create_folder (CamelStore *store, const char *parent_name, const char *folder_name, CamelException *ex); -static CamelFolderInfo *get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex); - -static void -camel_mbox_store_class_init (CamelMboxStoreClass *camel_mbox_store_class) -{ - CamelStoreClass *camel_store_class = CAMEL_STORE_CLASS (camel_mbox_store_class); - - parent_class = (CamelLocalStoreClass *)camel_type_get_global_classfuncs(camel_local_store_get_type()); - - /* virtual method overload */ - camel_store_class->get_folder = get_folder; - camel_store_class->delete_folder = delete_folder; - camel_store_class->rename_folder = rename_folder; - camel_store_class->create_folder = create_folder; - - camel_store_class->get_folder_info = get_folder_info; - camel_store_class->free_folder_info = camel_store_free_folder_info_full; -} - -CamelType -camel_mbox_store_get_type (void) -{ - static CamelType camel_mbox_store_type = CAMEL_INVALID_TYPE; - - if (camel_mbox_store_type == CAMEL_INVALID_TYPE) { - camel_mbox_store_type = camel_type_register (CAMEL_LOCAL_STORE_TYPE, "CamelMboxStore", - sizeof (CamelMboxStore), - sizeof (CamelMboxStoreClass), - (CamelObjectClassInitFunc) camel_mbox_store_class_init, - NULL, - NULL, - NULL); - } - - return camel_mbox_store_type; -} - -static char * -mbox_folder_name_to_path (CamelStore *store, const char *folder_name) -{ - const char *toplevel_dir = CAMEL_LOCAL_STORE (store)->toplevel_dir; - - return camel_mbox_folder_get_full_path (toplevel_dir, folder_name); -} - -static char * -mbox_folder_name_to_meta_path (CamelStore *store, const char *folder_name, const char *ext) -{ - const char *toplevel_dir = CAMEL_LOCAL_STORE (store)->toplevel_dir; - - return camel_mbox_folder_get_meta_path (toplevel_dir, folder_name, ext); -} - -static char *extensions[] = { - ".msf", ".ev-summary", ".ibex.index", ".ibex.index.data", ".cmeta" -}; - -static gboolean -ignore_file (const char *filename, gboolean sbd) -{ - int flen, len, i; - - flen = strlen (filename); - for (i = 0; i < (sizeof (extensions) / sizeof (extensions[0])); i++) { - len = strlen (extensions[i]); - if (len < flen && !strcmp (filename + flen - len, extensions[i])) - return TRUE; - } - - if (sbd && flen > 4 && !strcmp (filename + flen - 4, ".sbd")) - return TRUE; - - return FALSE; -} - -static CamelFolder * -get_folder (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex) -{ - struct stat st; - char *name; - - if (!((CamelStoreClass *) parent_class)->get_folder (store, folder_name, flags, ex)) - return NULL; - - name = mbox_folder_name_to_path (store, folder_name); - - if (stat (name, &st) == -1) { - char *dirname; - int fd; - - if (errno != ENOENT) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not open file `%s':\n%s"), - name, g_strerror (errno)); - g_free (name); - return NULL; - } - - if ((flags & CAMEL_STORE_FOLDER_CREATE) == 0) { - camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("Folder `%s' does not exist."), - folder_name); - g_free (name); - return NULL; - } - - dirname = g_path_get_dirname (name); - if (camel_mkdir (dirname, 0777) == -1 && errno != EEXIST) { - camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("Could not create directory `%s':\n%s"), - dirname, g_strerror (errno)); - g_free (dirname); - g_free (name); - return NULL; - } - - g_free (dirname); - - fd = open (name, O_WRONLY | O_CREAT | O_APPEND, 0666); - if (fd == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not create file `%s':\n%s"), - name, g_strerror (errno)); - g_free (name); - return NULL; - } - - g_free (name); - close (fd); - } else if (!S_ISREG (st.st_mode)) { - camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("`%s' is not a regular file."), - name); - g_free (name); - return NULL; - } else - g_free (name); - - return camel_mbox_folder_new (store, folder_name, flags, ex); -} - -static void -delete_folder (CamelStore *store, const char *folder_name, CamelException *ex) -{ - CamelFolderInfo *fi; - CamelException lex; - CamelFolder *lf; - char *name, *path; - struct stat st; - - name = mbox_folder_name_to_path (store, folder_name); - path = g_strdup_printf ("%s.sbd", name); - - if (rmdir (path) == -1 && errno != ENOENT) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not delete folder `%s':\n%s"), - folder_name, g_strerror (errno)); - g_free (path); - g_free (name); - return; - } - - g_free (path); - - if (stat (name, &st) == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not delete folder `%s':\n%s"), - folder_name, g_strerror (errno)); - g_free (name); - return; - } - - if (!S_ISREG (st.st_mode)) { - camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("`%s' is not a regular file."), name); - g_free (name); - return; - } - - if (st.st_size != 0) { - camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_NON_EMPTY, - _("Folder `%s' is not empty. Not deleted."), - folder_name); - g_free (name); - return; - } - - if (unlink (name) == -1 && errno != ENOENT) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not delete folder `%s':\n%s"), - name, g_strerror (errno)); - g_free (name); - return; - } - - /* FIXME: we have to do our own meta cleanup here rather than - * calling our parent class' delete_folder() method since our - * naming convention is different. Need to find a way for - * CamelLocalStore to be able to construct the folder & meta - * paths itself */ - path = mbox_folder_name_to_meta_path (store, folder_name, ".ev-summary"); - if (unlink (path) == -1 && errno != ENOENT) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not delete folder summary file `%s': %s"), - path, g_strerror (errno)); - g_free (path); - g_free (name); - return; - } - - g_free (path); - - path = mbox_folder_name_to_meta_path (store, folder_name, ".ibex"); - if (camel_text_index_remove (path) == -1 && errno != ENOENT) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not delete folder index file `%s': %s"), - path, g_strerror (errno)); - g_free (path); - g_free (name); - return; - } - - g_free (path); - - camel_exception_init (&lex); - if ((lf = camel_store_get_folder (store, folder_name, 0, &lex))) { - camel_object_get (lf, NULL, CAMEL_OBJECT_STATE_FILE, &path, NULL); - camel_object_set (lf, NULL, CAMEL_OBJECT_STATE_FILE, NULL, NULL); - camel_object_unref (lf); - } else { - camel_exception_clear (&lex); - } - - if (path == NULL) - path = mbox_folder_name_to_meta_path (store, folder_name, ".cmeta"); - - if (unlink (path) == -1 && errno != ENOENT) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not delete folder meta file `%s': %s"), - path, g_strerror (errno)); - - g_free (path); - g_free (name); - return; - } - - g_free (path); - g_free (name); - - fi = g_new0 (CamelFolderInfo, 1); - fi->full_name = g_strdup (folder_name); - fi->name = g_path_get_basename (folder_name); - fi->url = g_strdup_printf ("mbox:%s#%s", ((CamelService *) store)->url->path, folder_name); - fi->unread_message_count = -1; - camel_folder_info_build_path (fi, '/'); - - camel_object_trigger_event (store, "folder_deleted", fi); - - camel_folder_info_free (fi); -} - -static CamelFolderInfo * -create_folder (CamelStore *store, const char *parent_name, const char *folder_name, CamelException *ex) -{ - /* FIXME: this is almost an exact copy of CamelLocalStore::create_folder() except that we use - * different path schemes... need to find a way to share parent's code? */ - const char *toplevel_dir = ((CamelLocalStore *) store)->toplevel_dir; - CamelFolderInfo *info = NULL; - char *path, *name, *dir; - CamelFolder *folder; - struct stat st; - - if (toplevel_dir[0] != '/') { - camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("Store root %s is not an absolute path"), toplevel_dir); - return NULL; - } - - if (folder_name[0] == '.' || ignore_file (folder_name, TRUE)) { - camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot create a folder by this name.")); - return NULL; - } - - if (parent_name && *parent_name) - name = g_strdup_printf ("%s/%s", parent_name, folder_name); - else - name = g_strdup (folder_name); - - path = mbox_folder_name_to_path (store, name); - - dir = g_path_get_dirname (path); - if (camel_mkdir (dir, 0777) == -1 && errno != EEXIST) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create directory `%s': %s."), - dir, g_strerror (errno)); - - g_free (path); - g_free (name); - g_free (dir); - - return NULL; - } - - g_free (dir); - - if (stat (path, &st) == 0 || errno != ENOENT) { - camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("Cannot create folder: %s: %s"), - path, errno ? g_strerror (errno) : - _("Folder already exists")); - - g_free (path); - g_free (name); - - return NULL; - } - - g_free (path); - - folder = ((CamelStoreClass *) ((CamelObject *) store)->klass)->get_folder (store, name, CAMEL_STORE_FOLDER_CREATE, ex); - if (folder) { - camel_object_unref (folder); - info = ((CamelStoreClass *) ((CamelObject *) store)->klass)->get_folder_info (store, name, 0, ex); - } - - g_free (name); - - return info; -} - -static int -xrename (CamelStore *store, const char *old_name, const char *new_name, const char *ext, gboolean missingok, CamelException *ex) -{ - const char *toplevel_dir = ((CamelLocalStore *) store)->toplevel_dir; - char *oldpath, *newpath; - struct stat st; - int ret = -1; - int err = 0; - - if (ext != NULL) { - oldpath = camel_mbox_folder_get_meta_path (toplevel_dir, old_name, ext); - newpath = camel_mbox_folder_get_meta_path (toplevel_dir, new_name, ext); - } else { - oldpath = camel_mbox_folder_get_full_path (toplevel_dir, old_name); - newpath = camel_mbox_folder_get_full_path (toplevel_dir, new_name); - } - - if (stat (oldpath, &st) == -1) { - if (missingok && errno == ENOENT) { - ret = 0; - } else { - err = errno; - ret = -1; - } - } else if (S_ISDIR (st.st_mode)) { - /* use rename for dirs */ - if (rename (oldpath, newpath) == 0 || stat (newpath, &st) == 0) { - ret = 0; - } else { - err = errno; - ret = -1; - } - } else if (link (oldpath, newpath) == 0 /* and link for files */ - || (stat (newpath, &st) == 0 && st.st_nlink == 2)) { - if (unlink (oldpath) == 0) { - ret = 0; - } else { - err = errno; - unlink (newpath); - ret = -1; - } - } else { - err = errno; - ret = -1; - } - - if (ret == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not rename %s to %s: %s"), - oldpath, newpath, g_strerror (err)); - } - - g_free (oldpath); - g_free (newpath); - - return ret; -} - -static void -rename_folder (CamelStore *store, const char *old, const char *new, CamelException *ex) -{ - CamelLocalFolder *folder = NULL; - char *oldibex, *newibex; - - if (new[0] == '.' || ignore_file (new, TRUE)) { - printf ("exception: The new folder name is illegal.\n"); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("The new folder name is illegal.")); - return; - } - - /* try to rollback failures, has obvious races */ - - oldibex = mbox_folder_name_to_meta_path (store, old, ".ibex"); - newibex = mbox_folder_name_to_meta_path (store, new, ".ibex"); - - folder = camel_object_bag_get (store->folders, old); - if (folder && folder->index) { - if (camel_index_rename (folder->index, newibex) == -1) - goto ibex_failed; - } else { - /* TODO: camel_text_index_rename should find out if we have an active index itself? */ - if (camel_text_index_rename (oldibex, newibex) == -1) - goto ibex_failed; - } - - if (xrename (store, old, new, ".ev-summary", TRUE, ex)) - goto summary_failed; - - if (xrename (store, old, new, NULL, FALSE, ex)) - goto base_failed; - - g_free (oldibex); - g_free (newibex); - - if (folder) - camel_object_unref (folder); - - return; - - base_failed: - - xrename (store, new, old, ".ev-summary", TRUE, ex); - - summary_failed: - - if (folder) { - if (folder->index) - camel_index_rename (folder->index, oldibex); - } else - camel_text_index_rename (newibex, oldibex); - ibex_failed: - - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not rename '%s': %s"), - old, g_strerror (errno)); - - g_free (newibex); - g_free (oldibex); - - if (folder) - camel_object_unref (folder); -} - - -/* used to find out where we've visited already */ -struct _inode { - dev_t dnode; - ino_t inode; -}; - -static guint -inode_hash (const void *d) -{ - const struct _inode *v = d; - - return v->inode ^ v->dnode; -} - -static gboolean -inode_equal (const void *a, const void *b) -{ - const struct _inode *v1 = a, *v2 = b; - - return v1->inode == v2->inode && v1->dnode == v2->dnode; -} - -static void -inode_free (void *k, void *v, void *d) -{ - g_free (k); -} - -static CamelFolderInfo * -scan_dir (CamelStore *store, GHashTable *visited, CamelFolderInfo *parent, const char *root, - const char *name, guint32 flags, CamelException *ex) -{ - CamelFolderInfo *folders, *tail, *fi; - GHashTable *folder_hash; - struct dirent *dent; - DIR *dir; - - tail = folders = NULL; - - if (!(dir = opendir (root))) - return NULL; - - folder_hash = g_hash_table_new (g_str_hash, g_str_equal); - - /* FIXME: it would be better if we queue'd up the recursive - * scans till the end so that we can limit the number of - * directory descriptors open at any given time... */ - - while ((dent = readdir (dir))) { - char *short_name, *full_name, *path, *ext; - CamelFolder *folder; - struct stat st; - int unread = -1; - - if (dent->d_name[0] == '.') - continue; - - if (ignore_file (dent->d_name, FALSE)) - continue; - - path = g_strdup_printf ("%s/%s", root, dent->d_name); - if (stat (path, &st) == -1) { - g_free (path); - continue; - } - - if (S_ISDIR (st.st_mode)) { - struct _inode in = { st.st_dev, st.st_ino }; - - if (g_hash_table_lookup (visited, &in)) { - g_free (path); - continue; - } - } - - short_name = g_strdup (dent->d_name); - if ((ext = strrchr (short_name, '.')) && !strcmp (ext, ".sbd")) - *ext = '\0'; - - if (name != NULL) - full_name = g_strdup_printf ("%s/%s", name, short_name); - else - full_name = g_strdup (short_name); - - if (!S_ISDIR (st.st_mode)) { - folder = camel_object_bag_get (store->folders, full_name); - if (folder) { - if ((flags & CAMEL_STORE_FOLDER_INFO_FAST) == 0) - camel_folder_refresh_info (folder, NULL); - unread = camel_folder_get_unread_message_count (folder); - camel_object_unref (folder); - } - } - - if ((fi = g_hash_table_lookup (folder_hash, short_name)) != NULL) { - g_free (short_name); - g_free (full_name); - - if (S_ISDIR (st.st_mode)) { - fi->flags = (fi->flags & ~CAMEL_FOLDER_NOINFERIORS) | CAMEL_FOLDER_CHILDREN; - } else { - fi->unread_message_count = unread; - fi->flags &= ~CAMEL_FOLDER_NOSELECT; - if ((ext = strchr (fi->url, ';')) && !strncmp (ext, ";noselect=yes", 13)) - memmove (ext, ext + 13, strlen (ext + 13) + 1); - } - } else { - fi = g_new0 (CamelFolderInfo, 1); - fi->parent = parent; - - /* add ";noselect=yes" if we haven't found the mbox file yet. when we find it, remove the noselect */ - fi->url = g_strdup_printf ("mbox:%s%s#%s", ((CamelService *) store)->url->path, - S_ISDIR (st.st_mode) ? ";noselect=yes" : "", full_name); - fi->name = short_name; - fi->full_name = full_name; - fi->path = g_strdup_printf ("/%s", full_name); - fi->unread_message_count = unread; - - if (S_ISDIR (st.st_mode)) - fi->flags = CAMEL_FOLDER_NOSELECT; - else - fi->flags = CAMEL_FOLDER_NOINFERIORS; - - if (tail == NULL) - folders = fi; - else - tail->sibling = fi; - - tail = fi; - - g_hash_table_insert (folder_hash, fi->name, fi); - } - - if ((flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE) && S_ISDIR (st.st_mode)) { - struct _inode in = { st.st_dev, st.st_ino }; - - if (g_hash_table_lookup (visited, &in) == NULL) { - struct _inode *inew = g_new (struct _inode, 1); - - *inew = in; - - g_hash_table_insert (visited, inew, inew); - - if ((fi->child = scan_dir (store, visited, fi, path, fi->full_name, flags, ex))) - fi->flags |= CAMEL_FOLDER_CHILDREN; - } - } - - g_free (path); - } - - closedir (dir); - - g_hash_table_destroy (folder_hash); - - return folders; -} - -static CamelFolderInfo * -get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex) -{ - GHashTable *visited; - struct _inode *inode; - char *path, *subdir; - CamelFolderInfo *fi; - CamelFolder *folder; - const char *base; - struct stat st; - int unread = -1; - - top = top ? top : ""; - path = mbox_folder_name_to_path (store, top); - - if (*top == '\0') { - /* requesting root dir scan */ - if (stat (path, &st) == -1 || !S_ISDIR (st.st_mode)) { - g_free (path); - return NULL; - } - - visited = g_hash_table_new (inode_hash, inode_equal); - - inode = g_new (struct _inode, 1); - inode->dnode = st.st_dev; - inode->inode = st.st_ino; - - g_hash_table_insert (visited, inode, inode); - - fi = scan_dir (store, visited, NULL, path, NULL, flags, ex); - g_hash_table_foreach (visited, inode_free, NULL); - g_hash_table_destroy (visited); - g_free (path); - - return fi; - } - - /* requesting scan of specific folder */ - if (stat (path, &st) == -1 || !S_ISREG (st.st_mode)) { - g_free (path); - return NULL; - } - - visited = g_hash_table_new (inode_hash, inode_equal); - - if (!(base = strrchr (top, '/'))) - base = top; - else - base++; - - folder = camel_object_bag_get (store->folders, top); - if (folder) { - if ((flags & CAMEL_STORE_FOLDER_INFO_FAST) == 0) - camel_folder_refresh_info (folder, NULL); - unread = camel_folder_get_unread_message_count (folder); - camel_object_unref (folder); - } - - fi = g_new0 (CamelFolderInfo, 1); - fi->parent = NULL; - fi->url = g_strdup_printf ("mbox:%s#%s", ((CamelService *) store)->url->path, top); - fi->name = g_strdup (base); - fi->full_name = g_strdup (top); - fi->unread_message_count = unread; - fi->path = g_strdup_printf ("/%s", top); - - subdir = g_strdup_printf ("%s.sbd", path); - if (stat (subdir, &st) == 0 && S_ISDIR (st.st_mode)) - fi->child = scan_dir (store, visited, fi, subdir, top, flags, ex); - - if (fi->child) - fi->flags |= CAMEL_FOLDER_CHILDREN; - else - fi->flags |= CAMEL_FOLDER_NOINFERIORS; - - g_free (subdir); - - g_hash_table_foreach (visited, inode_free, NULL); - g_hash_table_destroy (visited); - g_free (path); - - return fi; -} diff --git a/camel/providers/local/camel-mbox-store.h b/camel/providers/local/camel-mbox-store.h deleted file mode 100644 index 5b6fbdd926..0000000000 --- a/camel/providers/local/camel-mbox-store.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Authors: Michael Zucchi <notzed@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_MBOX_STORE_H -#define CAMEL_MBOX_STORE_H 1 - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus }*/ - -#include "camel-local-store.h" - -#define CAMEL_MBOX_STORE_TYPE (camel_mbox_store_get_type ()) -#define CAMEL_MBOX_STORE(obj) (CAMEL_CHECK_CAST((obj), CAMEL_MBOX_STORE_TYPE, CamelMboxStore)) -#define CAMEL_MBOX_STORE_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_MBOX_STORE_TYPE, CamelMboxStoreClass)) -#define CAMEL_IS_MBOX_STORE(o) (CAMEL_CHECK_TYPE((o), CAMEL_MBOX_STORE_TYPE)) - -typedef struct { - CamelLocalStore parent_object; - -} CamelMboxStore; - -typedef struct { - CamelLocalStoreClass parent_class; - -} CamelMboxStoreClass; - -/* public methods */ - -/* Standard Camel function */ -CamelType camel_mbox_store_get_type (void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CAMEL_MBOX_STORE_H */ - - diff --git a/camel/providers/local/camel-mbox-summary.c b/camel/providers/local/camel-mbox-summary.c deleted file mode 100644 index 4018fc93c9..0000000000 --- a/camel/providers/local/camel-mbox-summary.c +++ /dev/null @@ -1,1029 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*- - * - * Copyright (C) 2000 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 "camel-mbox-summary.h" -#include "camel/camel-mime-message.h" -#include "camel/camel-operation.h" - -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/uio.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <stdlib.h> - -#include "camel-mbox-summary.h" -#include "camel/camel-file-utils.h" -#include "camel/camel-mime-message.h" -#include "camel/camel-operation.h" - -#define io(x) -#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/ - -#define CAMEL_MBOX_SUMMARY_VERSION (0x1000) - -static int summary_header_load (CamelFolderSummary *, FILE *); -static int summary_header_save (CamelFolderSummary *, FILE *); - -static CamelMessageInfo * message_info_new (CamelFolderSummary *, struct _camel_header_raw *); -static CamelMessageInfo * message_info_new_from_parser (CamelFolderSummary *, CamelMimeParser *); -static CamelMessageInfo * message_info_load (CamelFolderSummary *, FILE *); -static int message_info_save (CamelFolderSummary *, FILE *, CamelMessageInfo *); -/*static void message_info_free (CamelFolderSummary *, CamelMessageInfo *);*/ - -static int mbox_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changeinfo, CamelException *ex); -static int mbox_summary_sync(CamelLocalSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex); -#ifdef STATUS_PINE -static CamelMessageInfo *mbox_summary_add(CamelLocalSummary *cls, CamelMimeMessage *msg, const CamelMessageInfo *info, CamelFolderChangeInfo *ci, CamelException *ex); -#endif - -static int mbox_summary_sync_quick(CamelMboxSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex); -static int mbox_summary_sync_full(CamelMboxSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex); - -static void camel_mbox_summary_class_init (CamelMboxSummaryClass *klass); -static void camel_mbox_summary_init (CamelMboxSummary *obj); -static void camel_mbox_summary_finalise (CamelObject *obj); - -#ifdef STATUS_PINE -/* Which status flags are stored in each separate header */ -#define STATUS_XSTATUS (CAMEL_MESSAGE_FLAGGED|CAMEL_MESSAGE_ANSWERED|CAMEL_MESSAGE_DELETED) -#define STATUS_STATUS (CAMEL_MESSAGE_SEEN) - -static void encode_status(guint32 flags, char status[8]); -static guint32 decode_status(const char *status); -#endif - -static CamelLocalSummaryClass *camel_mbox_summary_parent; - -CamelType -camel_mbox_summary_get_type(void) -{ - static CamelType type = CAMEL_INVALID_TYPE; - - if (type == CAMEL_INVALID_TYPE) { - type = camel_type_register(camel_local_summary_get_type(), "CamelMboxSummary", - sizeof (CamelMboxSummary), - sizeof (CamelMboxSummaryClass), - (CamelObjectClassInitFunc) camel_mbox_summary_class_init, - NULL, - (CamelObjectInitFunc) camel_mbox_summary_init, - (CamelObjectFinalizeFunc) camel_mbox_summary_finalise); - } - - return type; -} - -static void -camel_mbox_summary_class_init(CamelMboxSummaryClass *klass) -{ - CamelFolderSummaryClass *sklass = (CamelFolderSummaryClass *)klass; - CamelLocalSummaryClass *lklass = (CamelLocalSummaryClass *)klass; - - camel_mbox_summary_parent = (CamelLocalSummaryClass *)camel_type_get_global_classfuncs(camel_local_summary_get_type()); - - sklass->summary_header_load = summary_header_load; - sklass->summary_header_save = summary_header_save; - - sklass->message_info_new = message_info_new; - sklass->message_info_new_from_parser = message_info_new_from_parser; - sklass->message_info_load = message_info_load; - sklass->message_info_save = message_info_save; - /*sklass->message_info_free = message_info_free;*/ - - lklass->check = mbox_summary_check; - lklass->sync = mbox_summary_sync; -#ifdef STATUS_PINE - lklass->add = mbox_summary_add; -#endif - - klass->sync_quick = mbox_summary_sync_quick; - klass->sync_full = mbox_summary_sync_full; -} - -static void -camel_mbox_summary_init(CamelMboxSummary *obj) -{ - struct _CamelFolderSummary *s = (CamelFolderSummary *)obj; - - /* subclasses need to set the right instance data sizes */ - s->message_info_size = sizeof(CamelMboxMessageInfo); - s->content_info_size = sizeof(CamelMboxMessageContentInfo); - - /* and a unique file version */ - s->version += CAMEL_MBOX_SUMMARY_VERSION; -} - -static void -camel_mbox_summary_finalise(CamelObject *obj) -{ - /*CamelMboxSummary *mbs = CAMEL_MBOX_SUMMARY(obj);*/ -} - -/** - * camel_mbox_summary_new: - * - * Create a new CamelMboxSummary object. - * - * Return value: A new CamelMboxSummary widget. - **/ -CamelMboxSummary * -camel_mbox_summary_new(const char *filename, const char *mbox_name, CamelIndex *index) -{ - CamelMboxSummary *new = (CamelMboxSummary *)camel_object_new(camel_mbox_summary_get_type()); - - camel_local_summary_construct((CamelLocalSummary *)new, filename, mbox_name, index); - return new; -} - -void camel_mbox_summary_xstatus(CamelMboxSummary *mbs, int state) -{ - mbs->xstatus = state; -} - -static int -summary_header_load(CamelFolderSummary *s, FILE *in) -{ - CamelMboxSummary *mbs = CAMEL_MBOX_SUMMARY(s); - - if (((CamelFolderSummaryClass *)camel_mbox_summary_parent)->summary_header_load(s, in) == -1) - return -1; - - return camel_file_util_decode_uint32(in, (guint32 *) &mbs->folder_size); -} - -static int -summary_header_save(CamelFolderSummary *s, FILE *out) -{ - CamelMboxSummary *mbs = CAMEL_MBOX_SUMMARY(s); - - if (((CamelFolderSummaryClass *)camel_mbox_summary_parent)->summary_header_save(s, out) == -1) - return -1; - - return camel_file_util_encode_uint32(out, mbs->folder_size); -} - -static CamelMessageInfo * -message_info_new(CamelFolderSummary *s, struct _camel_header_raw *h) -{ - CamelMessageInfo *mi; - CamelMboxSummary *mbs = (CamelMboxSummary *)s; - - mi = ((CamelFolderSummaryClass *)camel_mbox_summary_parent)->message_info_new(s, h); - if (mi) { - CamelMboxMessageInfo *mbi = (CamelMboxMessageInfo *)mi; - const char *xev, *uid; - CamelMessageInfo *info = NULL; - int add = 0; /* bitmask of things to add, 1 assign uid, 2, just add as new, 4 = recent */ -#ifdef STATUS_PINE - const char *status = NULL, *xstatus = NULL; - guint32 flags = 0; - - if (mbs->xstatus) { - /* check for existance of status & x-status headers */ - status = camel_header_raw_find(&h, "Status", NULL); - if (status) - flags = decode_status(status); - xstatus = camel_header_raw_find(&h, "X-Status", NULL); - if (xstatus) - flags |= decode_status(xstatus); - } -#endif - /* if we have an xev header, use it, else assign a new one */ - xev = camel_header_raw_find(&h, "X-Evolution", NULL); - if (xev != NULL - && camel_local_summary_decode_x_evolution((CamelLocalSummary *)s, xev, mi) == 0) { - uid = camel_message_info_uid(mi); - d(printf("found valid x-evolution: %s\n", uid)); - info = camel_folder_summary_uid(s, uid); - if (info) { - if ((info->flags & CAMEL_MESSAGE_FOLDER_NOTSEEN)) { - info->flags &= ~CAMEL_MESSAGE_FOLDER_NOTSEEN; - camel_folder_summary_info_free(s, mi); - mbi = (CamelMboxMessageInfo *)mi = info; - } else { - add = 7; - d(printf("seen '%s' before, adding anew\n", uid)); - camel_folder_summary_info_free(s, info); - } - } else { - add = 2; - d(printf("but isn't present in summary\n")); - } - } else { - d(printf("didn't find x-evolution\n")); - add = 7; - } - - if (add&1) { - mi->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED | CAMEL_MESSAGE_FOLDER_NOXEV; - camel_message_info_set_uid(mi, camel_folder_summary_next_uid_string(s)); - } else { - camel_folder_summary_set_uid(s, strtoul(camel_message_info_uid(mi), NULL, 10)); - } -#ifdef STATUS_PINE - if (mbs->xstatus && add&2) { - /* use the status as the flags when we read it the first time */ - if (status) - mi->flags = (mi->flags & ~(STATUS_STATUS)) | (flags & STATUS_STATUS); - if (xstatus) - mi->flags = (mi->flags & ~(STATUS_XSTATUS)) | (flags & STATUS_XSTATUS); - } -#endif - if (mbs->changes) { - if (add&2) - camel_folder_change_info_add_uid(mbs->changes, camel_message_info_uid(mi)); - if ((add&4) && status == NULL) - camel_folder_change_info_recent_uid(mbs->changes, camel_message_info_uid(mi)); - } - - mbi->frompos = -1; - } - - return mi; -} - -static CamelMessageInfo * -message_info_new_from_parser(CamelFolderSummary *s, CamelMimeParser *mp) -{ - CamelMessageInfo *mi; - - mi = ((CamelFolderSummaryClass *)camel_mbox_summary_parent)->message_info_new_from_parser(s, mp); - if (mi) { - CamelMboxMessageInfo *mbi = (CamelMboxMessageInfo *)mi; - - mbi->frompos = camel_mime_parser_tell_start_from(mp); - } - - return mi; -} - -static CamelMessageInfo * -message_info_load(CamelFolderSummary *s, FILE *in) -{ - CamelMessageInfo *mi; - - io(printf("loading mbox message info\n")); - - mi = ((CamelFolderSummaryClass *)camel_mbox_summary_parent)->message_info_load(s, in); - if (mi) { - CamelMboxMessageInfo *mbi = (CamelMboxMessageInfo *)mi; - - if (camel_file_util_decode_off_t(in, &mbi->frompos) == -1) - goto error; - } - - return mi; -error: - camel_folder_summary_info_free(s, mi); - return NULL; -} - -static int -message_info_save(CamelFolderSummary *s, FILE *out, CamelMessageInfo *mi) -{ - CamelMboxMessageInfo *mbi = (CamelMboxMessageInfo *)mi; - - io(printf("saving mbox message info\n")); - - if (((CamelFolderSummaryClass *)camel_mbox_summary_parent)->message_info_save(s, out, mi) == -1 - || camel_file_util_encode_off_t(out, mbi->frompos) == -1) - return -1; - - return 0; -} - -/* like summary_rebuild, but also do changeinfo stuff (if supplied) */ -static int -summary_update(CamelLocalSummary *cls, off_t offset, CamelFolderChangeInfo *changeinfo, CamelException *ex) -{ - int i, count; - CamelFolderSummary *s = (CamelFolderSummary *)cls; - CamelMboxSummary *mbs = (CamelMboxSummary *)cls; - CamelMimeParser *mp; - CamelMessageInfo *mi; - int fd; - int ok = 0; - struct stat st; - off_t size = 0; - - d(printf("Calling summary update, from pos %d\n", (int)offset)); - - cls->index_force = FALSE; - - camel_operation_start(NULL, _("Storing folder")); - - fd = open(cls->folder_path, O_RDONLY); - if (fd == -1) { - d(printf("%s failed to open: %s\n", cls->folder_path, strerror (errno))); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not open folder: %s: %s"), - cls->folder_path, g_strerror (errno)); - camel_operation_end(NULL); - return -1; - } - - if (fstat(fd, &st) == 0) - size = st.st_size; - - mp = camel_mime_parser_new(); - camel_mime_parser_init_with_fd(mp, fd); - camel_mime_parser_scan_from(mp, TRUE); - camel_mime_parser_seek(mp, offset, SEEK_SET); - - if (offset > 0) { - if (camel_mime_parser_step(mp, NULL, NULL) == CAMEL_MIME_PARSER_STATE_FROM - && camel_mime_parser_tell_start_from(mp) == offset) { - camel_mime_parser_unstep(mp); - } else { - g_warning("The next message didn't start where I expected, building summary from start"); - camel_mime_parser_drop_step(mp); - offset = 0; - camel_mime_parser_seek(mp, offset, SEEK_SET); - } - } - - /* we mark messages as to whether we've seen them or not. - If we're not starting from the start, we must be starting - from the old end, so everything must be treated as new */ - count = camel_folder_summary_count(s); - for (i=0;i<count;i++) { - mi = camel_folder_summary_index(s, i); - if (offset == 0) - mi->flags |= CAMEL_MESSAGE_FOLDER_NOTSEEN; - else - mi->flags &= ~CAMEL_MESSAGE_FOLDER_NOTSEEN; - camel_folder_summary_info_free(s, mi); - } - mbs->changes = changeinfo; - - while (camel_mime_parser_step(mp, NULL, NULL) == CAMEL_MIME_PARSER_STATE_FROM) { - CamelMessageInfo *info; - off_t pc = camel_mime_parser_tell_start_from (mp) + 1; - - camel_operation_progress (NULL, (int) (((float) pc / size) * 100)); - - info = camel_folder_summary_add_from_parser(s, mp); - if (info == NULL) { - camel_exception_setv(ex, 1, _("Fatal mail parser error near position %ld in folder %s"), - camel_mime_parser_tell(mp), cls->folder_path); - ok = -1; - break; - } - - g_assert(camel_mime_parser_step(mp, NULL, NULL) == CAMEL_MIME_PARSER_STATE_FROM_END); - } - - camel_object_unref(CAMEL_OBJECT (mp)); - - count = camel_folder_summary_count(s); - for (i=0;i<count;i++) { - mi = camel_folder_summary_index(s, i); - /* must've dissapeared from the file? */ - if (mi->flags & CAMEL_MESSAGE_FOLDER_NOTSEEN) { - d(printf("uid '%s' vanished, removing", camel_message_info_uid(mi))); - if (changeinfo) - camel_folder_change_info_remove_uid(changeinfo, camel_message_info_uid(mi)); - camel_folder_summary_remove(s, mi); - count--; - i--; - } - camel_folder_summary_info_free(s, mi); - } - mbs->changes = NULL; - - /* update the file size/mtime in the summary */ - if (ok != -1) { - if (stat(cls->folder_path, &st) == 0) { - camel_folder_summary_touch(s); - mbs->folder_size = st.st_size; - s->time = st.st_mtime; - } - } - - camel_operation_end(NULL); - - return ok; -} - -static int -mbox_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changes, CamelException *ex) -{ - CamelMboxSummary *mbs = (CamelMboxSummary *)cls; - CamelFolderSummary *s = (CamelFolderSummary *)cls; - struct stat st; - int ret = 0; - int i, count; - - d(printf("Checking summary\n")); - - /* check if the summary is up-to-date */ - if (stat(cls->folder_path, &st) == -1) { - camel_folder_summary_clear(s); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot check folder: %s: %s"), - cls->folder_path, g_strerror (errno)); - return -1; - } - - if (cls->check_force) - mbs->folder_size = 0; - cls->check_force = 0; - - if (st.st_size == 0) { - /* empty? No need to scan at all */ - d(printf("Empty mbox, clearing summary\n")); - count= camel_folder_summary_count(s); - for (i=0;i<count;i++) { - CamelMessageInfo *info = camel_folder_summary_index(s, i); - - if (info) { - camel_folder_change_info_remove_uid(changes, camel_message_info_uid(info)); - camel_folder_summary_info_free(s, info); - } - } - camel_folder_summary_clear(s); - ret = 0; - } else { - /* is the summary uptodate? */ - if (st.st_size != mbs->folder_size || st.st_mtime != s->time) { - if (mbs->folder_size < st.st_size) { - /* this will automatically rescan from 0 if there is a problem */ - d(printf("folder grew, attempting to rebuild from %d\n", mbs->folder_size)); - ret = summary_update(cls, mbs->folder_size, changes, ex); - } else { - d(printf("folder shrank! rebuilding from start\n")); - ret = summary_update(cls, 0, changes, ex); - } - } else { - d(printf("Folder unchanged, do nothing\n")); - } - } - - /* FIXME: move upstream? */ - - if (ret != -1) { - if (mbs->folder_size != st.st_size || s->time != st.st_mtime) { - mbs->folder_size = st.st_size; - s->time = st.st_mtime; - camel_folder_summary_touch(s); - } - } - - return ret; -} - -/* perform a full sync */ -static int -mbox_summary_sync_full(CamelMboxSummary *mbs, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex) -{ - CamelLocalSummary *cls = (CamelLocalSummary *)mbs; - int fd = -1, fdout = -1; - char *tmpname = NULL; - guint32 flags = (expunge?1:0); - - d(printf("performing full summary/sync\n")); - - camel_operation_start(NULL, _("Storing folder")); - - fd = open(cls->folder_path, O_RDONLY); - if (fd == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not open file: %s: %s"), - cls->folder_path, g_strerror (errno)); - camel_operation_end(NULL); - return -1; - } - - tmpname = g_alloca (strlen (cls->folder_path) + 5); - sprintf (tmpname, "%s.tmp", cls->folder_path); - d(printf("Writing tmp file to %s\n", tmpname)); - fdout = open(tmpname, O_WRONLY|O_CREAT|O_TRUNC, 0600); - if (fdout == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot open temporary mailbox: %s"), - g_strerror (errno)); - goto error; - } - - if (camel_mbox_summary_sync_mbox((CamelMboxSummary *)cls, flags, changeinfo, fd, fdout, ex) == -1) - goto error; - - d(printf("Closing folders\n")); - - if (close(fd) == -1) { - g_warning("Cannot close source folder: %s", strerror (errno)); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not close source folder %s: %s"), - cls->folder_path, g_strerror (errno)); - fd = -1; - goto error; - } - - if (close(fdout) == -1) { - g_warning("Cannot close tmp folder: %s", strerror (errno)); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not close temp folder: %s"), - g_strerror (errno)); - fdout = -1; - goto error; - } - - /* this should probably either use unlink/link/unlink, or recopy over - the original mailbox, for various locking reasons/etc */ - if (rename(tmpname, cls->folder_path) == -1) { - g_warning("Cannot rename folder: %s", strerror (errno)); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not rename folder: %s"), - g_strerror (errno)); - goto error; - } - tmpname = NULL; - - camel_operation_end(NULL); - - return 0; - error: - if (fd != -1) - close(fd); - - if (fdout != -1) - close(fdout); - - if (tmpname) - unlink(tmpname); - - camel_operation_end(NULL); - - return -1; -} - -/* perform a quick sync - only system flags have changed */ -static int -mbox_summary_sync_quick(CamelMboxSummary *mbs, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex) -{ - CamelLocalSummary *cls = (CamelLocalSummary *)mbs; - CamelFolderSummary *s = (CamelFolderSummary *)mbs; - CamelMimeParser *mp = NULL; - int i, count; - CamelMboxMessageInfo *info = NULL; - int fd = -1; - char *xevnew, *xevtmp; - const char *xev; - int len; - off_t lastpos; - - d(printf("Performing quick summary sync\n")); - - camel_operation_start(NULL, _("Storing folder")); - - fd = open(cls->folder_path, O_RDWR); - if (fd == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not open file: %s: %s"), - cls->folder_path, g_strerror (errno)); - - camel_operation_end(NULL); - return -1; - } - - mp = camel_mime_parser_new(); - camel_mime_parser_scan_from(mp, TRUE); - camel_mime_parser_scan_pre_from(mp, TRUE); - camel_mime_parser_init_with_fd(mp, fd); - - count = camel_folder_summary_count(s); - for (i = 0; i < count; i++) { - int xevoffset; - int pc = (i+1)*100/count; - - camel_operation_progress(NULL, pc); - - info = (CamelMboxMessageInfo *)camel_folder_summary_index(s, i); - - g_assert(info); - - d(printf("Checking message %s %08x\n", camel_message_info_uid(info), info->info.flags)); - - if ((info->info.flags & CAMEL_MESSAGE_FOLDER_FLAGGED) == 0) { - camel_folder_summary_info_free(s, (CamelMessageInfo *)info); - info = NULL; - continue; - } - - d(printf("Updating message %s\n", camel_message_info_uid(info))); - - camel_mime_parser_seek(mp, info->frompos, SEEK_SET); - - if (camel_mime_parser_step(mp, 0, 0) != CAMEL_MIME_PARSER_STATE_FROM) { - g_warning("Expected a From line here, didn't get it"); - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Summary and folder mismatch, even after a sync")); - goto error; - } - - if (camel_mime_parser_tell_start_from(mp) != info->frompos) { - g_warning("Didn't get the next message where I expected (%d) got %d instead", - (int)info->frompos, (int)camel_mime_parser_tell_start_from(mp)); - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Summary and folder mismatch, even after a sync")); - goto error; - } - - if (camel_mime_parser_step(mp, 0, 0) == CAMEL_MIME_PARSER_STATE_FROM_END) { - g_warning("camel_mime_parser_step failed (2)"); - goto error; - } - - xev = camel_mime_parser_header(mp, "X-Evolution", &xevoffset); - if (xev == NULL || camel_local_summary_decode_x_evolution(cls, xev, NULL) == -1) { - g_warning("We're supposed to have a valid x-ev header, but we dont"); - goto error; - } - xevnew = camel_local_summary_encode_x_evolution(cls, (CamelMessageInfo *)info); - /* SIGH: encode_param_list is about the only function which folds headers by itself. - This should be fixed somehow differently (either parser doesn't fold headers, - or param_list doesn't, or something */ - xevtmp = camel_header_unfold(xevnew); - /* the raw header contains a leading ' ', so (dis)count that too */ - if (strlen(xev)-1 != strlen(xevtmp)) { - printf ("strlen(xev)-1 = %d; strlen(xevtmp) = %d\n", strlen(xev)-1, strlen(xevtmp)); - printf ("xev='%s'; xevtmp='%s'\n", xev, xevtmp); - g_free(xevnew); - g_free(xevtmp); - g_warning("Hmm, the xev headers shouldn't have changed size, but they did"); - goto error; - } - g_free(xevtmp); - - /* we write out the xevnew string, assuming its been folded identically to the original too! */ - - lastpos = lseek(fd, 0, SEEK_CUR); - lseek(fd, xevoffset+strlen("X-Evolution: "), SEEK_SET); - do { - len = write(fd, xevnew, strlen(xevnew)); - } while (len == -1 && errno == EINTR); - lseek(fd, lastpos, SEEK_SET); - g_free(xevnew); - - camel_mime_parser_drop_step(mp); - camel_mime_parser_drop_step(mp); - - info->info.flags &= 0xffff; - camel_folder_summary_info_free(s, (CamelMessageInfo *)info); - } - - d(printf("Closing folders\n")); - - if (close(fd) == -1) { - g_warning ("Cannot close source folder: %s", strerror (errno)); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not close source folder %s: %s"), - cls->folder_path, g_strerror (errno)); - fd = -1; - goto error; - } - - camel_object_unref((CamelObject *)mp); - - camel_operation_end(NULL); - - return 0; - error: - if (fd != -1) - close(fd); - if (mp) - camel_object_unref((CamelObject *)mp); - if (info) - camel_folder_summary_info_free(s, (CamelMessageInfo *)info); - - camel_operation_end(NULL); - - return -1; -} - -static int -mbox_summary_sync(CamelLocalSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex) -{ - struct stat st; - CamelMboxSummary *mbs = (CamelMboxSummary *)cls; - CamelFolderSummary *s = (CamelFolderSummary *)cls; - int i, count; - int quick = TRUE, work=FALSE; - int ret; - - /* first, sync ourselves up, just to make sure */ - if (camel_local_summary_check(cls, changeinfo, ex) == -1) - return -1; - - count = camel_folder_summary_count(s); - if (count == 0) - return 0; - - /* check what work we have to do, if any */ - for (i=0;quick && i<count; i++) { - CamelMessageInfo *info = camel_folder_summary_index(s, i); - g_assert(info); - if ((expunge && (info->flags & CAMEL_MESSAGE_DELETED)) || - (info->flags & (CAMEL_MESSAGE_FOLDER_NOXEV|CAMEL_MESSAGE_FOLDER_XEVCHANGE))) - quick = FALSE; - else - work |= (info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0; - camel_folder_summary_info_free(s, info); - } - - /* yuck i hate this logic, but its to simplify the 'all ok, update summary' and failover cases */ - ret = -1; - if (quick) { - if (work) { - ret = ((CamelMboxSummaryClass *)((CamelObject *)cls)->klass)->sync_quick(mbs, expunge, changeinfo, ex); - if (ret == -1) { - g_warning("failed a quick-sync, trying a full sync"); - camel_exception_clear(ex); - } - } else { - ret = 0; - } - } - - if (ret == -1) - ret = ((CamelMboxSummaryClass *)((CamelObject *)cls)->klass)->sync_full(mbs, expunge, changeinfo, ex); - if (ret == -1) - return -1; - - if (stat(cls->folder_path, &st) == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Unknown error: %s"), g_strerror (errno)); - return -1; - } - - if (mbs->folder_size != st.st_size || s->time != st.st_mtime) { - s->time = st.st_mtime; - mbs->folder_size = st.st_size; - camel_folder_summary_touch(s); - } - - return ((CamelLocalSummaryClass *)camel_mbox_summary_parent)->sync(cls, expunge, changeinfo, ex); -} - -int -camel_mbox_summary_sync_mbox(CamelMboxSummary *cls, guint32 flags, CamelFolderChangeInfo *changeinfo, int fd, int fdout, CamelException *ex) -{ - CamelMboxSummary *mbs = (CamelMboxSummary *)cls; - CamelFolderSummary *s = (CamelFolderSummary *)mbs; - CamelMimeParser *mp = NULL; - int i, count; - CamelMboxMessageInfo *info = NULL; - char *buffer, *xevnew = NULL; - size_t len; - const char *fromline; - int lastdel = FALSE; -#ifdef STATUS_PINE - char statnew[8], xstatnew[8]; -#endif - - d(printf("performing full summary/sync\n")); - - /* need to dup this because the mime-parser owns the fd after we give it to it */ - fd = dup(fd); - if (fd == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not store folder: %s"), - g_strerror (errno)); - return -1; - } - - mp = camel_mime_parser_new(); - camel_mime_parser_scan_from(mp, TRUE); - camel_mime_parser_scan_pre_from(mp, TRUE); - camel_mime_parser_init_with_fd(mp, fd); - - count = camel_folder_summary_count(s); - for (i = 0; i < count; i++) { - int pc = (i + 1) * 100 / count; - - camel_operation_progress(NULL, pc); - - info = (CamelMboxMessageInfo *)camel_folder_summary_index(s, i); - - g_assert(info); - - d(printf("Looking at message %s\n", camel_message_info_uid(info))); - - /* only need to seek past deleted messages, otherwise we should be at the right spot/state already */ - if (lastdel) { - d(printf("seeking to %d\n", (int)info->frompos)); - camel_mime_parser_seek(mp, info->frompos, SEEK_SET); - } - - if (camel_mime_parser_step(mp, &buffer, &len) != CAMEL_MIME_PARSER_STATE_FROM) { - g_warning("Expected a From line here, didn't get it"); - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Summary and folder mismatch, even after a sync")); - goto error; - } - - if (camel_mime_parser_tell_start_from(mp) != info->frompos) { - g_warning("Didn't get the next message where I expected (%d) got %d instead", - (int)info->frompos, (int)camel_mime_parser_tell_start_from(mp)); - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Summary and folder mismatch, even after a sync")); - goto error; - } - - lastdel = FALSE; - if ((flags&1) && info->info.flags & CAMEL_MESSAGE_DELETED) { - const char *uid = camel_message_info_uid(info); - - d(printf("Deleting %s\n", uid)); - - if (((CamelLocalSummary *)cls)->index) - camel_index_delete_name(((CamelLocalSummary *)cls)->index, uid); - - /* remove it from the change list */ - camel_folder_change_info_remove_uid(changeinfo, uid); - camel_folder_summary_remove(s, (CamelMessageInfo *)info); - camel_folder_summary_info_free(s, (CamelMessageInfo *)info); - count--; - i--; - info = NULL; - lastdel = TRUE; - } else { - /* otherwise, the message is staying, copy its From_ line across */ -#if 0 - if (i>0) - write(fdout, "\n", 1); -#endif - info->frompos = lseek(fdout, 0, SEEK_CUR); - fromline = camel_mime_parser_from_line(mp); - write(fdout, fromline, strlen(fromline)); - } - - if (info && info->info.flags & (CAMEL_MESSAGE_FOLDER_NOXEV | CAMEL_MESSAGE_FOLDER_FLAGGED)) { - d(printf("Updating header for %s flags = %08x\n", camel_message_info_uid(info), info->info.flags)); - - if (camel_mime_parser_step(mp, &buffer, &len) == CAMEL_MIME_PARSER_STATE_FROM_END) { - g_warning("camel_mime_parser_step failed (2)"); - goto error; - } - - xevnew = camel_local_summary_encode_x_evolution((CamelLocalSummary *)cls, (CamelMessageInfo *)info); -#ifdef STATUS_PINE - if (mbs->xstatus) { - encode_status(((CamelMessageInfo *)info)->flags & STATUS_STATUS, statnew); - encode_status(((CamelMessageInfo *)info)->flags & STATUS_XSTATUS, xstatnew); - len = camel_local_summary_write_headers(fdout, camel_mime_parser_headers_raw(mp), xevnew, statnew, xstatnew); - } else { -#endif - len = camel_local_summary_write_headers(fdout, camel_mime_parser_headers_raw(mp), xevnew, NULL, NULL); -#ifdef STATUS_PINE - } -#endif - if (len == -1) { - d(printf("Error writing to tmp mailbox\n")); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Error writing to temp mailbox: %s"), - g_strerror (errno)); - goto error; - } - info->info.flags &= 0xffff; - g_free(xevnew); - xevnew = NULL; - camel_mime_parser_drop_step(mp); - } - - camel_mime_parser_drop_step(mp); - if (info) { - d(printf("looking for message content to copy across from %d\n", (int)camel_mime_parser_tell(mp))); - while (camel_mime_parser_step(mp, &buffer, &len) == CAMEL_MIME_PARSER_STATE_PRE_FROM) { - /*d(printf("copying mbox contents to tmp: '%.*s'\n", len, buffer));*/ - if (write(fdout, buffer, len) != len) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Writing to tmp mailbox failed: %s: %s"), - ((CamelLocalSummary *)cls)->folder_path, - g_strerror (errno)); - goto error; - } - } - - if (write(fdout, "\n", 1) != 1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Error writing to temp mailbox: %s"), - g_strerror (errno)); - goto error; - } - - d(printf("we are now at %d, from = %d\n", (int)camel_mime_parser_tell(mp), - (int)camel_mime_parser_tell_start_from(mp))); - camel_mime_parser_unstep(mp); - camel_folder_summary_info_free(s, (CamelMessageInfo *)info); - info = NULL; - } - } - -#if 0 - /* if last was deleted, append the \n we removed */ - if (lastdel && count > 0) - write(fdout, "\n", 1); -#endif - - camel_object_unref((CamelObject *)mp); - - return 0; - error: - g_free(xevnew); - - if (mp) - camel_object_unref((CamelObject *)mp); - if (info) - camel_folder_summary_info_free(s, (CamelMessageInfo *)info); - - return -1; -} - -#ifdef STATUS_PINE -static CamelMessageInfo * -mbox_summary_add(CamelLocalSummary *cls, CamelMimeMessage *msg, const CamelMessageInfo *info, CamelFolderChangeInfo *ci, CamelException *ex) -{ - CamelMessageInfo *mi; - - mi = ((CamelLocalSummaryClass *)camel_mbox_summary_parent)->add(cls, msg, info, ci, ex); - if (mi && ((CamelMboxSummary *)cls)->xstatus) { - char status[8]; - - /* we snoop and add status/x-status headers to suit */ - encode_status(mi->flags & STATUS_STATUS, status); - camel_medium_set_header((CamelMedium *)msg, "Status", status); - encode_status(mi->flags & STATUS_XSTATUS, status); - camel_medium_set_header((CamelMedium *)msg, "X-Status", status); - } - - return mi; -} - -static struct { - char tag; - guint32 flag; -} status_flags[] = { - { 'F', CAMEL_MESSAGE_FLAGGED }, - { 'A', CAMEL_MESSAGE_ANSWERED }, - { 'D', CAMEL_MESSAGE_DELETED }, - { 'R', CAMEL_MESSAGE_SEEN }, -}; - -static void -encode_status(guint32 flags, char status[8]) -{ - char *p; - int i; - - p = status; - for (i=0;i<sizeof(status_flags)/sizeof(status_flags[0]);i++) - if (status_flags[i].flag & flags) - *p++ = status_flags[i].tag; - *p++ = 'O'; - *p=0; -} - -static guint32 -decode_status(const char *status) -{ - const char *p; - char c; - guint32 flags = 0; - int i; - - p = status; - while ((c = *p++)) { - for (i=0;i<sizeof(status_flags)/sizeof(status_flags[0]);i++) - if (status_flags[i].tag == *p) - flags |= status_flags[i].flag; - } - - return flags; -} - -#endif /* STATUS_PINE */ diff --git a/camel/providers/local/camel-mbox-summary.h b/camel/providers/local/camel-mbox-summary.h deleted file mode 100644 index dc64aa23fa..0000000000 --- a/camel/providers/local/camel-mbox-summary.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2000 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_MBOX_SUMMARY_H -#define _CAMEL_MBOX_SUMMARY_H - -#include "camel-local-summary.h" - -/* Enable the use of elm/pine style "Status" & "X-Status" headers */ -#define STATUS_PINE - -#define CAMEL_MBOX_SUMMARY(obj) CAMEL_CHECK_CAST (obj, camel_mbox_summary_get_type (), CamelMboxSummary) -#define CAMEL_MBOX_SUMMARY_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_mbox_summary_get_type (), CamelMboxSummaryClass) -#define CAMEL_IS_MBOX_SUMMARY(obj) CAMEL_CHECK_TYPE (obj, camel_mbox_summary_get_type ()) - -typedef struct _CamelMboxSummary CamelMboxSummary; -typedef struct _CamelMboxSummaryClass CamelMboxSummaryClass; - -typedef struct _CamelMboxMessageContentInfo { - CamelMessageContentInfo info; -} CamelMboxMessageContentInfo; - -typedef struct _CamelMboxMessageInfo { - CamelMessageInfo info; - - off_t frompos; -} CamelMboxMessageInfo; - -struct _CamelMboxSummary { - CamelLocalSummary parent; - - CamelFolderChangeInfo *changes; /* used to build change sets */ - - size_t folder_size; /* size of the mbox file, last sync */ - - unsigned int xstatus:1; /* do we store/honour xstatus/status headers */ -}; - -struct _CamelMboxSummaryClass { - CamelLocalSummaryClass parent_class; - - /* sync in-place */ - int (*sync_quick)(CamelMboxSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex); - /* sync requires copy */ - int (*sync_full)(CamelMboxSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex); -}; - -CamelType camel_mbox_summary_get_type (void); -CamelMboxSummary *camel_mbox_summary_new (const char *filename, const char *mbox_name, CamelIndex *index); - -/* do we honour/use xstatus headers, etc */ -void camel_mbox_summary_xstatus(CamelMboxSummary *mbs, int state); - -/* build a new mbox from an existing mbox storing summary information */ -int camel_mbox_summary_sync_mbox(CamelMboxSummary *cls, guint32 flags, CamelFolderChangeInfo *changeinfo, int fd, int fdout, CamelException *ex); - -#endif /* ! _CAMEL_MBOX_SUMMARY_H */ - diff --git a/camel/providers/local/camel-mh-folder.c b/camel/providers/local/camel-mh-folder.c deleted file mode 100644 index 25dbacc49a..0000000000 --- a/camel/providers/local/camel-mh-folder.c +++ /dev/null @@ -1,231 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*- - * - * Authors: Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 1999, 2003 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 "camel-mh-folder.h" -#include "camel-mh-store.h" -#include "camel-stream-fs.h" -#include "camel-mh-summary.h" -#include "camel-data-wrapper.h" -#include "camel-mime-message.h" -#include "camel-exception.h" - -#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/ - -static CamelLocalFolderClass *parent_class = NULL; - -/* Returns the class for a CamelMhFolder */ -#define CMHF_CLASS(so) CAMEL_MH_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -#define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -#define CMHS_CLASS(so) CAMEL_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so)) - -static CamelLocalSummary *mh_create_summary(const char *path, const char *folder, CamelIndex *index); - -static void mh_append_message(CamelFolder * folder, CamelMimeMessage * message, const CamelMessageInfo *info, char **appended_uid, CamelException * ex); -static CamelMimeMessage *mh_get_message(CamelFolder * folder, const gchar * uid, CamelException * ex); - -static void mh_finalize(CamelObject * object); - -static void camel_mh_folder_class_init(CamelObjectClass * camel_mh_folder_class) -{ - CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS(camel_mh_folder_class); - CamelLocalFolderClass *lclass = (CamelLocalFolderClass *)camel_mh_folder_class; - - parent_class = CAMEL_LOCAL_FOLDER_CLASS (camel_type_get_global_classfuncs(camel_local_folder_get_type())); - - /* virtual method definition */ - - /* virtual method overload */ - camel_folder_class->append_message = mh_append_message; - camel_folder_class->get_message = mh_get_message; - - lclass->create_summary = mh_create_summary; -} - -static void mh_init(gpointer object, gpointer klass) -{ - /*CamelFolder *folder = object; - CamelMhFolder *mh_folder = object;*/ -} - -static void mh_finalize(CamelObject * object) -{ - /*CamelMhFolder *mh_folder = CAMEL_MH_FOLDER(object);*/ -} - -CamelType camel_mh_folder_get_type(void) -{ - static CamelType camel_mh_folder_type = CAMEL_INVALID_TYPE; - - if (camel_mh_folder_type == CAMEL_INVALID_TYPE) { - camel_mh_folder_type = camel_type_register(CAMEL_LOCAL_FOLDER_TYPE, "CamelMhFolder", - sizeof(CamelMhFolder), - sizeof(CamelMhFolderClass), - (CamelObjectClassInitFunc) camel_mh_folder_class_init, - NULL, - (CamelObjectInitFunc) mh_init, - (CamelObjectFinalizeFunc) mh_finalize); - } - - return camel_mh_folder_type; -} - -CamelFolder * -camel_mh_folder_new(CamelStore *parent_store, const char *full_name, guint32 flags, CamelException *ex) -{ - CamelFolder *folder; - - d(printf("Creating mh folder: %s\n", full_name)); - - folder = (CamelFolder *)camel_object_new(CAMEL_MH_FOLDER_TYPE); - folder = (CamelFolder *)camel_local_folder_construct((CamelLocalFolder *)folder, - parent_store, full_name, flags, ex); - - return folder; -} - -static CamelLocalSummary *mh_create_summary(const char *path, const char *folder, CamelIndex *index) -{ - return (CamelLocalSummary *)camel_mh_summary_new(path, folder, index); -} - -static void -mh_append_message (CamelFolder *folder, CamelMimeMessage *message, const CamelMessageInfo *info, char **appended_uid, CamelException *ex) -{ - CamelMhFolder *mh_folder = (CamelMhFolder *)folder; - CamelLocalFolder *lf = (CamelLocalFolder *)folder; - CamelStream *output_stream; - CamelMessageInfo *mi; - char *name; - - /* FIXME: probably needs additional locking (although mh doesn't appear do do it) */ - - d(printf("Appending message\n")); - - /* add it to the summary/assign the uid, etc */ - mi = camel_local_summary_add((CamelLocalSummary *)folder->summary, message, info, lf->changes, ex); - if (camel_exception_is_set (ex)) - return; - - d(printf("Appending message: uid is %s\n", camel_message_info_uid(mi))); - - /* write it out, use the uid we got from the summary */ - name = g_strdup_printf("%s/%s", lf->folder_path, camel_message_info_uid(mi)); - output_stream = camel_stream_fs_new_with_name(name, O_WRONLY|O_CREAT, 0600); - if (output_stream == NULL) - goto fail_write; - - if (camel_data_wrapper_write_to_stream ((CamelDataWrapper *)message, output_stream) == -1 - || camel_stream_close (output_stream) == -1) - goto fail_write; - - /* close this? */ - camel_object_unref (CAMEL_OBJECT (output_stream)); - - g_free(name); - - camel_object_trigger_event (CAMEL_OBJECT (folder), "folder_changed", - ((CamelLocalFolder *)mh_folder)->changes); - camel_folder_change_info_clear (((CamelLocalFolder *)mh_folder)->changes); - - if (appended_uid) - *appended_uid = g_strdup(camel_message_info_uid(mi)); - - return; - - fail_write: - - /* remove the summary info so we are not out-of-sync with the mh folder */ - camel_folder_summary_remove_uid (CAMEL_FOLDER_SUMMARY (folder->summary), - camel_message_info_uid (mi)); - - if (errno == EINTR) - camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, - _("MH append message cancelled")); - else - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot append message to mh folder: %s: %s"), - name, g_strerror (errno)); - - if (output_stream) { - camel_object_unref (CAMEL_OBJECT (output_stream)); - unlink (name); - } - - g_free (name); -} - -static CamelMimeMessage *mh_get_message(CamelFolder * folder, const gchar * uid, CamelException * ex) -{ - CamelLocalFolder *lf = (CamelLocalFolder *)folder; - CamelStream *message_stream = NULL; - CamelMimeMessage *message = NULL; - CamelMessageInfo *info; - char *name; - - d(printf("getting message: %s\n", uid)); - - /* get the message summary info */ - if ((info = camel_folder_summary_uid(folder->summary, uid)) == NULL) { - camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID, _("Cannot get message: %s\n %s"), uid, _("No such message")); - return NULL; - } - - /* we only need it to check the message exists */ - camel_folder_summary_info_free(folder->summary, info); - - name = g_strdup_printf("%s/%s", lf->folder_path, uid); - if ((message_stream = camel_stream_fs_new_with_name(name, O_RDONLY, 0)) == NULL) { - camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID, - _("Cannot get message: %s\n %s"), - name, g_strerror (errno)); - g_free(name); - return NULL; - } - - message = camel_mime_message_new(); - if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)message, message_stream) == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID, - _("Cannot get message: %s\n %s"), - name, _("Invalid message contents")); - g_free(name); - camel_object_unref((CamelObject *)message_stream); - camel_object_unref((CamelObject *)message); - return NULL; - - } - camel_object_unref((CamelObject *)message_stream); - g_free(name); - - return message; -} diff --git a/camel/providers/local/camel-mh-folder.h b/camel/providers/local/camel-mh-folder.h deleted file mode 100644 index 125f8c8ac5..0000000000 --- a/camel/providers/local/camel-mh-folder.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Authors: - * Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 1999 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_MH_FOLDER_H -#define CAMEL_MH_FOLDER_H 1 - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus } */ -#include "camel-local-folder.h" - -#define CAMEL_MH_FOLDER_TYPE (camel_mh_folder_get_type ()) -#define CAMEL_MH_FOLDER(obj) (CAMEL_CHECK_CAST((obj), CAMEL_MH_FOLDER_TYPE, CamelMhFolder)) -#define CAMEL_MH_FOLDER_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_MH_FOLDER_TYPE, CamelMhFolderClass)) -#define CAMEL_IS_MH_FOLDER(o) (CAMEL_CHECK_TYPE((o), CAMEL_MH_FOLDER_TYPE)) - -typedef struct { - CamelLocalFolder parent_object; - -} CamelMhFolder; - -typedef struct { - CamelLocalFolderClass parent_class; - - /* Virtual methods */ - -} CamelMhFolderClass; - -/* public methods */ -CamelFolder *camel_mh_folder_new(CamelStore *parent_store, const char *full_name, guint32 flags, CamelException *ex); - -/* Standard Camel function */ -CamelType camel_mh_folder_get_type(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* CAMEL_MH_FOLDER_H */ diff --git a/camel/providers/local/camel-mh-store.c b/camel/providers/local/camel-mh-store.c deleted file mode 100644 index 73a3d2046f..0000000000 --- a/camel/providers/local/camel-mh-store.c +++ /dev/null @@ -1,533 +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> - * - * 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 <errno.h> -#include <string.h> -#include <unistd.h> -#include <dirent.h> - -#include "camel-mh-store.h" -#include "camel-mh-folder.h" -#include "camel-exception.h" -#include "camel-url.h" -#include "camel-private.h" - -#include <camel/camel-stream-fs.h> -#include <camel/camel-stream-buffer.h> - -static CamelLocalStoreClass *parent_class = NULL; - -#define d(x) - -/* Returns the class for a CamelMhStore */ -#define CMHS_CLASS(so) CAMEL_MH_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -#define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -#define CMHF_CLASS(so) CAMEL_MH_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) - -static void construct (CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, CamelException *ex); -static CamelFolder *get_folder(CamelStore * store, const char *folder_name, guint32 flags, CamelException * ex); -static CamelFolder *get_inbox (CamelStore *store, CamelException *ex); -static void delete_folder(CamelStore * store, const char *folder_name, CamelException * ex); -static void rename_folder(CamelStore *store, const char *old, const char *new, CamelException *ex); -static CamelFolderInfo * get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex); - -static void camel_mh_store_class_init(CamelObjectClass * camel_mh_store_class) -{ - CamelStoreClass *camel_store_class = CAMEL_STORE_CLASS(camel_mh_store_class); - CamelServiceClass *camel_service_class = CAMEL_SERVICE_CLASS(camel_mh_store_class); - - parent_class = (CamelLocalStoreClass *)camel_type_get_global_classfuncs(camel_local_store_get_type()); - - /* virtual method overload, use defaults for most */ - camel_service_class->construct = construct; - - camel_store_class->get_folder = get_folder; - camel_store_class->get_inbox = get_inbox; - camel_store_class->delete_folder = delete_folder; - camel_store_class->rename_folder = rename_folder; - camel_store_class->get_folder_info = get_folder_info; -} - -CamelType camel_mh_store_get_type(void) -{ - static CamelType camel_mh_store_type = CAMEL_INVALID_TYPE; - - if (camel_mh_store_type == CAMEL_INVALID_TYPE) { - camel_mh_store_type = camel_type_register(CAMEL_LOCAL_STORE_TYPE, "CamelMhStore", - sizeof(CamelMhStore), - sizeof(CamelMhStoreClass), - (CamelObjectClassInitFunc) camel_mh_store_class_init, - NULL, - NULL, - NULL); - } - - return camel_mh_store_type; -} - -static void -construct (CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, CamelException *ex) -{ - CamelMhStore *mh_store = (CamelMhStore *)service; - - CAMEL_SERVICE_CLASS (parent_class)->construct (service, session, provider, url, ex); - if (camel_exception_is_set (ex)) - return; - - if (camel_url_get_param(url, "dotfolders")) - mh_store->flags |= CAMEL_MH_DOTFOLDERS; -} - -enum { - UPDATE_NONE, - UPDATE_ADD, - UPDATE_REMOVE, -}; - -/* update the .folders file if it exists, or create it if it doesn't */ -static void -folders_update(const char *root, const char *folder, int mode) -{ - char *tmp, *tmpnew, *line = NULL; - CamelStream *stream, *in = NULL, *out = NULL; - - tmpnew = g_alloca (strlen (root) + 16); - sprintf (tmpnew, "%s.folders~", root); - - out = camel_stream_fs_new_with_name(tmpnew, O_WRONLY|O_CREAT|O_TRUNC, 0666); - if (out == NULL) - goto fail; - - tmp = g_alloca (strlen (root) + 16); - sprintf (tmp, "%s.folders", root); - stream = camel_stream_fs_new_with_name(tmp, O_RDONLY, 0); - if (stream) { - in = camel_stream_buffer_new(stream, CAMEL_STREAM_BUFFER_READ); - camel_object_unref(stream); - } - if (in == NULL || stream == NULL) { - if (mode == UPDATE_ADD && camel_stream_printf(out, "%s\n", folder) == -1) - goto fail; - goto done; - } - - while ((line = camel_stream_buffer_read_line((CamelStreamBuffer *)in))) { - int copy = TRUE; - - switch (mode) { - case UPDATE_REMOVE: - if (strcmp(line, folder) == 0) - copy = FALSE; - break; - case UPDATE_ADD: { - int cmp = strcmp(line, folder); - - if (cmp > 0) { - /* found insertion point */ - if (camel_stream_printf(out, "%s\n", folder) == -1) - goto fail; - mode = UPDATE_NONE; - } else if (tmp == 0) { - /* already there */ - mode = UPDATE_NONE; - } - break; } - case UPDATE_NONE: - break; - } - - if (copy && camel_stream_printf(out, "%s\n", line) == -1) - goto fail; - - g_free(line); - line = NULL; - } - - /* add to end? */ - if (mode == UPDATE_ADD && camel_stream_printf(out, "%s\n", folder) == -1) - goto fail; - - if (camel_stream_close(out) == -1) - goto fail; - -done: - /* should we care if this fails? I suppose so ... */ - rename(tmpnew, tmp); -fail: - unlink(tmpnew); /* remove it if its there */ - g_free(line); - if (in) - camel_object_unref(in); - if (out) - camel_object_unref(out); -} - -static CamelFolder * -get_folder(CamelStore * store, const char *folder_name, guint32 flags, CamelException * ex) -{ - char *name; - struct stat st; - - if (!((CamelStoreClass *)parent_class)->get_folder(store, folder_name, flags, ex)) - return NULL; - - name = g_strdup_printf("%s%s", CAMEL_LOCAL_STORE(store)->toplevel_dir, folder_name); - - if (stat(name, &st) == -1) { - if (errno != ENOENT) { - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not open folder `%s':\n%s"), - folder_name, g_strerror (errno)); - g_free (name); - return NULL; - } - if ((flags & CAMEL_STORE_FOLDER_CREATE) == 0) { - camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("Folder `%s' does not exist."), folder_name); - g_free (name); - return NULL; - } - - if (mkdir(name, 0700) != 0) { - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not create folder `%s':\n%s"), - folder_name, g_strerror (errno)); - g_free (name); - return NULL; - } - - /* add to .folders if we are supposed to */ - /* FIXME: throw exception on error */ - if (((CamelMhStore *)store)->flags & CAMEL_MH_DOTFOLDERS) - folders_update(((CamelLocalStore *)store)->toplevel_dir, folder_name, UPDATE_ADD); - - } else if (!S_ISDIR(st.st_mode)) { - camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("`%s' is not a directory."), name); - g_free (name); - return NULL; - } - g_free(name); - - return camel_mh_folder_new(store, folder_name, flags, ex); -} - -static CamelFolder * -get_inbox (CamelStore *store, CamelException *ex) -{ - return get_folder (store, "inbox", 0, ex); -} - -static void delete_folder(CamelStore * store, const char *folder_name, CamelException * ex) -{ - char *name; - - /* remove folder directory - will fail if not empty */ - name = g_strdup_printf("%s%s", CAMEL_LOCAL_STORE(store)->toplevel_dir, folder_name); - if (rmdir(name) == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not delete folder `%s': %s"), - folder_name, g_strerror (errno)); - g_free(name); - return; - } - g_free(name); - - /* remove from .folders if we are supposed to */ - if (((CamelMhStore *)store)->flags & CAMEL_MH_DOTFOLDERS) - folders_update(((CamelLocalStore *)store)->toplevel_dir, folder_name, UPDATE_REMOVE); - - /* and remove metadata */ - ((CamelStoreClass *)parent_class)->delete_folder(store, folder_name, ex); -} - -static void -rename_folder(CamelStore *store, const char *old, const char *new, CamelException *ex) -{ - CamelException e; - - camel_exception_init(&e); - ((CamelStoreClass *)parent_class)->rename_folder(store, old, new, &e); - if (camel_exception_is_set(&e)) { - camel_exception_xfer(ex, &e); - return; - } - camel_exception_clear(&e); - - if (((CamelMhStore *)store)->flags & CAMEL_MH_DOTFOLDERS) { - /* yeah this is messy, but so is mh! */ - folders_update(((CamelLocalStore *)store)->toplevel_dir, new, UPDATE_ADD); - folders_update(((CamelLocalStore *)store)->toplevel_dir, old, UPDATE_REMOVE); - } -} - -static CamelFolderInfo *folder_info_new(CamelStore *store, const char *root, const char *path) -{ - CamelFolderInfo *fi; - char *base; - CamelFolder *folder; - - base = strrchr(path, '/'); - - /* Build the folder info structure. */ - fi = g_malloc0(sizeof(*fi)); - fi->url = g_strdup_printf("mh:%s#%s", root, path); - fi->full_name = g_strdup(path); - fi->name = g_strdup(base?base+1:path); - fi->unread_message_count = 0; - - /* check unread count if open */ - folder = camel_object_bag_get(store->folders, path); - if (folder) { - if ((((CamelMhStore *)store)->flags & CAMEL_STORE_FOLDER_INFO_FAST) == 0) - camel_folder_refresh_info(folder, NULL); - fi->unread_message_count = camel_folder_get_unread_message_count(folder); - camel_object_unref(folder); - } - - /* We could: if we have no folder, and FAST isn't specified, perform a full - scan of all messages for their status flags. But its probably not worth - it as we need to read the top of every file, i.e. very very slow */ - - camel_folder_info_build_path(fi, '/'); - - d(printf("New folderinfo:\n '%s'\n '%s'\n '%s'\n", fi->full_name, fi->url, fi->path)); - - return fi; -} - -/* used to find out where we've visited already */ -struct _inode { - dev_t dnode; - ino_t inode; -}; - -/* Scan path, under root, for directories to add folders for. Both - * root and path should have a trailing "/" if they aren't empty. */ -static void recursive_scan(CamelStore *store, CamelFolderInfo **fip, CamelFolderInfo *parent, GHashTable *visited, const char *root, const char *path) -{ - char *fullpath, *tmp; - DIR *dp; - struct dirent *d; - struct stat st; - CamelFolderInfo *fi; - struct _inode in, *inew; - - /* Open the specified directory. */ - if (path[0]) { - fullpath = alloca (strlen (root) + strlen (path) + 2); - sprintf (fullpath, "%s/%s", root, path); - } else - fullpath = (char *)root; - - if (stat(fullpath, &st) == -1 || !S_ISDIR(st.st_mode)) - return; - - in.dnode = st.st_dev; - in.inode = st.st_ino; - - /* see if we've visited already */ - if (g_hash_table_lookup(visited, &in) != NULL) - return; - - inew = g_malloc(sizeof(*inew)); - *inew = in; - g_hash_table_insert(visited, inew, inew); - - /* link in ... */ - fi = folder_info_new(store, root, path); - fi->parent = parent; - fi->sibling = *fip; - *fip = fi; - - if ((( ((CamelMhStore *)store)->flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE) || parent == NULL)) { - /* now check content for possible other directories */ - dp = opendir(fullpath); - if (dp == NULL) - return; - - /* Look for subdirectories to add and scan. */ - while ((d = readdir(dp)) != NULL) { - /* Skip current and parent directory. */ - if (strcmp(d->d_name, ".") == 0 - || strcmp(d->d_name, "..") == 0) - continue; - - /* skip fully-numerical entries (i.e. mh messages) */ - strtoul(d->d_name, &tmp, 10); - if (*tmp == 0) - continue; - - /* otherwise, treat at potential node, and recurse, a bit more expensive than needed, but tough! */ - if (path[0]) { - tmp = g_strdup_printf("%s/%s", path, d->d_name); - recursive_scan(store, &fi->child, fi, visited, root, tmp); - g_free(tmp); - } else { - recursive_scan(store, &fi->child, fi, visited, root, d->d_name); - } - } - - closedir(dp); - } -} - -/* scan a .folders file */ -static void -folders_scan(CamelStore *store, const char *root, const char *top, CamelFolderInfo **fip) -{ - CamelFolderInfo *fi; - char line[512], *path, *tmp; - CamelStream *stream, *in; - struct stat st; - GPtrArray *folders; - GHashTable *visited; - int len; - - tmp = g_alloca (strlen (root) + 16); - sprintf (tmp, "%s/.folders", root); - stream = camel_stream_fs_new_with_name(tmp, 0, O_RDONLY); - if (stream == NULL) - return; - - in = camel_stream_buffer_new(stream, CAMEL_STREAM_BUFFER_READ); - camel_object_unref(stream); - if (in == NULL) - return; - - visited = g_hash_table_new(g_str_hash, g_str_equal); - folders = g_ptr_array_new(); - - while ( (len = camel_stream_buffer_gets((CamelStreamBuffer *)in, line, sizeof(line))) > 0) { - /* ignore blank lines */ - if (len <= 1) - continue; - /* check for invalidly long lines, we abort evreything and fallback */ - if (line[len-1] != '\n') { - int i; - - for (i=0;i<folders->len;i++) - camel_folder_info_free(folders->pdata[i]); - g_ptr_array_set_size(folders, 0); - break; - } - line[len-1] = 0; - - /* check for \r ? */ - - if (top && top[0]) { - int toplen = strlen(top); - - /* check is subdir */ - if (strncmp(top, line, len) != 0) - continue; - - /* check is not sub-subdir if not recursive */ - if (( ((CamelMhStore *)store)->flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE) == 0 - && (tmp = strrchr(line, '/')) - && tmp > line+toplen) - continue; - } - - if (g_hash_table_lookup(visited, line) != NULL) - continue; - - tmp = g_strdup(line); - g_hash_table_insert(visited, tmp, tmp); - - path = g_strdup_printf("%s/%s", root, line); - if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) { - fi = folder_info_new(store, root, line); - g_ptr_array_add(folders, fi); - } - g_free(path); - } - - if (folders->len) - *fip = camel_folder_info_build(folders, NULL, '/', TRUE); - g_ptr_array_free(folders, TRUE); - - g_hash_table_foreach(visited, (GHFunc)g_free, NULL); - g_hash_table_destroy(visited); - - camel_object_unref(in); -} - -/* FIXME: move to camel-local, this is shared with maildir code */ -static guint inode_hash(const void *d) -{ - const struct _inode *v = d; - - return v->inode ^ v->dnode; -} - -static gboolean inode_equal(const void *a, const void *b) -{ - const struct _inode *v1 = a, *v2 = b; - - return v1->inode == v2->inode && v1->dnode == v2->dnode; -} - -static void inode_free(void *k, void *v, void *d) -{ - g_free(k); -} - -static CamelFolderInfo * -get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex) -{ - CamelFolderInfo *fi = NULL; - char *root; - - root = ((CamelService *)store)->url->path; - - /* use .folders if we are supposed to */ - if (((CamelMhStore *)store)->flags & CAMEL_MH_DOTFOLDERS) { - folders_scan(store, root, top, &fi); - } else { - GHashTable *visited = g_hash_table_new(inode_hash, inode_equal); - - if (top == NULL) - top = ""; - - recursive_scan(store, &fi, NULL, visited, root, top); - - /* if we actually scanned from root, we have a "" root node we dont want */ - if (fi != NULL && top[0] == 0) { - CamelFolderInfo *rfi; - - rfi = fi; - fi = rfi->child; - rfi->child = NULL; - camel_folder_info_free(rfi); - } - - g_hash_table_foreach(visited, inode_free, NULL); - g_hash_table_destroy(visited); - } - - return fi; -} diff --git a/camel/providers/local/camel-mh-store.h b/camel/providers/local/camel-mh-store.h deleted file mode 100644 index 96522cb01f..0000000000 --- a/camel/providers/local/camel-mh-store.h +++ /dev/null @@ -1,60 +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> - * - * 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_MH_STORE_H -#define CAMEL_MH_STORE_H 1 - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus } */ - -#include "camel-local-store.h" - -#define CAMEL_MH_STORE_TYPE (camel_mh_store_get_type ()) -#define CAMEL_MH_STORE(obj) (CAMEL_CHECK_CAST((obj), CAMEL_MH_STORE_TYPE, CamelMhStore)) -#define CAMEL_MH_STORE_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_MH_STORE_TYPE, CamelMhStoreClass)) -#define CAMEL_IS_MH_STORE(o) (CAMEL_CHECK_TYPE((o), CAMEL_MH_STORE_TYPE)) - -enum { - CAMEL_MH_DOTFOLDERS = (1<<0), /* update/use .folders file */ -}; - -typedef struct { - CamelLocalStore parent_object; - - guint32 flags; -} CamelMhStore; - -typedef struct { - CamelLocalStoreClass parent_class; - -} CamelMhStoreClass; - -/* public methods */ - -/* Standard Camel function */ -CamelType camel_mh_store_get_type(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* CAMEL_MH_STORE_H */ diff --git a/camel/providers/local/camel-mh-summary.c b/camel/providers/local/camel-mh-summary.c deleted file mode 100644 index 5dd26ac9ba..0000000000 --- a/camel/providers/local/camel-mh-summary.c +++ /dev/null @@ -1,420 +0,0 @@ -/* - * Copyright (C) 2000 Ximian Inc. - * - * Authors: Not Zed <notzed@lostzed.mmc.com.au> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> - -#include <sys/uio.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <stdlib.h> - -#include <dirent.h> - -#include <ctype.h> - -#include "camel-mh-summary.h" -#include <camel/camel-mime-message.h> - -#include "camel-private.h" - -#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/ - -#define CAMEL_MH_SUMMARY_VERSION (0x2000) - -static int mh_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changeinfo, CamelException *ex); -static int mh_summary_sync(CamelLocalSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex); -/*static int mh_summary_add(CamelLocalSummary *cls, CamelMimeMessage *msg, CamelMessageInfo *info, CamelFolderChangeInfo *, CamelException *ex);*/ - -static char *mh_summary_next_uid_string(CamelFolderSummary *s); - -static void camel_mh_summary_class_init (CamelMhSummaryClass *class); -static void camel_mh_summary_init (CamelMhSummary *gspaper); -static void camel_mh_summary_finalise (CamelObject *obj); - -#define _PRIVATE(x) (((CamelMhSummary *)(x))->priv) - -struct _CamelMhSummaryPrivate { - char *current_uid; -}; - -static CamelLocalSummaryClass *parent_class; - -CamelType -camel_mh_summary_get_type (void) -{ - static CamelType type = CAMEL_INVALID_TYPE; - - if (type == CAMEL_INVALID_TYPE) { - type = camel_type_register(camel_local_summary_get_type (), "CamelMhSummary", - sizeof(CamelMhSummary), - sizeof(CamelMhSummaryClass), - (CamelObjectClassInitFunc)camel_mh_summary_class_init, - NULL, - (CamelObjectInitFunc)camel_mh_summary_init, - (CamelObjectFinalizeFunc)camel_mh_summary_finalise); - } - - return type; -} - -static void -camel_mh_summary_class_init (CamelMhSummaryClass *class) -{ - CamelFolderSummaryClass *sklass = (CamelFolderSummaryClass *) class; - CamelLocalSummaryClass *lklass = (CamelLocalSummaryClass *)class; - - parent_class = (CamelLocalSummaryClass *)camel_type_get_global_classfuncs(camel_local_summary_get_type ()); - - /* override methods */ - sklass->next_uid_string = mh_summary_next_uid_string; - - lklass->check = mh_summary_check; - lklass->sync = mh_summary_sync; - /*lklass->add = mh_summary_add;*/ -} - -static void -camel_mh_summary_init (CamelMhSummary *o) -{ - struct _CamelFolderSummary *s = (CamelFolderSummary *) o; - - o->priv = g_malloc0(sizeof(*o->priv)); - /* set unique file version */ - s->version += CAMEL_MH_SUMMARY_VERSION; -} - -static void -camel_mh_summary_finalise(CamelObject *obj) -{ - CamelMhSummary *o = (CamelMhSummary *)obj; - - g_free(o->priv); -} - -/** - * camel_mh_summary_new: - * - * Create a new CamelMhSummary object. - * - * Return value: A new #CamelMhSummary object. - **/ -CamelMhSummary *camel_mh_summary_new (const char *filename, const char *mhdir, CamelIndex *index) -{ - CamelMhSummary *o = (CamelMhSummary *)camel_object_new(camel_mh_summary_get_type ()); - - camel_local_summary_construct((CamelLocalSummary *)o, filename, mhdir, index); - return o; -} - -static char *mh_summary_next_uid_string(CamelFolderSummary *s) -{ - CamelMhSummary *mhs = (CamelMhSummary *)s; - CamelLocalSummary *cls = (CamelLocalSummary *)s; - int fd = -1; - guint32 uid; - char *name; - char *uidstr; - - /* if we are working to add an existing file, then use current_uid */ - if (mhs->priv->current_uid) { - uidstr = g_strdup(mhs->priv->current_uid); - /* tell the summary of this, so we always append numbers to the end */ - camel_folder_summary_set_uid(s, strtoul(uidstr, NULL, 10)+1); - } else { - /* else scan for one - and create it too, to make sure */ - do { - close(fd); - uid = camel_folder_summary_next_uid(s); - name = g_strdup_printf("%s/%u", cls->folder_path, uid); - /* O_EXCL isn't guaranteed, sigh. Oh well, bad luck, mh has problems anyway */ - fd = open(name, O_WRONLY|O_CREAT|O_EXCL, 0600); - g_free(name); - } while (fd == -1 && errno == EEXIST); - - close(fd); - - uidstr = g_strdup_printf("%u", uid); - } - - return uidstr; -} - -static int camel_mh_summary_add(CamelLocalSummary *cls, const char *name, int forceindex) -{ - CamelMhSummary *mhs = (CamelMhSummary *)cls; - char *filename = g_strdup_printf("%s/%s", cls->folder_path, name); - int fd; - CamelMimeParser *mp; - - d(printf("summarising: %s\n", name)); - - fd = open(filename, O_RDONLY); - if (fd == -1) { - g_warning ("Cannot summarise/index: %s: %s", filename, strerror (errno)); - g_free(filename); - return -1; - } - mp = camel_mime_parser_new(); - camel_mime_parser_scan_from(mp, FALSE); - camel_mime_parser_init_with_fd(mp, fd); - if (cls->index && (forceindex || !camel_index_has_name(cls->index, name))) { - d(printf("forcing indexing of message content\n")); - camel_folder_summary_set_index((CamelFolderSummary *)mhs, cls->index); - } else { - camel_folder_summary_set_index((CamelFolderSummary *)mhs, NULL); - } - mhs->priv->current_uid = (char *)name; - camel_folder_summary_add_from_parser((CamelFolderSummary *)mhs, mp); - camel_object_unref((CamelObject *)mp); - mhs->priv->current_uid = NULL; - camel_folder_summary_set_index((CamelFolderSummary *)mhs, NULL); - g_free(filename); - return 0; -} - -static void -remove_summary(char *key, CamelMessageInfo *info, CamelLocalSummary *cls) -{ - d(printf("removing message %s from summary\n", key)); - if (cls->index) - camel_index_delete_name(cls->index, camel_message_info_uid(info)); - camel_folder_summary_remove((CamelFolderSummary *)cls, info); - camel_folder_summary_info_free((CamelFolderSummary *)cls, info); -} - -static int -sort_uid_cmp(const void *ap, const void *bp) -{ - const CamelMessageInfo - *a = *((CamelMessageInfo **)ap), - *b = *((CamelMessageInfo **)bp); - const char - *auid = camel_message_info_uid(a), - *buid = camel_message_info_uid(b); - int aval = atoi(auid), bval = atoi(buid); - - return (aval < bval) ? -1 : (aval > bval) ? 1 : 0; -} - -static int -mh_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changeinfo, CamelException *ex) -{ - DIR *dir; - struct dirent *d; - char *p, c; - CamelMessageInfo *info; - CamelFolderSummary *s = (CamelFolderSummary *)cls; - GHashTable *left; - int i, count; - int forceindex; - - /* FIXME: Handle changeinfo */ - - d(printf("checking summary ...\n")); - - /* scan the directory, check for mail files not in the index, or index entries that - no longer exist */ - dir = opendir(cls->folder_path); - if (dir == NULL) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot open MH directory path: %s: %s"), - cls->folder_path, g_strerror (errno)); - return -1; - } - - /* keeps track of all uid's that have not been processed */ - left = g_hash_table_new(g_str_hash, g_str_equal); - count = camel_folder_summary_count((CamelFolderSummary *)cls); - forceindex = count == 0; - for (i=0;i<count;i++) { - info = camel_folder_summary_index((CamelFolderSummary *)cls, i); - if (info) { - g_hash_table_insert(left, (char *)camel_message_info_uid(info), info); - } - } - - while ( (d = readdir(dir)) ) { - /* FIXME: also run stat to check for regular file */ - p = d->d_name; - while ( (c = *p++) ) { - if (!isdigit(c)) - break; - } - if (c==0) { - info = camel_folder_summary_uid((CamelFolderSummary *)cls, d->d_name); - if (info == NULL || (cls->index && (!camel_index_has_name(cls->index, d->d_name)))) { - /* need to add this file to the summary */ - if (info != NULL) { - g_hash_table_remove(left, camel_message_info_uid(info)); - camel_folder_summary_remove((CamelFolderSummary *)cls, info); - camel_folder_summary_info_free((CamelFolderSummary *)cls, info); - } - camel_mh_summary_add(cls, d->d_name, forceindex); - } else { - const char *uid = camel_message_info_uid(info); - CamelMessageInfo *old = g_hash_table_lookup(left, uid); - - if (old) { - camel_folder_summary_info_free((CamelFolderSummary *)cls, old); - g_hash_table_remove(left, uid); - } - camel_folder_summary_info_free((CamelFolderSummary *)cls, info); - } - } - } - closedir(dir); - g_hash_table_foreach(left, (GHFunc)remove_summary, cls); - g_hash_table_destroy(left); - - /* sort the summary based on message number (uid), since the directory order is not useful */ - CAMEL_SUMMARY_LOCK(s, summary_lock); - qsort(s->messages->pdata, s->messages->len, sizeof(CamelMessageInfo *), sort_uid_cmp); - CAMEL_SUMMARY_UNLOCK(s, summary_lock); - - return 0; -} - -static int -mh_summary_sync_message(CamelLocalSummary *cls, CamelMessageInfo *info, CamelException *ex) -{ - CamelMimeParser *mp; - const char *xev, *buffer; - int xevoffset; - int fd, outfd, len, outlen, ret=0; - char *name, *tmpname, *xevnew; - - name = g_strdup_printf("%s/%s", cls->folder_path, camel_message_info_uid(info)); - fd = open(name, O_RDWR); - if (fd == -1) - return -1; - - mp = camel_mime_parser_new(); - camel_mime_parser_init_with_fd(mp, fd); - if (camel_mime_parser_step(mp, 0, 0) != CAMEL_MIME_PARSER_STATE_EOF) { - xev = camel_mime_parser_header(mp, "X-Evolution", &xevoffset); - d(printf("xev = '%s'\n", xev)); - xevnew = camel_local_summary_encode_x_evolution(cls, info); - if (xev == NULL - || camel_local_summary_decode_x_evolution(cls, xev, NULL) == -1 - || strlen(xev)-1 != strlen(xevnew)) { - - d(printf("camel local summary_decode_xev = %d\n", camel_local_summary_decode_x_evolution(cls, xev, NULL))); - - /* need to write a new copy/unlink old */ - tmpname = g_strdup_printf("%s/.tmp.%d.%s", cls->folder_path, getpid(), camel_message_info_uid(info)); - d(printf("old xev was %d %s new xev is %d %s\n", strlen(xev), xev, strlen(xevnew), xevnew)); - d(printf("creating new message %s\n", tmpname)); - outfd = open(tmpname, O_CREAT|O_WRONLY|O_TRUNC, 0600); - if (outfd != -1) { - outlen = 0; - len = camel_local_summary_write_headers(outfd, camel_mime_parser_headers_raw(mp), xevnew, NULL, NULL); - if (len != -1) { - while (outlen != -1 && (len = camel_mime_parser_read(mp, &buffer, 10240)) > 0) { - d(printf("camel mime parser read, read %d bytes: %.*s\n", len, len, buffer)); - do { - outlen = write(outfd, buffer, len); - } while (outlen == -1 && errno == EINTR); - } - } - - d(printf("len = %d outlen = %d, renaming/finishing\n", len, outlen)); - if (close(outfd) == -1 - || len == -1 - || outlen == -1 - || rename(tmpname, name) == -1) { - unlink(tmpname); - ret = -1; - } - } else { - g_warning("sync can't create tmp file: %s", strerror (errno)); - } - g_free(tmpname); - } else { - d(printf("stamping in updated X-EV at %d\n", (int)xevoffset)); - /* else, we can just update the flags field */ - lseek(fd, xevoffset+strlen("X-Evolution: "), SEEK_SET); - do { - len = write(fd, xevnew, strlen(xevnew)); - } while (len == -1 && errno == EINTR); - if (len == -1) - ret = -1; - } - - g_free(xevnew); - } - - camel_object_unref((CamelObject *)mp); - g_free(name); - return ret; -} - -/* sync the summary file with the ondisk files */ -static int -mh_summary_sync(CamelLocalSummary *cls, gboolean expunge, CamelFolderChangeInfo *changes, CamelException *ex) -{ - int count, i; - CamelMessageInfo *info; - char *name; - const char *uid; - - d(printf("summary_sync(expunge=%s)\n", expunge?"true":"false")); - - /* we could probably get away without this ... but why not use it, esp if we're going to - be doing any significant io already */ - if (camel_local_summary_check(cls, changes, ex) == -1) - return -1; - - count = camel_folder_summary_count((CamelFolderSummary *)cls); - for (i=count-1;i>=0;i--) { - info = camel_folder_summary_index((CamelFolderSummary *)cls, i); - g_assert(info); - if (expunge && (info->flags & CAMEL_MESSAGE_DELETED)) { - uid = camel_message_info_uid(info); - name = g_strdup_printf("%s/%s", cls->folder_path, uid); - d(printf("deleting %s\n", name)); - if (unlink(name) == 0 || errno==ENOENT) { - - /* FIXME: put this in folder_summary::remove()? */ - if (cls->index) - camel_index_delete_name(cls->index, (char *)uid); - - camel_folder_change_info_remove_uid(changes, uid); - camel_folder_summary_remove((CamelFolderSummary *)cls, info); - } - g_free(name); - } else if (info->flags & (CAMEL_MESSAGE_FOLDER_NOXEV|CAMEL_MESSAGE_FOLDER_FLAGGED)) { - if (mh_summary_sync_message(cls, info, ex) != -1) { - info->flags &= 0xffff; - } else { - g_warning("Problem occured when trying to expunge, ignored"); - } - } - camel_folder_summary_info_free((CamelFolderSummary *)cls, info); - } - - return ((CamelLocalSummaryClass *)parent_class)->sync(cls, expunge, changes, ex); -} diff --git a/camel/providers/local/camel-mh-summary.h b/camel/providers/local/camel-mh-summary.h deleted file mode 100644 index 4ee30df63b..0000000000 --- a/camel/providers/local/camel-mh-summary.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2000 Ximian Inc. - * - * Authors: Not Zed <notzed@lostzed.mmc.com.au> - * - * 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_MH_SUMMARY_H -#define _CAMEL_MH_SUMMARY_H - -#include "camel-local-summary.h" -#include <camel/camel-folder.h> -#include <camel/camel-exception.h> -#include <camel/camel-index.h> - -#define CAMEL_MH_SUMMARY(obj) CAMEL_CHECK_CAST (obj, camel_mh_summary_get_type (), CamelMhSummary) -#define CAMEL_MH_SUMMARY_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_mh_summary_get_type (), CamelMhSummaryClass) -#define CAMEL_IS_MH_SUMMARY(obj) CAMEL_CHECK_TYPE (obj, camel_mh_summary_get_type ()) - -typedef struct _CamelMhSummary CamelMhSummary; -typedef struct _CamelMhSummaryClass CamelMhSummaryClass; - -struct _CamelMhSummary { - CamelLocalSummary parent; - struct _CamelMhSummaryPrivate *priv; -}; - -struct _CamelMhSummaryClass { - CamelLocalSummaryClass parent_class; - - /* virtual methods */ - - /* signals */ -}; - -CamelType camel_mh_summary_get_type (void); -CamelMhSummary *camel_mh_summary_new (const char *filename, const char *mhdir, CamelIndex *index); - -#endif /* ! _CAMEL_MH_SUMMARY_H */ - diff --git a/camel/providers/local/camel-spool-folder.c b/camel/providers/local/camel-spool-folder.c deleted file mode 100644 index 4c4a49fbf9..0000000000 --- a/camel/providers/local/camel-spool-folder.c +++ /dev/null @@ -1,186 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*- - * - * Authors: Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 2001-2003 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 <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 "camel-spool-folder.h" -#include "camel-spool-store.h" -#include "camel-stream-fs.h" -#include "camel-spool-summary.h" -#include "camel-data-wrapper.h" -#include "camel-mime-message.h" -#include "camel-stream-filter.h" -#include "camel-mime-filter-from.h" -#include "camel-exception.h" - -#include "camel-lock-client.h" - -#include "camel-local-private.h" - -#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/ - -static CamelFolderClass *parent_class = NULL; - -/* Returns the class for a CamelSpoolFolder */ -#define CSPOOLF_CLASS(so) CAMEL_SPOOL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -#define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -#define CSPOOLS_CLASS(so) CAMEL_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so)) - -static CamelLocalSummary *spool_create_summary(const char *path, const char *folder, CamelIndex *index); - -static int spool_lock(CamelLocalFolder *lf, CamelLockType type, CamelException *ex); -static void spool_unlock(CamelLocalFolder *lf); - -static void spool_finalize(CamelObject * object); - -static void -camel_spool_folder_class_init(CamelSpoolFolderClass *klass) -{ - CamelLocalFolderClass *lklass = (CamelLocalFolderClass *)klass; - - parent_class = (CamelFolderClass *)camel_mbox_folder_get_type(); - - /* virtual method overload */ - lklass->create_summary = spool_create_summary; - lklass->lock = spool_lock; - lklass->unlock = spool_unlock; -} - -static void -spool_init(gpointer object, gpointer klass) -{ - CamelSpoolFolder *spool_folder = object; - - spool_folder->lockid = -1; -} - -static void -spool_finalize(CamelObject * object) -{ - /*CamelSpoolFolder *spool_folder = CAMEL_SPOOL_FOLDER(object);*/ -} - -CamelType camel_spool_folder_get_type(void) -{ - static CamelType camel_spool_folder_type = CAMEL_INVALID_TYPE; - - if (camel_spool_folder_type == CAMEL_INVALID_TYPE) { - camel_spool_folder_type = camel_type_register(camel_mbox_folder_get_type(), "CamelSpoolFolder", - sizeof(CamelSpoolFolder), - sizeof(CamelSpoolFolderClass), - (CamelObjectClassInitFunc) camel_spool_folder_class_init, - NULL, - (CamelObjectInitFunc) spool_init, - (CamelObjectFinalizeFunc) spool_finalize); - } - - return camel_spool_folder_type; -} - -CamelFolder * -camel_spool_folder_new(CamelStore *parent_store, const char *full_name, guint32 flags, CamelException *ex) -{ - CamelFolder *folder; - - d(printf("Creating spool folder: %s in %s\n", full_name, camel_local_store_get_toplevel_dir((CamelLocalStore *)parent_store))); - - folder = (CamelFolder *)camel_object_new(CAMEL_SPOOL_FOLDER_TYPE); - - if (parent_store->flags & CAMEL_STORE_FILTER_INBOX - && strcmp(full_name, "INBOX") == 0) - folder->folder_flags |= CAMEL_FOLDER_FILTER_RECENT; - flags &= CAMEL_STORE_FOLDER_BODY_INDEX; - - folder = (CamelFolder *)camel_local_folder_construct((CamelLocalFolder *)folder, parent_store, full_name, flags, ex); - if (folder) { - if (camel_url_get_param(((CamelService *)parent_store)->url, "xstatus")) - camel_mbox_summary_xstatus((CamelMboxSummary *)folder->summary, TRUE); - } - - return folder; -} - -static CamelLocalSummary * -spool_create_summary(const char *path, const char *folder, CamelIndex *index) -{ - return (CamelLocalSummary *)camel_spool_summary_new(folder); -} - -static int -spool_lock(CamelLocalFolder *lf, CamelLockType type, CamelException *ex) -{ - int retry = 0; - CamelMboxFolder *mf = (CamelMboxFolder *)lf; - CamelSpoolFolder *sf = (CamelSpoolFolder *)lf; - - mf->lockfd = open(lf->folder_path, O_RDWR, 0); - if (mf->lockfd == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot create folder lock on %s: %s"), - lf->folder_path, g_strerror (errno)); - return -1; - } - - while (retry < CAMEL_LOCK_RETRY) { - if (retry > 0) - sleep(CAMEL_LOCK_DELAY); - - camel_exception_clear(ex); - - if (camel_lock_fcntl(mf->lockfd, type, ex) == 0) { - if (camel_lock_flock(mf->lockfd, type, ex) == 0) { - if ((sf->lockid = camel_lock_helper_lock(lf->folder_path, ex)) != -1) - return 0; - camel_unlock_flock(mf->lockfd); - } - camel_unlock_fcntl(mf->lockfd); - } - retry++; - } - - return -1; -} - -static void -spool_unlock(CamelLocalFolder *lf) -{ - CamelMboxFolder *mf = (CamelMboxFolder *)lf; - CamelSpoolFolder *sf = (CamelSpoolFolder *)lf; - - camel_lock_helper_unlock(sf->lockid); - sf->lockid = -1; - camel_unlock_flock(mf->lockfd); - camel_unlock_fcntl(mf->lockfd); - - close(mf->lockfd); - mf->lockfd = -1; -} diff --git a/camel/providers/local/camel-spool-folder.h b/camel/providers/local/camel-spool-folder.h deleted file mode 100644 index e778cdecf7..0000000000 --- a/camel/providers/local/camel-spool-folder.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Author: Michael Zucchi <notzed@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_SPOOL_FOLDER_H -#define CAMEL_SPOOL_FOLDER_H 1 - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus }*/ - -#include "camel-mbox-folder.h" -#include <camel/camel-folder-search.h> -#include <camel/camel-index.h> -#include "camel-spool-summary.h" -#include "camel-lock.h" - -/* #include "camel-store.h" */ - -#define CAMEL_SPOOL_FOLDER_TYPE (camel_spool_folder_get_type ()) -#define CAMEL_SPOOL_FOLDER(obj) (CAMEL_CHECK_CAST((obj), CAMEL_SPOOL_FOLDER_TYPE, CamelSpoolFolder)) -#define CAMEL_SPOOL_FOLDER_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_SPOOL_FOLDER_TYPE, CamelSpoolFolderClass)) -#define CAMEL_IS_SPOOL_FOLDER(o) (CAMEL_CHECK_TYPE((o), CAMEL_SPOOL_FOLDER_TYPE)) - -typedef struct { - CamelMboxFolder parent; - - struct _CamelSpoolFolderPrivate *priv; - - int lockid; /* lock id for dot locking */ -} CamelSpoolFolder; - -typedef struct { - CamelMboxFolderClass parent_class; -} CamelSpoolFolderClass; - -/* Standard Camel function */ -CamelType camel_spool_folder_get_type(void); - -CamelFolder *camel_spool_folder_new(CamelStore *parent_store, const char *full_name, guint32 flags, CamelException *ex); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CAMEL_SPOOL_FOLDER_H */ diff --git a/camel/providers/local/camel-spool-store.c b/camel/providers/local/camel-spool-store.c deleted file mode 100644 index 09720e4a01..0000000000 --- a/camel/providers/local/camel-spool-store.c +++ /dev/null @@ -1,483 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Authors: Michael Zucchi <notzed@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 - -#ifdef HAVE_ALLOCA_H -#include <alloca.h> -#endif - -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <errno.h> -#include <string.h> -#include <unistd.h> -#include <stdio.h> -#include <dirent.h> - -#include "camel-spool-store.h" -#include "camel-spool-folder.h" -#include "camel-exception.h" -#include "camel-url.h" -#include "camel-private.h" - -#define d(x) - -/* Returns the class for a CamelSpoolStore */ -#define CSPOOLS_CLASS(so) CAMEL_SPOOL_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -#define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) - -static void construct (CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, CamelException *ex); -static CamelFolder *get_folder(CamelStore * store, const char *folder_name, guint32 flags, CamelException * ex); -static char *get_name(CamelService *service, gboolean brief); -static CamelFolder *get_inbox (CamelStore *store, CamelException *ex); -static void rename_folder(CamelStore *store, const char *old_name, const char *new_name, CamelException *ex); -static CamelFolderInfo *get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex); -static void free_folder_info (CamelStore *store, CamelFolderInfo *fi); - -static void delete_folder(CamelStore *store, const char *folder_name, CamelException *ex); -static void rename_folder(CamelStore *store, const char *old, const char *new, CamelException *ex); - -static CamelStoreClass *parent_class = NULL; - -static void -camel_spool_store_class_init (CamelSpoolStoreClass *camel_spool_store_class) -{ - CamelStoreClass *camel_store_class = CAMEL_STORE_CLASS (camel_spool_store_class); - CamelServiceClass *camel_service_class = CAMEL_SERVICE_CLASS (camel_spool_store_class); - - parent_class = CAMEL_STORE_CLASS(camel_mbox_store_get_type()); - - /* virtual method overload */ - camel_service_class->construct = construct; - camel_service_class->get_name = get_name; - camel_store_class->get_folder = get_folder; - camel_store_class->get_inbox = get_inbox; - camel_store_class->get_folder_info = get_folder_info; - camel_store_class->free_folder_info = free_folder_info; - - camel_store_class->delete_folder = delete_folder; - camel_store_class->rename_folder = rename_folder; -} - -CamelType -camel_spool_store_get_type (void) -{ - static CamelType camel_spool_store_type = CAMEL_INVALID_TYPE; - - if (camel_spool_store_type == CAMEL_INVALID_TYPE) { - camel_spool_store_type = camel_type_register (camel_mbox_store_get_type(), "CamelSpoolStore", - sizeof (CamelSpoolStore), - sizeof (CamelSpoolStoreClass), - (CamelObjectClassInitFunc) camel_spool_store_class_init, - NULL, - NULL, - NULL); - } - - return camel_spool_store_type; -} - -static void -construct (CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, CamelException *ex) -{ - struct stat st; - - d(printf("constructing store of type %s '%s:%s'\n", - camel_type_to_name(((CamelObject *)service)->s.type), url->protocol, url->path)); - - CAMEL_SERVICE_CLASS (parent_class)->construct (service, session, provider, url, ex); - if (camel_exception_is_set (ex)) - return; - - if (service->url->path[0] != '/') { - camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("Store root %s is not an absolute path"), service->url->path); - return; - } - - if (stat(service->url->path, &st) == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("Spool `%s' cannot be opened: %s"), - service->url->path, g_strerror (errno)); - return; - } - - if (S_ISREG(st.st_mode)) - ((CamelSpoolStore *)service)->type = CAMEL_SPOOL_STORE_MBOX; - else if (S_ISDIR(st.st_mode)) - /* we could check here for slight variations */ - ((CamelSpoolStore *)service)->type = CAMEL_SPOOL_STORE_ELM; - else { - camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("Spool `%s' is not a regular file or directory"), - service->url->path); - return; - } -} - -static CamelFolder * -get_folder(CamelStore * store, const char *folder_name, guint32 flags, CamelException * ex) -{ - CamelFolder *folder = NULL; - struct stat st; - char *name; - - d(printf("opening folder %s on path %s\n", folder_name, path)); - - /* we only support an 'INBOX' in mbox mode */ - if (((CamelSpoolStore *)store)->type == CAMEL_SPOOL_STORE_MBOX) { - if (strcmp(folder_name, "INBOX") != 0) { - camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("Folder `%s/%s' does not exist."), - ((CamelService *)store)->url->path, folder_name); - } else { - folder = camel_spool_folder_new(store, folder_name, flags, ex); - } - } else { - name = g_strdup_printf("%s%s", CAMEL_LOCAL_STORE(store)->toplevel_dir, folder_name); - if (stat(name, &st) == -1) { - if (errno != ENOENT) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not open folder `%s':\n%s"), - folder_name, g_strerror (errno)); - } else if ((flags & CAMEL_STORE_FOLDER_CREATE) == 0) { - camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("Folder `%s' does not exist."), - folder_name); - } else { - if (creat (name, 0600) == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not create folder `%s':\n%s"), - folder_name, g_strerror (errno)); - } else { - folder = camel_spool_folder_new(store, folder_name, flags, ex); - } - } - } else if (!S_ISREG(st.st_mode)) { - camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("`%s' is not a mailbox file."), name); - } else { - folder = camel_spool_folder_new(store, folder_name, flags, ex); - } - g_free(name); - } - - return folder; -} - -static CamelFolder * -get_inbox(CamelStore *store, CamelException *ex) -{ - if (((CamelSpoolStore *)store)->type == CAMEL_SPOOL_STORE_MBOX) - return get_folder (store, "INBOX", CAMEL_STORE_FOLDER_CREATE, ex); - else { - camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("Store does not support an INBOX")); - return NULL; - } -} - -static char * -get_name (CamelService *service, gboolean brief) -{ - if (brief) - return g_strdup(service->url->path); - else - return g_strdup_printf(((CamelSpoolStore *)service)->type == CAMEL_SPOOL_STORE_MBOX? - _("Spool mail file %s"):_("Spool folder tree %s"), service->url->path); -} - -/* default implementation, rename all */ -static void -rename_folder(CamelStore *store, const char *old, const char *new, CamelException *ex) -{ - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Spool folders cannot be renamed")); -} - -/* default implementation, only delete metadata */ -static void -delete_folder(CamelStore *store, const char *folder_name, CamelException *ex) -{ - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Spool folders cannot be deleted")); -} - -static void free_folder_info (CamelStore *store, CamelFolderInfo *fi) -{ - if (fi) { - g_free(fi->url); - g_free(fi->name); - g_free(fi->full_name); - g_free(fi->path); - g_free(fi); - } -} - -static CamelFolderInfo * -camel_folder_info_new(const char *url, const char *full, const char *name, int unread) -{ - CamelFolderInfo *fi; - - fi = g_malloc0(sizeof(*fi)); - fi->url = g_strdup(url); - fi->full_name = g_strdup(full); - fi->name = g_strdup(name); - fi->unread_message_count = unread; - camel_folder_info_build_path(fi, '/'); - - d(printf("Adding spoold info: '%s' '%s' '%s' '%s'\n", fi->path, fi->name, fi->full_name, fi->url)); - - return fi; -} - -/* used to find out where we've visited already */ -struct _inode { - dev_t dnode; - ino_t inode; -}; - -/* returns number of records found at or below this level */ -static int scan_dir(CamelStore *store, GHashTable *visited, char *root, const char *path, guint32 flags, CamelFolderInfo *parent, CamelFolderInfo **fip, CamelException *ex) -{ - DIR *dir; - struct dirent *d; - char *name, *uri, *tmp, *fname; - CamelFolderInfo *fi = NULL; - struct stat st; - CamelFolder *folder; - int unread; - char from[80]; - FILE *fp; - - d(printf("checking dir '%s' part '%s' for mbox content\n", root, path)); - - /* look for folders matching the right structure, recursively */ - if (path) { - name = alloca(strlen(root) + strlen(path) + 2); - sprintf(name, "%s/%s", root, path); - } else - name = root; - - if (stat(name, &st) == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not scan folder `%s': %s"), - name, g_strerror (errno)); - } else if (S_ISREG(st.st_mode)) { - /* incase we start scanning from a file. messy duplication :-/ */ - if (path) { - folder = camel_object_bag_get(store->folders, path); - if (folder) { - /* should this refresh if ! FAST? */ - unread = camel_folder_get_unread_message_count(folder); - camel_object_unref(folder); - } else - unread = -1; - tmp = strrchr(path, '/'); - if (tmp) - tmp++; - else - tmp = (char *)path; - uri = g_strdup_printf("%s:%s#%s", ((CamelService *)store)->url->protocol, root, path); - fi = camel_folder_info_new(uri, path, tmp, unread); - fi->parent = parent; - fi->sibling = *fip; - *fip = fi; - g_free(uri); - } - return 0; - } - - dir = opendir(name); - if (dir == NULL) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not scan folder `%s': %s"), - name, g_strerror (errno)); - return -1; - } - - if (path != NULL) { - uri = g_strdup_printf("%s:%s;noselect=yes#%s", ((CamelService *)store)->url->protocol, root, path); - tmp = strrchr(path, '/'); - if (tmp == NULL) - tmp = (char *)path; - else - tmp++; - fi = camel_folder_info_new(uri, path, tmp, -1); - fi->parent = parent; - fi->sibling = *fip; - *fip = fi; - g_free(uri); - - fip = &fi->child; - parent = fi; - } - - while ( (d = readdir(dir)) ) { - if (strcmp(d->d_name, ".") == 0 - || strcmp(d->d_name, "..") == 0) - continue; - - tmp = g_strdup_printf("%s/%s", name, d->d_name); - if (stat(tmp, &st) == 0) { - if (path) - fname = g_strdup_printf("%s/%s", path, d->d_name); - else - fname = g_strdup(d->d_name); - - if (S_ISREG(st.st_mode)) { - /* first, see if we already have it open */ - folder = camel_object_bag_get(store->folders, fname); - if (folder) { - /* should this refresh if ! FAST? */ - unread = camel_folder_get_unread_message_count(folder); - camel_object_unref(folder); - } else - unread = -1; - - /* no? check its content to see if its a folder or not */ - if (folder == NULL) { - fp = fopen(tmp, "r"); - if (fp != NULL) { - if (st.st_size == 0 - || (fgets(from, sizeof(from), fp) != NULL - && strncmp(from, "From ", 5) == 0)) { - folder = (CamelFolder *)1; - /* TODO: if slow mode selected, we could look up unread counts here - - but its pretty expensive */ - } - fclose(fp); - } - } - - if (folder != NULL) { - uri = g_strdup_printf("%s:%s#%s", ((CamelService *)store)->url->protocol, root, fname); - fi = camel_folder_info_new(uri, fname, d->d_name, unread); - fi->parent = parent; - fi->sibling = *fip; - *fip = fi; - g_free(uri); - } - - } else if (S_ISDIR(st.st_mode)) { - struct _inode in = { st.st_dev, st.st_ino }; - - /* see if we've visited already */ - if (g_hash_table_lookup(visited, &in) == NULL) { - struct _inode *inew = g_malloc(sizeof(*inew)); - - *inew = in; - g_hash_table_insert(visited, inew, inew); - - if (scan_dir(store, visited, root, fname, flags, parent, fip, ex) == -1) { - g_free(tmp); - g_free(fname); - closedir(dir); - return -1; - } - } - } - g_free(fname); - - } - g_free(tmp); - } - closedir(dir); - - return 0; -} - -static guint inode_hash(const void *d) -{ - const struct _inode *v = d; - - return v->inode ^ v->dnode; -} - -static gboolean inode_equal(const void *a, const void *b) -{ - const struct _inode *v1 = a, *v2 = b; - - return v1->inode == v2->inode && v1->dnode == v2->dnode; -} - -static void inode_free(void *k, void *v, void *d) -{ - g_free(k); -} - -static CamelFolderInfo * -get_folder_info_elm(CamelStore *store, const char *top, guint32 flags, CamelException *ex) -{ - CamelFolderInfo *fi = NULL; - GHashTable *visited; - - visited = g_hash_table_new(inode_hash, inode_equal); - - if (scan_dir(store, visited, ((CamelService *)store)->url->path, top, flags, NULL, &fi, ex) == -1 && fi != NULL) { - camel_store_free_folder_info_full(store, fi); - fi = NULL; - } - - g_hash_table_foreach(visited, inode_free, NULL); - g_hash_table_destroy(visited); - - return fi; -} - -static CamelFolderInfo * -get_folder_info_mbox(CamelStore *store, const char *top, guint32 flags, CamelException *ex) -{ - CamelFolderInfo *fi = NULL; - CamelService *service = (CamelService *)store; - CamelFolder *folder; - - if (top == NULL || strcmp(top, "INBOX") == 0) { - fi = g_malloc0(sizeof(*fi)); - fi->full_name = g_strdup("INBOX"); - fi->name = g_strdup("INBOX"); - fi->url = g_strdup_printf("%s:%s#%s", service->url->protocol, service->url->path, fi->name); - - folder = camel_object_bag_get(store->folders, fi->full_name); - if (folder) { - fi->unread_message_count = camel_folder_get_unread_message_count(folder); - camel_object_unref(folder); - } else - fi->unread_message_count = -1; - - camel_folder_info_build_path(fi, '/'); - } - - return fi; -} - -static CamelFolderInfo * -get_folder_info(CamelStore *store, const char *top, guint32 flags, CamelException *ex) -{ - if (((CamelSpoolStore *)store)->type == CAMEL_SPOOL_STORE_MBOX) - return get_folder_info_mbox(store, top, flags, ex); - else - return get_folder_info_elm(store, top, flags, ex); -} diff --git a/camel/providers/local/camel-spool-store.h b/camel/providers/local/camel-spool-store.h deleted file mode 100644 index 1e1753481b..0000000000 --- a/camel/providers/local/camel-spool-store.h +++ /dev/null @@ -1,69 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Authors: Michael Zucchi <notzed@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_SPOOL_STORE_H -#define CAMEL_SPOOL_STORE_H 1 - - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus }*/ - -#include "camel-mbox-store.h" - -#define CAMEL_SPOOL_STORE_TYPE (camel_spool_store_get_type ()) -#define CAMEL_SPOOL_STORE(obj) (CAMEL_CHECK_CAST((obj), CAMEL_SPOOL_STORE_TYPE, CamelSpoolStore)) -#define CAMEL_SPOOL_STORE_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_SPOOL_STORE_TYPE, CamelSpoolStoreClass)) -#define CAMEL_IS_SPOOL_STORE(o) (CAMEL_CHECK_TYPE((o), CAMEL_SPOOL_STORE_TYPE)) - -typedef enum _camel_spool_store_t { - CAMEL_SPOOL_STORE_MBOX, /* a single mbox */ - CAMEL_SPOOL_STORE_ELM, /* elm/pine/etc tree of mbox files in folders */ -} camel_spool_store_t; - -typedef struct { - CamelMboxStore parent_object; - - camel_spool_store_t type; -} CamelSpoolStore; - - - -typedef struct { - CamelMboxStoreClass parent_class; - -} CamelSpoolStoreClass; - - -/* public methods */ - -/* Standard Camel function */ -CamelType camel_spool_store_get_type (void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CAMEL_SPOOL_STORE_H */ - - diff --git a/camel/providers/local/camel-spool-summary.c b/camel/providers/local/camel-spool-summary.c deleted file mode 100644 index 7991a881cc..0000000000 --- a/camel/providers/local/camel-spool-summary.c +++ /dev/null @@ -1,344 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*- - * - * Copyright (C) 2001 Ximian Inc. (www.ximian.com) - * - * 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 <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/uio.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <stdlib.h> - -#include <ctype.h> - -#include "camel-spool-summary.h" -#include "camel-mime-message.h" -#include "camel-file-utils.h" -#include "camel-operation.h" - -#define io(x) -#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/ - -#define CAMEL_SPOOL_SUMMARY_VERSION (0x400) - -static int spool_summary_load(CamelLocalSummary *cls, int forceindex, CamelException *ex); -static int spool_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changeinfo, CamelException *ex); - -static int spool_summary_sync_full(CamelMboxSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex); - -static void camel_spool_summary_class_init (CamelSpoolSummaryClass *klass); -static void camel_spool_summary_init (CamelSpoolSummary *obj); -static void camel_spool_summary_finalise (CamelObject *obj); - -static CamelFolderSummaryClass *camel_spool_summary_parent; - -CamelType -camel_spool_summary_get_type(void) -{ - static CamelType type = CAMEL_INVALID_TYPE; - - if (type == CAMEL_INVALID_TYPE) { - type = camel_type_register(camel_mbox_summary_get_type(), "CamelSpoolSummary", - sizeof (CamelSpoolSummary), - sizeof (CamelSpoolSummaryClass), - (CamelObjectClassInitFunc) camel_spool_summary_class_init, - NULL, - (CamelObjectInitFunc) camel_spool_summary_init, - (CamelObjectFinalizeFunc) camel_spool_summary_finalise); - } - - return type; -} - -static void -camel_spool_summary_class_init(CamelSpoolSummaryClass *klass) -{ - CamelLocalSummaryClass *lklass = (CamelLocalSummaryClass *)klass; - CamelMboxSummaryClass *mklass = (CamelMboxSummaryClass *)klass; - - camel_spool_summary_parent = CAMEL_FOLDER_SUMMARY_CLASS(camel_mbox_summary_get_type()); - - lklass->load = spool_summary_load; - lklass->check = spool_summary_check; - - mklass->sync_full = spool_summary_sync_full; -} - -static void -camel_spool_summary_init(CamelSpoolSummary *obj) -{ - struct _CamelFolderSummary *s = (CamelFolderSummary *)obj; - - /* message info size is from mbox parent */ - - /* and a unique file version */ - s->version += CAMEL_SPOOL_SUMMARY_VERSION; -} - -static void -camel_spool_summary_finalise(CamelObject *obj) -{ - /*CamelSpoolSummary *mbs = CAMEL_SPOOL_SUMMARY(obj);*/ -} - -CamelSpoolSummary * -camel_spool_summary_new(const char *mbox_name) -{ - CamelSpoolSummary *new = (CamelSpoolSummary *)camel_object_new(camel_spool_summary_get_type()); - - camel_local_summary_construct((CamelLocalSummary *)new, NULL, mbox_name, NULL); - return new; -} - -static int -spool_summary_load(CamelLocalSummary *cls, int forceindex, CamelException *ex) -{ - g_warning("spool summary - not loading anything\n"); - return 0; -} - -/* perform a full sync */ -static int -spool_summary_sync_full(CamelMboxSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex) -{ - int fd = -1, fdout = -1; - char *tmpname = NULL; - char *buffer, *p; - off_t spoollen, outlen; - int size, sizeout; - struct stat st; - guint32 flags = (expunge?1:0); - - d(printf("performing full summary/sync\n")); - - camel_operation_start(NULL, _("Storing folder")); - - fd = open(((CamelLocalSummary *)cls)->folder_path, O_RDWR); - if (fd == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not open file: %s: %s"), - ((CamelLocalSummary *)cls)->folder_path, - g_strerror (errno)); - camel_operation_end(NULL); - return -1; - } - -#ifdef HAVE_MKSTEMP - tmpname = alloca (64); - sprintf (tmpname, "/tmp/spool.camel.XXXXXX"); - fdout = mkstemp (tmpname); -#else -#warning "Your system has no mkstemp(3), spool updating may be insecure" - tmpname = alloca (L_tmpnam); - tmpnam (tmpname); - fdout = open (tmpname, O_RDWR|O_CREAT|O_EXCL, 0600); -#endif - d(printf("Writing tmp file to %s\n", tmpname)); - if (fdout == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot open temporary mailbox: %s"), - g_strerror (errno)); - goto error; - } - - if (camel_mbox_summary_sync_mbox((CamelMboxSummary *)cls, flags, changeinfo, fd, fdout, ex) == -1) - goto error; - - - /* sync out content */ - if (fsync(fdout) == -1) { - g_warning("Cannot sync temporary folder: %s", strerror (errno)); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not sync temporary folder %s: %s"), - ((CamelLocalSummary *)cls)->folder_path, - g_strerror (errno)); - goto error; - } - - /* see if we can write this much to the spool file */ - if (fstat(fd, &st) == -1) { - g_warning("Cannot sync temporary folder: %s", strerror (errno)); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not sync temporary folder %s: %s"), - ((CamelLocalSummary *)cls)->folder_path, - g_strerror (errno)); - goto error; - } - spoollen = st.st_size; - - if (fstat(fdout, &st) == -1) { - g_warning("Cannot sync temporary folder: %s", strerror (errno)); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not sync temporary folder %s: %s"), - ((CamelLocalSummary *)cls)->folder_path, - g_strerror (errno)); - goto error; - } - outlen = st.st_size; - - /* I think this is the right way to do this - checking that the file will fit the new data */ - if (outlen>0 - && (lseek(fd, outlen-1, SEEK_SET) == -1 - || write(fd, "", 1) != 1 - || fsync(fd) == -1 - || lseek(fd, 0, SEEK_SET) == -1 - || lseek(fdout, 0, SEEK_SET) == -1)) { - g_warning("Cannot sync spool folder: %s", strerror (errno)); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not sync spool folder %s: %s"), - ((CamelLocalSummary *)cls)->folder_path, - g_strerror (errno)); - /* incase we ran out of room, remove any trailing space first */ - ftruncate(fd, spoollen); - goto error; - } - - - /* now copy content back */ - buffer = g_malloc(8192); - size = 1; - while (size>0) { - do { - size = read(fdout, buffer, 8192); - } while (size == -1 && errno == EINTR); - - if (size > 0) { - p = buffer; - do { - sizeout = write(fd, p, size); - if (sizeout > 0) { - p+= sizeout; - size -= sizeout; - } - } while ((sizeout == -1 && errno == EINTR) && size > 0); - size = sizeout; - } - - if (size == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not sync spool folder %s: %s\n" - "Folder may be corrupt, copy saved in `%s'"), - ((CamelLocalSummary *)cls)->folder_path, - g_strerror (errno), tmpnam); - /* so we dont delete it */ - close(fdout); - tmpname = NULL; - fdout = -1; - g_free(buffer); - goto error; - } - } - - g_free(buffer); - - d(printf("Closing folders\n")); - - if (ftruncate(fd, outlen) == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not sync spool folder %s: %s\n" - "Folder may be corrupt, copy saved in `%s'"), - ((CamelLocalSummary *)cls)->folder_path, - g_strerror (errno), tmpnam); - close(fdout); - tmpname = NULL; - fdout = -1; - goto error; - } - - if (close(fd) == -1) { - g_warning("Cannot close source folder: %s", strerror (errno)); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not sync spool folder %s: %s\n" - "Folder may be corrupt, copy saved in `%s'"), - ((CamelLocalSummary *)cls)->folder_path, - g_strerror (errno), tmpnam); - close(fdout); - tmpname = NULL; - fdout = -1; - fd = -1; - goto error; - } - - close(fdout); - unlink(tmpname); - - camel_operation_end(NULL); - - return 0; - error: - if (fd != -1) - close(fd); - - if (fdout != -1) - close(fdout); - - if (tmpname) - unlink(tmpname); - - camel_operation_end(NULL); - - return -1; -} - -static int -spool_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changeinfo, CamelException *ex) -{ - int i, work, count; - struct stat st; - CamelFolderSummary *s = (CamelFolderSummary *)cls; - - if (((CamelLocalSummaryClass *)camel_spool_summary_parent)->check(cls, changeinfo, ex) == -1) - return -1; - - /* check to see if we need to copy/update the file; missing xev headers prompt this */ - work = FALSE; - count = camel_folder_summary_count(s); - for (i=0;!work && i<count; i++) { - CamelMessageInfo *info = camel_folder_summary_index(s, i); - g_assert(info); - work = (info->flags & (CAMEL_MESSAGE_FOLDER_NOXEV)) != 0; - camel_folder_summary_info_free(s, info); - } - - /* if we do, then write out the headers using sync_full, etc */ - if (work) { - d(printf("Have to add new headers, re-syncing from the start to accomplish this\n")); - if (((CamelMboxSummaryClass *)((CamelObject *)cls)->klass)->sync_full((CamelMboxSummary *)cls, FALSE, changeinfo, ex) == -1) - return -1; - - if (stat(cls->folder_path, &st) == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Unknown error: %s"), - g_strerror (errno)); - return -1; - } - - ((CamelMboxSummary *)cls)->folder_size = st.st_size; - ((CamelFolderSummary *)cls)->time = st.st_mtime; - } - - return 0; -} diff --git a/camel/providers/local/camel-spool-summary.h b/camel/providers/local/camel-spool-summary.h deleted file mode 100644 index b72aeda527..0000000000 --- a/camel/providers/local/camel-spool-summary.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2001 Ximian Inc. (www.ximian.com) - * - * 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_SPOOL_SUMMARY_H -#define _CAMEL_SPOOL_SUMMARY_H - -#include <camel/camel-folder-summary.h> -#include <camel/camel-folder.h> -#include <camel/camel-exception.h> -#include <camel/camel-index.h> -#include "camel-mbox-summary.h" - -#define CAMEL_SPOOL_SUMMARY(obj) CAMEL_CHECK_CAST (obj, camel_spool_summary_get_type (), CamelSpoolSummary) -#define CAMEL_SPOOL_SUMMARY_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_spool_summary_get_type (), CamelSpoolSummaryClass) -#define CAMEL_IS_SPOOL_SUMMARY(obj) CAMEL_CHECK_TYPE (obj, camel_spool_summary_get_type ()) - -typedef struct _CamelSpoolSummary CamelSpoolSummary; -typedef struct _CamelSpoolSummaryClass CamelSpoolSummaryClass; - -struct _CamelSpoolSummary { - CamelMboxSummary parent; - -}; - -struct _CamelSpoolSummaryClass { - CamelMboxSummaryClass parent_class; -}; - -CamelType camel_spool_summary_get_type (void); -void camel_spool_summary_construct (CamelSpoolSummary *new, const char *filename, const char *spool_name, CamelIndex *index); - -/* create the summary, in-memory only */ -CamelSpoolSummary *camel_spool_summary_new(const char *filename); - -/* load/check the summary */ -int camel_spool_summary_load(CamelSpoolSummary *cls, int forceindex, CamelException *ex); -/* check for new/removed messages */ -int camel_spool_summary_check(CamelSpoolSummary *cls, CamelFolderChangeInfo *, CamelException *ex); -/* perform a folder sync or expunge, if needed */ -int camel_spool_summary_sync(CamelSpoolSummary *cls, gboolean expunge, CamelFolderChangeInfo *, CamelException *ex); -/* add a new message to the summary */ -CamelMessageInfo *camel_spool_summary_add(CamelSpoolSummary *cls, CamelMimeMessage *msg, const CamelMessageInfo *info, CamelFolderChangeInfo *, CamelException *ex); - -/* generate an X-Evolution header line */ -char *camel_spool_summary_encode_x_evolution(CamelSpoolSummary *cls, const CamelMessageInfo *info); -int camel_spool_summary_decode_x_evolution(CamelSpoolSummary *cls, const char *xev, CamelMessageInfo *info); - -/* utility functions - write headers to a file with optional X-Evolution header */ -int camel_spool_summary_write_headers(int fd, struct _camel_header_raw *header, char *xevline); - -#endif /* ! _CAMEL_SPOOL_SUMMARY_H */ - diff --git a/camel/providers/local/libcamellocal.urls b/camel/providers/local/libcamellocal.urls deleted file mode 100644 index e2279ed72a..0000000000 --- a/camel/providers/local/libcamellocal.urls +++ /dev/null @@ -1,5 +0,0 @@ -mh -mbox -maildir -spool -spoold diff --git a/camel/providers/nntp/.cvsignore b/camel/providers/nntp/.cvsignore deleted file mode 100644 index 2fbeab8712..0000000000 --- a/camel/providers/nntp/.cvsignore +++ /dev/null @@ -1,12 +0,0 @@ -.deps -Makefile -Makefile.in -.libs -.deps -*.lo -*.la -test-newsrc -*.bb -*.bbg -*.da -*.gcov diff --git a/camel/providers/nntp/Makefile.am b/camel/providers/nntp/Makefile.am deleted file mode 100644 index 464624b82d..0000000000 --- a/camel/providers/nntp/Makefile.am +++ /dev/null @@ -1,36 +0,0 @@ -## Process this file with automake to produce Makefile.in - -libcamelnntpincludedir = $(privincludedir)/camel - -camel_provider_LTLIBRARIES = libcamelnntp.la -camel_provider_DATA = libcamelnntp.urls - -INCLUDES = -I../.. \ - -I$(top_srcdir)/camel \ - -I$(top_srcdir)/intl \ - -I$(top_srcdir)/e-util \ - -I$(top_srcdir) \ - $(CAMEL_CFLAGS) \ - $(GNOME_INCLUDEDIR) \ - $(GTK_INCLUDEDIR) \ - -DG_LOG_DOMAIN=\"camel-nntp-provider\" - -libcamelnntp_la_SOURCES = \ - camel-nntp-provider.c \ - camel-nntp-store.c \ - camel-nntp-folder.c \ - camel-nntp-stream.c \ - camel-nntp-summary.c - -libcamelnntpinclude_HEADERS = \ - camel-nntp-store.h \ - camel-nntp-folder.h \ - camel-nntp-stream.h \ - camel-nntp-summary.h - -noinst_HEADERS = \ - camel-nntp-private.h - -libcamelnntp_la_LDFLAGS = -avoid-version -module - -EXTRA_DIST = libcamelnntp.urls diff --git a/camel/providers/nntp/camel-nntp-auth.c b/camel/providers/nntp/camel-nntp-auth.c deleted file mode 100644 index f8d3a62e27..0000000000 --- a/camel/providers/nntp/camel-nntp-auth.c +++ /dev/null @@ -1,92 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-nntp-auth.c : authentication for nntp */ - -/* - * - * Copyright (C) 2000 Ximian, Inc. <toshok@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-nntp-auth.h> -#include <camel-nntp-store.h> -#include <camel-nntp-resp-codes.h> -#include <camel-exception.h> -#include <camel-session.h> - -int -camel_nntp_auth_authenticate (CamelNNTPStore *store, CamelException *ex) -{ - CamelService *service = CAMEL_SERVICE (store); - CamelSession *session = camel_service_get_session (service); - int resp; - - if (!service->url->authmech && !service->url->passwd) { - gchar *prompt; - - prompt = g_strdup_printf (_("Please enter the NNTP password for %s@%s"), - service->url->user, service->url->host); - service->url->passwd = - camel_session_get_password (session, prompt, - TRUE, service, "password", ex); - g_free (prompt); - - if (!service->url->passwd) { - camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, - "You didn\'t enter a password."); - resp = 666; - goto done; - } - } - - /* first send username */ - resp = camel_nntp_command (store, ex, NULL, "AUTHINFO USER %s", service->url->user); - - if (resp == NNTP_AUTH_REJECTED) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE, - _("Server rejected username")); - goto done; - - } - else if (resp != NNTP_AUTH_CONTINUE) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE, - _("Failed to send username to server")); - goto done; - } - - /* then send the username if the server asks for it */ - resp = camel_nntp_command (store, ex, NULL, "AUTHINFO PASS %s", service->url->passwd); - - if (resp == NNTP_AUTH_REJECTED) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE, - _("Server rejected username/password")); - goto done; - } - - done: - - if (service->url->passwd) { - /* let's be paranoid */ - memset (service->url->passwd, 0, strlen (service->url->passwd)); - g_free (service->url->passwd); - service->url->passwd = NULL; - } - return resp; -} diff --git a/camel/providers/nntp/camel-nntp-auth.h b/camel/providers/nntp/camel-nntp-auth.h deleted file mode 100644 index fc96cf6a4e..0000000000 --- a/camel/providers/nntp/camel-nntp-auth.h +++ /dev/null @@ -1,42 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-nntp-auth.h : authentication for nntp */ - -/* - * - * Author : Chris Toshok <toshok@ximian.com> - * - * Copyright (C) 1999 Ximian . - * - * 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_NNTP_AUTH_H -#define CAMEL_NNTP_AUTH_H 1 - -#include <camel-nntp-store.h> - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus }*/ - -int camel_nntp_auth_authenticate (CamelNNTPStore *store, CamelException *ex); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CAMEL_NNTP_AUTH_H */ diff --git a/camel/providers/nntp/camel-nntp-folder.c b/camel/providers/nntp/camel-nntp-folder.c deleted file mode 100644 index 9f0832bc33..0000000000 --- a/camel/providers/nntp/camel-nntp-folder.c +++ /dev/null @@ -1,405 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-nntp-folder.c : Class for a news folder - * - * Authors : Chris Toshok <toshok@ximian.com> - * Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 2001-2003 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 <stdlib.h> -#include <string.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <dirent.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> - -#include "camel/camel-file-utils.h" -#include "camel/camel-stream-mem.h" -#include "camel/camel-data-wrapper.h" -#include "camel/camel-mime-message.h" -#include "camel/camel-folder-search.h" -#include "camel/camel-exception.h" -#include "camel/camel-session.h" -#include "camel/camel-data-cache.h" - -#include "camel-nntp-summary.h" -#include "camel-nntp-store.h" -#include "camel-nntp-folder.h" -#include "camel-nntp-store.h" -#include "camel-nntp-private.h" - -static CamelFolderClass *parent_class = NULL; - -/* Returns the class for a CamelNNTPFolder */ -#define CNNTPF_CLASS(so) CAMEL_NNTP_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -#define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -#define CNNTPS_CLASS(so) CAMEL_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so)) - -static void -nntp_folder_sync (CamelFolder *folder, gboolean expunge, CamelException *ex) -{ - CamelNNTPStore *nntp_store; - CamelFolderChangeInfo *changes = NULL; - CamelNNTPFolder *nntp_folder; - - nntp_store = (CamelNNTPStore *)folder->parent_store; - nntp_folder = (CamelNNTPFolder *)folder; - - CAMEL_NNTP_STORE_LOCK(nntp_store, command_lock); - - if (camel_nntp_summary_check((CamelNNTPSummary *)folder->summary, nntp_folder->changes, ex) != -1) - camel_folder_summary_save (folder->summary); - - if (camel_folder_change_info_changed(nntp_folder->changes)) { - changes = nntp_folder->changes; - nntp_folder->changes = camel_folder_change_info_new(); - } - - CAMEL_NNTP_STORE_UNLOCK(nntp_store, command_lock); - - if (changes) { - camel_object_trigger_event((CamelObject *)folder, "folder_changed", changes); - camel_folder_change_info_free(changes); - } -} - -static void -nntp_folder_set_message_flags(CamelFolder *folder, const char *uid, guint32 flags, guint32 set) -{ - ((CamelFolderClass *)parent_class)->set_message_flags(folder, uid, flags, set); -} - -static CamelMimeMessage * -nntp_folder_get_message (CamelFolder *folder, const char *uid, CamelException *ex) -{ - CamelMimeMessage *message = NULL; - CamelNNTPStore *nntp_store; - CamelFolderChangeInfo *changes; - CamelNNTPFolder *nntp_folder; - CamelStream *stream = NULL; - int ret; - char *line; - const char *msgid; - - nntp_store = (CamelNNTPStore *)folder->parent_store; - nntp_folder = (CamelNNTPFolder *)folder; - - CAMEL_NNTP_STORE_LOCK(nntp_store, command_lock); - - msgid = strchr(uid, ','); - if (msgid == 0) { - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Internal error: uid in invalid format: %s"), uid); - goto fail; - } - msgid++; - - /* Lookup in cache, NEWS is global messageid's so use a global cache path */ - stream = camel_data_cache_get(nntp_store->cache, "cache", msgid, NULL); - if (stream == NULL) { - /* Not in cache, retrieve and put in cache */ - if (camel_nntp_store_set_folder(nntp_store, folder, nntp_folder->changes, ex) == -1) - goto fail; - - ret = camel_nntp_command(nntp_store, &line, "article %s", msgid); - if (ret == -1) - goto error; - - if (ret == 220) { - stream = camel_data_cache_add(nntp_store->cache, "cache", msgid, NULL); - if (stream) { - if (camel_stream_write_to_stream((CamelStream *)nntp_store->stream, stream) == -1) - goto error; - if (camel_stream_reset(stream) == -1) - goto error; - } else { - stream = (CamelStream *)nntp_store->stream; - camel_object_ref((CamelObject *)stream); - } - } - } - - if (stream) { - message = camel_mime_message_new(); - if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)message, stream) == -1) - goto error; - - CAMEL_NNTP_STORE_UNLOCK(nntp_store, command_lock); - - camel_object_unref((CamelObject *)stream); - return message; - } - - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot get message %s: %s"), uid, line); - -error: - if (errno == EINTR) - camel_exception_setv(ex, CAMEL_EXCEPTION_USER_CANCEL, _("User cancelled")); - else - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot get message %s: %s"), uid, strerror(errno)); - -fail: - if (message) - camel_object_unref((CamelObject *)message); - - if (stream) - camel_object_unref((CamelObject *)stream); - - if (camel_folder_change_info_changed(nntp_folder->changes)) { - changes = nntp_folder->changes; - nntp_folder->changes = camel_folder_change_info_new(); - } else { - changes = NULL; - } - - CAMEL_NNTP_STORE_UNLOCK(nntp_store, command_lock); - - if (changes) { - camel_object_trigger_event((CamelObject *)folder, "folder_changed", changes); - camel_folder_change_info_free(changes); - } - - return NULL; -} - -static GPtrArray* -nntp_folder_search_by_expression (CamelFolder *folder, const char *expression, CamelException *ex) -{ - CamelNNTPFolder *nntp_folder = CAMEL_NNTP_FOLDER (folder); - GPtrArray *matches, *summary; - - CAMEL_NNTP_FOLDER_LOCK(nntp_folder, search_lock); - - if(nntp_folder->search == NULL) - nntp_folder->search = camel_folder_search_new(); - - camel_folder_search_set_folder(nntp_folder->search, folder); - summary = camel_folder_get_summary(folder); - camel_folder_search_set_summary(nntp_folder->search, summary); - - matches = camel_folder_search_execute_expression(nntp_folder->search, expression, ex); - - CAMEL_NNTP_FOLDER_UNLOCK(nntp_folder, search_lock); - - camel_folder_free_summary(folder, summary); - - return matches; -} - -static GPtrArray * -nntp_folder_search_by_uids(CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex) -{ - CamelNNTPFolder *nntp_folder = CAMEL_NNTP_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_NNTP_FOLDER_LOCK(folder, search_lock); - - if (nntp_folder->search == NULL) - nntp_folder->search = camel_folder_search_new(); - - camel_folder_search_set_folder(nntp_folder->search, folder); - camel_folder_search_set_summary(nntp_folder->search, summary); - - matches = camel_folder_search_execute_expression(nntp_folder->search, expression, ex); - - CAMEL_NNTP_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 -nntp_folder_search_free(CamelFolder *folder, GPtrArray *result) -{ - CamelNNTPFolder *nntp_folder = CAMEL_NNTP_FOLDER (folder); - - camel_folder_search_free_result(nntp_folder->search, result); - -} - -static void -nntp_folder_init(CamelNNTPFolder *nntp_folder, CamelNNTPFolderClass *klass) -{ - struct _CamelNNTPFolderPrivate *p; - - nntp_folder->changes = camel_folder_change_info_new(); - p = nntp_folder->priv = g_malloc0(sizeof(*nntp_folder->priv)); - p->search_lock = g_mutex_new(); - p->cache_lock = g_mutex_new(); -} - -static void -nntp_folder_finalise (CamelNNTPFolder *nntp_folder) -{ - struct _CamelNNTPFolderPrivate *p; - - g_free(nntp_folder->storage_path); - - p = nntp_folder->priv; - g_mutex_free(p->search_lock); - g_mutex_free(p->cache_lock); - g_free(p); -} - -static void -nntp_folder_class_init (CamelNNTPFolderClass *camel_nntp_folder_class) -{ - CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS (camel_nntp_folder_class); - - parent_class = CAMEL_FOLDER_CLASS (camel_type_get_global_classfuncs (camel_folder_get_type ())); - - /* virtual method definition */ - - /* virtual method overload */ - camel_folder_class->sync = nntp_folder_sync; - camel_folder_class->set_message_flags = nntp_folder_set_message_flags; - camel_folder_class->get_message = nntp_folder_get_message; - camel_folder_class->search_by_expression = nntp_folder_search_by_expression; - camel_folder_class->search_by_uids = nntp_folder_search_by_uids; - camel_folder_class->search_free = nntp_folder_search_free; -} - -CamelType -camel_nntp_folder_get_type (void) -{ - static CamelType camel_nntp_folder_type = CAMEL_INVALID_TYPE; - - if (camel_nntp_folder_type == CAMEL_INVALID_TYPE) { - camel_nntp_folder_type = camel_type_register (CAMEL_FOLDER_TYPE, "CamelNNTPFolder", - sizeof (CamelNNTPFolder), - sizeof (CamelNNTPFolderClass), - (CamelObjectClassInitFunc) nntp_folder_class_init, - NULL, - (CamelObjectInitFunc) nntp_folder_init, - (CamelObjectFinalizeFunc) nntp_folder_finalise); - } - - return camel_nntp_folder_type; -} - - -/* not yet */ -/* Idea is we update in stages, but this requires a different xover command, etc */ -#ifdef ASYNC_SUMMARY -struct _folder_check_msg { - CamelSessionThreadMsg msg; - CamelNNTPFolder *folder; -}; - -static void -folder_check(CamelSession *session, CamelSessionThreadMsg *msg) -{ - struct _folder_check_msg *m = (struct _folder_check_msg *)msg; - CamelException *ex; - CamelNNTPStore *nntp_store; - - nntp_store = (CamelNNTPStore *)m->folder->parent.parent_store; - - CAMEL_NNTP_STORE_LOCK(nntp_store, command_lock); - - ex = camel_exception_new(); - camel_nntp_summary_check((CamelNNTPSummary *)m->folder->parent.summary, m->folder->changes, ex); - camel_exception_free(ex); - - CAMEL_NNTP_STORE_UNLOCK(nntp_store, command_lock); -} - -static void -folder_check_free(CamelSession *session, CamelSessionThreadMsg *msg) -{ - struct _folder_check_msg *m = (struct _folder_check_msg *)msg; - - camel_object_unref((CamelObject *)m->folder); -} - -static CamelSessionThreadOps folder_check_ops = { - folder_check, - folder_check_free, -}; -#endif - -CamelFolder * -camel_nntp_folder_new (CamelStore *parent, const char *folder_name, CamelException *ex) -{ - CamelFolder *folder; - CamelNNTPFolder *nntp_folder; - char *root; - CamelService *service; -#ifdef ASYNC_SUMMARY - struct _folder_check_msg *m; -#endif - - service = (CamelService *)parent; - root = camel_session_get_storage_path(service->session, service, ex); - if (root == NULL) - return NULL; - - /* If this doesn't work, stuff wont save, but let it continue anyway */ - camel_mkdir (root, 0777); - - folder = (CamelFolder *) camel_object_new (CAMEL_NNTP_FOLDER_TYPE); - nntp_folder = (CamelNNTPFolder *)folder; - - camel_folder_construct (folder, parent, folder_name, folder_name); - folder->folder_flags |= CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY|CAMEL_FOLDER_HAS_SEARCH_CAPABILITY; - - nntp_folder->storage_path = g_strdup_printf("%s/%s", root, folder->full_name); - g_free(root); - - folder->summary = (CamelFolderSummary *)camel_nntp_summary_new(nntp_folder); - camel_folder_summary_load (folder->summary); -#ifdef ASYNC_SUMMARY - m = camel_session_thread_msg_new(service->session, &folder_check_ops, sizeof(*m)); - m->folder = nntp_folder; - camel_object_ref((CamelObject *)folder); - camel_session_thread_queue(service->session, &m->msg, 0); -#else - if (camel_nntp_summary_check((CamelNNTPSummary *)folder->summary, nntp_folder->changes, ex) == -1) { - camel_object_unref((CamelObject *)folder); - folder = NULL; - } -#endif - - return folder; -} diff --git a/camel/providers/nntp/camel-nntp-folder.h b/camel/providers/nntp/camel-nntp-folder.h deleted file mode 100644 index 300d61762d..0000000000 --- a/camel/providers/nntp/camel-nntp-folder.h +++ /dev/null @@ -1,72 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-nntp-folder.h : NNTP group (folder) support. */ - -/* - * - * Author : Chris Toshok <toshok@ximian.com> - * - * Copyright (C) 2000 Ximian . - * - * 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_NNTP_FOLDER_H -#define CAMEL_NNTP_FOLDER_H 1 - - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus }*/ - -#include "camel/camel-folder.h" - -/* #include "camel-store.h" */ - -#define CAMEL_NNTP_FOLDER_TYPE (camel_nntp_folder_get_type ()) -#define CAMEL_NNTP_FOLDER(obj) (CAMEL_CHECK_CAST((obj), CAMEL_NNTP_FOLDER_TYPE, CamelNNTPFolder)) -#define CAMEL_NNTP_FOLDER_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_NNTP_FOLDER_TYPE, CamelNNTPFolderClass)) -#define CAMEL_IS_NNTP_FOLDER(o) (CAMEL_CHECK_TYPE((o), CAMEL_NNTP_FOLDER_TYPE)) - -typedef struct _CamelNNTPFolder { - CamelFolder parent; - - struct _CamelNNTPFolderPrivate *priv; - - struct _CamelFolderChangeInfo *changes; - char *storage_path; - CamelFolderSearch *search; -} CamelNNTPFolder; - -typedef struct _CamelNNTPFolderClass { - CamelFolderClass parent; - - /* Virtual methods */ - -} CamelNNTPFolderClass; - -/* public methods */ - -/* Standard Camel function */ -CamelType camel_nntp_folder_get_type (void); - -CamelFolder *camel_nntp_folder_new (CamelStore *parent, const char *folder_name, CamelException *ex); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CAMEL_NNTP_FOLDER_H */ diff --git a/camel/providers/nntp/camel-nntp-grouplist.c b/camel/providers/nntp/camel-nntp-grouplist.c deleted file mode 100644 index 7f3850f9c1..0000000000 --- a/camel/providers/nntp/camel-nntp-grouplist.c +++ /dev/null @@ -1,219 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-nntp-grouplist.c : getting/updating the list of newsgroups on the server. */ - -/* - * Author : Chris Toshok <toshok@ximian.com> - * - * Copyright (C) 2000 Ximian . - * - * 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 - */ - -#include <config.h> -#include <errno.h> -#include <string.h> - -#include "camel-exception.h" -#include "camel-nntp-grouplist.h" -#include "camel-nntp-resp-codes.h" - -static CamelNNTPGroupList * -camel_nntp_get_grouplist_from_server (CamelNNTPStore *store, CamelException *ex) -{ - int status; - gboolean done = FALSE; - CamelNNTPGroupList *list; - - CAMEL_NNTP_STORE_LOCK(store); - status = camel_nntp_command (store, ex, NULL, - "LIST"); - - if (status != NNTP_LIST_FOLLOWS) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not get group list from server.")); - return NULL; - } - - list = g_new0 (CamelNNTPGroupList, 1); - list->time = time (NULL); - - while (!done) { - char *line; - - if (camel_remote_store_recv_line (CAMEL_REMOTE_STORE (store), &line, ex) < 0) { - list->group_list = g_list_reverse(list->group_list); - return list; - } - - if (*line == '.') { - done = TRUE; - } - else { - CamelNNTPGroupListEntry *entry = g_new (CamelNNTPGroupListEntry, 1); - char **split_line = g_strsplit (line, " ", 4); - - entry->group_name = g_strdup (split_line[0]); - entry->high = atoi (split_line[1]); - entry->low = atoi (split_line[2]); - - g_strfreev (split_line); - - list->group_list = g_list_prepend (list->group_list, entry); - } - } - CAMEL_NNTP_STORE_UNLOCK(store); - - list->group_list = g_list_reverse(list->group_list); - return list; -} - -static CamelNNTPGroupList* -camel_nntp_get_grouplist_from_file (CamelNNTPStore *store, CamelException *ex) -{ - gchar *root_dir = camel_nntp_store_get_toplevel_dir(CAMEL_NNTP_STORE(store)); - gchar *grouplist_file = g_strdup_printf ("%s/grouplist", root_dir); - CamelNNTPGroupList *list; - FILE *fp; - char buf[300]; - unsigned long time; - - g_free (root_dir); - fp = fopen (grouplist_file, "r"); - g_free (grouplist_file); - - if (fp == NULL) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Unable to load grouplist file for %s: %s"), - CAMEL_SERVICE(store)->url->host, - strerror(errno)); - return NULL; - } - - /* read the time */ - if (!fgets (buf, sizeof (buf), fp)) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Unable to load grouplist file for %s: %s"), - CAMEL_SERVICE(store)->url->host, - strerror(errno)); - fclose (fp); - return NULL; - } - - - list = g_new0 (CamelNNTPGroupList, 1); - list->store = store; - sscanf (buf, "%lu", &time); - list->time = time; - - while (fgets (buf, sizeof (buf), fp)) { - CamelNNTPGroupListEntry *entry = g_new (CamelNNTPGroupListEntry, 1); - char **split_line = g_strsplit (buf, " ", 4); - - entry->group_name = g_strdup (split_line[0]); - entry->high = atoi (split_line[1]); - entry->low = atoi (split_line[2]); - - g_strfreev (split_line); - - list->group_list = g_list_prepend (list->group_list, entry); - } - - fclose (fp); - - list->group_list = g_list_reverse(list->group_list); - return list; -} - -static void -save_entry (CamelNNTPGroupListEntry *entry, FILE *fp) -{ - fprintf (fp, "%s %d %d\n", entry->group_name, entry->low, entry->high); -} - -void -camel_nntp_grouplist_save (CamelNNTPGroupList *group_list, CamelException *ex) -{ - FILE *fp; - gchar *root_dir = camel_nntp_store_get_toplevel_dir(CAMEL_NNTP_STORE(group_list->store)); - gchar *grouplist_file = g_strdup_printf ("%s/grouplist", root_dir); - - g_free (root_dir); - fp = fopen (grouplist_file, "w"); - g_free (grouplist_file); - - if (fp == NULL) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Unable to save grouplist file for %s: %s"), - CAMEL_SERVICE(group_list->store)->url->host, - strerror(errno)); - return; - } - - fprintf (fp, "%lu\n", (long)group_list->time); - - g_list_foreach (group_list->group_list, (GFunc)save_entry, fp); - - fclose (fp); -} - -static void -free_entry (CamelNNTPGroupListEntry *entry, void *data) -{ - g_free (entry->group_name); - g_free (entry); -} - -void -camel_nntp_grouplist_free (CamelNNTPGroupList *group_list) -{ - g_return_if_fail (group_list); - - g_list_foreach (group_list->group_list, (GFunc)free_entry, NULL); - - g_free (group_list); -} - -CamelNNTPGroupList* -camel_nntp_grouplist_fetch (CamelNNTPStore *store, CamelException *ex) -{ - CamelNNTPGroupList *list; - - list = camel_nntp_get_grouplist_from_file (store, ex); - - printf ("camel_nntp_get_grouplist_from_file returned %p\n", list); - - if (!list) { - camel_exception_clear (ex); - - list = camel_nntp_get_grouplist_from_server (store, ex); - - if (!list) { - camel_nntp_grouplist_free (list); - } - else { - list->store = store; - camel_nntp_grouplist_save (list, ex); - return list; - } - } - - return list; -} - -gint -camel_nntp_grouplist_update (CamelNNTPGroupList *group_list, CamelException *ex) -{ - return 0; -} diff --git a/camel/providers/nntp/camel-nntp-grouplist.h b/camel/providers/nntp/camel-nntp-grouplist.h deleted file mode 100644 index edd1e64cb9..0000000000 --- a/camel/providers/nntp/camel-nntp-grouplist.h +++ /dev/null @@ -1,48 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-nntp-grouplist.h : getting/updating the list of newsgroups on the server. */ - -/* - * Author : Chris Toshok <toshok@ximian.com> - * - * Copyright (C) 2000 Ximian . - * - * 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_NNTP_GROUPLIST_H -#define CAMEL_NNTP_GROUPLIST_H 1 - -#include <time.h> -#include "camel-nntp-store.h" - -struct CamelNNTPGroupListEntry { - char *group_name; - guint32 low; - guint32 high; - guint32 flags; -}; - -struct CamelNNTPGroupList { - CamelNNTPStore *store; - time_t time; - GList *group_list; -}; - -CamelNNTPGroupList* camel_nntp_grouplist_fetch (CamelNNTPStore *store, CamelException *ex); -gint camel_nntp_grouplist_update (CamelNNTPGroupList *group_list, CamelException *ex); -void camel_nntp_grouplist_save (CamelNNTPGroupList *group_list, CamelException *ex); -void camel_nntp_grouplist_free (CamelNNTPGroupList *group_list); - -#endif /* CAMEL_NNTP_GROUPLIST_H */ diff --git a/camel/providers/nntp/camel-nntp-newsrc.c b/camel/providers/nntp/camel-nntp-newsrc.c deleted file mode 100644 index 309e1f45c8..0000000000 --- a/camel/providers/nntp/camel-nntp-newsrc.c +++ /dev/null @@ -1,651 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Authors: Chris Toshok <toshok@ximian.com> - * - * Copyright 2000-2003 Ximian, Inc. (www.ximian.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. - * - */ - - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <glib.h> - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <pthread.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> - -#include "camel-nntp-newsrc.h" -#include <camel/camel-folder-summary.h> - -#define NEWSRC_LOCK(f, l) (g_mutex_lock(((CamelNNTPNewsrc *)f)->l)) -#define NEWSRC_UNLOCK(f, l) (g_mutex_unlock(((CamelNNTPNewsrc *)f)->l)) - -typedef struct { - guint low; - guint high; -} ArticleRange; - -typedef struct { - char *name; - GArray *ranges; - gboolean subscribed; -} NewsrcGroup; - -struct CamelNNTPNewsrc { - gchar *filename; - GHashTable *groups; - gboolean dirty; - GMutex *lock; -}; - - -static NewsrcGroup * -camel_nntp_newsrc_group_add (CamelNNTPNewsrc *newsrc, const char *group_name, gboolean subscribed) -{ - NewsrcGroup *new_group = g_malloc(sizeof(NewsrcGroup)); - - new_group->name = g_strdup(group_name); - new_group->subscribed = subscribed; - new_group->ranges = g_array_new (FALSE, FALSE, sizeof (ArticleRange)); - - g_hash_table_insert (newsrc->groups, new_group->name, new_group); - - newsrc->dirty = TRUE; - - return new_group; -} - -static int -camel_nntp_newsrc_group_get_highest_article_read(CamelNNTPNewsrc *newsrc, NewsrcGroup *group) -{ - if (!group || group->ranges->len == 0) - return 0; - - return g_array_index(group->ranges, ArticleRange, group->ranges->len - 1).high; -} - -static int -camel_nntp_newsrc_group_get_num_articles_read(CamelNNTPNewsrc *newsrc, NewsrcGroup *group) -{ - int i; - int count = 0; - - if (group == NULL) - return 0; - - for (i = 0; i < group->ranges->len; i ++) - count += (g_array_index(group->ranges, ArticleRange, i).high - - g_array_index(group->ranges, ArticleRange, i).low) + 1; - - return count; -} - - -static void -camel_nntp_newsrc_group_mark_range_read(CamelNNTPNewsrc *newsrc, NewsrcGroup *group, long low, long high) -{ - int i; - - if (group->ranges->len == 1 - && g_array_index (group->ranges, ArticleRange, 0).low == 0 - && g_array_index (group->ranges, ArticleRange, 0).high == 0) { - g_array_index (group->ranges, ArticleRange, 0).low = low; - g_array_index (group->ranges, ArticleRange, 0).high = high; - - newsrc->dirty = TRUE; - } - else { - ArticleRange tmp_range; - - for (i = 0; i < group->ranges->len; i ++) { - guint range_low = g_array_index (group->ranges, ArticleRange, i).low; - guint range_high = g_array_index (group->ranges, ArticleRange, i).high; - - /* if it's already part of a range, return immediately. */ - if (low >= range_low && - low <= range_high && - high >= range_low && - high <= range_high) { - return; - } - /* if we have a new lower bound for this range, set it. */ - else if (low <= range_low - && high >= range_low - && high <= range_high) { - g_array_index (group->ranges, ArticleRange, i).low = low; - newsrc->dirty = TRUE; - return; - } - /* if we have a new upper bound for this range, set it. */ - else if (high >= range_high - && low >= range_low - && low <= range_high) { - g_array_index (group->ranges, ArticleRange, i).high = high; - newsrc->dirty = TRUE; - return; - } - /* if we would be inserting another range that - starts one index higher than an existing - one, make the upper value of the existing - range the upper value of the new one. */ - else if (low == range_high + 1) { - g_array_index (group->ranges, ArticleRange, i).high = high; - newsrc->dirty = TRUE; - return; - } - /* if we would be inserting another range that - ends one index lower than an existing one, - group the existing range by setting its low - to the new low */ - else if (high == range_low - 1) { - g_array_index (group->ranges, ArticleRange, i).low = low; - newsrc->dirty = TRUE; - return; - } - /* if the range lies entirely outside another - range, doesn't coincide with it's - endpoints, and has lower values, insert it - into the middle of the list. */ - else if (low < range_low - && high < range_low) { - tmp_range.low = low; - tmp_range.high = high; - - group->ranges = g_array_insert_val (group->ranges, i, tmp_range); - newsrc->dirty = TRUE; - - return; - } - } - - /* if we made it here, the range needs to go at the end */ - tmp_range.low = low; - tmp_range.high = high; - group->ranges = g_array_append_val (group->ranges, tmp_range); - newsrc->dirty = TRUE; - } -} - -int -camel_nntp_newsrc_get_highest_article_read (CamelNNTPNewsrc *newsrc, const char *group_name) -{ - NewsrcGroup *group; - int ret; - - NEWSRC_LOCK(newsrc, lock); - - group = g_hash_table_lookup (newsrc->groups, group_name); - - if (group) - ret = camel_nntp_newsrc_group_get_highest_article_read (newsrc, group); - else - ret = 0; - - NEWSRC_UNLOCK(newsrc, lock); - - return ret; -} - -int -camel_nntp_newsrc_get_num_articles_read (CamelNNTPNewsrc *newsrc, const char *group_name) -{ - NewsrcGroup *group; - int ret; - - NEWSRC_LOCK(newsrc, lock); - - group = g_hash_table_lookup (newsrc->groups, group_name); - - if (group) - ret = camel_nntp_newsrc_group_get_num_articles_read (newsrc, group); - else - ret = 0; - - NEWSRC_UNLOCK(newsrc, lock); - - return ret; -} - -void -camel_nntp_newsrc_mark_article_read (CamelNNTPNewsrc *newsrc, const char *group_name, int num) -{ - camel_nntp_newsrc_mark_range_read (newsrc, group_name, num, num); -} - -void -camel_nntp_newsrc_mark_range_read(CamelNNTPNewsrc *newsrc, const char *group_name, long low, long high) -{ - NewsrcGroup *group; - - /* swap them if they're in the wrong order. */ - if (low > high) { - long tmp; - - tmp = high; - high = low; - low = tmp; - } - - NEWSRC_LOCK(newsrc, lock); - group = g_hash_table_lookup (newsrc->groups, group_name); - - if (group) - camel_nntp_newsrc_group_mark_range_read (newsrc, group, low, high); - NEWSRC_UNLOCK(newsrc, lock); -} - -gboolean -camel_nntp_newsrc_article_is_read (CamelNNTPNewsrc *newsrc, const char *group_name, long num) -{ - int i; - NewsrcGroup *group; - int ret = FALSE; - - NEWSRC_LOCK(newsrc, lock); - group = g_hash_table_lookup (newsrc->groups, group_name); - - if (group) { - for (i = 0; i < group->ranges->len; i++) { - if (num >= g_array_index (group->ranges, ArticleRange, i).low && - num <= g_array_index (group->ranges, ArticleRange, i).high) { - ret = TRUE; - break; - } - } - } - - NEWSRC_UNLOCK(newsrc, lock); - - return FALSE; -} - -gboolean -camel_nntp_newsrc_group_is_subscribed (CamelNNTPNewsrc *newsrc, const char *group_name) -{ - NewsrcGroup *group; - int ret = FALSE; - - NEWSRC_LOCK(newsrc, lock); - - group = g_hash_table_lookup (newsrc->groups, group_name); - - if (group) { - ret = group->subscribed; - } - - NEWSRC_UNLOCK(newsrc, lock); - - return ret; -} - -void -camel_nntp_newsrc_subscribe_group (CamelNNTPNewsrc *newsrc, const char *group_name) -{ - NewsrcGroup *group; - - NEWSRC_LOCK(newsrc, lock); - - group = g_hash_table_lookup (newsrc->groups, group_name); - - if (group) { - if (!group->subscribed) - newsrc->dirty = TRUE; - group->subscribed = TRUE; - } - else { - camel_nntp_newsrc_group_add (newsrc, group_name, TRUE); - } - - NEWSRC_UNLOCK(newsrc, lock); -} - -void -camel_nntp_newsrc_unsubscribe_group (CamelNNTPNewsrc *newsrc, const char *group_name) -{ - NewsrcGroup *group; - - NEWSRC_LOCK(newsrc, lock); - - group = g_hash_table_lookup (newsrc->groups, group_name); - if (group) { - if (group->subscribed) - newsrc->dirty = TRUE; - group->subscribed = FALSE; - } - else { - camel_nntp_newsrc_group_add (newsrc, group_name, FALSE); - } - - NEWSRC_UNLOCK(newsrc, lock); -} - -struct newsrc_ptr_array { - GPtrArray *ptr_array; - gboolean subscribed_only; -}; - -/* this needs to strdup the grup_name, if the group array is likely to change */ -static void -get_group_foreach (char *group_name, NewsrcGroup *group, struct newsrc_ptr_array *npa) -{ - if (group->subscribed || !npa->subscribed_only) { - g_ptr_array_add (npa->ptr_array, group_name); - } -} - -GPtrArray * -camel_nntp_newsrc_get_subscribed_group_names (CamelNNTPNewsrc *newsrc) -{ - struct newsrc_ptr_array npa; - - g_return_val_if_fail (newsrc, NULL); - - NEWSRC_LOCK(newsrc, lock); - - npa.ptr_array = g_ptr_array_new(); - npa.subscribed_only = TRUE; - - g_hash_table_foreach (newsrc->groups, - (GHFunc)get_group_foreach, &npa); - - NEWSRC_UNLOCK(newsrc, lock); - - return npa.ptr_array; -} - -GPtrArray * -camel_nntp_newsrc_get_all_group_names (CamelNNTPNewsrc *newsrc) -{ - struct newsrc_ptr_array npa; - - g_return_val_if_fail (newsrc, NULL); - - NEWSRC_LOCK(newsrc, lock); - - npa.ptr_array = g_ptr_array_new(); - npa.subscribed_only = FALSE; - - g_hash_table_foreach (newsrc->groups, - (GHFunc)get_group_foreach, &npa); - - NEWSRC_UNLOCK(newsrc, lock); - - return npa.ptr_array; -} - -void -camel_nntp_newsrc_free_group_names (CamelNNTPNewsrc *newsrc, GPtrArray *group_names) -{ - g_ptr_array_free (group_names, TRUE); -} - -struct newsrc_fp { - CamelNNTPNewsrc *newsrc; - FILE *fp; -}; - -static void -camel_nntp_newsrc_write_group_line(gpointer key, NewsrcGroup *group, struct newsrc_fp *newsrc_fp) -{ - CamelNNTPNewsrc *newsrc; - FILE *fp; - int i; - - fp = newsrc_fp->fp; - newsrc = newsrc_fp->newsrc; - - fprintf (fp, "%s%c", group->name, group->subscribed ? ':' : '!'); - - if (group->ranges->len == 1 - && g_array_index (group->ranges, ArticleRange, 0).low == 0 - && g_array_index (group->ranges, ArticleRange, 0).high == 0) { - fprintf (fp, "\n"); - - return; /* special case since our parsing code will insert this - bogus range if there were no read articles. The code - to add a range is smart enough to remove this one if we - ever mark an article read, but we still need to deal with - it if that code doesn't get hit. */ - } - - fprintf (fp, " "); - - for (i = 0; i < group->ranges->len; i ++) { - char range_buffer[100]; - guint low = g_array_index (group->ranges, ArticleRange, i).low; - guint high = g_array_index (group->ranges, ArticleRange, i).high; - - if (low == high) - sprintf(range_buffer, "%d", low); - else if (low == high - 1) - sprintf(range_buffer, "%d,%d", low, high); - else - sprintf(range_buffer, "%d-%d", low, high); - - if (i != group->ranges->len - 1) - strcat(range_buffer, ","); - - fprintf (fp, range_buffer); - } - - fprintf (fp, "\n"); -} - -void -camel_nntp_newsrc_write_to_file(CamelNNTPNewsrc *newsrc, FILE *fp) -{ - struct newsrc_fp newsrc_fp; - - g_return_if_fail (newsrc); - - newsrc_fp.newsrc = newsrc; - newsrc_fp.fp = fp; - - NEWSRC_LOCK(newsrc, lock); - - g_hash_table_foreach (newsrc->groups, - (GHFunc)camel_nntp_newsrc_write_group_line, - &newsrc_fp); - - NEWSRC_UNLOCK(newsrc, lock); -} - -void -camel_nntp_newsrc_write(CamelNNTPNewsrc *newsrc) -{ - FILE *fp; - - g_return_if_fail (newsrc); - - NEWSRC_LOCK(newsrc, lock); - - if (!newsrc->dirty) { - NEWSRC_UNLOCK(newsrc, lock); - return; - } - - if ((fp = fopen(newsrc->filename, "w")) == NULL) { - g_warning ("Couldn't open newsrc file '%s'.\n", newsrc->filename); - NEWSRC_UNLOCK(newsrc, lock); - return; - } - - newsrc->dirty = FALSE; - NEWSRC_UNLOCK(newsrc, lock); - - camel_nntp_newsrc_write_to_file(newsrc, fp); - - fclose(fp); -} - -static void -camel_nntp_newsrc_parse_line(CamelNNTPNewsrc *newsrc, char *line) -{ - char *p, *comma, *dash; - gboolean is_subscribed; - NewsrcGroup *group; - - p = strchr(line, ':'); - - if (p) { - is_subscribed = TRUE; - } - else { - p = strchr(line, '!'); - if (p) - is_subscribed = FALSE; - else - return; /* bogus line. */ - } - - *p++ = '\0'; - - group = camel_nntp_newsrc_group_add (newsrc, line, is_subscribed); - - do { - guint high, low; - - comma = strchr(p, ','); - - if (comma) - *comma = '\0'; - - dash = strchr(p, '-'); - - if (!dash) { /* there wasn't a dash. must be just one number */ - high = low = atol(p); - } - else { /* there was a dash. */ - *dash = '\0'; - low = atol(p); - *dash = '-'; - p = dash + 1; - high = atol(p); - } - - camel_nntp_newsrc_group_mark_range_read (newsrc, group, low, high); - - if (comma) { - *comma = ','; - p = comma + 1; - } - - } while(comma); -} - -static char* -get_line (char *buf, char **p) -{ - char *l; - char *line; - - g_assert (*p == NULL || **p == '\n' || **p == '\0'); - - if (*p == NULL) { - *p = buf; - - if (**p == '\0') - return NULL; - } - else { - if (**p == '\0') - return NULL; - - (*p) ++; - - /* if we just incremented to the end of the buffer, return NULL */ - if (**p == '\0') - return NULL; - } - - l = strchr (*p, '\n'); - if (l) { - *l = '\0'; - line = g_strdup (*p); - *l = '\n'; - *p = l; - } - else { - /* we're at the last line (which isn't terminated by a \n, btw) */ - line = g_strdup (*p); - (*p) += strlen (*p); - } - - return line; -} - -CamelNNTPNewsrc * -camel_nntp_newsrc_read_for_server (const char *server) -{ - int fd; - char buf[1024]; - char *file_contents, *line, *p; - char *filename; - CamelNNTPNewsrc *newsrc; - int newsrc_len; - int len_read = 0; - struct stat sb; - - filename = g_strdup_printf ("%s/.newsrc-%s", g_get_home_dir(), server); - - newsrc = g_new0(CamelNNTPNewsrc, 1); - newsrc->filename = filename; - newsrc->groups = g_hash_table_new (g_str_hash, g_str_equal); - newsrc->lock = g_mutex_new(); - - if ((fd = open(filename, O_RDONLY)) == -1) { - g_warning ("~/.newsrc-%s not present.\n", server); - return newsrc; - } - - if (fstat (fd, &sb) == -1) { - g_warning ("failed fstat on ~/.newsrc-%s: %s\n", server, strerror(errno)); - return newsrc; - } - newsrc_len = sb.st_size; - - file_contents = g_malloc (newsrc_len + 1); - - while (len_read < newsrc_len) { - int c = read (fd, buf, sizeof (buf)); - - if (c == -1) - break; - - memcpy (&file_contents[len_read], buf, c); - len_read += c; - } - file_contents [len_read] = 0; - - p = NULL; - while ((line = get_line (file_contents, &p))) { - camel_nntp_newsrc_parse_line(newsrc, line); - g_free (line); - } - - close (fd); - g_free (file_contents); - - return newsrc; -} diff --git a/camel/providers/nntp/camel-nntp-newsrc.h b/camel/providers/nntp/camel-nntp-newsrc.h deleted file mode 100644 index 652e3edbce..0000000000 --- a/camel/providers/nntp/camel-nntp-newsrc.h +++ /dev/null @@ -1,34 +0,0 @@ - -#ifndef _CAMEL_NNTP_NEWSRC_H_ -#define _CAMEL_NNTP_NEWSRC_H_ - -#include <stdio.h> -#include "glib.h" - -typedef struct CamelNNTPNewsrc CamelNNTPNewsrc; - -int camel_nntp_newsrc_get_highest_article_read (CamelNNTPNewsrc *newsrc, const char *group_name); -int camel_nntp_newsrc_get_num_articles_read (CamelNNTPNewsrc *newsrc, const char *group_name); -void camel_nntp_newsrc_mark_article_read (CamelNNTPNewsrc *newsrc, - const char *group_name, int num); -void camel_nntp_newsrc_mark_range_read (CamelNNTPNewsrc *newsrc, - const char *group_name, long low, long high); - -gboolean camel_nntp_newsrc_article_is_read (CamelNNTPNewsrc *newsrc, - const char *group_name, long num); - -gboolean camel_nntp_newsrc_group_is_subscribed (CamelNNTPNewsrc *newsrc, const char *group_name); -void camel_nntp_newsrc_subscribe_group (CamelNNTPNewsrc *newsrc, const char *group_name); -void camel_nntp_newsrc_unsubscribe_group (CamelNNTPNewsrc *newsrc, const char *group_name); - -GPtrArray* camel_nntp_newsrc_get_subscribed_group_names (CamelNNTPNewsrc *newsrc); -GPtrArray* camel_nntp_newsrc_get_all_group_names (CamelNNTPNewsrc *newsrc); -void camel_nntp_newsrc_free_group_names (CamelNNTPNewsrc *newsrc, GPtrArray *group_names); - -void camel_nntp_newsrc_write_to_file (CamelNNTPNewsrc *newsrc, FILE *fp); -void camel_nntp_newsrc_write (CamelNNTPNewsrc *newsrc); -CamelNNTPNewsrc *camel_nntp_newsrc_read_for_server (const char *server); - -#endif /* _CAMEL_NNTP_NEWSRC_H_ */ - - diff --git a/camel/providers/nntp/camel-nntp-private.h b/camel/providers/nntp/camel-nntp-private.h deleted file mode 100644 index f2cca4e187..0000000000 --- a/camel/providers/nntp/camel-nntp-private.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * camel-nntp-private.h: Private info for nntp. - * - * 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_NNTP_PRIVATE_H -#define CAMEL_NNTP_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 - -#include "e-util/e-msgport.h" - -struct _CamelNNTPStorePrivate { - EMutex *command_lock; /* for locking the command stream for a complete operation */ -}; - -#define CAMEL_NNTP_STORE_LOCK(f, l) (e_mutex_lock(((CamelNNTPStore *)f)->priv->l)) -#define CAMEL_NNTP_STORE_UNLOCK(f, l) (e_mutex_unlock(((CamelNNTPStore *)f)->priv->l)) - - -struct _CamelNNTPFolderPrivate { - GMutex *search_lock; /* for locking the search object */ - GMutex *cache_lock; /* for locking the cache object */ -}; - -#define CAMEL_NNTP_FOLDER_LOCK(f, l) (g_mutex_lock(((CamelNNTPFolder *)f)->priv->l)) -#define CAMEL_NNTP_FOLDER_UNLOCK(f, l) (g_mutex_unlock(((CamelNNTPFolder *)f)->priv->l)) -#else -#define CAMEL_NNTP_FOLDER_LOCK(f, l) -#define CAMEL_NNTP_FOLDER_UNLOCK(f, l) - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CAMEL_NNTP_PRIVATE_H */ - diff --git a/camel/providers/nntp/camel-nntp-provider.c b/camel/providers/nntp/camel-nntp-provider.c deleted file mode 100644 index 8f54b3ee98..0000000000 --- a/camel/providers/nntp/camel-nntp-provider.c +++ /dev/null @@ -1,113 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-nntp-provider.c: nntp provider registration code */ - -/* - * Authors : - * Chris Toshok <toshok@ximian.com> - * - * Copyright (C) 2000 Ximian, Inc. (www.ximian.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * 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-nntp-store.h" -#include "camel-provider.h" -#include "camel-session.h" - -static void add_hash (guint *hash, char *s); -static guint nntp_url_hash (gconstpointer key); -static gint check_equal (char *s1, char *s2); -static gint nntp_url_equal (gconstpointer a, gconstpointer b); - -static CamelProvider news_provider = { - "nntp", - N_("USENET news"), - - N_("This is a provider for reading from and posting to" - "USENET newsgroups."), - - "news", - - CAMEL_PROVIDER_IS_REMOTE | CAMEL_PROVIDER_IS_SOURCE | - CAMEL_PROVIDER_IS_STORAGE, - - CAMEL_URL_NEED_HOST | CAMEL_URL_ALLOW_USER | - CAMEL_URL_ALLOW_PASSWORD | CAMEL_URL_ALLOW_AUTH, - - /* ... */ -}; - -void -camel_provider_module_init (CamelSession *session) -{ - news_provider.object_types[CAMEL_PROVIDER_STORE] = - camel_nntp_store_get_type(); - - news_provider.url_hash = nntp_url_hash; - news_provider.url_equal = nntp_url_equal; - - camel_session_register_provider (session, &news_provider); -} - -static void -add_hash (guint *hash, char *s) -{ - if (s) - *hash ^= g_str_hash(s); -} - -static guint -nntp_url_hash (gconstpointer key) -{ - const CamelURL *u = (CamelURL *)key; - guint hash = 0; - - add_hash (&hash, u->user); - 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 -nntp_url_equal (gconstpointer a, gconstpointer b) -{ - const CamelURL *u1 = a, *u2 = b; - - return check_equal (u1->user, u2->user) - && check_equal (u1->host, u2->host) - && u1->port == u2->port; -} diff --git a/camel/providers/nntp/camel-nntp-resp-codes.h b/camel/providers/nntp/camel-nntp-resp-codes.h deleted file mode 100644 index d9aace81ef..0000000000 --- a/camel/providers/nntp/camel-nntp-resp-codes.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-nntp-resp-codes.h : #defines for all the response codes we care about */ - -/* - * - * Copyright (C) 2000 Ximian, Inc. <toshok@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_NNTP_RESP_CODES_H -#define CAMEL_NNTP_RESP_CODES_H 1 - -#define CAMEL_NNTP_OK(x) ((x) < 400) -#define CAMEL_NNTP_ERR(x) (!CAMEL_NNTP_OK(x) && (x) < 500) -#define CAMEL_NNTP_FAIL(x) (!CAMEL_NNTP_OK(x) && !CAMEL_NNTP_ERR(x)) - -#define NNTP_GREETING_POSTING_OK 200 -#define NNTP_GREETING_NO_POSTING 201 - -#define NNTP_EXTENSIONS_SUPPORTED 202 -#define NNTP_GROUP_SELECTED 211 -#define NNTP_LIST_FOLLOWS 215 -#define NNTP_ARTICLE_FOLLOWS 220 -#define NNTP_HEAD_FOLLOWS 221 -#define NNTP_DATA_FOLLOWS 224 -#define NNTP_NEW_ARTICLE_LIST_FOLLOWS 230 -#define NNTP_NEW_GROUP_LIST_FOLLOWS 231 - -#define NNTP_NO_SUCH_GROUP 411 -#define NNTP_NO_SUCH_ARTICLE 430 - -#define NNTP_NO_PERMISSION 502 - -/* authentication */ -#define NNTP_AUTH_ACCEPTED 281 -#define NNTP_AUTH_CONTINUE 381 -#define NNTP_AUTH_REQUIRED 480 -#define NNTP_AUTH_REJECTED 482 - -#define NNTP_PROTOCOL_ERROR 666 - -#endif /* CAMEL_NNTP_RESP_CODES_H */ diff --git a/camel/providers/nntp/camel-nntp-store.c b/camel/providers/nntp/camel-nntp-store.c deleted file mode 100644 index 531d4aefdf..0000000000 --- a/camel/providers/nntp/camel-nntp-store.c +++ /dev/null @@ -1,576 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * - * Copyright (C) 2001-2003 Ximian, Inc. <www.ximain.com> - * - * Authors: Christopher Toshok <toshok@ximian.com> - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> -#include <unistd.h> -#include <dirent.h> -#include <errno.h> - -#include <camel/camel-url.h> -#include <camel/camel-string-utils.h> -#include <camel/camel-session.h> -#include <camel/camel-tcp-stream-raw.h> -#include <camel/camel-tcp-stream-ssl.h> - -#include "camel-nntp-summary.h" -#include "camel-nntp-store.h" -#include "camel-nntp-folder.h" -#include "camel-nntp-private.h" - -#define w(x) -extern int camel_verbose_debug; -#define dd(x) (camel_verbose_debug?(x):0) - -#define NNTP_PORT 119 -#define NNTPS_PORT 563 - -#define DUMP_EXTENSIONS - -/* define if you want the subscribe ui to show folders in tree form */ -/* #define INFO_AS_TREE */ - -static CamelStoreClass *parent_class = NULL; -static CamelServiceClass *service_class = NULL; - -/* Returns the class for a CamelNNTPStore */ -#define CNNTPS_CLASS(so) CAMEL_NNTP_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -#define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -#define CNNTPF_CLASS(so) CAMEL_NNTP_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) - - -enum { - USE_SSL_NEVER, - USE_SSL_ALWAYS, - USE_SSL_WHEN_POSSIBLE -}; - -static gboolean -connect_to_server (CamelService *service, int ssl_mode, CamelException *ex) -{ - CamelNNTPStore *store = (CamelNNTPStore *) service; - CamelStream *tcp_stream; - gboolean retval = FALSE; - unsigned char *buf; - unsigned int len; - struct hostent *h; - int port, ret; - - CAMEL_NNTP_STORE_LOCK(store, command_lock); - - /* setup store-wide cache */ - if (store->cache == NULL) { - char *root; - - root = camel_session_get_storage_path (service->session, service, ex); - if (root == NULL) - goto fail; - - store->cache = camel_data_cache_new (root, 0, ex); - g_free (root); - if (store->cache == NULL) - goto fail; - - /* Default cache expiry - 2 weeks old, or not visited in 5 days */ - camel_data_cache_set_expire_age (store->cache, 60*60*24*14); - camel_data_cache_set_expire_access (store->cache, 60*60*24*5); - } - - h = camel_service_gethost (service, ex); - if (!h) - goto fail; - - port = service->url->port ? service->url->port : NNTP_PORT; - -#ifdef HAVE_SSL - if (ssl_mode != USE_SSL_NEVER) { - port = service->url->port ? service->url->port : NNTPS_PORT; - tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3); - } 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)); - - goto fail; - } - - store->stream = (CamelNNTPStream *) camel_nntp_stream_new (tcp_stream); - camel_object_unref (CAMEL_OBJECT (tcp_stream)); - - /* Read the greeting, if any. */ - if (camel_nntp_stream_line (store->stream, &buf, &len) == -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 read greeting from %s: %s"), - service->url->host, g_strerror (errno)); - - camel_object_unref (CAMEL_OBJECT (store->stream)); - store->stream = NULL; - - goto fail; - } - - len = strtoul (buf, (char **) &buf, 10); - if (len != 200 && len != 201) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("NNTP server %s returned error code %d: %s"), - service->url->host, len, buf); - - camel_object_unref (CAMEL_OBJECT (store->stream)); - store->stream = NULL; - - goto fail; - } - - /* set 'reader' mode & ignore return code */ - camel_nntp_command (store, (char **) &buf, "mode reader"); - retval = TRUE; - - fail: - CAMEL_NNTP_STORE_UNLOCK(store, command_lock); - - return retval; -} - -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 -nntp_connect (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) { - /* Connect via SSL */ - return connect_to_server (service, ssl_mode, ex); - } else if (ssl_mode == USE_SSL_WHEN_POSSIBLE) { - /* If the server supports SSL, use it */ - if (!connect_to_server (service, ssl_mode, ex)) { - if (camel_exception_get_id (ex) == CAMEL_EXCEPTION_SERVICE_UNAVAILABLE) { - /* The ssl port seems to be unavailable, fall back to plain NNTP */ - camel_exception_clear (ex); - return connect_to_server (service, USE_SSL_NEVER, ex); - } else { - return FALSE; - } - } - - return TRUE; - } else { - /* User doesn't care about SSL */ - return connect_to_server (service, ssl_mode, ex); - } -#else - return connect_to_server (service, USE_SSL_NEVER, ex); -#endif -} - -static gboolean -nntp_disconnect (CamelService *service, gboolean clean, CamelException *ex) -{ - CamelNNTPStore *store = CAMEL_NNTP_STORE (service); - char *line; - - CAMEL_NNTP_STORE_LOCK(store, command_lock); - - if (clean) - camel_nntp_command (store, &line, "quit"); - - if (!service_class->disconnect (service, clean, ex)) - return FALSE; - - camel_object_unref((CamelObject *)store->stream); - store->stream = NULL; - - CAMEL_NNTP_STORE_UNLOCK(store, command_lock); - - return TRUE; -} - -static char * -nntp_store_get_name (CamelService *service, gboolean brief) -{ - if (brief) - return g_strdup_printf ("%s", service->url->host); - else - return g_strdup_printf (_("USENET News via %s"), service->url->host); - -} - -static CamelServiceAuthType password_authtype = { - N_("Password"), - - N_("This option will authenticate with the NNTP server using a " - "plaintext password."), - - "", - TRUE -}; - -static GList * -nntp_store_query_auth_types (CamelService *service, CamelException *ex) -{ - g_warning ("nntp::query_auth_types: not implemented. Defaulting."); - - return g_list_append (NULL, &password_authtype); -} - -static CamelFolder * -nntp_store_get_folder(CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex) -{ - CamelNNTPStore *nntp_store = CAMEL_NNTP_STORE (store); - CamelFolder *folder; - - CAMEL_NNTP_STORE_LOCK(nntp_store, command_lock); - - folder = camel_nntp_folder_new(store, folder_name, ex); - - CAMEL_NNTP_STORE_UNLOCK(nntp_store, command_lock); - - return folder; -} - -static CamelFolderInfo * -nntp_store_get_folder_info(CamelStore *store, const char *top, guint32 flags, CamelException *ex) -{ - CamelURL *url = CAMEL_SERVICE (store)->url; - CamelNNTPStore *nntp_store = (CamelNNTPStore *)store; - CamelFolderInfo *groups = NULL, *last = NULL, *fi; - unsigned int len; - unsigned char *line, *space; - int ret = -1; - - CAMEL_NNTP_STORE_LOCK(nntp_store, command_lock); - - ret = camel_nntp_command(nntp_store, (char **)&line, "list"); - if (ret != 215) { - ret = -1; - goto error; - } - - while ( (ret = camel_nntp_stream_line(nntp_store->stream, &line, &len)) > 0) { - space = strchr(line, ' '); - if (space) - *space = 0; - - if (top == NULL || top[0] == 0 || strcmp(top, line) == 0) { - fi = g_malloc0(sizeof(*fi)); - fi->name = g_strdup(line); - fi->full_name = g_strdup(line); - if (url->user) - fi->url = g_strdup_printf ("nntp://%s@%s/%s", url->user, url->host, line); - else - fi->url = g_strdup_printf ("nntp://%s/%s", url->host, line); - fi->unread_message_count = -1; - camel_folder_info_build_path(fi, '/'); - - if (last) - last->sibling = fi; - else - groups = fi; - last = fi; - } - } - - if (ret < 0) - goto error; - - CAMEL_NNTP_STORE_UNLOCK(nntp_store, command_lock); - - return groups; - -error: - CAMEL_NNTP_STORE_UNLOCK(nntp_store, command_lock); - - if (groups) - camel_store_free_folder_info(store, groups); - - return NULL; -} - -static gboolean -nntp_store_folder_subscribed (CamelStore *store, const char *folder_name) -{ - CamelNNTPStore *nntp_store = CAMEL_NNTP_STORE (store); - - nntp_store = nntp_store; - - /* FIXME: implement */ - - return TRUE; -} - -static void -nntp_store_subscribe_folder (CamelStore *store, const char *folder_name, - CamelException *ex) -{ - CamelNNTPStore *nntp_store = CAMEL_NNTP_STORE (store); - - nntp_store = nntp_store; - - /* FIXME: implement */ -} - -static void -nntp_store_unsubscribe_folder (CamelStore *store, const char *folder_name, - CamelException *ex) -{ - CamelNNTPStore *nntp_store = CAMEL_NNTP_STORE (store); - - nntp_store = nntp_store; - - /* FIXME: implement */ -} - -static void -nntp_store_finalise (CamelObject *object) -{ - CamelNNTPStore *nntp_store = CAMEL_NNTP_STORE (object); - struct _CamelNNTPStorePrivate *p = nntp_store->priv; - - camel_service_disconnect((CamelService *)object, TRUE, NULL); - - camel_object_unref((CamelObject *)nntp_store->mem); - nntp_store->mem = NULL; - if (nntp_store->stream) - camel_object_unref((CamelObject *)nntp_store->stream); - - e_mutex_destroy(p->command_lock); - - g_free(p); -} - -static void -nntp_store_class_init (CamelNNTPStoreClass *camel_nntp_store_class) -{ - CamelStoreClass *camel_store_class = CAMEL_STORE_CLASS (camel_nntp_store_class); - CamelServiceClass *camel_service_class = CAMEL_SERVICE_CLASS (camel_nntp_store_class); - - parent_class = CAMEL_STORE_CLASS (camel_type_get_global_classfuncs (camel_store_get_type ())); - - service_class = CAMEL_SERVICE_CLASS (camel_type_get_global_classfuncs (camel_service_get_type ())); - - /* virtual method overload */ - camel_service_class->connect = nntp_connect; - camel_service_class->disconnect = nntp_disconnect; - camel_service_class->query_auth_types = nntp_store_query_auth_types; - camel_service_class->get_name = nntp_store_get_name; - - camel_store_class->get_folder = nntp_store_get_folder; - camel_store_class->get_folder_info = nntp_store_get_folder_info; - camel_store_class->free_folder_info = camel_store_free_folder_info_full; - - camel_store_class->folder_subscribed = nntp_store_folder_subscribed; - camel_store_class->subscribe_folder = nntp_store_subscribe_folder; - camel_store_class->unsubscribe_folder = nntp_store_unsubscribe_folder; -} - -static void -nntp_store_init (gpointer object, gpointer klass) -{ - CamelNNTPStore *nntp_store = CAMEL_NNTP_STORE(object); - CamelStore *store = CAMEL_STORE (object); - struct _CamelNNTPStorePrivate *p; - - store->flags = CAMEL_STORE_SUBSCRIPTIONS; - - nntp_store->mem = (CamelStreamMem *)camel_stream_mem_new(); - - p = nntp_store->priv = g_malloc0(sizeof(*p)); - p->command_lock = e_mutex_new(E_MUTEX_REC); -} - -CamelType -camel_nntp_store_get_type (void) -{ - static CamelType camel_nntp_store_type = CAMEL_INVALID_TYPE; - - if (camel_nntp_store_type == CAMEL_INVALID_TYPE) { - camel_nntp_store_type = - camel_type_register (CAMEL_STORE_TYPE, - "CamelNNTPStore", - sizeof (CamelNNTPStore), - sizeof (CamelNNTPStoreClass), - (CamelObjectClassInitFunc) nntp_store_class_init, - NULL, - (CamelObjectInitFunc) nntp_store_init, - (CamelObjectFinalizeFunc) nntp_store_finalise); - } - - return camel_nntp_store_type; -} - -/* enter owning lock */ -int -camel_nntp_store_set_folder (CamelNNTPStore *store, CamelFolder *folder, CamelFolderChangeInfo *changes, CamelException *ex) -{ - int ret; - - if (store->current_folder && strcmp(folder->full_name, store->current_folder) == 0) - return 0; - - /* FIXME: Do something with changeinfo */ - ret = camel_nntp_summary_check((CamelNNTPSummary *)folder->summary, changes, ex); - - g_free(store->current_folder); - store->current_folder = g_strdup(folder->full_name); - - return ret; -} - -static gboolean -nntp_connected (CamelNNTPStore *store, CamelException *ex) -{ - if (store->stream == NULL) - return camel_service_connect (CAMEL_SERVICE (store), ex); - return TRUE; -} - -/* Enter owning lock */ -int -camel_nntp_command(CamelNNTPStore *store, char **line, const char *fmt, ...) -{ - const unsigned char *p, *ps; - unsigned char c; - va_list ap; - char *s; - int d; - unsigned int u, u2; - - e_mutex_assert_locked(store->priv->command_lock); - - if (!nntp_connected (store, NULL)) - return -1; - - /* Check for unprocessed data, ! */ - if (store->stream->mode == CAMEL_NNTP_STREAM_DATA) { - g_warning("Unprocessed data left in stream, flushing"); - while (camel_nntp_stream_getd(store->stream, (unsigned char **)&p, &u) > 0) - ; - } - camel_nntp_stream_set_mode(store->stream, CAMEL_NNTP_STREAM_LINE); - - va_start(ap, fmt); - ps = p = fmt; - while ( (c = *p++) ) { - switch (c) { - case '%': - c = *p++; - camel_stream_write((CamelStream *)store->mem, ps, p-ps-(c=='%'?1:2)); - ps = p; - switch (c) { - case 's': - s = va_arg(ap, char *); - camel_stream_write((CamelStream *)store->mem, s, strlen(s)); - break; - case 'd': - d = va_arg(ap, int); - camel_stream_printf((CamelStream *)store->mem, "%d", d); - break; - case 'u': - u = va_arg(ap, unsigned int); - camel_stream_printf((CamelStream *)store->mem, "%u", u); - break; - case 'm': - s = va_arg(ap, char *); - camel_stream_printf((CamelStream *)store->mem, "<%s>", s); - break; - case 'r': - u = va_arg(ap, unsigned int); - u2 = va_arg(ap, unsigned int); - if (u == u2) - camel_stream_printf((CamelStream *)store->mem, "%u", u); - else - camel_stream_printf((CamelStream *)store->mem, "%u-%u", u, u2); - break; - default: - g_warning("Passing unknown format to nntp_command: %c\n", c); - g_assert(0); - } - } - } - - camel_stream_write((CamelStream *)store->mem, ps, p-ps-1); - dd(printf("NNTP_COMMAND: '%.*s'\n", (int)store->mem->buffer->len, store->mem->buffer->data)); - camel_stream_write((CamelStream *)store->mem, "\r\n", 2); - camel_stream_write((CamelStream *)store->stream, store->mem->buffer->data, store->mem->buffer->len); - camel_stream_reset((CamelStream *)store->mem); - /* FIXME: hack */ - g_byte_array_set_size(store->mem->buffer, 0); - - if (camel_nntp_stream_line(store->stream, (unsigned char **)line, &u) == -1) - return -1; - - u = strtoul(*line, NULL, 10); - - /* Handle all switching to data mode here, to make callers job easier */ - if (u == 215 || (u >= 220 && u <=224) || (u >= 230 && u <= 231)) - camel_nntp_stream_set_mode(store->stream, CAMEL_NNTP_STREAM_DATA); - - return u; -} - diff --git a/camel/providers/nntp/camel-nntp-store.h b/camel/providers/nntp/camel-nntp-store.h deleted file mode 100644 index a201c2cea2..0000000000 --- a/camel/providers/nntp/camel-nntp-store.h +++ /dev/null @@ -1,92 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-nntp-store.h : class for an nntp store */ - -/* - * - * Copyright (C) 2000 Ximian, Inc. <toshok@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_NNTP_STORE_H -#define CAMEL_NNTP_STORE_H 1 - - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus */ - -#include <camel/camel-store.h> -#include <camel/camel-stream-mem.h> -#include <camel/camel-data-cache.h> -#include <camel/camel-exception.h> -#include <camel/camel-folder.h> - -#include "camel-nntp-stream.h" - -#define CAMEL_NNTP_STORE_TYPE (camel_nntp_store_get_type ()) -#define CAMEL_NNTP_STORE(obj) (CAMEL_CHECK_CAST((obj), CAMEL_NNTP_STORE_TYPE, CamelNNTPStore)) -#define CAMEL_NNTP_STORE_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_NNTP_STORE_TYPE, CamelNNTPStoreClass)) -#define CAMEL_IS_NNTP_STORE(o) (CAMEL_CHECK_TYPE((o), CAMEL_NNTP_STORE_TYPE)) - -#define CAMEL_NNTP_EXT_SEARCH (1<<0) -#define CAMEL_NNTP_EXT_SETGET (1<<1) -#define CAMEL_NNTP_EXT_OVER (1<<2) -#define CAMEL_NNTP_EXT_XPATTEXT (1<<3) -#define CAMEL_NNTP_EXT_XACTIVE (1<<4) -#define CAMEL_NNTP_EXT_LISTMOTD (1<<5) -#define CAMEL_NNTP_EXT_LISTSUBSCR (1<<6) -#define CAMEL_NNTP_EXT_LISTPNAMES (1<<7) - -typedef struct _CamelNNTPStore CamelNNTPStore; -typedef struct _CamelNNTPStoreClass CamelNNTPStoreClass; - -struct _CamelNNTPStore { - CamelStore parent_object; - - struct _CamelNNTPStorePrivate *priv; - - guint32 extensions; - - gboolean posting_allowed; - - CamelNNTPStream *stream; - CamelStreamMem *mem; - - CamelDataCache *cache; - - char *current_folder; -}; - -struct _CamelNNTPStoreClass { - CamelStoreClass parent_class; - -}; - -/* Standard Camel function */ -CamelType camel_nntp_store_get_type (void); - -int camel_nntp_command(CamelNNTPStore *store, char **line, const char *fmt, ...); -int camel_nntp_store_set_folder(CamelNNTPStore *store, CamelFolder *folder, CamelFolderChangeInfo *changes, CamelException *ex); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CAMEL_NNTP_STORE_H */ - - diff --git a/camel/providers/nntp/camel-nntp-stream.c b/camel/providers/nntp/camel-nntp-stream.c deleted file mode 100644 index 1e2dcb23f9..0000000000 --- a/camel/providers/nntp/camel-nntp-stream.c +++ /dev/null @@ -1,462 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*- - * - * Author: - * 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 - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> - -#include <string.h> -#include <stdio.h> - -#include <glib.h> - -#include "camel-nntp-stream.h" - -extern int camel_verbose_debug; -#define dd(x) (camel_verbose_debug?(x):0) - -static CamelObjectClass *parent_class = NULL; - -/* Returns the class for a CamelStream */ -#define CS_CLASS(so) CAMEL_NNTP_STREAM_CLASS(CAMEL_OBJECT_GET_CLASS(so)) - -#define CAMEL_NNTP_STREAM_SIZE (4096) -#define CAMEL_NNTP_STREAM_LINE (1024) /* maximum line size */ - -static int -stream_fill(CamelNNTPStream *is) -{ - int left = 0; - - if (is->source) { - left = is->end - is->ptr; - memcpy(is->buf, is->ptr, left); - is->end = is->buf + left; - is->ptr = is->buf; - left = camel_stream_read(is->source, is->end, CAMEL_NNTP_STREAM_SIZE - (is->end - is->buf)); - if (left > 0) { - is->end += left; - is->end[0] = '\n'; - return is->end - is->ptr; - } else { - dd(printf("NNTP_STREAM_FILL(ERROR): '%s'\n", strerror(errno))); - return -1; - } - } - - return 0; -} - -static ssize_t -stream_read(CamelStream *stream, char *buffer, size_t n) -{ - CamelNNTPStream *is = (CamelNNTPStream *)stream; - char *o, *oe; - unsigned char *p, *e, c; - int state; - - if (is->mode != CAMEL_NNTP_STREAM_DATA || n == 0) - return 0; - - o = buffer; - oe = buffer + n; - state = is->state; - - /* Need to copy/strip '.'s and whatnot */ - p = is->ptr; - e = is->end; - - switch(state) { - state_0: - case 0: /* start of line, always read at least 3 chars */ - while (e - p < 3) { - is->ptr = p; - if (stream_fill(is) == -1) - return -1; - p = is->ptr; - e = is->end; - } - if (p[0] == '.') { - if (p[1] == '\r' && p[2] == '\n') { - is->ptr = p+3; - is->mode = CAMEL_NNTP_STREAM_EOD; - is->state = 0; - dd(printf("NNTP_STREAM_READ(%d):\n%.*s\n", o-buffer, o-buffer, buffer)); - return o-buffer; - } - p++; - } - state = 1; - /* FALLS THROUGH */ - case 1: /* looking for next sol */ - while (o < oe) { - c = *p++; - if (c == '\n') { - /* end of input sentinal check */ - if (p > e) { - is->ptr = e; - if (stream_fill(is) == -1) - return -1; - p = is->ptr; - e = is->end; - } else { - *o++ = '\n'; - state = 0; - goto state_0; - } - } else if (c != '\r') { - *o++ = c; - } - } - break; - } - - is->ptr = p; - is->state = state; - - dd(printf("NNTP_STREAM_READ(%d):\n%.*s\n", o-buffer, o-buffer, buffer)); - - return o-buffer; -} - -static ssize_t -stream_write(CamelStream *stream, const char *buffer, size_t n) -{ - CamelNNTPStream *is = (CamelNNTPStream *)stream; - - return camel_stream_write(is->source, buffer, n); -} - -static int -stream_close(CamelStream *stream) -{ - /* nop? */ - return 0; -} - -static int -stream_flush(CamelStream *stream) -{ - /* nop? */ - return 0; -} - -static gboolean -stream_eos(CamelStream *stream) -{ - CamelNNTPStream *is = (CamelNNTPStream *)stream; - - return is->mode != CAMEL_NNTP_STREAM_DATA; -} - -static int -stream_reset(CamelStream *stream) -{ - /* nop? reset literal mode? */ - return 0; -} - -static void -camel_nntp_stream_class_init (CamelStreamClass *camel_nntp_stream_class) -{ - CamelStreamClass *camel_stream_class = (CamelStreamClass *)camel_nntp_stream_class; - - parent_class = camel_type_get_global_classfuncs( CAMEL_OBJECT_TYPE ); - - /* virtual method definition */ - camel_stream_class->read = stream_read; - camel_stream_class->write = stream_write; - camel_stream_class->close = stream_close; - camel_stream_class->flush = stream_flush; - camel_stream_class->eos = stream_eos; - camel_stream_class->reset = stream_reset; -} - -static void -camel_nntp_stream_init(CamelNNTPStream *is, CamelNNTPStreamClass *isclass) -{ - /* +1 is room for appending a 0 if we need to for a line */ - is->ptr = is->end = is->buf = g_malloc(CAMEL_NNTP_STREAM_SIZE+1); - is->lineptr = is->linebuf = g_malloc(CAMEL_NNTP_STREAM_LINE+1); - is->lineend = is->linebuf + CAMEL_NNTP_STREAM_LINE; - - /* init sentinal */ - is->ptr[0] = '\n'; - - is->state = 0; - is->mode = CAMEL_NNTP_STREAM_LINE; -} - -static void -camel_nntp_stream_finalise(CamelNNTPStream *is) -{ - g_free(is->buf); - g_free(is->linebuf); - if (is->source) - camel_object_unref((CamelObject *)is->source); -} - -CamelType -camel_nntp_stream_get_type (void) -{ - static CamelType camel_nntp_stream_type = CAMEL_INVALID_TYPE; - - if (camel_nntp_stream_type == CAMEL_INVALID_TYPE) { - camel_nntp_stream_type = camel_type_register( camel_stream_get_type(), - "CamelNNTPStream", - sizeof( CamelNNTPStream ), - sizeof( CamelNNTPStreamClass ), - (CamelObjectClassInitFunc) camel_nntp_stream_class_init, - NULL, - (CamelObjectInitFunc) camel_nntp_stream_init, - (CamelObjectFinalizeFunc) camel_nntp_stream_finalise ); - } - - return camel_nntp_stream_type; -} - -/** - * camel_nntp_stream_new: - * - * Returns a NULL stream. A null stream is always at eof, and - * always returns success for all reads and writes. - * - * Return value: the stream - **/ -CamelStream * -camel_nntp_stream_new(CamelStream *source) -{ - CamelNNTPStream *is; - - is = (CamelNNTPStream *)camel_object_new(camel_nntp_stream_get_type ()); - camel_object_ref((CamelObject *)source); - is->source = source; - - return (CamelStream *)is; -} - -/* Get one line from the nntp stream */ -int -camel_nntp_stream_line(CamelNNTPStream *is, unsigned char **data, unsigned int *len) -{ - register unsigned char c, *p, *o, *oe; - int newlen, oldlen; - unsigned char *e; - - if (is->mode == CAMEL_NNTP_STREAM_EOD) { - *data = is->linebuf; - *len = 0; - return 0; - } - - o = is->linebuf; - oe = is->lineend - 1; - p = is->ptr; - e = is->end; - - /* Data mode, convert leading '..' to '.', and stop when we reach a solitary '.' */ - if (is->mode == CAMEL_NNTP_STREAM_DATA) { - /* need at least 3 chars in buffer */ - while (e-p < 3) { - is->ptr = p; - if (stream_fill(is) == -1) - return -1; - p = is->ptr; - e = is->end; - } - - /* check for isolated '.\r\n' or begging of line '.' */ - if (p[0] == '.') { - if (p[1] == '\r' && p[2] == '\n') { - is->ptr = p+3; - is->mode = CAMEL_NNTP_STREAM_EOD; - *data = is->linebuf; - *len = 0; - is->linebuf[0] = 0; - - dd(printf("NNTP_STREAM_LINE(END)\n")); - - return 0; - } - p++; - } - } - - while (1) { - while (o < oe) { - c = *p++; - if (c == '\n') { - /* sentinal? */ - if (p> e) { - is->ptr = e; - if (stream_fill(is) == -1) - return -1; - p = is->ptr; - e = is->end; - } else { - is->ptr = p; - *data = is->linebuf; - *len = o - is->linebuf; - *o = 0; - - dd(printf("NNTP_STREAM_LINE(%d): '%s'\n", *len, *data)); - - return 1; - } - } else if (c != '\r') { - *o++ = c; - } - } - - /* limit this for bad server data? */ - oldlen = o - is->linebuf; - newlen = (is->lineend - is->linebuf) * 3 / 2; - is->lineptr = is->linebuf = g_realloc(is->linebuf, newlen); - is->lineend = is->linebuf + newlen; - oe = is->lineend - 1; - o = is->linebuf + oldlen; - } - - return -1; -} - -/* returns -1 on error, 0 if last lot of data, >0 if more remaining */ -int camel_nntp_stream_gets(CamelNNTPStream *is, unsigned char **start, unsigned int *len) -{ - int max; - unsigned char *end; - - *len = 0; - - max = is->end - is->ptr; - if (max == 0) { - max = stream_fill(is); - if (max <= 0) - return max; - } - - *start = is->ptr; - end = memchr(is->ptr, '\n', max); - if (end) - max = (end - is->ptr) + 1; - *start = is->ptr; - *len = max; - is->ptr += max; - - dd(printf("NNTP_STREAM_GETS(%s,%d): '%.*s'\n", end==NULL?"more":"last", *len, (int)*len, *start)); - - return end == NULL?1:0; -} - -void camel_nntp_stream_set_mode(CamelNNTPStream *is, camel_nntp_stream_mode_t mode) -{ - is->mode = mode; -} - -/* returns -1 on erorr, 0 if last data, >0 if more data left */ -int camel_nntp_stream_getd(CamelNNTPStream *is, unsigned char **start, unsigned int *len) -{ - unsigned char *p, *e, *s; - int state; - - *len = 0; - - if (is->mode == CAMEL_NNTP_STREAM_EOD) - return 0; - - if (is->mode == CAMEL_NNTP_STREAM_LINE) { - g_warning("nntp_stream reading data in line mode\n"); - return 0; - } - - state = is->state; - p = is->ptr; - e = is->end; - - while (e - p < 3) { - is->ptr = p; - if (stream_fill(is) == -1) - return -1; - p = is->ptr; - e = is->end; - } - - s = p; - - do { - switch(state) { - case 0: - /* check leading '.', ... */ - if (p[0] == '.') { - if (p[1] == '\r' && p[2] == '\n') { - is->ptr = p+3; - *len = p-s; - *start = s; - is->mode = CAMEL_NNTP_STREAM_EOD; - is->state = 0; - - dd(printf("NNTP_STREAM_GETD(%s,%d): '%.*s'\n", "last", *len, (int)*len, *start)); - - return 0; - } - - /* If at start, just skip '.', else return data upto '.' but skip it */ - if (p == s) { - s++; - p++; - } else { - is->ptr = p+1; - *len = p-s; - *start = s; - is->state = 1; - - dd(printf("NNTP_STREAM_GETD(%s,%d): '%.*s'\n", "more", *len, (int)*len, *start)); - - return 1; - } - } - state = 1; - case 1: - /* Scan for sentinal */ - while ((*p++)!='\n') - ; - - if (p > e) { - p = e; - } else { - state = 0; - } - break; - } - } while ((e-p) >= 3); - - is->state = state; - is->ptr = p; - *len = p-s; - *start = s; - - dd(printf("NNTP_STREAM_GETD(%s,%d): '%.*s'\n", "more", *len, (int)*len, *start)); - return 1; -} - diff --git a/camel/providers/nntp/camel-nntp-stream.h b/camel/providers/nntp/camel-nntp-stream.h deleted file mode 100644 index eef217cef2..0000000000 --- a/camel/providers/nntp/camel-nntp-stream.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2001 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_NNTP_STREAM_H -#define _CAMEL_NNTP_STREAM_H - -#include <camel/camel-stream.h> - -#define CAMEL_NNTP_STREAM(obj) CAMEL_CHECK_CAST (obj, camel_nntp_stream_get_type (), CamelNNTPStream) -#define CAMEL_NNTP_STREAM_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_nntp_stream_get_type (), CamelNNTPStreamClass) -#define CAMEL_IS_NNTP_STREAM(obj) CAMEL_CHECK_TYPE (obj, camel_nntp_stream_get_type ()) - -typedef struct _CamelNNTPStreamClass CamelNNTPStreamClass; -typedef struct _CamelNNTPStream CamelNNTPStream; - -typedef enum { - CAMEL_NNTP_STREAM_LINE, - CAMEL_NNTP_STREAM_DATA, - CAMEL_NNTP_STREAM_EOD, /* end of data, acts as if end of stream */ -} camel_nntp_stream_mode_t; - -struct _CamelNNTPStream { - CamelStream parent; - - CamelStream *source; - - camel_nntp_stream_mode_t mode; - int state; - - unsigned char *buf, *ptr, *end; - unsigned char *linebuf, *lineptr, *lineend; -}; - -struct _CamelNNTPStreamClass { - CamelStreamClass parent_class; -}; - -CamelType camel_nntp_stream_get_type (void); - -CamelStream *camel_nntp_stream_new (CamelStream *source); - - -void camel_nntp_stream_set_mode (CamelNNTPStream *is, camel_nntp_stream_mode_t mode); - -int camel_nntp_stream_line (CamelNNTPStream *is, unsigned char **data, unsigned int *len); -int camel_nntp_stream_gets (CamelNNTPStream *is, unsigned char **start, unsigned int *len); -int camel_nntp_stream_getd (CamelNNTPStream *is, unsigned char **start, unsigned int *len); - -#endif /* ! _CAMEL_NNTP_STREAM_H */ diff --git a/camel/providers/nntp/camel-nntp-summary.c b/camel/providers/nntp/camel-nntp-summary.c deleted file mode 100644 index 2a9669d697..0000000000 --- a/camel/providers/nntp/camel-nntp-summary.c +++ /dev/null @@ -1,584 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*- */ -/* - * Copyright (C) 2000 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 <ctype.h> -#include <sys/stat.h> -#include <sys/uio.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <stdlib.h> - -#include "camel/camel-file-utils.h" -#include "camel/camel-mime-message.h" -#include "camel/camel-stream-null.h" -#include "camel/camel-operation.h" -#include "camel/camel-data-cache.h" - -#include "camel-nntp-summary.h" -#include "camel-nntp-folder.h" -#include "camel-nntp-store.h" -#include "camel-nntp-stream.h" - -#define w(x) -#define io(x) -#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/ -extern int camel_verbose_debug; -#define dd(x) (camel_verbose_debug?(x):0) - -#define CAMEL_NNTP_SUMMARY_VERSION (0x200) - -static int xover_setup(CamelNNTPSummary *cns, CamelException *ex); -static int add_range_xover(CamelNNTPSummary *cns, unsigned int high, unsigned int low, CamelFolderChangeInfo *changes, CamelException *ex); -static int add_range_head(CamelNNTPSummary *cns, unsigned int high, unsigned int low, CamelFolderChangeInfo *changes, CamelException *ex); - -enum _xover_t { - XOVER_STRING = 0, - XOVER_MSGID, - XOVER_SIZE, -}; - -struct _xover_header { - struct _xover_header *next; - - const char *name; - unsigned int skip:8; - enum _xover_t type:8; -}; - -struct _CamelNNTPSummaryPrivate { - char *uid; - - struct _xover_header *xover; /* xoverview format */ - int xover_setup; -}; - -#define _PRIVATE(o) (((CamelNNTPSummary *)(o))->priv) - -static CamelMessageInfo * message_info_new (CamelFolderSummary *, struct _camel_header_raw *); -static int summary_header_load(CamelFolderSummary *, FILE *); -static int summary_header_save(CamelFolderSummary *, FILE *); - -static void camel_nntp_summary_class_init (CamelNNTPSummaryClass *klass); -static void camel_nntp_summary_init (CamelNNTPSummary *obj); -static void camel_nntp_summary_finalise (CamelObject *obj); -static CamelFolderSummaryClass *camel_nntp_summary_parent; - -CamelType -camel_nntp_summary_get_type(void) -{ - static CamelType type = CAMEL_INVALID_TYPE; - - if (type == CAMEL_INVALID_TYPE) { - type = camel_type_register(camel_folder_summary_get_type(), "CamelNNTPSummary", - sizeof (CamelNNTPSummary), - sizeof (CamelNNTPSummaryClass), - (CamelObjectClassInitFunc) camel_nntp_summary_class_init, - NULL, - (CamelObjectInitFunc) camel_nntp_summary_init, - (CamelObjectFinalizeFunc) camel_nntp_summary_finalise); - } - - return type; -} - -static void -camel_nntp_summary_class_init(CamelNNTPSummaryClass *klass) -{ - CamelFolderSummaryClass *sklass = (CamelFolderSummaryClass *) klass; - - camel_nntp_summary_parent = CAMEL_FOLDER_SUMMARY_CLASS(camel_type_get_global_classfuncs(camel_folder_summary_get_type())); - - sklass->message_info_new = message_info_new; - sklass->summary_header_load = summary_header_load; - sklass->summary_header_save = summary_header_save; -} - -static void -camel_nntp_summary_init(CamelNNTPSummary *obj) -{ - struct _CamelNNTPSummaryPrivate *p; - struct _CamelFolderSummary *s = (CamelFolderSummary *)obj; - - p = _PRIVATE(obj) = g_malloc0(sizeof(*p)); - - /* subclasses need to set the right instance data sizes */ - s->message_info_size = sizeof(CamelMessageInfo); - s->content_info_size = sizeof(CamelMessageContentInfo); - - /* and a unique file version */ - s->version += CAMEL_NNTP_SUMMARY_VERSION; -} - -static void -camel_nntp_summary_finalise(CamelObject *obj) -{ - CamelNNTPSummary *cns = CAMEL_NNTP_SUMMARY(obj); - struct _xover_header *xover, *xn; - - xover = cns->priv->xover; - while (xover) { - xn = xover->next; - g_free(xover); - xover = xn; - } - - g_free(cns->priv); -} - -CamelNNTPSummary * -camel_nntp_summary_new(CamelNNTPFolder *folder) -{ - CamelNNTPSummary *cns = (CamelNNTPSummary *)camel_object_new(camel_nntp_summary_get_type()); - char *path; - - cns->folder = folder; - path = g_strdup_printf("%s.ev-summary", folder->storage_path); - camel_folder_summary_set_filename((CamelFolderSummary *)cns, path); - g_free(path); - - camel_folder_summary_set_build_content((CamelFolderSummary *)cns, FALSE); - - return cns; -} - -static CamelMessageInfo * -message_info_new(CamelFolderSummary *s, struct _camel_header_raw *h) -{ - CamelMessageInfo *mi; - CamelNNTPSummary *cns = (CamelNNTPSummary *)s; - - /* error to call without this setup */ - if (cns->priv->uid == NULL) - return NULL; - - /* we shouldn't be here if we already have this uid */ - g_assert(camel_folder_summary_uid(s, cns->priv->uid) == NULL); - - mi = ((CamelFolderSummaryClass *)camel_nntp_summary_parent)->message_info_new(s, h); - if (mi) { - camel_message_info_set_uid(mi, cns->priv->uid); - cns->priv->uid = NULL; - } - - return mi; -} - -static int -summary_header_load(CamelFolderSummary *s, FILE *in) -{ - CamelNNTPSummary *cns = CAMEL_NNTP_SUMMARY(s); - - if (((CamelFolderSummaryClass *)camel_nntp_summary_parent)->summary_header_load(s, in) == -1 - || camel_file_util_decode_fixed_int32(in, &cns->high) == -1 - || camel_file_util_decode_fixed_int32(in, &cns->low) == -1) - return -1; - - return 0; -} - -static int -summary_header_save(CamelFolderSummary *s, FILE *out) -{ - CamelNNTPSummary *cns = CAMEL_NNTP_SUMMARY(s); - - if (((CamelFolderSummaryClass *)camel_nntp_summary_parent)->summary_header_save(s, out) == -1 - || camel_file_util_encode_fixed_int32(out, cns->high) == -1 - || camel_file_util_encode_fixed_int32(out, cns->low) == -1) - return -1; - - return 0; -} - -/* Assumes we have the stream */ -int -camel_nntp_summary_check(CamelNNTPSummary *cns, CamelFolderChangeInfo *changes, CamelException *ex) -{ - CamelNNTPStore *store; - CamelFolder *folder; - CamelFolderSummary *s; - int ret, i; - char *line; - unsigned int n, f, l; - int count; - - if (xover_setup(cns, ex) == -1) - return -1; - - folder = (CamelFolder *)cns->folder; - store = (CamelNNTPStore *)folder->parent_store; - s = (CamelFolderSummary *)cns; - - ret = camel_nntp_command(store, &line, "group %s", folder->full_name); - if (ret == 411) { - camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID, - _("No such folder: %s"), line); - return -1; - } else if (ret != 211) { - camel_exception_setv(ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Could not get group: %s"), line); - return -1; - } - - line +=3; - n = strtoul(line, &line, 10); - f = strtoul(line, &line, 10); - l = strtoul(line, &line, 10); - - dd(printf("nntp_summary: got last '%u' first '%u'\n" - "nntp_summary: high '%u' low '%u'\n", l, f, cns->high, cns->low)); - - if (cns->low == f && cns->high == l) { - dd(printf("nntp_summary: no work to do!\n")); - return 0; - } - - /* Need to work out what to do with our messages */ - - /* Check for messages no longer on the server */ - if (cns->low != f) { - count = camel_folder_summary_count(s); - for (i = 0; i < count; i++) { - CamelMessageInfo *mi = camel_folder_summary_index(s, i); - - if (mi) { - const char *uid = camel_message_info_uid(mi); - const char *msgid; - - n = strtoul(uid, NULL, 10); - if (n < f || n > l) { - dd(printf("nntp_summary: %u is lower/higher than lowest/highest article, removed\n", n)); - /* Since we use a global cache this could prematurely remove - a cached message that might be in another folder - not that important as - it is a true cache */ - msgid = strchr(uid, ','); - if (msgid) - camel_data_cache_remove(store->cache, "cache", msgid+1, NULL); - camel_folder_change_info_remove_uid(changes, uid); - camel_folder_summary_remove(s, mi); - count--; - i--; - } - - camel_folder_summary_info_free(s, mi); - } - } - cns->low = f; - } - - if (cns->high < l) { - if (cns->high < f) - cns->high = f-1; - - if (cns->priv->xover) { - ret = add_range_xover(cns, l, cns->high+1, changes, ex); - } else { - ret = add_range_head(cns, l, cns->high+1, changes, ex); - } - } - - camel_folder_summary_touch(s); - - return ret; -} - -static struct { - const char *name; - int type; -} headers[] = { - { "subject", 0 }, - { "from", 0 }, - { "date", 0 }, - { "message-id", 1 }, - { "references", 0 }, - { "bytes", 2 }, -}; - -static int -xover_setup(CamelNNTPSummary *cns, CamelException *ex) -{ - CamelNNTPStore *store; - CamelFolder *folder; - CamelFolderSummary *s; - int ret, i; - char *line; - unsigned int len; - unsigned char c, *p; - struct _xover_header *xover, *last; - - if (cns->priv->xover_setup) - return 0; - - /* manual override */ - if (getenv("CAMEL_NNTP_DISABLE_XOVER") != NULL) { - cns->priv->xover_setup = TRUE; - return 0; - } - - folder = (CamelFolder *)cns->folder; - store = (CamelNNTPStore *)folder->parent_store; - s = (CamelFolderSummary *)cns; - - ret = camel_nntp_command(store, &line, "list overview.fmt"); - if (ret == -1) { - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("NNTP Command failed: %s"), strerror(errno)); - return -1; - } - - cns->priv->xover_setup = TRUE; - - /* unsupported command? */ - if (ret != 215) - return 0; - - last = (struct _xover_header *)&cns->priv->xover; - - /* supported command */ - while ((ret = camel_nntp_stream_line(store->stream, (unsigned char **)&line, &len)) > 0) { - p = line; - xover = g_malloc0(sizeof(*xover)); - last->next = xover; - last = xover; - while ((c = *p++)) { - if (c == ':') { - p[-1] = 0; - for (i=0;i<sizeof(headers)/sizeof(headers[0]);i++) { - if (strcmp(line, headers[i].name) == 0) { - xover->name = headers[i].name; - if (strncmp(p, "full", 4) == 0) - xover->skip = strlen(xover->name)+1; - else - xover->skip = 0; - xover->type = headers[i].type; - break; - } - } - break; - } else { - p[-1] = tolower(c); - } - } - } - - return ret; -} - -static int -add_range_xover(CamelNNTPSummary *cns, unsigned int high, unsigned int low, CamelFolderChangeInfo *changes, CamelException *ex) -{ - CamelNNTPStore *store; - CamelFolder *folder; - CamelFolderSummary *s; - CamelMessageInfo *mi; - struct _camel_header_raw *headers = NULL; - char *line, *tab; - int len, ret; - unsigned int n, count, total, size; - struct _xover_header *xover; - time_t last, now; - - folder = (CamelFolder *)cns->folder; - store = (CamelNNTPStore *)folder->parent_store; - s = (CamelFolderSummary *)cns; - - camel_operation_start(NULL, _("%s: Scanning new messages"), ((CamelService *)store)->url->host); - - ret = camel_nntp_command(store, &line, "xover %r", low, high); - if (ret != 224) { - camel_operation_end(NULL); - return -1; - } - - last = time(0); - count = 0; - total = high-low+1; - while ((ret = camel_nntp_stream_line(store->stream, (unsigned char **)&line, &len)) > 0) { - camel_operation_progress(NULL, (count * 100) / total); - count++; - n = strtoul(line, &tab, 10); - if (*tab != '\t') - continue; - tab++; - xover = cns->priv->xover; - size = 0; - for (;tab[0] && xover;xover = xover->next) { - line = tab; - tab = strchr(line, '\t'); - if (tab) - *tab++ = 0; - else - tab = line+strlen(line); - - /* do we care about this column? */ - if (xover->name) { - line += xover->skip; - if (line < tab) { - camel_header_raw_append(&headers, xover->name, line, -1); - switch(xover->type) { - case XOVER_STRING: - break; - case XOVER_MSGID: - cns->priv->uid = g_strdup_printf("%u,%s", n, line); - break; - case XOVER_SIZE: - size = strtoul(line, NULL, 10); - break; - } - } - } - } - - /* truncated line? ignore? */ - if (xover == NULL) { - mi = camel_folder_summary_uid(s, cns->priv->uid); - if (mi == NULL) { - mi = camel_folder_summary_add_from_header(s, headers); - if (mi) { - mi->size = size; - cns->high = n; - camel_folder_change_info_add_uid(changes, camel_message_info_uid(mi)); - } - } else { - camel_folder_summary_info_free(s, mi); - } - } - - if (cns->priv->uid) { - g_free(cns->priv->uid); - cns->priv->uid = NULL; - } - - camel_header_raw_clear(&headers); - - now = time(0); - if (last + 2 < now) { - camel_object_trigger_event((CamelObject *)folder, "folder_changed", changes); - camel_folder_change_info_clear(changes); - last = now; - } - } - - camel_operation_end(NULL); - - return ret; -} - -static int -add_range_head(CamelNNTPSummary *cns, unsigned int high, unsigned int low, CamelFolderChangeInfo *changes, CamelException *ex) -{ - CamelNNTPStore *store; - CamelFolder *folder; - CamelFolderSummary *s; - int i, ret = -1; - char *line, *msgid; - unsigned int n, count, total; - CamelMessageInfo *mi; - CamelMimeParser *mp; - time_t now, last; - - folder = (CamelFolder *)cns->folder; - store = (CamelNNTPStore *)folder->parent_store; - s = (CamelFolderSummary *)cns; - - mp = camel_mime_parser_new(); - - camel_operation_start(NULL, _("%s: Scanning new messages"), ((CamelService *)store)->url->host); - - last = time(0); - count = 0; - total = high-low+1; - for (i=low;i<high+1;i++) { - camel_operation_progress(NULL, (count * 100) / total); - count++; - ret = camel_nntp_command(store, &line, "head %u", i); - /* unknown article, ignore */ - if (ret == 423) - continue; - else if (ret == -1) - goto error; - else if (ret != 221) { - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Unknown server response: %s"), line); - goto ioerror; - } - line += 3; - n = strtoul(line, &line, 10); - if (n != i) - g_warning("retrieved message '%d' when i expected '%d'?\n", n, i); - - if ((msgid = strchr(line, '<')) && (line = strchr(msgid+1, '>'))){ - line[1] = 0; - cns->priv->uid = g_strdup_printf("%u,%s\n", n, msgid); - mi = camel_folder_summary_uid(s, cns->priv->uid); - if (mi == NULL) { - if (camel_mime_parser_init_with_stream(mp, (CamelStream *)store->stream) == -1) - goto error; - mi = camel_folder_summary_add_from_parser(s, mp); - while (camel_mime_parser_step(mp, NULL, NULL) != CAMEL_MIME_PARSER_STATE_EOF) - ; - if (mi == NULL) { - goto error; - } - cns->high = i; - camel_folder_change_info_add_uid(changes, camel_message_info_uid(mi)); - } else { - /* already have, ignore */ - camel_folder_summary_info_free(s, mi); - } - if (cns->priv->uid) { - g_free(cns->priv->uid); - cns->priv->uid = NULL; - } - } - - now = time(0); - if (last + 2 < now) { - camel_object_trigger_event((CamelObject *)folder, "folder_changed", changes); - camel_folder_change_info_clear(changes); - last = now; - } - } - - ret = 0; -error: - - if (ret == -1) { - if (errno == EINTR) - camel_exception_setv(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Use cancel")); - else - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Operation failed: %s"), strerror(errno)); - } -ioerror: - - if (cns->priv->uid) { - g_free(cns->priv->uid); - cns->priv->uid = NULL; - } - camel_object_unref((CamelObject *)mp); - - camel_operation_end(NULL); - - return ret; -} diff --git a/camel/providers/nntp/camel-nntp-summary.h b/camel/providers/nntp/camel-nntp-summary.h deleted file mode 100644 index 82070cdc31..0000000000 --- a/camel/providers/nntp/camel-nntp-summary.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2000 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_NNTP_SUMMARY_H -#define _CAMEL_NNTP_SUMMARY_H - -#include <camel/camel-folder-summary.h> -#include <camel/camel-folder.h> -#include <camel/camel-exception.h> -#include <libibex/ibex.h> - -#define CAMEL_NNTP_SUMMARY(obj) CAMEL_CHECK_CAST (obj, camel_nntp_summary_get_type (), CamelNNTPSummary) -#define CAMEL_NNTP_SUMMARY_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_nntp_summary_get_type (), CamelNNTPSummaryClass) -#define CAMEL_IS_LOCAL_SUMMARY(obj) CAMEL_CHECK_TYPE (obj, camel_nntp_summary_get_type ()) - -typedef struct _CamelNNTPSummary CamelNNTPSummary; -typedef struct _CamelNNTPSummaryClass CamelNNTPSummaryClass; - -struct _CamelNNTPSummary { - CamelFolderSummary parent; - - struct _CamelNNTPSummaryPrivate *priv; - - struct _CamelNNTPFolder *folder; - - guint32 high, low; -}; - -struct _CamelNNTPSummaryClass { - CamelFolderSummaryClass parent_class; -}; - -CamelType camel_nntp_summary_get_type (void); -CamelNNTPSummary *camel_nntp_summary_new(struct _CamelNNTPFolder *folder); - -int camel_nntp_summary_check(CamelNNTPSummary *cns, CamelFolderChangeInfo *, CamelException *ex); - -#if 0 -/* load/check the summary */ -int camel_nntp_summary_load(CamelNNTPSummary *cls, CamelException *ex); -/* check for new/removed messages */ -int camel_nntp_summary_check(CamelNNTPSummary *cls, CamelFolderChangeInfo *, CamelException *ex); -/* perform a folder sync or expunge, if needed */ -int camel_nntp_summary_sync(CamelNNTPSummary *cls, gboolean expunge, CamelFolderChangeInfo *, CamelException *ex); -/* add a new message to the summary */ -CamelMessageInfo *camel_nntp_summary_add(CamelNNTPSummary *cls, CamelMimeMessage *msg, const CamelMessageInfo *info, CamelFolderChangeInfo *, CamelException *ex); -#endif - -#endif /* ! _CAMEL_NNTP_SUMMARY_H */ - diff --git a/camel/providers/nntp/camel-nntp-types.h b/camel/providers/nntp/camel-nntp-types.h deleted file mode 100644 index a37179c521..0000000000 --- a/camel/providers/nntp/camel-nntp-types.h +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-nntp-grouplist.h : getting/updating the list of newsgroups on the server. */ - -/* - * Author : Chris Toshok <toshok@ximian.com> - * - * Copyright (C) 2000 Ximian . - * - * 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_NNTP_TYPES_H -#define CAMEL_NNTP_TYPES_H 1 - -typedef struct CamelNNTPGroupList CamelNNTPGroupList; -typedef struct CamelNNTPGroupListEntry CamelNNTPGroupListEntry; -typedef struct CamelNNTPOverField CamelNNTPOverField; -typedef struct CamelNNTPStore CamelNNTPStore; -typedef struct CamelNNTPStoreClass CamelNNTPStoreClass; - -#endif /* CAMEL_NNTP_TYPES_H */ diff --git a/camel/providers/nntp/camel-nntp-utils.c b/camel/providers/nntp/camel-nntp-utils.c deleted file mode 100644 index d8000a85ee..0000000000 --- a/camel/providers/nntp/camel-nntp-utils.c +++ /dev/null @@ -1,299 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-nntp-utils.c : utilities used by the nntp code. */ - -/* - * Author : Chris Toshok <toshok@ximian.com> - * - * Copyright (C) 2000 Ximian . - * - * 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 - */ - -#include "camel-folder-summary.h" -#include "camel-nntp-resp-codes.h" -#include "camel-nntp-folder.h" -#include "camel-nntp-store.h" -#include "camel-nntp-utils.h" -#include "camel-stream-mem.h" -#include "camel-exception.h" - -#include "e-util/md5-utils.h" - -#include <stdlib.h> -#include <string.h> - -static void -get_XOVER_headers(CamelNNTPStore *nntp_store, CamelFolder *folder, - int first_message, int last_message, CamelException *ex) -{ - int status; - CamelNNTPFolder *nntp_folder = CAMEL_NNTP_FOLDER (folder); - char digest[16]; - - status = camel_nntp_command (nntp_store, ex, NULL, - "XOVER %d-%d", - first_message, - last_message); - - if (status == NNTP_DATA_FOLLOWS) { - gboolean done = FALSE; - - while (!done) { - char *line; - - if (camel_remote_store_recv_line (CAMEL_REMOTE_STORE (nntp_store), &line, ex) < 0) { - g_warning ("failed to recv_line while building OVER header list\n"); - break; - } - - if (*line == '.') { - done = TRUE; - g_print ("done\n"); - } - else { - CamelMessageInfo *new_info = camel_folder_summary_info_new(folder->summary); - char **split_line = g_strsplit (line, "\t", 7); - char *subject, *from, *date, *message_id, *bytes; - char *uid; - - subject = split_line [nntp_store->overview_field [CAMEL_NNTP_OVER_SUBJECT].index]; - from = split_line [nntp_store->overview_field [CAMEL_NNTP_OVER_FROM].index]; - date = split_line [nntp_store->overview_field [CAMEL_NNTP_OVER_DATE].index]; - message_id = split_line [nntp_store->overview_field [CAMEL_NNTP_OVER_MESSAGE_ID].index]; - bytes = split_line [nntp_store->overview_field [CAMEL_NNTP_OVER_BYTES].index]; - - /* if the overview format flagged this - field as "full", skip over the - preceding field name and colon */ - if (nntp_store->overview_field [ CAMEL_NNTP_OVER_SUBJECT ].full) - subject += strlen ("Subject:"); - if (nntp_store->overview_field [ CAMEL_NNTP_OVER_FROM ].full) - from += strlen ("From:"); - if (nntp_store->overview_field [ CAMEL_NNTP_OVER_DATE ].full) - date += strlen ("Date:"); - if (nntp_store->overview_field [ CAMEL_NNTP_OVER_MESSAGE_ID ].full) - message_id += strlen ("Message-ID:"); - if (nntp_store->overview_field [ CAMEL_NNTP_OVER_BYTES ].full) - bytes += strlen ("Bytes:"); - - uid = g_strdup_printf ("%s,%s", split_line[0], message_id); - camel_message_info_set_subject(new_info, g_strdup(subject)); - camel_message_info_set_from(new_info, g_strdup(from)); - camel_message_info_set_to(new_info, g_strdup(folder->name)); - camel_message_info_set_uid(new_info, uid); - - new_info->date_sent = camel_header_decode_date(date, NULL); -#if 0 - /* XXX do we need to fill in both dates? */ - new_info->headers.date_received = g_strdup(date); -#endif - new_info->size = atoi(bytes); - md5_get_digest(message_id, strlen(message_id), digest); - memcpy(new_info->message_id.id.hash, digest, sizeof(new_info->message_id.id.hash)); - - if (camel_nntp_newsrc_article_is_read (nntp_store->newsrc, - folder->name, - atoi (split_line[0]))) - new_info->flags |= CAMEL_MESSAGE_SEEN; - - camel_folder_summary_add (folder->summary, new_info); - g_strfreev (split_line); - } - g_free (line); - } - } - else { - /* XXX */ - g_warning ("weird nntp response for XOVER: %d\n", status); - } -} - -#if 0 -static GArray* -get_HEAD_headers(CamelNNTPStore *nntp_store, CamelFolder *folder, - int first_message, int last_message, CamelException *ex) -{ - int i; - int status; - - for (i = first_message; i < last_message; i ++) { - status = camel_nntp_command (nntp_store, ex, NULL, - "HEAD %d", i); - - if (status == NNTP_HEAD_FOLLOWS) { - gboolean done = FALSE; - char *buf; - int buf_len; - int buf_alloc; - int h; - CamelStream *header_stream; - GArray *header_array; - CamelStream *nntp_istream; - CamelMessageInfo *new_info = g_new0(CamelMessageInfo, 1); - - buf_alloc = 2048; - buf_len = 0; - buf = g_malloc(buf_alloc); - done = FALSE; - - buf[0] = 0; - - nntp_istream = nntp_store->istream; - - while (!done) { - char *line; - int line_length; - - line = camel_stream_buffer_read_line ( - CAMEL_STREAM_BUFFER ( nntp_istream )); - line_length = strlen ( line ); - - if (*line == '.') { - done = TRUE; - } - else { - if (buf_len + line_length > buf_alloc) { - buf_alloc *= 2; - buf = g_realloc (buf, buf_alloc); - } - strcat(buf, line); - strcat(buf, "\n"); - buf_len += strlen(line); - g_free (line); - } - } - - /* create a stream from which to parse the headers */ - header_stream = camel_stream_mem_new_with_buffer (buf, buf_len, - CAMEL_STREAM_MEM_READ); - - header_array = get_header_array_from_stream (header_stream); - - memset (&info, 0, sizeof(info)); - - for (h = 0; h < header_array->len; h ++) { - Rfc822Header *header = &((Rfc822Header*)header_array->data)[h]; - if (!g_strcasecmp(header->name, "From")) - new_info->from = g_strdup(header->value); - else if (!g_strcasecmp(header->name, "To")) - new_info->to = g_strdup(header->value); - else if (!g_strcasecmp(header->name, "Subject")) - new_info->subject = g_strdup(header->value); - else if (!g_strcasecmp(header->name, "Message-ID")) { - new_info->uid = g_strdup_printf("%d,%s", i, header->value); - new_info->message_id = g_strdup(header->value); - } - else if (!g_strcasecmp(header->name, "Date")) { - new_info->date_sent = camel_header_decode_date (header->value); -#if 0 - new_info->date_sent = g_strdup(header->value); - new_info->date_received = g_strdup(header->value); -#endif - } - } - - camel_folder_summary_add (nntp_folder->summary, new_info); - } - else if (status == CAMEL_NNTP_FAIL) { - /* nasty things are afoot */ - g_warning ("failure doing HEAD\n"); - break; - } - } -} -#endif - -static inline int -uid_num (CamelFolderSummary *summary, int index) -{ - char *tmp; - char *brk; - CamelMessageInfo *minfo; - int ret; - - minfo = camel_folder_summary_index(summary, index); - if(minfo == NULL) - return 0; - - tmp = g_strdup(camel_message_info_uid(minfo)); - camel_message_info_free(minfo); - - if((brk = strchr(tmp, ',')) == NULL) - ret = 0; - else { - *brk = 0; - ret = atoi(tmp); - } - - g_free(tmp); - - return ret; -} - -void -camel_nntp_get_headers (CamelStore *store, - CamelNNTPFolder *nntp_folder, - CamelException *ex) -{ - CamelNNTPStore *nntp_store = CAMEL_NNTP_STORE (store); - CamelFolder *folder = CAMEL_FOLDER (nntp_folder); - char *ret; - int first_message, nb_message, last_message, last_summary; - int status; - int i; - - status = camel_nntp_command (nntp_store, ex, &ret, - "GROUP %s", folder->name); - sscanf (ret, "%d %d %d", &nb_message, &first_message, &last_message); - g_free (ret); - - i = camel_folder_summary_count(folder->summary); - if(i != 0) { - last_summary = uid_num(folder->summary, i-1); - - if(last_summary < first_message) - camel_folder_summary_clear(folder->summary); - else { - while(uid_num(folder->summary, 0) < first_message) - camel_folder_summary_remove_index(folder->summary, 0); - - if(last_summary >= last_message) - return; - - first_message = last_summary; - } - } - - if (status == NNTP_NO_SUCH_GROUP) { - /* XXX throw invalid group exception */ - camel_exception_setv (ex, - CAMEL_EXCEPTION_FOLDER_INVALID, - "group %s not found on server", - folder->name); - return; - } - - - if (nntp_store->extensions & CAMEL_NNTP_EXT_OVER) { - get_XOVER_headers (nntp_store, folder, first_message, last_message, ex); - } - else { - g_warning ("need to fix get_HEAD_headers\n"); -#if 0 - get_HEAD_headers (nntp_store, folder, first_message, last_message, ex); -#endif - } - -} diff --git a/camel/providers/nntp/camel-nntp-utils.h b/camel/providers/nntp/camel-nntp-utils.h deleted file mode 100644 index 48fd7490c9..0000000000 --- a/camel/providers/nntp/camel-nntp-utils.h +++ /dev/null @@ -1,41 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-nntp-utils.h : Utilities for the NNTP provider */ - -/* - * - * Author : Chris Toshok <toshok@ximian.com> - * - * Copyright (C) 1999 Ximian . - * - * 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_NNTP_UTILS_H -#define CAMEL_NNTP_UTILS_H 1 - - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus }*/ - -void camel_nntp_get_headers (CamelStore *store, CamelNNTPFolder *nntp_folder, CamelException *ex); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CAMEL_NNTP_UTILS_H */ diff --git a/camel/providers/nntp/libcamelnntp.urls b/camel/providers/nntp/libcamelnntp.urls deleted file mode 100644 index dee2e70f14..0000000000 --- a/camel/providers/nntp/libcamelnntp.urls +++ /dev/null @@ -1,2 +0,0 @@ -news -nntp diff --git a/camel/providers/nntp/test-newsrc.c b/camel/providers/nntp/test-newsrc.c deleted file mode 100644 index c4b985e565..0000000000 --- a/camel/providers/nntp/test-newsrc.c +++ /dev/null @@ -1,10 +0,0 @@ -#include <stdio.h> -#include <glib.h> -#include "camel-nntp-newsrc.h" - -int -main(int argc, char *argv[]) -{ - CamelNNTPNewsrc *newsrc = camel_nntp_newsrc_read_for_server (argv[1]); - camel_nntp_newsrc_write_to_file (newsrc, stdout); -} diff --git a/camel/providers/pop3/.cvsignore b/camel/providers/pop3/.cvsignore deleted file mode 100644 index ddf4c8b28d..0000000000 --- a/camel/providers/pop3/.cvsignore +++ /dev/null @@ -1,10 +0,0 @@ -Makefile -Makefile.in -.libs -.deps -*.lo -*.la -*.bb -*.bbg -*.da -*.gcov diff --git a/camel/providers/pop3/Makefile.am b/camel/providers/pop3/Makefile.am deleted file mode 100644 index 84f5477f97..0000000000 --- a/camel/providers/pop3/Makefile.am +++ /dev/null @@ -1,38 +0,0 @@ -## Process this file with automake to produce Makefile.in - -libcamelpop3includedir = $(privincludedir)/camel - -camel_provider_LTLIBRARIES = libcamelpop3.la -camel_provider_DATA = libcamelpop3.urls - -INCLUDES = \ - -I.. \ - -I$(srcdir)/.. \ - -I$(srcdir)/../../.. \ - -I$(top_srcdir)/intl \ - -I$(top_srcdir)/camel \ - -I$(top_srcdir)/e-util \ - $(CAMEL_CFLAGS) \ - $(GNOME_INCLUDEDIR) \ - $(GTK_INCLUDEDIR) \ - -DG_LOG_DOMAIN=\"camel-pop3-provider\" - -libcamelpop3_la_SOURCES = \ - camel-pop3-engine.c \ - camel-pop3-folder.c \ - camel-pop3-provider.c \ - camel-pop3-stream.c \ - camel-pop3-store.c - -libcamelpop3include_HEADERS = \ - camel-pop3-engine.h \ - camel-pop3-folder.h \ - camel-pop3-stream.h \ - camel-pop3-store.h - - -libcamelpop3_la_LDFLAGS = -avoid-version -module - -libcamelpop3_la_LIBADD = $(top_builddir)/e-util/libeutil.la - -EXTRA_DIST = libcamelpop3.urls diff --git a/camel/providers/pop3/camel-pop3-engine.c b/camel/providers/pop3/camel-pop3-engine.c deleted file mode 100644 index 2186136f95..0000000000 --- a/camel/providers/pop3/camel-pop3-engine.c +++ /dev/null @@ -1,382 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*- - * - * Author: - * 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 - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> - -#include <string.h> -#include <stdio.h> - -#include <glib.h> - -#include "camel-pop3-engine.h" -#include "camel-pop3-stream.h" -#include <camel/camel-service.h> -#include <camel/camel-sasl.h> - -/* max 'outstanding' bytes in output stream, so we can't deadlock waiting - for the server to accept our data when pipelining */ -#define CAMEL_POP3_SEND_LIMIT (1024) - - -extern int camel_verbose_debug; -#define dd(x) (camel_verbose_debug?(x):0) - -static void get_capabilities(CamelPOP3Engine *pe, int read_greeting); - -static CamelObjectClass *parent_class = NULL; - -/* Returns the class for a CamelStream */ -#define CS_CLASS(so) CAMEL_POP3_ENGINE_CLASS(CAMEL_OBJECT_GET_CLASS(so)) - -static void -camel_pop3_engine_class_init (CamelPOP3EngineClass *camel_pop3_engine_class) -{ - parent_class = camel_type_get_global_classfuncs( CAMEL_OBJECT_TYPE ); -} - -static void -camel_pop3_engine_init(CamelPOP3Engine *pe, CamelPOP3EngineClass *peclass) -{ - e_dlist_init(&pe->active); - e_dlist_init(&pe->queue); - e_dlist_init(&pe->done); - pe->state = CAMEL_POP3_ENGINE_DISCONNECT; -} - -static void -camel_pop3_engine_finalise(CamelPOP3Engine *pe) -{ - /* FIXME: Also flush/free any outstanding requests, etc */ - - if (pe->stream) - camel_object_unref((CamelObject *)pe->stream); -} - -CamelType -camel_pop3_engine_get_type (void) -{ - static CamelType camel_pop3_engine_type = CAMEL_INVALID_TYPE; - - if (camel_pop3_engine_type == CAMEL_INVALID_TYPE) { - camel_pop3_engine_type = camel_type_register(camel_object_get_type(), - "CamelPOP3Engine", - sizeof( CamelPOP3Engine ), - sizeof( CamelPOP3EngineClass ), - (CamelObjectClassInitFunc) camel_pop3_engine_class_init, - NULL, - (CamelObjectInitFunc) camel_pop3_engine_init, - (CamelObjectFinalizeFunc) camel_pop3_engine_finalise ); - } - - return camel_pop3_engine_type; -} - -/** - * camel_pop3_engine_new: - * @source: source stream - * @flags: engine flags - * - * Returns a NULL stream. A null stream is always at eof, and - * always returns success for all reads and writes. - * - * Return value: the stream - **/ -CamelPOP3Engine * -camel_pop3_engine_new(CamelStream *source, guint32 flags) -{ - CamelPOP3Engine *pe; - - pe = (CamelPOP3Engine *)camel_object_new(camel_pop3_engine_get_type ()); - - pe->stream = (CamelPOP3Stream *)camel_pop3_stream_new(source); - pe->state = CAMEL_POP3_ENGINE_AUTH; - pe->flags = flags; - - get_capabilities(pe, TRUE); - - return pe; -} - - -/** - * camel_pop3_engine_reget_capabilities: - * @engine: pop3 engine - * - * Regets server capabilities (needed after a STLS command is issued for example). - **/ -void -camel_pop3_engine_reget_capabilities (CamelPOP3Engine *engine) -{ - g_return_if_fail (CAMEL_IS_POP3_ENGINE (engine)); - - get_capabilities (engine, FALSE); -} - - -/* TODO: read implementation too? - etc? */ -struct { - char *cap; - guint32 flag; -} capa[] = { - { "APOP" , CAMEL_POP3_CAP_APOP }, - { "TOP" , CAMEL_POP3_CAP_TOP }, - { "UIDL", CAMEL_POP3_CAP_UIDL }, - { "PIPELINING", CAMEL_POP3_CAP_PIPE }, - { "STLS", CAMEL_POP3_CAP_STLS }, /* STARTTLS */ -}; - -static void -cmd_capa(CamelPOP3Engine *pe, CamelPOP3Stream *stream, void *data) -{ - unsigned char *line, *tok, *next; - unsigned int len; - int ret; - int i; - CamelServiceAuthType *auth; - - dd(printf("cmd_capa\n")); - - do { - ret = camel_pop3_stream_line(stream, &line, &len); - if (ret >= 0) { - if (strncmp(line, "SASL ", 5) == 0) { - tok = line+5; - dd(printf("scanning tokens '%s'\n", tok)); - while (tok) { - next = strchr(tok, ' '); - if (next) - *next++ = 0; - auth = camel_sasl_authtype(tok); - if (auth) { - dd(printf("got auth type '%s'\n", tok)); - pe->auth = g_list_prepend(pe->auth, auth); - } else { - dd(printf("unsupported auth type '%s'\n", tok)); - } - tok = next; - } - } else { - for (i=0;i<sizeof(capa)/sizeof(capa[0]);i++) { - if (strcmp(capa[i].cap, line) == 0) - pe->capa |= capa[i].flag; - } - } - } - } while (ret>0); -} - -static void -get_capabilities(CamelPOP3Engine *pe, int read_greeting) -{ - CamelPOP3Command *pc; - unsigned char *line, *apop, *apopend; - unsigned int len; - extern CamelServiceAuthType camel_pop3_password_authtype; - extern CamelServiceAuthType camel_pop3_apop_authtype; - - if (read_greeting) { - /* first, read the greeting */ - if (camel_pop3_stream_line(pe->stream, &line, &len) == -1 - || strncmp(line, "+OK", 3) != 0) - return; - - if ((apop = strchr(line+3, '<')) - && (apopend = strchr(apop, '>'))) { - apopend[1] = 0; - pe->apop = g_strdup(apop); - pe->capa = CAMEL_POP3_CAP_APOP; - pe->auth = g_list_append(pe->auth, &camel_pop3_apop_authtype); - } - - pe->auth = g_list_prepend(pe->auth, &camel_pop3_password_authtype); - } - - if (!(pe->flags & CAMEL_POP3_ENGINE_DISABLE_EXTENSIONS)) { - pc = camel_pop3_engine_command_new(pe, CAMEL_POP3_COMMAND_MULTI, cmd_capa, NULL, "CAPA\r\n"); - while (camel_pop3_engine_iterate(pe, pc) > 0) - ; - camel_pop3_engine_command_free(pe, pc); - - if (pe->state == CAMEL_POP3_ENGINE_TRANSACTION && !(pe->capa & CAMEL_POP3_CAP_UIDL)) { - /* check for UIDL support manually */ - pc = camel_pop3_engine_command_new (pe, CAMEL_POP3_COMMAND_SIMPLE, NULL, NULL, "UIDL 1\r\n"); - while (camel_pop3_engine_iterate (pe, pc) > 0) - ; - - if (pc->state == CAMEL_POP3_COMMAND_OK) - pe->capa |= CAMEL_POP3_CAP_UIDL; - - camel_pop3_engine_command_free (pe, pc); - } - } -} - -/* returns true if the command was sent, false if it was just queued */ -static int -engine_command_queue(CamelPOP3Engine *pe, CamelPOP3Command *pc) -{ - if (((pe->capa & CAMEL_POP3_CAP_PIPE) == 0 || (pe->sentlen + strlen(pc->data)) > CAMEL_POP3_SEND_LIMIT) - && pe->current != NULL) { - e_dlist_addtail(&pe->queue, (EDListNode *)pc); - return FALSE; - } else { - /* ??? */ - if (camel_stream_write((CamelStream *)pe->stream, pc->data, strlen(pc->data)) == -1) { - e_dlist_addtail(&pe->queue, (EDListNode *)pc); - return FALSE; - } - - pe->sentlen += strlen(pc->data); - - pc->state = CAMEL_POP3_COMMAND_DISPATCHED; - - if (pe->current == NULL) - pe->current = pc; - else - e_dlist_addtail(&pe->active, (EDListNode *)pc); - - return TRUE; - } -} - -/* returns -1 on error (sets errno), 0 when no work to do, or >0 if work remaining */ -int -camel_pop3_engine_iterate(CamelPOP3Engine *pe, CamelPOP3Command *pcwait) -{ - unsigned char *p; - unsigned int len; - CamelPOP3Command *pc, *pw, *pn; - - if (pcwait && pcwait->state >= CAMEL_POP3_COMMAND_OK) - return 0; - - pc = pe->current; - if (pc == NULL) - return 0; - - /* LOCK */ - - if (camel_pop3_stream_line(pe->stream, &pe->line, &pe->linelen) == -1) - return -1; - - p = pe->line; - switch (p[0]) { - case '+': - dd(printf("Got + response\n")); - if (pc->flags & CAMEL_POP3_COMMAND_MULTI) { - pc->state = CAMEL_POP3_COMMAND_DATA; - camel_pop3_stream_set_mode(pe->stream, CAMEL_POP3_STREAM_DATA); - - if (pc->func) - pc->func(pe, pe->stream, pc->func_data); - - /* Make sure we get all data before going back to command mode */ - while (camel_pop3_stream_getd(pe->stream, &p, &len) > 0) - ; - camel_pop3_stream_set_mode(pe->stream, CAMEL_POP3_STREAM_LINE); - } else { - pc->state = CAMEL_POP3_COMMAND_OK; - } - break; - case '-': - pc->state = CAMEL_POP3_COMMAND_ERR; - break; - default: - /* what do we do now? f'knows! */ - g_warning("Bad server response: %s\n", p); - pc->state = CAMEL_POP3_COMMAND_ERR; - break; - } - - e_dlist_addtail(&pe->done, (EDListNode *)pc); - pe->sentlen -= strlen(pc->data); - - /* Set next command */ - pe->current = (CamelPOP3Command *)e_dlist_remhead(&pe->active); - - /* check the queue for sending any we can now send also */ - pw = (CamelPOP3Command *)pe->queue.head; - pn = pw->next; - while (pn) { - if (((pe->capa & CAMEL_POP3_CAP_PIPE) == 0 || (pe->sentlen + strlen(pw->data)) > CAMEL_POP3_SEND_LIMIT) - && pe->current != NULL) - break; - - if (camel_stream_write((CamelStream *)pe->stream, pw->data, strlen(pw->data)) == -1) - return -1; - - e_dlist_remove((EDListNode *)pw); - - pe->sentlen += strlen(pw->data); - pw->state = CAMEL_POP3_COMMAND_DISPATCHED; - - if (pe->current == NULL) - pe->current = pw; - else - e_dlist_addtail(&pe->active, (EDListNode *)pw); - - pw = pn; - pn = pn->next; - } - - /* UNLOCK */ - - if (pcwait && pcwait->state >= CAMEL_POP3_COMMAND_OK) - return 0; - - return pe->current==NULL?0:1; -} - -CamelPOP3Command * -camel_pop3_engine_command_new(CamelPOP3Engine *pe, guint32 flags, CamelPOP3CommandFunc func, void *data, const char *fmt, ...) -{ - CamelPOP3Command *pc; - va_list ap; - - pc = g_malloc0(sizeof(*pc)); - pc->func = func; - pc->func_data = data; - pc->flags = flags; - - va_start(ap, fmt); - pc->data = g_strdup_vprintf(fmt, ap); - pc->state = CAMEL_POP3_COMMAND_IDLE; - - /* TODO: what about write errors? */ - engine_command_queue(pe, pc); - - return pc; -} - -void -camel_pop3_engine_command_free(CamelPOP3Engine *pe, CamelPOP3Command *pc) -{ - if (pe->current != pc) - e_dlist_remove((EDListNode *)pc); - g_free(pc->data); - g_free(pc); -} diff --git a/camel/providers/pop3/camel-pop3-engine.h b/camel/providers/pop3/camel-pop3-engine.h deleted file mode 100644 index 3114980311..0000000000 --- a/camel/providers/pop3/camel-pop3-engine.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2001 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_POP3_ENGINE_H -#define _CAMEL_POP3_ENGINE_H - -#include <camel/camel-object.h> -#include "e-util/e-msgport.h" -#include "camel-pop3-stream.h" - -#define CAMEL_POP3_ENGINE(obj) CAMEL_CHECK_CAST (obj, camel_pop3_engine_get_type (), CamelPOP3Engine) -#define CAMEL_POP3_ENGINE_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_pop3_engine_get_type (), CamelPOP3EngineClass) -#define CAMEL_IS_POP3_ENGINE(obj) CAMEL_CHECK_TYPE (obj, camel_pop3_engine_get_type ()) - -typedef struct _CamelPOP3EngineClass CamelPOP3EngineClass; -typedef struct _CamelPOP3Engine CamelPOP3Engine; -typedef struct _CamelPOP3Command CamelPOP3Command; - -/* pop 3 connection states, actually since we're given a connected socket, we always start in auth state */ -typedef enum { - CAMEL_POP3_ENGINE_DISCONNECT = 0, - CAMEL_POP3_ENGINE_AUTH, - CAMEL_POP3_ENGINE_TRANSACTION, - CAMEL_POP3_ENGINE_UPDATE, -} camel_pop3_engine_t; - -/* state of a command */ -typedef enum { - CAMEL_POP3_COMMAND_IDLE = 0, /* command created or queued, not yet sent (e.g. non pipelined server) */ - CAMEL_POP3_COMMAND_DISPATCHED, /* command sent to server */ - - /* completion codes */ - CAMEL_POP3_COMMAND_OK, /* plain ok response */ - CAMEL_POP3_COMMAND_DATA, /* processing command response */ - CAMEL_POP3_COMMAND_ERR, /* error response */ -} camel_pop3_command_t; - -/* flags for command types */ -enum { - CAMEL_POP3_COMMAND_SIMPLE = 0, /* dont expect multiline response */ - CAMEL_POP3_COMMAND_MULTI = 1, /* expect multiline response */ -}; - -/* flags for server options */ -enum { - CAMEL_POP3_CAP_APOP = 1<<0, - CAMEL_POP3_CAP_UIDL = 1<<1, - CAMEL_POP3_CAP_SASL = 1<<2, - CAMEL_POP3_CAP_TOP = 1<<3, - CAMEL_POP3_CAP_PIPE = 1<<4, - CAMEL_POP3_CAP_STLS = 1<<5 -}; - -/* enable/disable flags for the engine itself */ -enum { - CAMEL_POP3_ENGINE_DISABLE_EXTENSIONS = 1<<0, -}; - -typedef void (*CamelPOP3CommandFunc)(CamelPOP3Engine *pe, CamelPOP3Stream *stream, void *data); - -struct _CamelPOP3Command { - struct _CamelPOP3Command *next; - struct _CamelPOP3Command *prev; - - guint32 flags; - camel_pop3_command_t state; - - CamelPOP3CommandFunc func; - void *func_data; - - int data_size; - char *data; -}; - -struct _CamelPOP3Engine { - CamelObject parent; - - guint32 flags; - - camel_pop3_engine_t state; - - GList *auth; /* authtypes supported */ - - guint32 capa; /* capabilities */ - char *apop; /* apop time string */ - - unsigned char *line; /* current line buffer */ - unsigned int linelen; - - struct _CamelPOP3Stream *stream; - - unsigned int sentlen; /* data sent (so we dont overflow network buffer) */ - - EDList active; /* active commands */ - EDList queue; /* queue of waiting commands */ - EDList done; /* list of done commands, awaiting free */ - - CamelPOP3Command *current; /* currently busy (downloading) response */ -}; - -struct _CamelPOP3EngineClass { - CamelObjectClass parent_class; -}; - -CamelType camel_pop3_engine_get_type (void); - -CamelPOP3Engine *camel_pop3_engine_new (CamelStream *source, guint32 flags); - -void camel_pop3_engine_reget_capabilities (CamelPOP3Engine *engine); - -void camel_pop3_engine_command_free(CamelPOP3Engine *pe, CamelPOP3Command *pc); - -int camel_pop3_engine_iterate (CamelPOP3Engine *pe, CamelPOP3Command *pc); - -CamelPOP3Command *camel_pop3_engine_command_new (CamelPOP3Engine *pe, guint32 flags, CamelPOP3CommandFunc func, void *data, const char *fmt, ...); - -#endif /* ! _CAMEL_POP3_ENGINE_H */ diff --git a/camel/providers/pop3/camel-pop3-folder.c b/camel/providers/pop3/camel-pop3-folder.c deleted file mode 100644 index db77ad8191..0000000000 --- a/camel/providers/pop3/camel-pop3-folder.c +++ /dev/null @@ -1,558 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-pop3-folder.c : class for a pop3 folder */ - -/* - * Authors: - * Dan Winship <danw@ximian.com> - * Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 2002 Ximian, Inc. (www.ximian.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> - -#include "camel-pop3-folder.h" -#include "camel-pop3-store.h" -#include "camel-exception.h" -#include "camel-stream-mem.h" -#include "camel-stream-filter.h" -#include "camel-mime-message.h" -#include "camel-operation.h" -#include "camel-data-cache.h" - -#include <e-util/md5-utils.h> - -#include <stdlib.h> -#include <string.h> - -#define d(x) - -#define CF_CLASS(o) (CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(o))) -static CamelFolderClass *parent_class; - -static void pop3_finalize (CamelObject *object); -static void pop3_refresh_info (CamelFolder *folder, CamelException *ex); -static void pop3_sync (CamelFolder *folder, gboolean expunge, CamelException *ex); -static gint pop3_get_message_count (CamelFolder *folder); -static GPtrArray *pop3_get_uids (CamelFolder *folder); -static CamelMimeMessage *pop3_get_message (CamelFolder *folder, const char *uid, CamelException *ex); -static void pop3_set_message_flags (CamelFolder *folder, const char *uid, guint32 flags, guint32 set); - -static void -camel_pop3_folder_class_init (CamelPOP3FolderClass *camel_pop3_folder_class) -{ - CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS(camel_pop3_folder_class); - - parent_class = CAMEL_FOLDER_CLASS(camel_folder_get_type()); - - /* virtual method overload */ - camel_folder_class->refresh_info = pop3_refresh_info; - camel_folder_class->sync = pop3_sync; - - camel_folder_class->get_message_count = pop3_get_message_count; - camel_folder_class->get_uids = pop3_get_uids; - camel_folder_class->free_uids = camel_folder_free_shallow; - - camel_folder_class->get_message = pop3_get_message; - camel_folder_class->set_message_flags = pop3_set_message_flags; -} - -CamelType -camel_pop3_folder_get_type (void) -{ - static CamelType camel_pop3_folder_type = CAMEL_INVALID_TYPE; - - if (!camel_pop3_folder_type) { - camel_pop3_folder_type = camel_type_register (CAMEL_FOLDER_TYPE, "CamelPOP3Folder", - sizeof (CamelPOP3Folder), - sizeof (CamelPOP3FolderClass), - (CamelObjectClassInitFunc) camel_pop3_folder_class_init, - NULL, - NULL, - (CamelObjectFinalizeFunc) pop3_finalize); - } - - return camel_pop3_folder_type; -} - -static void -pop3_finalize (CamelObject *object) -{ - CamelPOP3Folder *pop3_folder = CAMEL_POP3_FOLDER (object); - CamelPOP3FolderInfo **fi = (CamelPOP3FolderInfo **)pop3_folder->uids->pdata; - CamelPOP3Store *pop3_store = (CamelPOP3Store *)((CamelFolder *)pop3_folder)->parent_store; - int i; - - if (pop3_folder->uids) { - for (i=0;i<pop3_folder->uids->len;i++,fi++) { - if (fi[0]->cmd) { - while (camel_pop3_engine_iterate(pop3_store->engine, fi[0]->cmd) > 0) - ; - camel_pop3_engine_command_free(pop3_store->engine, fi[0]->cmd); - } - - g_free(fi[0]->uid); - g_free(fi[0]); - } - - g_ptr_array_free(pop3_folder->uids, TRUE); - g_hash_table_destroy(pop3_folder->uids_uid); - } -} - -CamelFolder * -camel_pop3_folder_new (CamelStore *parent, CamelException *ex) -{ - CamelFolder *folder; - - d(printf("opening pop3 INBOX folder\n")); - - folder = CAMEL_FOLDER (camel_object_new (CAMEL_POP3_FOLDER_TYPE)); - camel_folder_construct (folder, parent, "inbox", "inbox"); - - /* mt-ok, since we dont have the folder-lock for new() */ - camel_folder_refresh_info (folder, ex);/* mt-ok */ - if (camel_exception_is_set (ex)) { - camel_object_unref (CAMEL_OBJECT (folder)); - folder = NULL; - } - - return folder; -} - -/* create a uid from md5 of 'top' output */ -static void -cmd_builduid(CamelPOP3Engine *pe, CamelPOP3Stream *stream, void *data) -{ - CamelPOP3FolderInfo *fi = data; - MD5Context md5; - unsigned char digest[16]; - struct _camel_header_raw *h; - CamelMimeParser *mp; - - /* TODO; somehow work out the limit and use that for proper progress reporting - We need a pointer to the folder perhaps? */ - camel_operation_progress_count(NULL, fi->id); - - md5_init(&md5); - mp = camel_mime_parser_new(); - camel_mime_parser_init_with_stream(mp, (CamelStream *)stream); - switch (camel_mime_parser_step(mp, NULL, NULL)) { - case CAMEL_MIME_PARSER_STATE_HEADER: - case CAMEL_MIME_PARSER_STATE_MESSAGE: - case CAMEL_MIME_PARSER_STATE_MULTIPART: - h = camel_mime_parser_headers_raw(mp); - while (h) { - if (strcasecmp(h->name, "status") != 0 - && strcasecmp(h->name, "x-status") != 0) { - md5_update(&md5, h->name, strlen(h->name)); - md5_update(&md5, h->value, strlen(h->value)); - } - h = h->next; - } - default: - break; - } - camel_object_unref(mp); - md5_final(&md5, digest); - fi->uid = camel_base64_encode_simple(digest, 16); - - d(printf("building uid for id '%d' = '%s'\n", fi->id, fi->uid)); -} - -static void -cmd_list(CamelPOP3Engine *pe, CamelPOP3Stream *stream, void *data) -{ - int ret; - unsigned int len, id, size; - unsigned char *line; - CamelFolder *folder = data; - CamelPOP3Store *pop3_store = CAMEL_POP3_STORE (folder->parent_store); - CamelPOP3FolderInfo *fi; - - do { - ret = camel_pop3_stream_line(stream, &line, &len); - if (ret>=0) { - if (sscanf(line, "%u %u", &id, &size) == 2) { - fi = g_malloc0(sizeof(*fi)); - fi->size = size; - fi->id = id; - fi->index = ((CamelPOP3Folder *)folder)->uids->len; - if ((pop3_store->engine->capa & CAMEL_POP3_CAP_UIDL) == 0) - fi->cmd = camel_pop3_engine_command_new(pe, CAMEL_POP3_COMMAND_MULTI, cmd_builduid, fi, "TOP %u 0\r\n", id); - g_ptr_array_add(((CamelPOP3Folder *)folder)->uids, fi); - g_hash_table_insert(((CamelPOP3Folder *)folder)->uids_id, GINT_TO_POINTER(id), fi); - } - } - } while (ret>0); -} - -static void -cmd_uidl(CamelPOP3Engine *pe, CamelPOP3Stream *stream, void *data) -{ - int ret; - unsigned int len; - unsigned char *line; - char uid[1025]; - unsigned int id; - CamelPOP3FolderInfo *fi; - CamelPOP3Folder *folder = data; - - do { - ret = camel_pop3_stream_line(stream, &line, &len); - if (ret>=0) { - if (strlen(line) > 1024) - line[1024] = 0; - if (sscanf(line, "%u %s", &id, uid) == 2) { - fi = g_hash_table_lookup(folder->uids_id, GINT_TO_POINTER(id)); - if (fi) { - camel_operation_progress(NULL, (fi->index+1) * 100 / folder->uids->len); - fi->uid = g_strdup(uid); - g_hash_table_insert(folder->uids_uid, fi->uid, fi); - } else { - g_warning("ID %u (uid: %s) not in previous LIST output", id, uid); - } - } - } - } while (ret>0); -} - -static void -pop3_refresh_info (CamelFolder *folder, CamelException *ex) -{ - CamelPOP3Store *pop3_store = CAMEL_POP3_STORE (folder->parent_store); - CamelPOP3Folder *pop3_folder = (CamelPOP3Folder *) folder; - CamelPOP3Command *pcl, *pcu = NULL; - int i; - - camel_operation_start (NULL, _("Retrieving POP summary")); - - pop3_folder->uids = g_ptr_array_new (); - pop3_folder->uids_uid = g_hash_table_new(g_str_hash, g_str_equal); - /* only used during setup */ - pop3_folder->uids_id = g_hash_table_new(NULL, NULL); - - pcl = camel_pop3_engine_command_new(pop3_store->engine, CAMEL_POP3_COMMAND_MULTI, cmd_list, folder, "LIST\r\n"); - if (pop3_store->engine->capa & CAMEL_POP3_CAP_UIDL) { - pcu = camel_pop3_engine_command_new(pop3_store->engine, CAMEL_POP3_COMMAND_MULTI, cmd_uidl, folder, "UIDL\r\n"); - } - while ((i = camel_pop3_engine_iterate(pop3_store->engine, NULL)) > 0) - ; - - if (i == -1) { - if (errno == EINTR) - camel_exception_setv(ex, CAMEL_EXCEPTION_USER_CANCEL, _("User cancelled")); - else - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot get POP summary: %s"), - g_strerror (errno)); - } - - /* TODO: check every id has a uid & commands returned OK too? */ - - camel_pop3_engine_command_free(pop3_store->engine, pcl); - - if (pop3_store->engine->capa & CAMEL_POP3_CAP_UIDL) { - camel_pop3_engine_command_free(pop3_store->engine, pcu); - } else { - for (i=0;i<pop3_folder->uids->len;i++) { - CamelPOP3FolderInfo *fi = pop3_folder->uids->pdata[i]; - if (fi->cmd) { - camel_pop3_engine_command_free(pop3_store->engine, fi->cmd); - fi->cmd = NULL; - } - if (fi->uid) - g_hash_table_insert(pop3_folder->uids_uid, fi->uid, fi); - } - } - - /* dont need this anymore */ - g_hash_table_destroy(pop3_folder->uids_id); - - camel_operation_end (NULL); - return; -} - -static void -pop3_sync (CamelFolder *folder, gboolean expunge, CamelException *ex) -{ - CamelPOP3Folder *pop3_folder; - CamelPOP3Store *pop3_store; - int i; - CamelPOP3FolderInfo *fi; - - if (!expunge) - return; - - pop3_folder = CAMEL_POP3_FOLDER (folder); - pop3_store = CAMEL_POP3_STORE (folder->parent_store); - - camel_operation_start(NULL, _("Expunging deleted messages")); - - for (i = 0; i < pop3_folder->uids->len; i++) { - fi = pop3_folder->uids->pdata[i]; - /* busy already? wait for that to finish first */ - if (fi->cmd) { - while (camel_pop3_engine_iterate(pop3_store->engine, fi->cmd) > 0) - ; - camel_pop3_engine_command_free(pop3_store->engine, fi->cmd); - fi->cmd = NULL; - } - - if (fi->flags & CAMEL_MESSAGE_DELETED) { - fi->cmd = camel_pop3_engine_command_new(pop3_store->engine, 0, NULL, NULL, "DELE %u\r\n", fi->id); - - /* also remove from cache */ - if (pop3_store->cache && fi->uid) - camel_data_cache_remove(pop3_store->cache, "cache", fi->uid, NULL); - } - } - - for (i = 0; i < pop3_folder->uids->len; i++) { - fi = pop3_folder->uids->pdata[i]; - /* wait for delete commands to finish */ - if (fi->cmd) { - while (camel_pop3_engine_iterate(pop3_store->engine, fi->cmd) > 0) - ; - camel_pop3_engine_command_free(pop3_store->engine, fi->cmd); - fi->cmd = NULL; - } - camel_operation_progress(NULL, (i+1) * 100 / pop3_folder->uids->len); - } - - camel_operation_end(NULL); - - camel_pop3_store_expunge (pop3_store, ex); -} - -static void -cmd_tocache(CamelPOP3Engine *pe, CamelPOP3Stream *stream, void *data) -{ - CamelPOP3FolderInfo *fi = data; - char buffer[2048]; - int w = 0, n; - - /* What if it fails? */ - - /* We write an '*' to the start of the stream to say its not complete yet */ - /* This should probably be part of the cache code */ - if ((n = camel_stream_write(fi->stream, "*", 1)) == -1) - goto done; - - while ((n = camel_stream_read((CamelStream *)stream, buffer, sizeof(buffer))) > 0) { - n = camel_stream_write(fi->stream, buffer, n); - if (n == -1) - break; - - w += n; - if (w > fi->size) - w = fi->size; - if (fi->size != 0) - camel_operation_progress(NULL, (w * 100) / fi->size); - } - - /* it all worked, output a '#' to say we're a-ok */ - if (n != -1) { - camel_stream_reset(fi->stream); - n = camel_stream_write(fi->stream, "#", 1); - } -done: - if (n == -1) { - fi->err = errno; - g_warning("POP3 retrieval failed: %s", strerror(errno)); - } else { - fi->err = 0; - } - - camel_object_unref((CamelObject *)fi->stream); - fi->stream = NULL; -} - -static CamelMimeMessage * -pop3_get_message (CamelFolder *folder, const char *uid, CamelException *ex) -{ - CamelMimeMessage *message = NULL; - CamelPOP3Store *pop3_store = CAMEL_POP3_STORE (folder->parent_store); - CamelPOP3Folder *pop3_folder = (CamelPOP3Folder *)folder; - CamelPOP3Command *pcr; - CamelPOP3FolderInfo *fi; - char buffer[1]; - int ok, i, last; - CamelStream *stream = NULL; - - fi = g_hash_table_lookup(pop3_folder->uids_uid, uid); - if (fi == NULL) { - camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID, - _("No message with uid %s"), uid); - return NULL; - } - - /* Sigh, most of the crap in this function is so that the cancel button - returns the proper exception code. Sigh. */ - - camel_operation_start_transient(NULL, _("Retrieving POP message %d"), fi->id); - - /* If we have an oustanding retrieve message running, wait for that to complete - & then retrieve from cache, otherwise, start a new one, and similar */ - - if (fi->cmd != NULL) { - while ((i = camel_pop3_engine_iterate(pop3_store->engine, fi->cmd)) > 0) - ; - - if (i == -1) - fi->err = errno; - - /* getting error code? */ - ok = fi->cmd->state == CAMEL_POP3_COMMAND_DATA; - camel_pop3_engine_command_free(pop3_store->engine, fi->cmd); - fi->cmd = NULL; - - if (fi->err != 0) { - if (fi->err == EINTR) - camel_exception_setv(ex, CAMEL_EXCEPTION_USER_CANCEL, _("User cancelled")); - else - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot get message %s: %s"), - uid, g_strerror (fi->err)); - goto fail; - } - } - - /* check to see if we have safely written flag set */ - if (pop3_store->cache == NULL - || (stream = camel_data_cache_get(pop3_store->cache, "cache", fi->uid, NULL)) == NULL - || camel_stream_read(stream, buffer, 1) != 1 - || buffer[0] != '#') { - - /* Initiate retrieval, if disk backing fails, use a memory backing */ - if (pop3_store->cache == NULL - || (stream = camel_data_cache_add(pop3_store->cache, "cache", fi->uid, NULL)) == NULL) - stream = camel_stream_mem_new(); - - /* ref it, the cache storage routine unref's when done */ - camel_object_ref((CamelObject *)stream); - fi->stream = stream; - fi->err = EIO; - pcr = camel_pop3_engine_command_new(pop3_store->engine, CAMEL_POP3_COMMAND_MULTI, cmd_tocache, fi, "RETR %u\r\n", fi->id); - - /* Also initiate retrieval of some of the following messages, assume we'll be receiving them */ - if (pop3_store->cache != NULL) { - /* This should keep track of the last one retrieved, also how many are still - oustanding incase of random access on large folders */ - i = fi->index+1; - last = MIN(i+10, pop3_folder->uids->len); - for (;i<last;i++) { - CamelPOP3FolderInfo *pfi = pop3_folder->uids->pdata[i]; - - if (pfi->uid && pfi->cmd == NULL) { - pfi->stream = camel_data_cache_add(pop3_store->cache, "cache", pfi->uid, NULL); - if (pfi->stream) { - pfi->err = EIO; - pfi->cmd = camel_pop3_engine_command_new(pop3_store->engine, CAMEL_POP3_COMMAND_MULTI, - cmd_tocache, pfi, "RETR %u\r\n", pfi->id); - } - } - } - } - - /* now wait for the first one to finish */ - while ((i = camel_pop3_engine_iterate(pop3_store->engine, pcr)) > 0) - ; - - if (i == -1) - fi->err = errno; - - /* getting error code? */ - ok = pcr->state == CAMEL_POP3_COMMAND_DATA; - camel_pop3_engine_command_free(pop3_store->engine, pcr); - camel_stream_reset(stream); - - /* Check to see we have safely written flag set */ - if (fi->err != 0) { - if (fi->err == EINTR) - camel_exception_setv(ex, CAMEL_EXCEPTION_USER_CANCEL, _("User cancelled")); - else - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot get message %s: %s"), - uid, g_strerror (fi->err)); - goto done; - } - - if (camel_stream_read(stream, buffer, 1) != 1 || buffer[0] != '#') { - camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID, - _("Cannot get message %s: %s"), uid, _("Unknown reason")); - goto done; - } - } - - message = camel_mime_message_new (); - if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)message, stream) == -1) { - if (errno == EINTR) - camel_exception_setv(ex, CAMEL_EXCEPTION_USER_CANCEL, _("User cancelled")); - else - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot get message %s: %s"), - uid, g_strerror (errno)); - camel_object_unref((CamelObject *)message); - message = NULL; - } -done: - camel_object_unref((CamelObject *)stream); -fail: - camel_operation_end(NULL); - - return message; -} - -static void -pop3_set_message_flags (CamelFolder *folder, const char *uid, guint32 flags, guint32 set) -{ - CamelPOP3Folder *pop3_folder = CAMEL_POP3_FOLDER (folder); - CamelPOP3FolderInfo *fi; - - fi = g_hash_table_lookup(pop3_folder->uids_uid, uid); - if (fi) - fi->flags = (fi->flags & ~flags) | (set & flags); -} - -static gint -pop3_get_message_count (CamelFolder *folder) -{ - CamelPOP3Folder *pop3_folder = CAMEL_POP3_FOLDER (folder); - - return pop3_folder->uids->len; -} - -static GPtrArray * -pop3_get_uids (CamelFolder *folder) -{ - CamelPOP3Folder *pop3_folder = CAMEL_POP3_FOLDER (folder); - GPtrArray *uids = g_ptr_array_new(); - CamelPOP3FolderInfo **fi = (CamelPOP3FolderInfo **)pop3_folder->uids->pdata; - int i; - - for (i=0;i<pop3_folder->uids->len;i++,fi++) { - if (fi[0]->uid) - g_ptr_array_add(uids, fi[0]->uid); - } - - return uids; -} diff --git a/camel/providers/pop3/camel-pop3-folder.h b/camel/providers/pop3/camel-pop3-folder.h deleted file mode 100644 index 7dab07124c..0000000000 --- a/camel/providers/pop3/camel-pop3-folder.h +++ /dev/null @@ -1,77 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-pop3-folder.h : Class for a POP3 folder */ - -/* - * Authors: - * Dan Winship <danw@ximian.com> - * Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 2002 Ximian, Inc. (www.ximian.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - */ - -#ifndef CAMEL_POP3_FOLDER_H -#define CAMEL_POP3_FOLDER_H 1 - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus }*/ - -#include "camel-folder.h" - -#define CAMEL_POP3_FOLDER_TYPE (camel_pop3_folder_get_type ()) -#define CAMEL_POP3_FOLDER(obj) (CAMEL_CHECK_CAST((obj), CAMEL_POP3_FOLDER_TYPE, CamelPOP3Folder)) -#define CAMEL_POP3_FOLDER_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_POP3_FOLDER_TYPE, CamelPOP3FolderClass)) -#define CAMEL_IS_POP3_FOLDER(o) (CAMEL_CHECK_TYPE((o), CAMEL_POP3_FOLDER_TYPE)) - -typedef struct { - guint32 id; - guint32 size; - guint32 flags; - guint32 index; /* index of request */ - char *uid; - int err; - struct _CamelPOP3Command *cmd; - struct _CamelStream *stream; -} CamelPOP3FolderInfo; - -typedef struct { - CamelFolder parent_object; - - GPtrArray *uids; - GHashTable *uids_uid; /* messageinfo by uid */ - GHashTable *uids_id; /* messageinfo by id */ -} CamelPOP3Folder; - -typedef struct { - CamelFolderClass parent_class; - - /* Virtual methods */ - -} CamelPOP3FolderClass; - -/* public methods */ -CamelFolder *camel_pop3_folder_new (CamelStore *parent, CamelException *ex); - -/* Standard Camel function */ -CamelType camel_pop3_folder_get_type (void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CAMEL_POP3_FOLDER_H */ diff --git a/camel/providers/pop3/camel-pop3-provider.c b/camel/providers/pop3/camel-pop3-provider.c deleted file mode 100644 index 1354470e69..0000000000 --- a/camel/providers/pop3/camel-pop3-provider.c +++ /dev/null @@ -1,108 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-pop3-provider.c: pop3 provider registration code */ - -/* - * Authors : - * Dan Winship <danw@ximian.com> - * Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 2000 Ximian, Inc. (www.ximian.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * 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 "camel-pop3-store.h" -#include "camel-provider.h" -#include "camel-session.h" -#include "camel-url.h" -#include "camel-sasl.h" - -CamelProviderConfEntry pop3_conf_entries[] = { - { CAMEL_PROVIDER_CONF_SECTION_START, NULL, NULL, - N_("Message storage") }, - { CAMEL_PROVIDER_CONF_CHECKBOX, "keep_on_server", NULL, - N_("Leave messages on server"), "0" }, -#ifdef NOT_FOR_1_0 - { CAMEL_PROVIDER_CONF_CHECKSPIN, "delete_after", "UNIMPLEMENTED", - N_("Delete after %s day(s)"), "0:1:7:365" }, -#endif - { CAMEL_PROVIDER_CONF_CHECKBOX, "disable_extensions", NULL, - N_("Disable support for all POP3 extensions"), "0" }, - { CAMEL_PROVIDER_CONF_SECTION_END }, - { CAMEL_PROVIDER_CONF_END } -}; - -static CamelProvider pop3_provider = { - "pop", - - N_("POP"), - - N_("For connecting to and downloading mail from POP servers."), - - "mail", - - CAMEL_PROVIDER_IS_REMOTE | CAMEL_PROVIDER_IS_SOURCE | - CAMEL_PROVIDER_SUPPORTS_SSL, - - CAMEL_URL_NEED_USER | CAMEL_URL_NEED_HOST | CAMEL_URL_ALLOW_AUTH, - - pop3_conf_entries, - - /* ... */ -}; - -CamelServiceAuthType camel_pop3_password_authtype = { - N_("Password"), - - N_("This option will connect to the POP server using a plaintext " - "password. This is the only option supported by many POP servers."), - - "", - TRUE -}; - -CamelServiceAuthType camel_pop3_apop_authtype = { - "APOP", - - N_("This option will connect to the POP server using an encrypted " - "password via the APOP protocol. This may not work for all users " - "even on servers that claim to support it."), - - "+APOP", - TRUE -}; - -void -camel_provider_module_init (CamelSession *session) -{ - CamelServiceAuthType *auth; - - pop3_provider.object_types[CAMEL_PROVIDER_STORE] = camel_pop3_store_get_type(); - pop3_provider.url_hash = camel_url_hash; - pop3_provider.url_equal = camel_url_equal; - - pop3_provider.authtypes = camel_sasl_authtype_list (FALSE); - auth = camel_sasl_authtype("LOGIN"); - if (auth) - pop3_provider.authtypes = g_list_prepend(pop3_provider.authtypes, auth); - pop3_provider.authtypes = g_list_prepend(pop3_provider.authtypes, &camel_pop3_apop_authtype); - pop3_provider.authtypes = g_list_prepend(pop3_provider.authtypes, &camel_pop3_password_authtype); - - camel_session_register_provider(session, &pop3_provider); -} diff --git a/camel/providers/pop3/camel-pop3-store.c b/camel/providers/pop3/camel-pop3-store.c deleted file mode 100644 index fbdae86833..0000000000 --- a/camel/providers/pop3/camel-pop3-store.c +++ /dev/null @@ -1,657 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-pop3-store.c : class for a pop3 store */ - -/* - * Authors: - * Dan Winship <danw@ximian.com> - * Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 2000-2002 Ximian, Inc. (www.ximian.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> - -#include "camel-operation.h" - -#include "camel-pop3-store.h" -#include "camel-pop3-folder.h" -#include "camel-stream-buffer.h" -#include "camel-session.h" -#include "camel-exception.h" -#include "camel-url.h" -#include "e-util/md5-utils.h" -#include "camel-pop3-engine.h" -#include "camel-sasl.h" -#include "camel-data-cache.h" -#include "camel-tcp-stream.h" -#include "camel-tcp-stream-raw.h" -#ifdef HAVE_SSL -#include "camel-tcp-stream-ssl.h" -#endif - -/* Specified in RFC 1939 */ -#define POP3_PORT 110 - -static CamelStoreClass *parent_class = NULL; - -static void finalize (CamelObject *object); - -static gboolean pop3_connect (CamelService *service, CamelException *ex); -static gboolean pop3_disconnect (CamelService *service, gboolean clean, CamelException *ex); -static GList *query_auth_types (CamelService *service, CamelException *ex); - -static CamelFolder *get_folder (CamelStore *store, const char *folder_name, - guint32 flags, CamelException *ex); - -static void init_trash (CamelStore *store); -static CamelFolder *get_trash (CamelStore *store, CamelException *ex); - -static void -camel_pop3_store_class_init (CamelPOP3StoreClass *camel_pop3_store_class) -{ - CamelServiceClass *camel_service_class = - CAMEL_SERVICE_CLASS (camel_pop3_store_class); - CamelStoreClass *camel_store_class = - CAMEL_STORE_CLASS (camel_pop3_store_class); - - parent_class = CAMEL_STORE_CLASS (camel_type_get_global_classfuncs (camel_store_get_type ())); - - /* virtual method overload */ - camel_service_class->query_auth_types = query_auth_types; - camel_service_class->connect = pop3_connect; - camel_service_class->disconnect = pop3_disconnect; - - camel_store_class->get_folder = get_folder; - camel_store_class->init_trash = init_trash; - camel_store_class->get_trash = get_trash; -} - - - -static void -camel_pop3_store_init (gpointer object, gpointer klass) -{ - ; -} - -CamelType -camel_pop3_store_get_type (void) -{ - static CamelType camel_pop3_store_type = CAMEL_INVALID_TYPE; - - if (!camel_pop3_store_type) { - camel_pop3_store_type = camel_type_register (CAMEL_STORE_TYPE, - "CamelPOP3Store", - sizeof (CamelPOP3Store), - sizeof (CamelPOP3StoreClass), - (CamelObjectClassInitFunc) camel_pop3_store_class_init, - NULL, - (CamelObjectInitFunc) camel_pop3_store_init, - finalize); - } - - return camel_pop3_store_type; -} - -static void -finalize (CamelObject *object) -{ - CamelPOP3Store *pop3_store = CAMEL_POP3_STORE (object); - - /* force disconnect so we dont have it run later, after we've cleaned up some stuff */ - /* SIGH */ - - camel_service_disconnect((CamelService *)pop3_store, TRUE, NULL); - - if (pop3_store->engine) - camel_object_unref((CamelObject *)pop3_store->engine); - if (pop3_store->cache) - camel_object_unref((CamelObject *)pop3_store->cache); -} - -enum { - USE_SSL_NEVER, - USE_SSL_ALWAYS, - USE_SSL_WHEN_POSSIBLE -}; - -#define SSL_PORT_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3) -#define STARTTLS_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_TLS) - -static gboolean -connect_to_server (CamelService *service, int ssl_mode, int try_starttls, CamelException *ex) -{ - CamelPOP3Store *store = CAMEL_POP3_STORE (service); - CamelStream *tcp_stream; - CamelPOP3Command *pc; - struct hostent *h; - guint32 flags = 0; - int clean_quit; - int ret, port; - - h = camel_service_gethost (service, ex); - if (!h) - return FALSE; - - port = service->url->port ? service->url->port : 110; - - if (ssl_mode != USE_SSL_NEVER) { -#ifdef HAVE_SSL - if (try_starttls) { - tcp_stream = camel_tcp_stream_ssl_new_raw (service->session, service->url->host, STARTTLS_FLAGS); - } else { - port = service->url->port ? service->url->port : 995; - tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, SSL_PORT_FLAGS); - } -#else - if (!try_starttls) - port = service->url->port ? service->url->port : 995; - - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Could not connect to %s (port %d): %s"), - service->url->host, port, - _("SSL unavailable")); - - camel_free_host (h); - - return FALSE; -#endif /* HAVE_SSL */ - } else { - tcp_stream = camel_tcp_stream_raw_new (); - } - - 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 POP server %s (port %d): %s"), - service->url->host, port, g_strerror (errno)); - - camel_object_unref (CAMEL_OBJECT (tcp_stream)); - - return FALSE; - } - - /* parent class connect initialization */ - if (CAMEL_SERVICE_CLASS (parent_class)->connect (service, ex) == FALSE) { - camel_object_unref (CAMEL_OBJECT (tcp_stream)); - return FALSE; - } - - if (camel_url_get_param (service->url, "disable_extensions")) - flags |= CAMEL_POP3_ENGINE_DISABLE_EXTENSIONS; - - store->engine = camel_pop3_engine_new (tcp_stream, flags); - -#ifdef HAVE_SSL - if (store->engine) { - if (ssl_mode == USE_SSL_WHEN_POSSIBLE) { - if (store->engine->capa & CAMEL_POP3_CAP_STLS) - goto starttls; - } else if (ssl_mode == USE_SSL_ALWAYS) { - if (try_starttls) { - if (store->engine->capa & CAMEL_POP3_CAP_STLS) { - /* attempt to toggle STARTTLS mode */ - goto starttls; - } else { - /* server doesn't support STARTTLS, abort */ - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Failed to connect to POP server %s in secure mode: %s"), - service->url->host, _("SSL/TLS extension not supported.")); - /* we have the possibility of quitting cleanly here */ - clean_quit = TRUE; - goto stls_exception; - } - } - } - } -#endif /* HAVE_SSL */ - - camel_object_unref (CAMEL_OBJECT (tcp_stream)); - - return store->engine != NULL; - -#ifdef HAVE_SSL - starttls: - /* as soon as we send a STLS command, all hope is lost of a clean QUIT if problems arise */ - clean_quit = FALSE; - - pc = camel_pop3_engine_command_new (store->engine, 0, NULL, NULL, "STLS\r\n"); - while (camel_pop3_engine_iterate (store->engine, NULL) > 0) - ; - - ret = pc->state == CAMEL_POP3_COMMAND_OK; - camel_pop3_engine_command_free (store->engine, pc); - - if (ret == FALSE) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Failed to connect to POP server %s in secure mode: %s"), - service->url->host, store->engine->line); - goto stls_exception; - } - - /* Okay, now toggle SSL/TLS mode */ - ret = camel_tcp_stream_ssl_enable_ssl (CAMEL_TCP_STREAM_SSL (tcp_stream)); - - camel_object_unref (CAMEL_OBJECT (tcp_stream)); - - if (ret == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Failed to connect to POP server %s in secure mode: %s"), - service->url->host, _("SSL negotiations failed")); - goto stls_exception; - } - - /* rfc2595, section 4 states that after a successful STLS - command, the client MUST discard prior CAPA responses */ - camel_pop3_engine_reget_capabilities (store->engine); - - return TRUE; - - stls_exception: - if (clean_quit) { - /* try to disconnect cleanly */ - pc = camel_pop3_engine_command_new (store->engine, 0, NULL, NULL, "QUIT\r\n"); - while (camel_pop3_engine_iterate (store->engine, NULL) > 0) - ; - camel_pop3_engine_command_free (store->engine, pc); - } - - camel_object_unref (CAMEL_OBJECT (store->engine)); - camel_object_unref (CAMEL_OBJECT (tcp_stream)); - store->engine = NULL; - - return FALSE; -#endif /* HAVE_SSL */ -} - -static struct { - char *value; - int mode; -} ssl_options[] = { - { "", USE_SSL_ALWAYS }, - { "always", USE_SSL_ALWAYS }, - { "when-possible", USE_SSL_WHEN_POSSIBLE }, - { "never", USE_SSL_NEVER }, - { NULL, USE_SSL_NEVER }, -}; - -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_pop3_password_authtype; -extern CamelServiceAuthType camel_pop3_apop_authtype; - -static GList * -query_auth_types (CamelService *service, CamelException *ex) -{ - CamelPOP3Store *store = CAMEL_POP3_STORE (service); - GList *types = NULL; - - types = CAMEL_SERVICE_CLASS (parent_class)->query_auth_types (service, ex); - if (camel_exception_is_set (ex)) - return NULL; - - if (connect_to_server_wrapper (service, NULL)) { - types = g_list_concat(types, g_list_copy(store->engine->auth)); - pop3_disconnect (service, TRUE, NULL); - } else { - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Could not connect to POP server %s"), - service->url->host); - } - - return types; -} - -/** - * camel_pop3_store_expunge: - * @store: the store - * @ex: a CamelException - * - * Expunge messages from the store. This will result in the connection - * being closed, which may cause later commands to fail if they can't - * reconnect. - **/ -void -camel_pop3_store_expunge (CamelPOP3Store *store, CamelException *ex) -{ - CamelPOP3Command *pc; - - pc = camel_pop3_engine_command_new(store->engine, 0, NULL, NULL, "QUIT\r\n"); - while (camel_pop3_engine_iterate(store->engine, NULL) > 0) - ; - camel_pop3_engine_command_free(store->engine, pc); - - camel_service_disconnect (CAMEL_SERVICE (store), FALSE, ex); -} - -static int -try_sasl(CamelPOP3Store *store, const char *mech, CamelException *ex) -{ - CamelPOP3Stream *stream = store->engine->stream; - unsigned char *line, *resp; - CamelSasl *sasl; - unsigned int len; - int ret; - - sasl = camel_sasl_new("pop3", mech, (CamelService *)store); - if (sasl == NULL) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_URL_INVALID, - _("Unable to connect to POP server %s: " - "No support for requested authentication mechanism."), - CAMEL_SERVICE (store)->url->host); - return -1; - } - - if (camel_stream_printf((CamelStream *)stream, "AUTH %s\r\n", mech) == -1) - goto ioerror; - - while (1) { - if (camel_pop3_stream_line(stream, &line, &len) == -1) - goto ioerror; - if (strncmp(line, "+OK", 3) == 0) - break; - if (strncmp(line, "-ERR", 4) == 0) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE, - _("SASL `%s' Login failed for POP server %s: %s"), - mech, CAMEL_SERVICE (store)->url->host, line); - goto done; - } - /* If we dont get continuation, or the sasl object's run out of work, or we dont get a challenge, - its a protocol error, so fail, and try reset the server */ - if (strncmp(line, "+ ", 2) != 0 - || camel_sasl_authenticated(sasl) - || (resp = camel_sasl_challenge_base64(sasl, line+2, ex)) == NULL) { - camel_stream_printf((CamelStream *)stream, "*\r\n"); - camel_pop3_stream_line(stream, &line, &len); - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE, - _("Cannot login to POP server %s: SASL Protocol error"), - CAMEL_SERVICE (store)->url->host); - goto done; - } - - ret = camel_stream_printf((CamelStream *)stream, "%s\r\n", resp); - g_free(resp); - if (ret == -1) - goto ioerror; - - } - camel_object_unref((CamelObject *)sasl); - return 0; - - ioerror: - if (errno == EINTR) { - camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled")); - } else { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Failed to authenticate on POP server %s: %s"), - CAMEL_SERVICE (store)->url->host, g_strerror (errno)); - } - done: - camel_object_unref((CamelObject *)sasl); - return -1; -} - -static int -pop3_try_authenticate (CamelService *service, gboolean reprompt, const char *errmsg, CamelException *ex) -{ - CamelPOP3Store *store = (CamelPOP3Store *)service; - CamelPOP3Command *pcu = NULL, *pcp = NULL; - int status; - - /* override, testing only */ - /*printf("Forcing authmech to 'login'\n"); - service->url->authmech = g_strdup("LOGIN");*/ - - if (!service->url->passwd) { - char *prompt; - - prompt = g_strdup_printf (_("%sPlease enter the POP password for %s@%s"), - errmsg ? errmsg : "", - service->url->user, - service->url->host); - service->url->passwd = camel_session_get_password (camel_service_get_session (service), - prompt, reprompt, TRUE, service, "password", ex); - g_free (prompt); - if (!service->url->passwd) - return FALSE; - } - - if (!service->url->authmech) { - /* pop engine will take care of pipelining ability */ - pcu = camel_pop3_engine_command_new(store->engine, 0, NULL, NULL, "USER %s\r\n", service->url->user); - pcp = camel_pop3_engine_command_new(store->engine, 0, NULL, NULL, "PASS %s\r\n", service->url->passwd); - } else if (strcmp(service->url->authmech, "+APOP") == 0 && store->engine->apop) { - char *secret, md5asc[33], *d; - unsigned char md5sum[16], *s; - - secret = g_alloca(strlen(store->engine->apop)+strlen(service->url->passwd)+1); - sprintf(secret, "%s%s", store->engine->apop, service->url->passwd); - md5_get_digest(secret, strlen (secret), md5sum); - - for (s = md5sum, d = md5asc; d < md5asc + 32; s++, d += 2) - sprintf (d, "%.2x", *s); - - pcp = camel_pop3_engine_command_new(store->engine, 0, NULL, NULL, "APOP %s %s\r\n", - service->url->user, md5asc); - } else { - CamelServiceAuthType *auth; - GList *l; - - l = store->engine->auth; - while (l) { - auth = l->data; - if (strcmp(auth->authproto, service->url->authmech) == 0) - return try_sasl(store, service->url->authmech, ex) == -1; - l = l->next; - } - - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_URL_INVALID, - _("Unable to connect to POP server %s: " - "No support for requested authentication mechanism."), - CAMEL_SERVICE (store)->url->host); - return FALSE; - } - - while ((status = camel_pop3_engine_iterate(store->engine, pcp)) > 0) - ; - - if (status == -1) { - if (errno == EINTR) { - camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled")); - } else { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Unable to connect to POP server %s.\n" - "Error sending password: %s"), - CAMEL_SERVICE (store)->url->host, - errno ? g_strerror (errno) : _("Unknown error")); - } - } else if (pcp->state != CAMEL_POP3_COMMAND_OK) - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE, - _("Unable to connect to POP server %s.\n" - "Error sending password: %s"), - CAMEL_SERVICE (store)->url->host, - store->engine->line ? (char *)store->engine->line : _("Unknown error")); - - camel_pop3_engine_command_free(store->engine, pcp); - - if (pcu) - camel_pop3_engine_command_free(store->engine, pcu); - - return status; -} - -static gboolean -pop3_connect (CamelService *service, CamelException *ex) -{ - CamelPOP3Store *store = (CamelPOP3Store *)service; - gboolean reprompt = FALSE; - CamelSession *session; - char *errbuf = NULL; - int status; - - session = camel_service_get_session (service); - - if (store->cache == NULL) { - char *root; - - root = camel_session_get_storage_path (session, service, ex); - if (root) { - store->cache = camel_data_cache_new(root, 0, ex); - g_free(root); - if (store->cache) { - /* Default cache expiry - 1 week or not visited in a day */ - camel_data_cache_set_expire_age(store->cache, 60*60*24*7); - camel_data_cache_set_expire_access(store->cache, 60*60*24); - } - } - } - - if (!connect_to_server_wrapper (service, ex)) - return FALSE; - - do { - camel_exception_clear (ex); - status = pop3_try_authenticate (service, reprompt, errbuf, ex); - g_free (errbuf); - errbuf = NULL; - - /* we only re-prompt if we failed to authenticate, any other error and we just abort */ - if (camel_exception_get_id (ex) == CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE) { - errbuf = g_strdup_printf ("%s\n\n", camel_exception_get_description (ex)); - g_free (service->url->passwd); - service->url->passwd = NULL; - reprompt = TRUE; - } - } while (status != -1 && ex->id == CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE); - - g_free (errbuf); - - if (status == -1 || camel_exception_is_set(ex)) { - camel_service_disconnect(service, TRUE, ex); - return FALSE; - } - - /* Now that we are in the TRANSACTION state, try regetting the capabilities */ - store->engine->state = CAMEL_POP3_ENGINE_TRANSACTION; - camel_pop3_engine_reget_capabilities (store->engine); - - return TRUE; -} - -static gboolean -pop3_disconnect (CamelService *service, gboolean clean, CamelException *ex) -{ - CamelPOP3Store *store = CAMEL_POP3_STORE (service); - - if (clean) { - CamelPOP3Command *pc; - - pc = camel_pop3_engine_command_new(store->engine, 0, NULL, NULL, "QUIT\r\n"); - while (camel_pop3_engine_iterate(store->engine, NULL) > 0) - ; - camel_pop3_engine_command_free(store->engine, pc); - } - - if (!CAMEL_SERVICE_CLASS (parent_class)->disconnect (service, clean, ex)) - return FALSE; - - camel_object_unref((CamelObject *)store->engine); - store->engine = NULL; - - return TRUE; -} - -static CamelFolder * -get_folder (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex) -{ - if (strcasecmp (folder_name, "inbox") != 0) { - camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID, - _("No such folder `%s'."), folder_name); - return NULL; - } - return camel_pop3_folder_new (store, ex); -} - -static void -init_trash (CamelStore *store) -{ - /* no-op */ - ; -} - -static CamelFolder * -get_trash (CamelStore *store, CamelException *ex) -{ - /* no-op */ - return NULL; -} diff --git a/camel/providers/pop3/camel-pop3-store.h b/camel/providers/pop3/camel-pop3-store.h deleted file mode 100644 index 3b9b1f7ae1..0000000000 --- a/camel/providers/pop3/camel-pop3-store.h +++ /dev/null @@ -1,79 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-pop3-store.h : class for an pop3 store */ - -/* - * Authors: - * Dan Winship <danw@ximian.com> - * Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 2000-2002 Ximian, Inc. (www.ximian.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - */ - - -#ifndef CAMEL_POP3_STORE_H -#define CAMEL_POP3_STORE_H 1 - - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus }*/ - -#include <camel/camel-types.h> -#include <camel/camel-store.h> -#include "camel-pop3-engine.h" - -#define CAMEL_POP3_STORE_TYPE (camel_pop3_store_get_type ()) -#define CAMEL_POP3_STORE(obj) (CAMEL_CHECK_CAST((obj), CAMEL_POP3_STORE_TYPE, CamelPOP3Store)) -#define CAMEL_POP3_STORE_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_POP3_STORE_TYPE, CamelPOP3StoreClass)) -#define CAMEL_IS_POP3_STORE(o) (CAMEL_CHECK_TYPE((o), CAMEL_POP3_STORE_TYPE)) - - -typedef struct { - CamelStore parent_object; - - CamelPOP3Engine *engine; /* pop processing engine */ - - struct _CamelDataCache *cache; -} CamelPOP3Store; - - - -typedef struct { - CamelStoreClass parent_class; - -} CamelPOP3StoreClass; - - -/* public methods */ -void camel_pop3_store_expunge (CamelPOP3Store *store, CamelException *ex); - -/* support functions */ -enum { CAMEL_POP3_OK, CAMEL_POP3_ERR, CAMEL_POP3_FAIL }; -int camel_pop3_command (CamelPOP3Store *store, char **ret, CamelException *ex, char *fmt, ...); -char *camel_pop3_command_get_additional_data (CamelPOP3Store *store, int total, CamelException *ex); - -/* Standard Camel function */ -CamelType camel_pop3_store_get_type (void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CAMEL_POP3_STORE_H */ - - diff --git a/camel/providers/pop3/camel-pop3-stream.c b/camel/providers/pop3/camel-pop3-stream.c deleted file mode 100644 index cb27bece26..0000000000 --- a/camel/providers/pop3/camel-pop3-stream.c +++ /dev/null @@ -1,471 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*- - * - * Author: - * Michael Zucchi <notzed@ximian.com> - * - * Copyright 2002 Ximian, Inc. (www.ximian.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - */ - -/* This is *identical* to the camel-nntp-stream, so should probably - work out a way to merge them */ - - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> - -#include <string.h> -#include <stdio.h> - -#include <glib.h> - -#include "camel-pop3-stream.h" - -extern int camel_verbose_debug; -#define dd(x) (camel_verbose_debug?(x):0) - -static CamelObjectClass *parent_class = NULL; - -/* Returns the class for a CamelStream */ -#define CS_CLASS(so) CAMEL_POP3_STREAM_CLASS(CAMEL_OBJECT_GET_CLASS(so)) - -#define CAMEL_POP3_STREAM_SIZE (4096) -#define CAMEL_POP3_STREAM_LINE (1024) /* maximum line size */ - -static int -stream_fill(CamelPOP3Stream *is) -{ - int left = 0; - - if (is->source) { - left = is->end - is->ptr; - memcpy(is->buf, is->ptr, left); - is->end = is->buf + left; - is->ptr = is->buf; - left = camel_stream_read(is->source, is->end, CAMEL_POP3_STREAM_SIZE - (is->end - is->buf)); - if (left > 0) { - is->end += left; - is->end[0] = '\n'; - return is->end - is->ptr; - } else { - dd(printf("POP3_STREAM_FILL(ERROR): '%s'\n", strerror (errno))); - return -1; - } - } - - return 0; -} - -static ssize_t -stream_read(CamelStream *stream, char *buffer, size_t n) -{ - CamelPOP3Stream *is = (CamelPOP3Stream *)stream; - char *o, *oe; - unsigned char *p, *e, c; - int state; - - if (is->mode != CAMEL_POP3_STREAM_DATA || n == 0) - return 0; - - o = buffer; - oe = buffer + n; - state = is->state; - - /* Need to copy/strip '.'s and whatnot */ - p = is->ptr; - e = is->end; - - switch(state) { - state_0: - case 0: /* start of line, always read at least 3 chars */ - while (e - p < 3) { - is->ptr = p; - if (stream_fill(is) == -1) - return -1; - p = is->ptr; - e = is->end; - } - if (p[0] == '.') { - if (p[1] == '\r' && p[2] == '\n') { - is->ptr = p+3; - is->mode = CAMEL_POP3_STREAM_EOD; - is->state = 0; - dd(printf("POP3_STREAM_READ(%d):\n%.*s\n", o-buffer, o-buffer, buffer)); - return o-buffer; - } - p++; - } - state = 1; - /* FALLS THROUGH */ - case 1: /* looking for next sol */ - while (o < oe) { - c = *p++; - if (c == '\n') { - /* end of input sentinal check */ - if (p > e) { - is->ptr = e; - if (stream_fill(is) == -1) - return -1; - p = is->ptr; - e = is->end; - } else { - *o++ = '\n'; - state = 0; - goto state_0; - } - } else if (c != '\r') { - *o++ = c; - } - } - break; - } - - is->ptr = p; - is->state = state; - - dd(printf("POP3_STREAM_READ(%d):\n%.*s\n", o-buffer, o-buffer, buffer)); - - return o-buffer; -} - -static ssize_t -stream_write(CamelStream *stream, const char *buffer, size_t n) -{ - CamelPOP3Stream *is = (CamelPOP3Stream *)stream; - - if (strncmp (buffer, "PASS ", 5) != 0) - dd(printf("POP3_STREAM_WRITE(%d):\n%.*s\n", n, (int)n, buffer)); - else - dd(printf("POP3_STREAM_WRITE(%d):\nPASS xxxxxxxx\n", n)); - - return camel_stream_write(is->source, buffer, n); -} - -static int -stream_close(CamelStream *stream) -{ - /* nop? */ - return 0; -} - -static int -stream_flush(CamelStream *stream) -{ - /* nop? */ - return 0; -} - -static gboolean -stream_eos(CamelStream *stream) -{ - CamelPOP3Stream *is = (CamelPOP3Stream *)stream; - - return is->mode != CAMEL_POP3_STREAM_DATA; -} - -static int -stream_reset(CamelStream *stream) -{ - /* nop? reset literal mode? */ - return 0; -} - -static void -camel_pop3_stream_class_init (CamelStreamClass *camel_pop3_stream_class) -{ - CamelStreamClass *camel_stream_class = (CamelStreamClass *)camel_pop3_stream_class; - - parent_class = camel_type_get_global_classfuncs( CAMEL_OBJECT_TYPE ); - - /* virtual method definition */ - camel_stream_class->read = stream_read; - camel_stream_class->write = stream_write; - camel_stream_class->close = stream_close; - camel_stream_class->flush = stream_flush; - camel_stream_class->eos = stream_eos; - camel_stream_class->reset = stream_reset; -} - -static void -camel_pop3_stream_init(CamelPOP3Stream *is, CamelPOP3StreamClass *isclass) -{ - /* +1 is room for appending a 0 if we need to for a line */ - is->ptr = is->end = is->buf = g_malloc(CAMEL_POP3_STREAM_SIZE+1); - is->lineptr = is->linebuf = g_malloc(CAMEL_POP3_STREAM_LINE+1); - is->lineend = is->linebuf + CAMEL_POP3_STREAM_LINE; - - /* init sentinal */ - is->ptr[0] = '\n'; - - is->state = 0; - is->mode = CAMEL_POP3_STREAM_LINE; -} - -static void -camel_pop3_stream_finalise(CamelPOP3Stream *is) -{ - g_free(is->buf); - g_free(is->linebuf); - if (is->source) - camel_object_unref((CamelObject *)is->source); -} - -CamelType -camel_pop3_stream_get_type (void) -{ - static CamelType camel_pop3_stream_type = CAMEL_INVALID_TYPE; - - if (camel_pop3_stream_type == CAMEL_INVALID_TYPE) { - camel_pop3_stream_type = camel_type_register( camel_stream_get_type(), - "CamelPOP3Stream", - sizeof( CamelPOP3Stream ), - sizeof( CamelPOP3StreamClass ), - (CamelObjectClassInitFunc) camel_pop3_stream_class_init, - NULL, - (CamelObjectInitFunc) camel_pop3_stream_init, - (CamelObjectFinalizeFunc) camel_pop3_stream_finalise ); - } - - return camel_pop3_stream_type; -} - -/** - * camel_pop3_stream_new: - * - * Returns a NULL stream. A null stream is always at eof, and - * always returns success for all reads and writes. - * - * Return value: the stream - **/ -CamelStream * -camel_pop3_stream_new(CamelStream *source) -{ - CamelPOP3Stream *is; - - is = (CamelPOP3Stream *)camel_object_new(camel_pop3_stream_get_type ()); - camel_object_ref((CamelObject *)source); - is->source = source; - - return (CamelStream *)is; -} - -/* Get one line from the pop3 stream */ -int -camel_pop3_stream_line(CamelPOP3Stream *is, unsigned char **data, unsigned int *len) -{ - register unsigned char c, *p, *o, *oe; - int newlen, oldlen; - unsigned char *e; - - if (is->mode == CAMEL_POP3_STREAM_EOD) { - *data = is->linebuf; - *len = 0; - return 0; - } - - o = is->linebuf; - oe = is->lineend - 1; - p = is->ptr; - e = is->end; - - /* Data mode, convert leading '..' to '.', and stop when we reach a solitary '.' */ - if (is->mode == CAMEL_POP3_STREAM_DATA) { - /* need at least 3 chars in buffer */ - while (e-p < 3) { - is->ptr = p; - if (stream_fill(is) == -1) - return -1; - p = is->ptr; - e = is->end; - } - - /* check for isolated '.\r\n' or begging of line '.' */ - if (p[0] == '.') { - if (p[1] == '\r' && p[2] == '\n') { - is->ptr = p+3; - is->mode = CAMEL_POP3_STREAM_EOD; - *data = is->linebuf; - *len = 0; - is->linebuf[0] = 0; - - dd(printf("POP3_STREAM_LINE(END)\n")); - - return 0; - } - p++; - } - } - - while (1) { - while (o < oe) { - c = *p++; - if (c == '\n') { - /* sentinal? */ - if (p> e) { - is->ptr = e; - if (stream_fill(is) == -1) - return -1; - p = is->ptr; - e = is->end; - } else { - is->ptr = p; - *data = is->linebuf; - *len = o - is->linebuf; - *o = 0; - - dd(printf("POP3_STREAM_LINE(%d): '%s'\n", *len, *data)); - - return 1; - } - } else if (c != '\r') { - *o++ = c; - } - } - - /* limit this for bad server data? */ - oldlen = o - is->linebuf; - newlen = (is->lineend - is->linebuf) * 3 / 2; - is->lineptr = is->linebuf = g_realloc(is->linebuf, newlen); - is->lineend = is->linebuf + newlen; - oe = is->lineend - 1; - o = is->linebuf + oldlen; - } - - return -1; -} - -/* returns -1 on error, 0 if last lot of data, >0 if more remaining */ -int camel_pop3_stream_gets(CamelPOP3Stream *is, unsigned char **start, unsigned int *len) -{ - int max; - unsigned char *end; - - *len = 0; - - max = is->end - is->ptr; - if (max == 0) { - max = stream_fill(is); - if (max <= 0) - return max; - } - - *start = is->ptr; - end = memchr(is->ptr, '\n', max); - if (end) - max = (end - is->ptr) + 1; - *start = is->ptr; - *len = max; - is->ptr += max; - - dd(printf("POP3_STREAM_GETS(%s,%d): '%.*s'\n", end==NULL?"more":"last", *len, (int)*len, *start)); - - return end == NULL?1:0; -} - -void camel_pop3_stream_set_mode(CamelPOP3Stream *is, camel_pop3_stream_mode_t mode) -{ - is->mode = mode; -} - -/* returns -1 on erorr, 0 if last data, >0 if more data left */ -int camel_pop3_stream_getd(CamelPOP3Stream *is, unsigned char **start, unsigned int *len) -{ - unsigned char *p, *e, *s; - int state; - - *len = 0; - - if (is->mode == CAMEL_POP3_STREAM_EOD) - return 0; - - if (is->mode == CAMEL_POP3_STREAM_LINE) { - g_warning("pop3_stream reading data in line mode\n"); - return 0; - } - - state = is->state; - p = is->ptr; - e = is->end; - - while (e - p < 3) { - is->ptr = p; - if (stream_fill(is) == -1) - return -1; - p = is->ptr; - e = is->end; - } - - s = p; - - do { - switch(state) { - case 0: - /* check leading '.', ... */ - if (p[0] == '.') { - if (p[1] == '\r' && p[2] == '\n') { - is->ptr = p+3; - *len = p-s; - *start = s; - is->mode = CAMEL_POP3_STREAM_EOD; - is->state = 0; - - dd(printf("POP3_STREAM_GETD(%s,%d): '%.*s'\n", "last", *len, (int)*len, *start)); - - return 0; - } - - /* If at start, just skip '.', else return data upto '.' but skip it */ - if (p == s) { - s++; - p++; - } else { - is->ptr = p+1; - *len = p-s; - *start = s; - is->state = 1; - - dd(printf("POP3_STREAM_GETD(%s,%d): '%.*s'\n", "more", *len, (int)*len, *start)); - - return 1; - } - } - state = 1; - case 1: - /* Scan for sentinal */ - while ((*p++)!='\n') - ; - - if (p > e) { - p = e; - } else { - state = 0; - } - break; - } - } while ((e-p) >= 3); - - is->state = state; - is->ptr = p; - *len = p-s; - *start = s; - - dd(printf("POP3_STREAM_GETD(%s,%d): '%.*s'\n", "more", *len, (int)*len, *start)); - - return 1; -} diff --git a/camel/providers/pop3/camel-pop3-stream.h b/camel/providers/pop3/camel-pop3-stream.h deleted file mode 100644 index 2a4ebc01f2..0000000000 --- a/camel/providers/pop3/camel-pop3-stream.h +++ /dev/null @@ -1,69 +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. - */ - -/* This is *identical* to the camel-nntp-stream, so should probably - work out a way to merge them */ - -#ifndef _CAMEL_POP3_STREAM_H -#define _CAMEL_POP3_STREAM_H - -#include <camel/camel-stream.h> - -#define CAMEL_POP3_STREAM(obj) CAMEL_CHECK_CAST (obj, camel_pop3_stream_get_type (), CamelPOP3Stream) -#define CAMEL_POP3_STREAM_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_pop3_stream_get_type (), CamelPOP3StreamClass) -#define CAMEL_IS_POP3_STREAM(obj) CAMEL_CHECK_TYPE (obj, camel_pop3_stream_get_type ()) - -typedef struct _CamelPOP3StreamClass CamelPOP3StreamClass; -typedef struct _CamelPOP3Stream CamelPOP3Stream; - -typedef enum { - CAMEL_POP3_STREAM_LINE, - CAMEL_POP3_STREAM_DATA, - CAMEL_POP3_STREAM_EOD, /* end of data, acts as if end of stream */ -} camel_pop3_stream_mode_t; - -struct _CamelPOP3Stream { - CamelStream parent; - - CamelStream *source; - - camel_pop3_stream_mode_t mode; - int state; - - unsigned char *buf, *ptr, *end; - unsigned char *linebuf, *lineptr, *lineend; -}; - -struct _CamelPOP3StreamClass { - CamelStreamClass parent_class; -}; - -CamelType camel_pop3_stream_get_type (void); - -CamelStream *camel_pop3_stream_new (CamelStream *source); - - -void camel_pop3_stream_set_mode (CamelPOP3Stream *is, camel_pop3_stream_mode_t mode); - -int camel_pop3_stream_line (CamelPOP3Stream *is, unsigned char **data, unsigned int *len); -int camel_pop3_stream_gets (CamelPOP3Stream *is, unsigned char **start, unsigned int *len); -int camel_pop3_stream_getd (CamelPOP3Stream *is, unsigned char **start, unsigned int *len); - -#endif /* ! _CAMEL_POP3_STREAM_H */ diff --git a/camel/providers/pop3/libcamelpop3.urls b/camel/providers/pop3/libcamelpop3.urls deleted file mode 100644 index 7fffa4d861..0000000000 --- a/camel/providers/pop3/libcamelpop3.urls +++ /dev/null @@ -1 +0,0 @@ -pop diff --git a/camel/providers/sendmail/.cvsignore b/camel/providers/sendmail/.cvsignore deleted file mode 100644 index 097fdedafb..0000000000 --- a/camel/providers/sendmail/.cvsignore +++ /dev/null @@ -1,11 +0,0 @@ -Makefile -Makefile.in -.deps -.libs -*.lo -*.la -*.o -*.bb -*.bbg -*.da -*.gcov diff --git a/camel/providers/sendmail/Makefile.am b/camel/providers/sendmail/Makefile.am deleted file mode 100644 index 8c75af2de8..0000000000 --- a/camel/providers/sendmail/Makefile.am +++ /dev/null @@ -1,28 +0,0 @@ -## Process this file with automake to produce Makefile.in - -libcamelsendmailincludedir = $(privincludedir)/camel - -camel_provider_LTLIBRARIES = libcamelsendmail.la -camel_provider_DATA = libcamelsendmail.urls - -INCLUDES = \ - -I.. \ - -I$(srcdir)/.. \ - -I$(srcdir)/../../.. \ - -I$(top_srcdir)/intl \ - -I$(top_srcdir)/camel \ - $(CAMEL_CFLAGS) \ - $(GNOME_INCLUDEDIR) \ - $(GTK_INCLUDEDIR) \ - -DG_LOG_DOMAIN=\"camel-sendmail-provider\" - -libcamelsendmail_la_SOURCES = \ - camel-sendmail-provider.c \ - camel-sendmail-transport.c - -libcamelsendmailinclude_HEADERS = \ - camel-sendmail-transport.h - -libcamelsendmail_la_LDFLAGS = -avoid-version -module - -EXTRA_DIST = libcamelsendmail.urls diff --git a/camel/providers/sendmail/camel-sendmail-provider.c b/camel/providers/sendmail/camel-sendmail-provider.c deleted file mode 100644 index 9615dff1b4..0000000000 --- a/camel/providers/sendmail/camel-sendmail-provider.c +++ /dev/null @@ -1,63 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-sendmail-provider.c: sendmail provider registration code */ - -/* - * Authors : - * Dan Winship <danw@ximian.com> - * - * Copyright (C) 2000 Ximian, Inc. (www.ximian.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * 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 "camel-provider.h" -#include "camel-sendmail-transport.h" -#include "camel-session.h" -#include "camel-url.h" - -static CamelProvider sendmail_provider = { - "sendmail", - N_("Sendmail"), - - N_("For delivering mail by passing it to the \"sendmail\" program " - "on the local system."), - - "mail", - - 0, /* flags */ - - 0, /* url_flags */ - - /* ... */ -}; - -void -camel_provider_module_init (CamelSession *session) -{ - sendmail_provider.object_types[CAMEL_PROVIDER_TRANSPORT] = - camel_sendmail_transport_get_type(); - - sendmail_provider.url_hash = camel_url_hash; - sendmail_provider.url_equal = camel_url_equal; - - camel_session_register_provider (session, &sendmail_provider); -} - - - diff --git a/camel/providers/sendmail/camel-sendmail-transport.c b/camel/providers/sendmail/camel-sendmail-transport.c deleted file mode 100644 index fbf6f08a6b..0000000000 --- a/camel/providers/sendmail/camel-sendmail-transport.c +++ /dev/null @@ -1,262 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-sendmail-transport.c: Sendmail-based transport class. */ - -/* - * - * 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 - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> -#include <fcntl.h> -#include <signal.h> -#include <sys/wait.h> -#include <unistd.h> -#include <string.h> - -#include "camel-sendmail-transport.h" -#include "camel-mime-filter-crlf.h" -#include "camel-stream-filter.h" -#include "camel-mime-message.h" -#include "camel-data-wrapper.h" -#include "camel-stream-fs.h" -#include "camel-exception.h" - -static char *get_name (CamelService *service, gboolean brief); - -static gboolean sendmail_send_to (CamelTransport *transport, - CamelMimeMessage *message, - CamelAddress *from, CamelAddress *recipients, - CamelException *ex); - - -static void -camel_sendmail_transport_class_init (CamelSendmailTransportClass *camel_sendmail_transport_class) -{ - CamelTransportClass *camel_transport_class = - CAMEL_TRANSPORT_CLASS (camel_sendmail_transport_class); - CamelServiceClass *camel_service_class = - CAMEL_SERVICE_CLASS (camel_sendmail_transport_class); - - /* virtual method overload */ - camel_service_class->get_name = get_name; - camel_transport_class->send_to = sendmail_send_to; -} - -CamelType -camel_sendmail_transport_get_type (void) -{ - static CamelType camel_sendmail_transport_type = CAMEL_INVALID_TYPE; - - if (camel_sendmail_transport_type == CAMEL_INVALID_TYPE) { - camel_sendmail_transport_type = - camel_type_register (CAMEL_TRANSPORT_TYPE, "CamelSendmailTransport", - sizeof (CamelSendmailTransport), - sizeof (CamelSendmailTransportClass), - (CamelObjectClassInitFunc) camel_sendmail_transport_class_init, - NULL, - (CamelObjectInitFunc) NULL, - NULL); - } - - return camel_sendmail_transport_type; -} - - -static gboolean -sendmail_send_to (CamelTransport *transport, CamelMimeMessage *message, - CamelAddress *from, CamelAddress *recipients, - CamelException *ex) -{ - struct _camel_header_raw *header, *savedbcc, *n, *tail; - const char *from_addr, *addr, **argv; - int i, len, fd[2], nullfd, wstat; - CamelStreamFilter *filter; - CamelMimeFilter *crlf; - sigset_t mask, omask; - CamelStream *out; - pid_t pid; - - if (!camel_internet_address_get (CAMEL_INTERNET_ADDRESS (from), 0, NULL, &from_addr)) - return FALSE; - - len = camel_address_length (recipients); - argv = g_malloc ((len + 6) * sizeof (char *)); - argv[0] = "sendmail"; - argv[1] = "-i"; - argv[2] = "-f"; - argv[3] = from_addr; - argv[4] = "--"; - - for (i = 0; i < len; i++) { - if (!camel_internet_address_get (CAMEL_INTERNET_ADDRESS (recipients), i, NULL, &addr)) { - camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not parse recipient list")); - g_free (argv); - return FALSE; - } - - argv[i + 5] = addr; - } - - argv[i + 5] = NULL; - - /* unlink the bcc headers */ - savedbcc = NULL; - tail = (struct _camel_header_raw *) &savedbcc; - - header = (struct _camel_header_raw *) &CAMEL_MIME_PART (message)->headers; - n = header->next; - while (n != NULL) { - if (!strcasecmp (n->name, "Bcc")) { - header->next = n->next; - tail->next = n; - n->next = NULL; - tail = n; - } else { - header = n; - } - - n = header->next; - } - - if (pipe (fd) == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not create pipe to sendmail: " - "%s: mail not sent"), - g_strerror (errno)); - - /* restore the bcc headers */ - header->next = savedbcc; - - return FALSE; - } - - /* Block SIGCHLD so the calling application doesn't notice - * sendmail exiting before we do. - */ - sigemptyset (&mask); - sigaddset (&mask, SIGCHLD); - sigprocmask (SIG_BLOCK, &mask, &omask); - - pid = fork (); - switch (pid) { - case -1: - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not fork sendmail: " - "%s: mail not sent"), - g_strerror (errno)); - sigprocmask (SIG_SETMASK, &omask, NULL); - g_free (argv); - - /* restore the bcc headers */ - header->next = savedbcc; - - return FALSE; - case 0: - /* Child process */ - nullfd = open ("/dev/null", O_RDWR); - dup2 (fd[0], STDIN_FILENO); - /*dup2 (nullfd, STDOUT_FILENO); - dup2 (nullfd, STDERR_FILENO);*/ - close (nullfd); - close (fd[1]); - - execv (SENDMAIL_PATH, (char **)argv); - _exit (255); - } - g_free (argv); - - /* Parent process. Write the message out. */ - close (fd[0]); - out = camel_stream_fs_new_with_fd (fd[1]); - - /* workaround for lame sendmail implementations that can't handle CRLF eoln sequences */ - filter = camel_stream_filter_new_with_stream (out); - crlf = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_DECODE, CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY); - camel_stream_filter_add (filter, crlf); - camel_object_unref (crlf); - camel_object_unref (out); - - out = (CamelStream *) filter; - if (camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), out) == -1 - || camel_stream_close (out) == -1) { - camel_object_unref (CAMEL_OBJECT (out)); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not send message: %s"), - g_strerror (errno)); - - /* Wait for sendmail to exit. */ - while (waitpid (pid, &wstat, 0) == -1 && errno == EINTR) - ; - - sigprocmask (SIG_SETMASK, &omask, NULL); - - /* restore the bcc headers */ - header->next = savedbcc; - - return FALSE; - } - - camel_object_unref (CAMEL_OBJECT (out)); - - /* Wait for sendmail to exit. */ - while (waitpid (pid, &wstat, 0) == -1 && errno == EINTR) - ; - - sigprocmask (SIG_SETMASK, &omask, NULL); - - /* restore the bcc headers */ - header->next = savedbcc; - - if (!WIFEXITED (wstat)) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("sendmail exited with signal %s: " - "mail not sent."), - g_strsignal (WTERMSIG (wstat))); - return FALSE; - } else if (WEXITSTATUS (wstat) != 0) { - if (WEXITSTATUS (wstat) == 255) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not execute %s: " - "mail not sent."), - SENDMAIL_PATH); - } else { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("sendmail exited with status " - "%d: mail not sent."), - WEXITSTATUS (wstat)); - } - return FALSE; - } - - return TRUE; -} - -static char * -get_name (CamelService *service, gboolean brief) -{ - if (brief) - return g_strdup (_("sendmail")); - else - return g_strdup (_("Mail delivery via the sendmail program")); -} diff --git a/camel/providers/sendmail/camel-sendmail-transport.h b/camel/providers/sendmail/camel-sendmail-transport.h deleted file mode 100644 index 056be03bc8..0000000000 --- a/camel/providers/sendmail/camel-sendmail-transport.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-sendmail-transport.h: Sendmail-based transport class */ - -/* - * - * 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 - */ - - -#ifndef CAMEL_SENDMAIL_TRANSPORT_H -#define CAMEL_SENDMAIL_TRANSPORT_H 1 - - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus }*/ - -#include "camel-transport.h" - -#define CAMEL_SENDMAIL_TRANSPORT_TYPE (camel_sendmail_transport_get_type ()) -#define CAMEL_SENDMAIL_TRANSPORT(obj) (CAMEL_CHECK_CAST((obj), CAMEL_SENDMAIL_TRANSPORT_TYPE, CamelSendmailTransport)) -#define CAMEL_SENDMAIL_TRANSPORT_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_SENDMAIL_TRANSPORT_TYPE, CamelSendmailTransportClass)) -#define CAMEL_IS_SENDMAIL_TRANSPORT(o) (CAMEL_CHECK_TYPE((o), CAMEL_SENDMAIL_TRANSPORT_TYPE)) - - -typedef struct { - CamelTransport parent_object; - -} CamelSendmailTransport; - - -typedef struct { - CamelTransportClass parent_class; - -} CamelSendmailTransportClass; - - -/* Standard Camel function */ -CamelType camel_sendmail_transport_get_type (void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CAMEL_SENDMAIL_TRANSPORT_H */ diff --git a/camel/providers/sendmail/libcamelsendmail.urls b/camel/providers/sendmail/libcamelsendmail.urls deleted file mode 100644 index ccad52828e..0000000000 --- a/camel/providers/sendmail/libcamelsendmail.urls +++ /dev/null @@ -1 +0,0 @@ -sendmail diff --git a/camel/providers/smtp/.cvsignore b/camel/providers/smtp/.cvsignore deleted file mode 100644 index b948585108..0000000000 --- a/camel/providers/smtp/.cvsignore +++ /dev/null @@ -1,10 +0,0 @@ -.deps -.libs -Makefile -Makefile.in -*.lo -*.la -*.bb -*.bbg -*.da -*.gcov diff --git a/camel/providers/smtp/Makefile.am b/camel/providers/smtp/Makefile.am deleted file mode 100644 index b6bba766d6..0000000000 --- a/camel/providers/smtp/Makefile.am +++ /dev/null @@ -1,35 +0,0 @@ -## Process this file with automake to produce Makefile.in - -libcamelsmtpincludedir = $(privincludedir)/camel - -camel_provider_LTLIBRARIES = libcamelsmtp.la -camel_provider_DATA = libcamelsmtp.urls - -INCLUDES = \ - -I.. \ - -I$(srcdir)/.. \ - -I$(srcdir)/../../.. \ - -I$(top_srcdir)/intl \ - -I$(top_srcdir)/camel \ - -I$(top_srcdir)/e-util \ - $(CAMEL_CFLAGS) \ - $(GNOME_INCLUDEDIR) \ - $(GTK_INCLUDEDIR) \ - $(NSPR_CFLAGS) \ - $(NSS_CFLAGS) \ - $(OPENSSL_CFLAGS) \ - -DG_LOG_DOMAIN=\"camel-smtp-provider\" - -libcamelsmtp_la_SOURCES = \ - camel-smtp-provider.c \ - camel-smtp-transport.c - -libcamelsmtpinclude_HEADERS = \ - camel-smtp-transport.h - - -libcamelsmtp_la_LDFLAGS = -avoid-version -module - -libcamelsmtp_la_LIBADD = $(top_builddir)/e-util/libeutil.la - -EXTRA_DIST = libcamelsmtp.urls diff --git a/camel/providers/smtp/camel-smtp-provider.c b/camel/providers/smtp/camel-smtp-provider.c deleted file mode 100644 index 07991eb695..0000000000 --- a/camel/providers/smtp/camel-smtp-provider.c +++ /dev/null @@ -1,65 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-smtp-provider.c: smtp provider registration code */ -/* - * Authors: Jeffrey Stedfast <fejj@ximian.com> - * - * Copyright 2002 Ximian, Inc. (www.ximian.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. - * - */ - - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "camel-smtp-transport.h" -#include "camel-provider.h" -#include "camel-session.h" -#include "camel-url.h" -#include "camel-sasl.h" - -static CamelProvider smtp_provider = { - "smtp", - N_("SMTP"), - - N_("For delivering mail by connecting to a remote mailhub " - "using SMTP.\n"), - - "mail", - - CAMEL_PROVIDER_IS_REMOTE | CAMEL_PROVIDER_SUPPORTS_SSL, - - CAMEL_URL_NEED_HOST | CAMEL_URL_ALLOW_AUTH | CAMEL_URL_ALLOW_USER, - - /* ... */ -}; - -void -camel_provider_module_init (CamelSession *session) -{ - smtp_provider.object_types[CAMEL_PROVIDER_TRANSPORT] = - camel_smtp_transport_get_type (); - smtp_provider.authtypes = g_list_append (camel_sasl_authtype_list (TRUE), camel_sasl_authtype ("LOGIN")); - smtp_provider.authtypes = g_list_append (smtp_provider.authtypes, camel_sasl_authtype ("POPB4SMTP")); - smtp_provider.url_hash = camel_url_hash; - smtp_provider.url_equal = camel_url_equal; - - camel_session_register_provider (session, &smtp_provider); -} - - - diff --git a/camel/providers/smtp/camel-smtp-transport.c b/camel/providers/smtp/camel-smtp-transport.c deleted file mode 100644 index 5bf5add2ee..0000000000 --- a/camel/providers/smtp/camel-smtp-transport.c +++ /dev/null @@ -1,1455 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-smtp-transport.c : class for a smtp transport */ - -/* - * Authors: Jeffrey Stedfast <fejj@ximian.com> - * - * Copyright (C) 2000 Ximian, Inc. (www.ximian.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * 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/param.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <unistd.h> -#undef MIN -#undef MAX -#include "camel-mime-filter-crlf.h" -#include "camel-stream-filter.h" -#include "camel-smtp-transport.h" -#include "camel-mime-message.h" -#include "camel-multipart.h" -#include "camel-mime-part.h" -#include "camel-operation.h" -#include "camel-stream-buffer.h" -#include "camel-tcp-stream.h" -#include "camel-tcp-stream-raw.h" -#ifdef HAVE_SSL -#include "camel-tcp-stream-ssl.h" -#endif -#include "camel-session.h" -#include "camel-exception.h" -#include "camel-sasl.h" - - -extern int camel_verbose_debug; -#define d(x) (camel_verbose_debug ? (x) : 0) - -/* Specified in RFC 821 */ -#define SMTP_PORT 25 - -/* camel smtp transport class prototypes */ -static gboolean smtp_send_to (CamelTransport *transport, CamelMimeMessage *message, - CamelAddress *from, CamelAddress *recipients, CamelException *ex); - -/* support prototypes */ -static void smtp_construct (CamelService *service, CamelSession *session, - CamelProvider *provider, CamelURL *url, - CamelException *ex); -static gboolean smtp_connect (CamelService *service, CamelException *ex); -static gboolean smtp_disconnect (CamelService *service, gboolean clean, CamelException *ex); -static GHashTable *esmtp_get_authtypes (const unsigned char *buffer); -static GList *query_auth_types (CamelService *service, CamelException *ex); -static char *get_name (CamelService *service, gboolean brief); - -static gboolean smtp_helo (CamelSmtpTransport *transport, CamelException *ex); -static gboolean smtp_auth (CamelSmtpTransport *transport, const char *mech, CamelException *ex); -static gboolean smtp_mail (CamelSmtpTransport *transport, const char *sender, - gboolean has_8bit_parts, CamelException *ex); -static gboolean smtp_rcpt (CamelSmtpTransport *transport, const char *recipient, CamelException *ex); -static gboolean smtp_data (CamelSmtpTransport *transport, CamelMimeMessage *message, CamelException *ex); -static gboolean smtp_rset (CamelSmtpTransport *transport, CamelException *ex); -static gboolean smtp_quit (CamelSmtpTransport *transport, CamelException *ex); - -static void smtp_set_exception (CamelSmtpTransport *transport, const char *respbuf, - const char *message, CamelException *ex); - -/* private data members */ -static CamelTransportClass *parent_class = NULL; - -static void -camel_smtp_transport_class_init (CamelSmtpTransportClass *camel_smtp_transport_class) -{ - CamelTransportClass *camel_transport_class = - CAMEL_TRANSPORT_CLASS (camel_smtp_transport_class); - CamelServiceClass *camel_service_class = - CAMEL_SERVICE_CLASS (camel_smtp_transport_class); - - parent_class = CAMEL_TRANSPORT_CLASS (camel_type_get_global_classfuncs (camel_transport_get_type ())); - - /* virtual method overload */ - camel_service_class->construct = smtp_construct; - camel_service_class->connect = smtp_connect; - camel_service_class->disconnect = smtp_disconnect; - camel_service_class->query_auth_types = query_auth_types; - camel_service_class->get_name = get_name; - - camel_transport_class->send_to = smtp_send_to; -} - -static void -camel_smtp_transport_init (gpointer object) -{ - CamelSmtpTransport *smtp = CAMEL_SMTP_TRANSPORT (object); - - smtp->flags = 0; - smtp->connected = FALSE; -} - -CamelType -camel_smtp_transport_get_type (void) -{ - static CamelType type = CAMEL_INVALID_TYPE; - - if (type == CAMEL_INVALID_TYPE) { - type = camel_type_register (CAMEL_TRANSPORT_TYPE, - "CamelSmtpTransport", - sizeof (CamelSmtpTransport), - sizeof (CamelSmtpTransportClass), - (CamelObjectClassInitFunc) camel_smtp_transport_class_init, - NULL, - (CamelObjectInitFunc) camel_smtp_transport_init, - NULL); - } - - return type; -} - -static void -smtp_construct (CamelService *service, CamelSession *session, - CamelProvider *provider, CamelURL *url, - CamelException *ex) -{ - CamelSmtpTransport *smtp_transport = CAMEL_SMTP_TRANSPORT (service); - const char *use_ssl; - - CAMEL_SERVICE_CLASS (parent_class)->construct (service, session, provider, url, ex); - - if ((use_ssl = camel_url_get_param (url, "use_ssl"))) { - /* Note: previous versions would use "" to toggle use_ssl to 'on' */ - if (!*use_ssl || !strcmp (use_ssl, "always")) - smtp_transport->flags |= CAMEL_SMTP_TRANSPORT_USE_SSL_ALWAYS; - else if (!strcmp (use_ssl, "when-possible")) - smtp_transport->flags |= CAMEL_SMTP_TRANSPORT_USE_SSL_WHEN_POSSIBLE; - } -} - -static const char * -smtp_error_string (int error) -{ - /* SMTP error codes grabbed from rfc821 */ - switch (error) { - case 0: - /* looks like a read problem, check errno */ - if (errno) - return g_strerror (errno); - else - return _("Unknown"); - case 500: - return _("Syntax error, command unrecognized"); - case 501: - return _("Syntax error in parameters or arguments"); - case 502: - return _("Command not implemented"); - case 504: - return _("Command parameter not implemented"); - case 211: - return _("System status, or system help reply"); - case 214: - return _("Help message"); - case 220: - return _("Service ready"); - case 221: - return _("Service closing transmission channel"); - case 421: - return _("Service not available, closing transmission channel"); - case 250: - return _("Requested mail action okay, completed"); - case 251: - return _("User not local; will forward to <forward-path>"); - case 450: - return _("Requested mail action not taken: mailbox unavailable"); - case 550: - return _("Requested action not taken: mailbox unavailable"); - case 451: - return _("Requested action aborted: error in processing"); - case 551: - return _("User not local; please try <forward-path>"); - case 452: - return _("Requested action not taken: insufficient system storage"); - case 552: - return _("Requested mail action aborted: exceeded storage allocation"); - case 553: - return _("Requested action not taken: mailbox name not allowed"); - case 354: - return _("Start mail input; end with <CRLF>.<CRLF>"); - case 554: - return _("Transaction failed"); - - /* AUTH error codes: */ - case 432: - return _("A password transition is needed"); - case 534: - return _("Authentication mechanism is too weak"); - case 538: - return _("Encryption required for requested authentication mechanism"); - case 454: - return _("Temporary authentication failure"); - case 530: - return _("Authentication required"); - - default: - return _("Unknown"); - } -} - -#define SSL_PORT_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3) -#define STARTTLS_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_TLS) - -static gboolean -connect_to_server (CamelService *service, int try_starttls, CamelException *ex) -{ - CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service); - CamelStream *tcp_stream; - char *respbuf = NULL; - struct hostent *h; - int port, ret; - - if (!CAMEL_SERVICE_CLASS (parent_class)->connect (service, ex)) - return FALSE; - - h = camel_service_gethost (service, ex); - if (!h) - return FALSE; - - /* set some smtp transport defaults */ - transport->flags &= CAMEL_SMTP_TRANSPORT_USE_SSL; /* reset all but ssl flags */ - transport->authtypes = NULL; - - port = service->url->port ? service->url->port : SMTP_PORT; - - if (transport->flags & CAMEL_SMTP_TRANSPORT_USE_SSL) { -#ifdef HAVE_SSL - if (try_starttls) { - tcp_stream = camel_tcp_stream_ssl_new_raw (service->session, service->url->host, STARTTLS_FLAGS); - } else { - port = service->url->port ? service->url->port : 465; - tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, SSL_PORT_FLAGS); - } -#else - if (!try_starttls) - port = service->url->port ? service->url->port : 465; - - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Could not connect to %s (port %d): %s"), - service->url->host, port, - _("SSL unavailable")); - - camel_free_host (h); - - return FALSE; -#endif /* HAVE_SSL */ - } else { - tcp_stream = camel_tcp_stream_raw_new (); - } - - ret = camel_tcp_stream_connect (CAMEL_TCP_STREAM (tcp_stream), h, port); - camel_free_host (h); - if (ret == -1) { - 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 (tcp_stream); - - return FALSE; - } - - transport->connected = TRUE; - - /* get the localaddr - needed later by smtp_helo */ - transport->localaddr = camel_tcp_stream_get_local_address (CAMEL_TCP_STREAM (tcp_stream)); - - transport->ostream = tcp_stream; - transport->istream = camel_stream_buffer_new (tcp_stream, CAMEL_STREAM_BUFFER_READ); - - /* Read the greeting, note whether the server is ESMTP or not. */ - do { - /* Check for "220" */ - g_free (respbuf); - respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream)); - if (!respbuf || strncmp (respbuf, "220", 3)) { - smtp_set_exception (transport, respbuf, _("Welcome response error"), ex); - g_free (respbuf); - return FALSE; - } - } while (*(respbuf+3) == '-'); /* if we got "220-" then loop again */ - g_free (respbuf); - - /* Try sending EHLO */ - transport->flags |= CAMEL_SMTP_TRANSPORT_IS_ESMTP; - if (!smtp_helo (transport, ex)) { - if (!transport->connected) - return FALSE; - - /* Fall back to HELO */ - camel_exception_clear (ex); - transport->flags &= ~CAMEL_SMTP_TRANSPORT_IS_ESMTP; - if (!smtp_helo (transport, ex) && !transport->connected) - return FALSE; - } - - /* clear any EHLO/HELO exception and assume that any SMTP errors encountered were non-fatal */ - camel_exception_clear (ex); - -#ifdef HAVE_SSL - if (transport->flags & CAMEL_SMTP_TRANSPORT_USE_SSL_WHEN_POSSIBLE) { - /* try_starttls is always TRUE here */ - if (transport->flags & CAMEL_SMTP_TRANSPORT_STARTTLS) - goto starttls; - } else if (transport->flags & CAMEL_SMTP_TRANSPORT_USE_SSL_ALWAYS) { - if (try_starttls) { - if (transport->flags & CAMEL_SMTP_TRANSPORT_STARTTLS) { - goto starttls; - } else { - /* server doesn't support STARTTLS, abort */ - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Failed to connect to SMTP server %s in secure mode: %s"), - service->url->host, _("server does not appear to support SSL")); - goto exception_cleanup; - } - } - } -#endif /* HAVE_SSL */ - - return TRUE; - -#ifdef HAVE_SSL - starttls: - d(fprintf (stderr, "sending : STARTTLS\r\n")); - if (camel_stream_write (tcp_stream, "STARTTLS\r\n", 10) == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("STARTTLS request timed out: %s"), - g_strerror (errno)); - goto exception_cleanup; - } - - respbuf = NULL; - - do { - /* Check for "220 Ready for TLS" */ - g_free (respbuf); - respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream)); - - d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)")); - - if (!respbuf || strncmp (respbuf, "220", 3)) { - smtp_set_exception (transport, respbuf, _("STARTTLS response error"), ex); - g_free (respbuf); - goto exception_cleanup; - } - } while (*(respbuf+3) == '-'); /* if we got "220-" then loop again */ - - /* 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 SMTP server %s in secure mode: %s"), - service->url->host, g_strerror (errno)); - goto exception_cleanup; - } - - /* We are supposed to re-EHLO after a successful STARTTLS to - re-fetch any supported extensions. */ - if (!smtp_helo (transport, ex) && !transport->connected) - return FALSE; - - return TRUE; - - exception_cleanup: - - camel_object_unref (transport->istream); - transport->istream = NULL; - camel_object_unref (transport->ostream); - transport->ostream = NULL; - - transport->connected = FALSE; - - return FALSE; -#endif /* HAVE_SSL */ -} - -static gboolean -connect_to_server_wrapper (CamelService *service, CamelException *ex) -{ -#ifdef HAVE_SSL - CamelSmtpTransport *transport = (CamelSmtpTransport *) service; - - if (transport->flags & CAMEL_SMTP_TRANSPORT_USE_SSL_ALWAYS) { - /* First try connecting to the SSL port */ - if (!connect_to_server (service, FALSE, ex)) { - if (camel_exception_get_id (ex) == CAMEL_EXCEPTION_SERVICE_UNAVAILABLE) { - /* Seems the SSL port is unavailable, lets try STARTTLS */ - camel_exception_clear (ex); - return connect_to_server (service, TRUE, ex); - } else { - return FALSE; - } - } - - return TRUE; - } else if (transport->flags & CAMEL_SMTP_TRANSPORT_USE_SSL_WHEN_POSSIBLE) { - /* If the server supports STARTTLS, use it */ - return connect_to_server (service, TRUE, ex); - } else { - /* User doesn't care about SSL */ - return connect_to_server (service, FALSE, ex); - } -#else - return connect_to_server (service, FALSE, ex); -#endif -} - -static gboolean -smtp_connect (CamelService *service, CamelException *ex) -{ - CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service); - gboolean has_authtypes; - - /* We (probably) need to check popb4smtp before we connect ... */ - if (service->url->authmech && !strcmp (service->url->authmech, "POPB4SMTP")) { - int truth; - GByteArray *chal; - CamelSasl *sasl; - - sasl = camel_sasl_new ("smtp", "POPB4SMTP", service); - chal = camel_sasl_challenge (sasl, NULL, ex); - truth = camel_sasl_authenticated (sasl); - if (chal) - g_byte_array_free (chal, TRUE); - camel_object_unref (sasl); - - if (!truth) - return FALSE; - - return connect_to_server_wrapper (service, ex); - } - - if (!connect_to_server_wrapper (service, ex)) - return FALSE; - - /* check to see if AUTH is required, if so...then AUTH ourselves */ - has_authtypes = transport->authtypes ? g_hash_table_size (transport->authtypes) > 0 : FALSE; - if (service->url->authmech && (transport->flags & CAMEL_SMTP_TRANSPORT_IS_ESMTP) && has_authtypes) { - CamelSession *session = camel_service_get_session (service); - CamelServiceAuthType *authtype; - gboolean authenticated = FALSE; - char *errbuf = NULL; - - if (!g_hash_table_lookup (transport->authtypes, service->url->authmech)) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE, - _("SMTP server %s does not support requested " - "authentication type %s."), - service->url->host, service->url->authmech); - camel_service_disconnect (service, TRUE, NULL); - 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); - camel_service_disconnect (service, TRUE, NULL); - return FALSE; - } - - if (!authtype->need_password) { - /* authentication mechanism doesn't need a password, - so if it fails there's nothing we can do */ - authenticated = smtp_auth (transport, authtype->authproto, ex); - if (!authenticated) { - camel_service_disconnect (service, TRUE, NULL); - return FALSE; - } - } - - /* keep trying to login until either we succeed or the user cancels */ - while (!authenticated) { - if (errbuf) { - /* We need to un-cache the password before prompting again */ - camel_session_forget_password (session, service, "password", NULL); - g_free (service->url->passwd); - service->url->passwd = NULL; - } - - if (!service->url->passwd) { - char *prompt; - - prompt = g_strdup_printf (_("%sPlease enter the SMTP password for %s@%s"), - errbuf ? errbuf : "", service->url->user, - service->url->host); - - service->url->passwd = camel_session_get_password (session, prompt, FALSE, TRUE, - service, "password", ex); - - g_free (prompt); - g_free (errbuf); - errbuf = NULL; - - if (!service->url->passwd) { - camel_service_disconnect (service, TRUE, NULL); - return FALSE; - } - } - - authenticated = smtp_auth (transport, authtype->authproto, ex); - if (!authenticated) { - errbuf = g_strdup_printf (_("Unable to authenticate " - "to SMTP server.\n%s\n\n"), - camel_exception_get_description (ex)); - camel_exception_clear (ex); - } - } - - /* The spec says we have to re-EHLO, but some servers - * we won't bother to name don't want you to... so ignore - * errors. - */ - if (!smtp_helo (transport, ex) && !transport->connected) - return FALSE; - - camel_exception_clear (ex); - } - - return TRUE; -} - -static void -authtypes_free (gpointer key, gpointer value, gpointer data) -{ - g_free (value); -} - -static gboolean -smtp_disconnect (CamelService *service, gboolean clean, CamelException *ex) -{ - CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service); - - /*if (!service->connected) - * return TRUE; - */ - - if (transport->connected && clean) { - /* send the QUIT command to the SMTP server */ - smtp_quit (transport, ex); - } - - if (!CAMEL_SERVICE_CLASS (parent_class)->disconnect (service, clean, ex)) - return FALSE; - - if (transport->authtypes) { - g_hash_table_foreach (transport->authtypes, authtypes_free, NULL); - g_hash_table_destroy (transport->authtypes); - transport->authtypes = NULL; - } - - if (transport->istream) { - camel_object_unref (transport->istream); - transport->istream = NULL; - } - - if (transport->ostream) { - camel_object_unref (transport->ostream); - transport->ostream = NULL; - } - - camel_tcp_address_free (transport->localaddr); - transport->localaddr = NULL; - - transport->connected = FALSE; - - return TRUE; -} - -static GHashTable * -esmtp_get_authtypes (const unsigned char *buffer) -{ - const unsigned char *start, *end; - GHashTable *table = NULL; - - /* advance to the first token */ - start = buffer; - while (isspace ((int) *start) || *start == '=') - start++; - - if (!*start) - return NULL; - - table = g_hash_table_new (g_str_hash, g_str_equal); - - for ( ; *start; ) { - char *type; - - /* advance to the end of the token */ - end = start; - while (*end && !isspace ((int) *end)) - end++; - - type = g_strndup (start, end - start); - g_hash_table_insert (table, type, type); - - /* advance to the next token */ - start = end; - while (isspace ((int) *start)) - start++; - } - - return table; -} - -static GList * -query_auth_types (CamelService *service, CamelException *ex) -{ - CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service); - CamelServiceAuthType *authtype; - GList *types, *t, *next; - - if (!connect_to_server_wrapper (service, ex)) - return NULL; - - types = g_list_copy (service->provider->authtypes); - for (t = types; t; t = next) { - authtype = t->data; - next = t->next; - - if (!g_hash_table_lookup (transport->authtypes, authtype->authproto)) { - types = g_list_remove_link (types, t); - g_list_free_1 (t); - } - } - - smtp_disconnect (service, TRUE, NULL); - - return types; -} - -static char * -get_name (CamelService *service, gboolean brief) -{ - if (brief) - return g_strdup_printf (_("SMTP server %s"), service->url->host); - else { - return g_strdup_printf (_("SMTP mail delivery via %s"), - service->url->host); - } -} - -static gboolean -smtp_send_to (CamelTransport *transport, CamelMimeMessage *message, - CamelAddress *from, CamelAddress *recipients, - CamelException *ex) -{ - CamelSmtpTransport *smtp_transport = CAMEL_SMTP_TRANSPORT (transport); - const CamelInternetAddress *cia; - gboolean has_8bit_parts; - const char *addr; - int i, len; - - if (!camel_internet_address_get (CAMEL_INTERNET_ADDRESS (from), 0, NULL, &addr)) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot send message: " - "sender address not valid.")); - return FALSE; - } - - camel_operation_start (NULL, _("Sending message")); - - /* find out if the message has 8bit mime parts */ - has_8bit_parts = camel_mime_message_has_8bit_parts (message); - - /* rfc1652 (8BITMIME) requires that you notify the ESMTP daemon that - you'll be sending an 8bit mime message at "MAIL FROM:" time. */ - if (!smtp_mail (smtp_transport, addr, has_8bit_parts, ex)) { - camel_operation_end (NULL); - return FALSE; - } - - len = camel_address_length (recipients); - if (len == 0) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot send message: no recipients defined.")); - camel_operation_end (NULL); - return FALSE; - } - - cia = CAMEL_INTERNET_ADDRESS (recipients); - for (i = 0; i < len; i++) { - char *enc; - - if (!camel_internet_address_get (cia, i, NULL, &addr)) { - camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot send message: one or more invalid recipients")); - camel_operation_end (NULL); - return FALSE; - } - - enc = camel_internet_address_encode_address(NULL, NULL, addr); - if (!smtp_rcpt (smtp_transport, enc, ex)) { - g_free(enc); - camel_operation_end (NULL); - return FALSE; - } - g_free(enc); - } - - if (!smtp_data (smtp_transport, message, ex)) { - camel_operation_end (NULL); - return FALSE; - } - - /* reset the service for our next transfer session */ - smtp_rset (smtp_transport, ex); - - camel_operation_end (NULL); - - return TRUE; -} - -static const char * -smtp_next_token (const char *buf) -{ - const unsigned char *token; - - token = (const unsigned char *) buf; - while (*token && !isspace ((int) *token)) - token++; - - while (*token && isspace ((int) *token)) - token++; - - return (const char *) token; -} - -#define HEXVAL(c) (isdigit (c) ? (c) - '0' : (c) - 'A' + 10) - -/** - * example (rfc2034): - * 5.1.1 Mailbox "nosuchuser" does not exist - * - * The human-readable status code is what we want. Since this text - * could possibly be encoded, we must decode it. - * - * "xtext" is formally defined as follows: - * - * xtext = *( xchar / hexchar / linear-white-space / comment ) - * - * xchar = any ASCII CHAR between "!" (33) and "~" (126) inclusive, - * except for "+", "\" and "(". - * - * "hexchar"s are intended to encode octets that cannot be represented - * as plain text, either because they are reserved, or because they are - * non-printable. However, any octet value may be represented by a - * "hexchar". - * - * hexchar = ASCII "+" immediately followed by two upper case - * hexadecimal digits - **/ -static char * -smtp_decode_status_code (const char *in, size_t len) -{ - unsigned char *inptr, *outptr; - const unsigned char *inend; - char *outbuf; - - outptr = outbuf = g_malloc (len + 1); - - inptr = (unsigned char *) in; - inend = inptr + len; - while (inptr < inend) { - if (*inptr == '+') { - if (isxdigit (inptr[1]) && isxdigit (inptr[2])) { - *outptr++ = HEXVAL (inptr[1]) * 16 + HEXVAL (inptr[2]); - inptr += 3; - } else - *outptr++ = *inptr++; - } else - *outptr++ = *inptr++; - } - - *outptr = '\0'; - - return outbuf; -} - -static void -smtp_set_exception (CamelSmtpTransport *transport, const char *respbuf, const char *message, CamelException *ex) -{ - const char *token, *rbuf = respbuf; - char *buffer = NULL; - GString *string; - int error; - - if (!respbuf || !(transport->flags & CAMEL_SMTP_TRANSPORT_ENHANCEDSTATUSCODES)) { - fake_status_code: - error = respbuf ? atoi (respbuf) : 0; - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, "%s: %s", message, - smtp_error_string (error)); - } else { - string = g_string_new (""); - do { - token = smtp_next_token (rbuf + 4); - if (*token == '\0') { - g_free (buffer); - g_string_free (string, TRUE); - goto fake_status_code; - } - - g_string_append (string, token); - if (*(rbuf + 3) == '-') { - g_free (buffer); - buffer = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream)); - g_string_append_c (string, '\n'); - } else { - g_free (buffer); - buffer = NULL; - } - - rbuf = buffer; - } while (rbuf); - - buffer = smtp_decode_status_code (string->str, string->len); - g_string_free (string, TRUE); - if (!buffer) - goto fake_status_code; - - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - "%s: %s", message, buffer); - - g_free (buffer); - } - - if (!respbuf) { - /* we got disconnected */ - transport->connected = FALSE; - } -} - -static gboolean -smtp_helo (CamelSmtpTransport *transport, CamelException *ex) -{ - /* say hello to the server */ - char *name = NULL, *cmdbuf = NULL, *respbuf = NULL; - struct hostent *host; - CamelException err; - const char *token; - int af; - - /* these are flags that we set, so unset them in case we - are being called a second time (ie, after a STARTTLS) */ - transport->flags &= ~(CAMEL_SMTP_TRANSPORT_8BITMIME | - CAMEL_SMTP_TRANSPORT_ENHANCEDSTATUSCODES | - CAMEL_SMTP_TRANSPORT_STARTTLS); - - if (transport->authtypes) { - g_hash_table_foreach (transport->authtypes, authtypes_free, NULL); - g_hash_table_destroy (transport->authtypes); - transport->authtypes = NULL; - } - - camel_operation_start_transient (NULL, _("SMTP Greeting")); - - /* get the local host name */ - camel_exception_init (&err); -#ifdef ENABLE_IPv6 - af = transport->localaddr->family == CAMEL_TCP_ADDRESS_IPv6 ? AF_INET6 : AF_INET; -#else - af = AF_INET; -#endif - host = camel_gethostbyaddr ((char *) &transport->localaddr->address, - transport->localaddr->length, af, &err); - - camel_exception_clear (&err); - - if (host && host->h_name && *host->h_name) { - name = g_strdup (host->h_name); - } else { -#ifdef ENABLE_IPv6 - char ip[MAXHOSTNAMELEN + 1]; - const char *proto; - - proto = transport->localaddr->family == CAMEL_TCP_ADDRESS_IPv6 ? "IPv6:" : ""; - name = g_strdup_printf ("[%s%s]", proto, inet_ntop (af, transport->localaddr->address, ip, MAXHOSTNAMELEN)); -#else - /* We *could* use inet_ntoa() here, but it's probably - not worth it since we would have to worry about - some systems not having inet_ntoa() */ - name = g_strdup_printf ("[%d.%d.%d.%d]", - transport->localaddr->address[0], - transport->localaddr->address[1], - transport->localaddr->address[2], - transport->localaddr->address[3]); -#endif - } - - if (host) - camel_free_host (host); - - /* hiya server! how are you today? */ - if (transport->flags & CAMEL_SMTP_TRANSPORT_IS_ESMTP) - cmdbuf = g_strdup_printf ("EHLO %s\r\n", name); - else - cmdbuf = g_strdup_printf ("HELO %s\r\n", name); - g_free (name); - - d(fprintf (stderr, "sending : %s", cmdbuf)); - if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) { - g_free (cmdbuf); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("HELO request timed out: %s"), - g_strerror (errno)); - camel_operation_end (NULL); - - transport->connected = FALSE; - camel_object_unref (transport->istream); - transport->istream = NULL; - camel_object_unref (transport->ostream); - transport->ostream = NULL; - - return FALSE; - } - g_free (cmdbuf); - - do { - /* Check for "250" */ - g_free (respbuf); - respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream)); - - d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)")); - - if (!respbuf || strncmp (respbuf, "250", 3)) { - smtp_set_exception (transport, respbuf, _("HELO response error"), ex); - camel_operation_end (NULL); - g_free (respbuf); - - return FALSE; - } - - token = respbuf + 4; - - if (transport->flags & CAMEL_SMTP_TRANSPORT_IS_ESMTP) { - if (!strncmp (token, "8BITMIME", 8)) { - d(fprintf (stderr, "This server supports 8bit MIME\n")); - transport->flags |= CAMEL_SMTP_TRANSPORT_8BITMIME; - } else if (!strncmp (token, "ENHANCEDSTATUSCODES", 19)) { - d(fprintf (stderr, "This server supports enhanced status codes\n")); - transport->flags |= CAMEL_SMTP_TRANSPORT_ENHANCEDSTATUSCODES; - } else if (!strncmp (token, "STARTTLS", 8)) { - d(fprintf (stderr, "This server supports STARTTLS\n")); - transport->flags |= CAMEL_SMTP_TRANSPORT_STARTTLS; - } else if (!strncmp (token, "AUTH", 4)) { - if (!transport->authtypes || transport->flags & CAMEL_SMTP_TRANSPORT_AUTH_EQUAL) { - /* Don't bother parsing any authtypes if we already have a list. - * Some servers will list AUTH twice, once the standard way and - * once the way Microsoft Outlook requires them to be: - * - * 250-AUTH LOGIN PLAIN DIGEST-MD5 CRAM-MD5 - * 250-AUTH=LOGIN PLAIN DIGEST-MD5 CRAM-MD5 - * - * Since they can come in any order, parse each list that we get - * until we parse an authtype list that does not use the AUTH= - * format. We want to let the standard way have priority over the - * broken way. - **/ - - if (token[4] == '=') - transport->flags |= CAMEL_SMTP_TRANSPORT_AUTH_EQUAL; - else - transport->flags &= ~CAMEL_SMTP_TRANSPORT_AUTH_EQUAL; - - /* parse for supported AUTH types */ - token += 5; - - if (transport->authtypes) { - g_hash_table_foreach (transport->authtypes, authtypes_free, NULL); - g_hash_table_destroy (transport->authtypes); - } - - transport->authtypes = esmtp_get_authtypes (token); - } - } - } - } while (*(respbuf+3) == '-'); /* if we got "250-" then loop again */ - g_free (respbuf); - - camel_operation_end (NULL); - - return TRUE; -} - -static gboolean -smtp_auth (CamelSmtpTransport *transport, const char *mech, CamelException *ex) -{ - char *cmdbuf, *respbuf = NULL, *challenge; - gboolean auth_challenge = FALSE; - CamelSasl *sasl = NULL; - - camel_operation_start_transient (NULL, _("SMTP Authentication")); - - sasl = camel_sasl_new ("smtp", mech, CAMEL_SERVICE (transport)); - if (!sasl) { - camel_operation_end (NULL); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Error creating SASL authentication object.")); - return FALSE; - } - - challenge = camel_sasl_challenge_base64 (sasl, NULL, ex); - if (challenge) { - auth_challenge = TRUE; - cmdbuf = g_strdup_printf ("AUTH %s %s\r\n", mech, challenge); - g_free (challenge); - } else { - cmdbuf = g_strdup_printf ("AUTH %s\r\n", mech); - } - - d(fprintf (stderr, "sending : %s", cmdbuf)); - if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) { - g_free (cmdbuf); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("AUTH request timed out: %s"), - g_strerror (errno)); - goto lose; - } - g_free (cmdbuf); - - respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream)); - d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)")); - - while (!camel_sasl_authenticated (sasl)) { - if (!respbuf) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("AUTH request timed out: %s"), - g_strerror (errno)); - goto lose; - } - - /* the server challenge/response should follow a 334 code */ - if (strncmp (respbuf, "334", 3)) { - g_free (respbuf); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("AUTH request failed.")); - goto lose; - } - - if (FALSE) { - broken_smtp_server: - d(fprintf (stderr, "Your SMTP server's implementation of the %s SASL\n" - "authentication mechanism is broken. Please report this to the\n" - "appropriate vendor and suggest that they re-read rfc2554 again\n" - "for the first time (specifically Section 4).\n", - mech)); - } - - /* eat whtspc */ - for (challenge = respbuf + 4; isspace (*challenge); challenge++); - - challenge = camel_sasl_challenge_base64 (sasl, challenge, ex); - g_free (respbuf); - if (challenge == NULL) - goto break_and_lose; - - /* send our challenge */ - cmdbuf = g_strdup_printf ("%s\r\n", challenge); - g_free (challenge); - d(fprintf (stderr, "sending : %s", cmdbuf)); - if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) { - g_free (cmdbuf); - goto lose; - } - g_free (cmdbuf); - - /* get the server's response */ - respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream)); - d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)")); - } - - /* check that the server says we are authenticated */ - if (!respbuf || strncmp (respbuf, "235", 3)) { - if (respbuf && auth_challenge && !strncmp (respbuf, "334", 3)) { - /* broken server, but lets try and work around it anyway... */ - goto broken_smtp_server; - } - g_free (respbuf); - goto lose; - } - - camel_object_unref (sasl); - camel_operation_end (NULL); - - return TRUE; - - break_and_lose: - /* Get the server out of "waiting for continuation data" mode. */ - d(fprintf (stderr, "sending : *\n")); - camel_stream_write (transport->ostream, "*\r\n", 3); - respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream)); - d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)")); - - lose: - if (!camel_exception_is_set (ex)) { - camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE, - _("Bad authentication response from server.\n")); - } - - camel_object_unref (sasl); - camel_operation_end (NULL); - - return FALSE; -} - -static gboolean -smtp_mail (CamelSmtpTransport *transport, const char *sender, gboolean has_8bit_parts, CamelException *ex) -{ - /* we gotta tell the smtp server who we are. (our email addy) */ - char *cmdbuf, *respbuf = NULL; - - if (transport->flags & CAMEL_SMTP_TRANSPORT_8BITMIME && has_8bit_parts) - cmdbuf = g_strdup_printf ("MAIL FROM:<%s> BODY=8BITMIME\r\n", sender); - else - cmdbuf = g_strdup_printf ("MAIL FROM:<%s>\r\n", sender); - - d(fprintf (stderr, "sending : %s", cmdbuf)); - - if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) { - g_free (cmdbuf); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("MAIL FROM request timed out: %s: mail not sent"), - g_strerror (errno)); - - camel_object_unref (transport->istream); - transport->istream = NULL; - camel_object_unref (transport->ostream); - transport->ostream = NULL; - - return FALSE; - } - g_free (cmdbuf); - - do { - /* Check for "250 Sender OK..." */ - g_free (respbuf); - respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream)); - - d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)")); - - if (!respbuf || strncmp (respbuf, "250", 3)) { - smtp_set_exception (transport, respbuf, _("MAIL FROM response error"), ex); - g_free (respbuf); - return FALSE; - } - } while (*(respbuf+3) == '-'); /* if we got "250-" then loop again */ - g_free (respbuf); - - return TRUE; -} - -static gboolean -smtp_rcpt (CamelSmtpTransport *transport, const char *recipient, CamelException *ex) -{ - /* we gotta tell the smtp server who we are going to be sending - * our email to */ - char *cmdbuf, *respbuf = NULL; - - cmdbuf = g_strdup_printf ("RCPT TO:<%s>\r\n", recipient); - - d(fprintf (stderr, "sending : %s", cmdbuf)); - - if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) { - g_free (cmdbuf); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("RCPT TO request timed out: %s: mail not sent"), - g_strerror (errno)); - - camel_object_unref (transport->istream); - transport->istream = NULL; - camel_object_unref (transport->ostream); - transport->ostream = NULL; - - return FALSE; - } - g_free (cmdbuf); - - do { - /* Check for "250 Recipient OK..." */ - g_free (respbuf); - respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream)); - - d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)")); - - if (!respbuf || strncmp (respbuf, "250", 3)) { - char *message; - - message = g_strdup_printf (_("RCPT TO <%s> failed"), recipient); - smtp_set_exception (transport, respbuf, message, ex); - g_free (message); - g_free (respbuf); - return FALSE; - } - } while (*(respbuf+3) == '-'); /* if we got "250-" then loop again */ - g_free (respbuf); - - return TRUE; -} - -static gboolean -smtp_data (CamelSmtpTransport *transport, CamelMimeMessage *message, CamelException *ex) -{ - CamelBestencEncoding enctype = CAMEL_BESTENC_8BIT; - struct _camel_header_raw *header, *savedbcc, *n, *tail; - char *cmdbuf, *respbuf = NULL; - CamelStreamFilter *filtered_stream; - CamelMimeFilter *crlffilter; - int ret; - - /* If the server doesn't support 8BITMIME, set our required encoding to be 7bit */ - if (!(transport->flags & CAMEL_SMTP_TRANSPORT_8BITMIME)) - enctype = CAMEL_BESTENC_7BIT; - - /* FIXME: should we get the best charset too?? */ - /* Changes the encoding of all mime parts to fit within our required - encoding type and also force any text parts with long lines (longer - than 998 octets) to wrap by QP or base64 encoding them. */ - camel_mime_message_set_best_encoding (message, CAMEL_BESTENC_GET_ENCODING, enctype); - - cmdbuf = g_strdup ("DATA\r\n"); - - d(fprintf (stderr, "sending : %s", cmdbuf)); - - if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) { - g_free (cmdbuf); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("DATA request timed out: %s: mail not sent"), - g_strerror (errno)); - - camel_object_unref (transport->istream); - transport->istream = NULL; - camel_object_unref (transport->ostream); - transport->ostream = NULL; - - return FALSE; - } - g_free (cmdbuf); - - respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream)); - - d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)")); - - if (!respbuf || strncmp (respbuf, "354", 3)) { - /* we should have gotten instructions on how to use the DATA command: - * 354 Enter mail, end with "." on a line by itself - */ - smtp_set_exception (transport, respbuf, _("DATA response error"), ex); - g_free (respbuf); - return FALSE; - } - - g_free (respbuf); - respbuf = NULL; - - /* setup stream filtering */ - crlffilter = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_ENCODE, CAMEL_MIME_FILTER_CRLF_MODE_CRLF_DOTS); - filtered_stream = camel_stream_filter_new_with_stream (transport->ostream); - camel_stream_filter_add (filtered_stream, CAMEL_MIME_FILTER (crlffilter)); - camel_object_unref (crlffilter); - - /* unlink the bcc headers */ - savedbcc = NULL; - tail = (struct _camel_header_raw *) &savedbcc; - - header = (struct _camel_header_raw *) &CAMEL_MIME_PART (message)->headers; - n = header->next; - while (n != NULL) { - if (!strcasecmp (n->name, "Bcc")) { - header->next = n->next; - tail->next = n; - n->next = NULL; - tail = n; - } else { - header = n; - } - - n = header->next; - } - - /* write the message */ - ret = camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), CAMEL_STREAM (filtered_stream)); - - /* restore the bcc headers */ - header->next = savedbcc; - - if (ret == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("DATA send timed out: message termination: " - "%s: mail not sent"), - g_strerror (errno)); - - camel_object_unref (filtered_stream); - - camel_object_unref (transport->istream); - transport->istream = NULL; - camel_object_unref (transport->ostream); - transport->ostream = NULL; - - return FALSE; - } - - camel_stream_flush (CAMEL_STREAM (filtered_stream)); - camel_object_unref (filtered_stream); - - /* terminate the message body */ - - d(fprintf (stderr, "sending : \\r\\n.\\r\\n\n")); - - if (camel_stream_write (transport->ostream, "\r\n.\r\n", 5) == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("DATA send timed out: message termination: " - "%s: mail not sent"), - g_strerror (errno)); - - camel_object_unref (transport->istream); - transport->istream = NULL; - camel_object_unref (transport->ostream); - transport->ostream = NULL; - - return FALSE; - } - - do { - /* Check for "250 Sender OK..." */ - g_free (respbuf); - respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream)); - - d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)")); - - if (!respbuf || strncmp (respbuf, "250", 3)) { - smtp_set_exception (transport, respbuf, _("DATA termination response error"), ex); - g_free (respbuf); - return FALSE; - } - } while (*(respbuf+3) == '-'); /* if we got "250-" then loop again */ - g_free (respbuf); - - return TRUE; -} - -static gboolean -smtp_rset (CamelSmtpTransport *transport, CamelException *ex) -{ - /* we are going to reset the smtp server (just to be nice) */ - char *cmdbuf, *respbuf = NULL; - - cmdbuf = g_strdup ("RSET\r\n"); - - d(fprintf (stderr, "sending : %s", cmdbuf)); - - if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) { - g_free (cmdbuf); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("RSET request timed out: %s"), - g_strerror (errno)); - - camel_object_unref (transport->istream); - transport->istream = NULL; - camel_object_unref (transport->ostream); - transport->ostream = NULL; - - return FALSE; - } - g_free (cmdbuf); - - do { - /* Check for "250" */ - g_free (respbuf); - respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream)); - - d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)")); - - if (!respbuf || strncmp (respbuf, "250", 3)) { - smtp_set_exception (transport, respbuf, _("RSET response error"), ex); - g_free (respbuf); - return FALSE; - } - } while (*(respbuf+3) == '-'); /* if we got "250-" then loop again */ - g_free (respbuf); - - return TRUE; -} - -static gboolean -smtp_quit (CamelSmtpTransport *transport, CamelException *ex) -{ - /* we are going to reset the smtp server (just to be nice) */ - char *cmdbuf, *respbuf = NULL; - - cmdbuf = g_strdup ("QUIT\r\n"); - - d(fprintf (stderr, "sending : %s", cmdbuf)); - - if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) { - g_free (cmdbuf); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("QUIT request timed out: %s"), - g_strerror (errno)); - - camel_object_unref (transport->istream); - transport->istream = NULL; - camel_object_unref (transport->ostream); - transport->ostream = NULL; - - return FALSE; - } - g_free (cmdbuf); - - do { - /* Check for "221" */ - g_free (respbuf); - respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream)); - - d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)")); - - if (!respbuf || strncmp (respbuf, "221", 3)) { - smtp_set_exception (transport, respbuf, _("QUIT response error"), ex); - g_free (respbuf); - return FALSE; - } - } while (*(respbuf+3) == '-'); /* if we got "221-" then loop again */ - g_free (respbuf); - - return TRUE; -} diff --git a/camel/providers/smtp/camel-smtp-transport.h b/camel/providers/smtp/camel-smtp-transport.h deleted file mode 100644 index ef15f2b07d..0000000000 --- a/camel/providers/smtp/camel-smtp-transport.h +++ /dev/null @@ -1,89 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-smtp-transport.h : class for an smtp transfer */ - -/* - * Authors: - * Jeffrey Stedfast <fejj@stampede.org> - * - * Copyright (C) 2000 Ximian, Inc. (www.ximian.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * 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_SMTP_TRANSPORT_H -#define CAMEL_SMTP_TRANSPORT_H 1 - - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus */ - - -#include "camel-transport.h" -#include "camel-tcp-stream.h" - -#define CAMEL_SMTP_TRANSPORT_TYPE (camel_smtp_transport_get_type ()) -#define CAMEL_SMTP_TRANSPORT(obj) (CAMEL_CHECK_CAST((obj), CAMEL_SMTP_TRANSPORT_TYPE, CamelSmtpTransport)) -#define CAMEL_SMTP_TRANSPORT_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_SMTP_TRANSPORT_TYPE, CamelSmtpTransportClass)) -#define CAMEL_IS_SMTP_TRANSPORT(o) (CAMEL_CHECK_TYPE((o), CAMEL_SMTP_TRANSPORT_TYPE)) - - -#define CAMEL_SMTP_TRANSPORT_IS_ESMTP (1 << 0) -#define CAMEL_SMTP_TRANSPORT_8BITMIME (1 << 1) -#define CAMEL_SMTP_TRANSPORT_ENHANCEDSTATUSCODES (1 << 2) -#define CAMEL_SMTP_TRANSPORT_STARTTLS (1 << 3) - -#define CAMEL_SMTP_TRANSPORT_USE_SSL_ALWAYS (1 << 4) -#define CAMEL_SMTP_TRANSPORT_USE_SSL_WHEN_POSSIBLE (1 << 5) - -#define CAMEL_SMTP_TRANSPORT_USE_SSL (CAMEL_SMTP_TRANSPORT_USE_SSL_ALWAYS | \ - CAMEL_SMTP_TRANSPORT_USE_SSL_WHEN_POSSIBLE) - -#define CAMEL_SMTP_TRANSPORT_AUTH_EQUAL (1 << 6) /* set if we are using authtypes from a broken AUTH= */ - -typedef struct { - CamelTransport parent_object; - - CamelStream *istream, *ostream; - - guint32 flags; - - gboolean connected; - CamelTcpAddress *localaddr; - - GHashTable *authtypes; - -} CamelSmtpTransport; - - - -typedef struct { - CamelTransportClass parent_class; - -} CamelSmtpTransportClass; - - -/* Standard Camel function */ -CamelType camel_smtp_transport_get_type (void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CAMEL_SMTP_TRANSPORT_H */ - - diff --git a/camel/providers/smtp/libcamelsmtp.urls b/camel/providers/smtp/libcamelsmtp.urls deleted file mode 100644 index ec2fc0fc16..0000000000 --- a/camel/providers/smtp/libcamelsmtp.urls +++ /dev/null @@ -1 +0,0 @@ -smtp |