diff options
-rw-r--r-- | camel/ChangeLog | 13 | ||||
-rw-r--r-- | camel/Makefile.am | 2 | ||||
-rw-r--r-- | camel/camel-debug.c | 115 | ||||
-rw-r--r-- | camel/camel-debug.h | 46 | ||||
-rw-r--r-- | camel/camel-exception.c | 6 | ||||
-rw-r--r-- | camel/camel.c | 12 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-folder.c | 135 |
7 files changed, 260 insertions, 69 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog index dd0cf84034..6ba3a3b09d 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,5 +1,18 @@ 2004-03-23 Not Zed <NotZed@Ximian.com> + * camel-exception.c (camel_exception_setv): use camel debug to add + some debug here. + + * camel.c (camel_init): call camel_debug_init(). + + * camel-debug.c (camel_debug_init, camel_debug): new util stuff + for extended debug options. + + * providers/imap/camel-imap-folder.c (imap_get_message): if we're + supposed to be online, check we are online before proceeding. + Actually major restructure so we re-try the fetch a couple of + times first before failing. i.e. silent reconnect. See #55381. + * providers/imap/camel-imap-store.c (get_folder_info_online): connect lock around this. was getting a race with mem corruption otherwise. diff --git a/camel/Makefile.am b/camel/Makefile.am index 07bfdbaead..4432d0e4a2 100644 --- a/camel/Makefile.am +++ b/camel/Makefile.am @@ -27,6 +27,7 @@ libcamel_la_SOURCES = \ camel-cipher-context.c \ camel-data-cache.c \ camel-data-wrapper.c \ + camel-debug.c \ camel-digest-folder.c \ camel-digest-store.c \ camel-digest-summary.c \ @@ -128,6 +129,7 @@ libcamelinclude_HEADERS = \ camel-cipher-context.h \ camel-data-cache.h \ camel-data-wrapper.h \ + camel-debug.h \ camel-digest-folder.h \ camel-digest-store.h \ camel-digest-summary.h \ diff --git a/camel/camel-debug.c b/camel/camel-debug.c new file mode 100644 index 0000000000..7c16c9a614 --- /dev/null +++ b/camel/camel-debug.c @@ -0,0 +1,115 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * + * + * Author: Michael Zucchi <notzed@ximian.com> + * + * Copyright 2004 Novell Inc. (www.novell.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 + */ + +#include <stdlib.h> +#include <string.h> + +#include "camel-debug.h" + +int camel_verbose_debug; + +static GHashTable *debug_table = NULL; + +/** + * camel_debug_init: + * @void: + * + * Init camel debug. Maintain legacy CAMEL_VERBOSE_DEBUG as well as the + * new CAMEL_DEBUG based environment variable interfaces. + * + * CAMEL_VERBOSE_DEBUG is set to a number to turn debug on. + * + * CAMEL_DEBUG is set to a comma separated list of modules to debug. + * The modules can contain module-specific specifiers after a ':', or + * just act as a wildcard for the module or even specifier. e.g. 'imap' + * for imap debug, or 'imap:folder' for imap folder debug. Additionaly, + * ':folder' can be used for a wildcard for any folder operations. + **/ +void camel_debug_init(void) +{ + char *d; + + d = getenv("CAMEL_VERBOSE_DEBUG"); + if (d) + camel_verbose_debug = atoi(d); + + d = g_strdup(getenv("CAMEL_DEBUG")); + if (d) { + char *p; + + debug_table = g_hash_table_new(g_str_hash, g_str_equal); + p = d; + while (*p) { + while (*p && *p != ',') + p++; + if (*p) + *p++ = 0; + g_hash_table_insert(debug_table, d, d); + d = p; + } + + if (g_hash_table_lookup(debug_table, "all")) + camel_verbose_debug = 1; + } +} + +/** + * camel_debug: + * @mode: + * + * Check to see if a debug mode is activated. @mode takes one of two forms, + * a fully qualified 'module:target', or a wildcard 'module' name. It + * returns a boolean to indicate if the module or module and target is + * currently activated for debug output. + * + * Return value: + **/ +gboolean camel_debug(const char *mode) +{ + if (camel_verbose_debug) + return TRUE; + + if (debug_table) { + char *colon; + char *fallback; + + if (g_hash_table_lookup(debug_table, mode)) + return TRUE; + + /* Check for fully qualified debug */ + colon = strchr(mode, ':'); + if (colon) { + fallback = g_alloca(strlen(mode)+1); + strcpy(fallback, mode); + colon = (colon-mode) + fallback; + /* Now check 'module[:*]' */ + *colon = 0; + if (g_hash_table_lookup(debug_table, fallback)) + return TRUE; + /* Now check ':subsystem' */ + *colon = ':'; + if (g_hash_table_lookup(debug_table, colon)) + return TRUE; + } + } + + return FALSE; +} diff --git a/camel/camel-debug.h b/camel/camel-debug.h new file mode 100644 index 0000000000..7ebf1eb9c0 --- /dev/null +++ b/camel/camel-debug.h @@ -0,0 +1,46 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * + * + * Author: Michael Zucchi <notzed@ximian.com> + * + * Copyright 2004 Novell Inc. (www.novell.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_DEBUG_H +#define CAMEL_DEBUG_H 1 + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus }*/ + +#include <glib.h> + +/* This is how the basic debug checking strings should be done */ +#define CAMEL_DEBUG_IMAP "imap" +#define CAMEL_DEBUG_IMAP_FOLDER "imap:folder" + +void camel_debug_init(void); +gboolean camel_debug(const char *mode); + +/* This interface is deprecated */ +extern int camel_verbose_debug; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CAMEL_DEBUG_H */ diff --git a/camel/camel-exception.c b/camel/camel-exception.c index 95e376624a..c67ab66c22 100644 --- a/camel/camel-exception.c +++ b/camel/camel-exception.c @@ -25,12 +25,15 @@ #include <config.h> #endif +#include <stdio.h> #include <glib.h> #include <pthread.h> #include "camel-exception.h" #include "e-util/e-memory.h" +#include "camel-debug.h" + /* i dont know why gthread_mutex stuff even exists, this is easier */ /* also, i'm not convinced mutexes are needed here. But it @@ -204,6 +207,9 @@ camel_exception_setv (CamelException *ex, { va_list args; char *old; + + if (camel_debug("exception")) + printf("CamelException.setv(%p, %d, '%s')\n", ex, id, format); if (!ex) return; diff --git a/camel/camel.c b/camel/camel.c index 8241b5b0ac..09ba07caf4 100644 --- a/camel/camel.c +++ b/camel/camel.c @@ -39,8 +39,7 @@ #include "camel-certdb.h" #include "camel-mime-utils.h" #include "camel-provider.h" - -int camel_verbose_debug = 0; +#include "camel-debug.h" static int initialised = FALSE; @@ -76,13 +75,12 @@ camel_init (const char *configdir, gboolean nss_init) if (initialised) return 0; - - if (getenv ("CAMEL_VERBOSE_DEBUG")) - camel_verbose_debug = atoi(getenv("CAMEL_VERBOSE_DEBUG")); - + + camel_debug_init(); + /* initialise global camel_object_type */ camel_object_get_type(); - + camel_mime_utils_init(); camel_operation_init(); camel_provider_init(); diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c index 7db367a8cb..f2b62073a2 100644 --- a/camel/providers/imap/camel-imap-folder.c +++ b/camel/providers/imap/camel-imap-folder.c @@ -1958,7 +1958,8 @@ imap_get_message (CamelFolder *folder, const char *uid, CamelException *ex) CamelMessageInfo *mi; CamelMimeMessage *msg; CamelStream *stream = NULL; - + int retry; + /* If the server doesn't support IMAP4rev1, or we already have * the whole thing cached, fetch it in one piece. */ @@ -1972,74 +1973,84 @@ imap_get_message (CamelFolder *folder, const char *uid, CamelException *ex) _("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 (content_info_incomplete (mi->content)) { - 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; + + /* All this mess is so we silently retry a fetch if we fail with + service_unavailable, without an (equivalent) mess of gotos */ + retry = 0; + do { + msg = NULL; + retry++; + camel_exception_clear(ex); + + /* If we are online, make sure we're also connected */ + if (camel_disco_store_status((CamelDiscoStore *)store) == CAMEL_DISCO_STORE_ONLINE + && !camel_imap_store_connected(store, ex)) + goto fail; + + /* If the message is small, fetch it in one piece. */ + if (mi->size < IMAP_SMALL_BODY_SIZE) { + msg = get_message_simple (imap_folder, uid, NULL, ex); + } else if (content_info_incomplete (mi->content)) { + + /* 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.) + */ + 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")); + goto fail; } - } - if (body) - imap_parse_body ((const char **) &body, folder, mi->content); + response = camel_imap_command (store, folder, ex, "UID FETCH %s BODY", uid); + if (response) { + 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 (fetch_data) - g_datalist_clear (&fetch_data); + if (body) + imap_parse_body ((const char **) &body, folder, mi->content); - camel_imap_response_free (store, response); + if (fetch_data) + g_datalist_clear (&fetch_data); - if (content_info_incomplete (mi->content)) { - /* 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); + camel_imap_response_free (store, response); + + /* 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. + */ + if (content_info_incomplete (mi->content)) + msg = get_message_simple (imap_folder, uid, NULL, ex); + else + msg = get_message (imap_folder, uid, "", mi->content, ex); + } } - } - - msg = get_message (imap_folder, uid, "", mi->content, ex); + } while (msg == NULL + && retry < 2 + && camel_exception_get_id(ex) == CAMEL_EXCEPTION_SERVICE_UNAVAILABLE); + /* FIXME, this shouldn't be done this way. */ - camel_medium_set_header (CAMEL_MEDIUM (msg), "X-Evolution-Source", - store->base_url); + if (msg) + camel_medium_set_header (CAMEL_MEDIUM (msg), "X-Evolution-Source", store->base_url); +fail: camel_folder_summary_info_free (folder->summary, mi); return msg; |