aboutsummaryrefslogtreecommitdiffstats
path: root/camel/providers/imap
diff options
context:
space:
mode:
authorNot Zed <NotZed@HelixCode.com>2000-12-24 08:46:20 +0800
committerMichael Zucci <zucchi@src.gnome.org>2000-12-24 08:46:20 +0800
commit6de256c2a2b23f30d35e4a2213ad5839bf141d06 (patch)
treea34d8be64c0718070c4e1ea9548282912f37b387 /camel/providers/imap
parent6183d89039ba67a7f3869f460c13aff09a548471 (diff)
downloadgsoc2013-evolution-6de256c2a2b23f30d35e4a2213ad5839bf141d06.tar
gsoc2013-evolution-6de256c2a2b23f30d35e4a2213ad5839bf141d06.tar.gz
gsoc2013-evolution-6de256c2a2b23f30d35e4a2213ad5839bf141d06.tar.bz2
gsoc2013-evolution-6de256c2a2b23f30d35e4a2213ad5839bf141d06.tar.lz
gsoc2013-evolution-6de256c2a2b23f30d35e4a2213ad5839bf141d06.tar.xz
gsoc2013-evolution-6de256c2a2b23f30d35e4a2213ad5839bf141d06.tar.zst
gsoc2013-evolution-6de256c2a2b23f30d35e4a2213ad5839bf141d06.zip
Lock the command channel while searching. (imap_body_contains): If
2000-12-24 Not Zed <NotZed@HelixCode.com> * providers/imap/camel-imap-search.c (imap_body_contains): Lock the command channel while searching. (imap_body_contains): If performing a whole uid search, then add references to our own summary items, dont look it up in the folder. This way they can't vanish unexpectedly. * providers/imap/camel-imap-folder.h (CamelImapFolder): Added a private field. * providers/imap/camel-imap-private.h: Added lock for imap searches. * Merge from camel-mt-branch. * providers/imap/camel-imap-folder.c (imap_update_summary): Merge fix, use the folder->summary. (imap_get_message_flags, imap_set_message_flags, imap_get_message_user_flag, imap_set_message_user_flag): Removed again. (camel_imap_folder_init): Setup private data/lock. (imap_finalize): Free private data/search lock. (imap_search_free): Lock the search_lock. (imap_search_by_expression): Lock the search lock when using the search object. Also copy/ref hte summary, rather than getting it directly. (imap_refresh_info): Free any info lookups. Use folder->summary not imap_folder->summary. And lock around commands. svn path=/trunk/; revision=7150
Diffstat (limited to 'camel/providers/imap')
-rw-r--r--camel/providers/imap/Makefile.am3
-rw-r--r--camel/providers/imap/camel-imap-auth.c15
-rw-r--r--camel/providers/imap/camel-imap-command.c5
-rw-r--r--camel/providers/imap/camel-imap-folder.c233
-rw-r--r--camel/providers/imap/camel-imap-folder.h2
-rw-r--r--camel/providers/imap/camel-imap-private.h74
-rw-r--r--camel/providers/imap/camel-imap-search.c32
-rw-r--r--camel/providers/imap/camel-imap-store.c55
-rw-r--r--camel/providers/imap/camel-imap-store.h3
9 files changed, 248 insertions, 174 deletions
diff --git a/camel/providers/imap/Makefile.am b/camel/providers/imap/Makefile.am
index 03dec12608..35a4a97e77 100644
--- a/camel/providers/imap/Makefile.am
+++ b/camel/providers/imap/Makefile.am
@@ -42,6 +42,9 @@ libcamelimapinclude_HEADERS = \
libcamelimap_la_LDFLAGS = $(KRB4_LDFLAGS) -version-info 0:0:0
+noinst_HEADERS = \
+ camel-imap-private.h
+
EXTRA_DIST = libcamelimap.urls
diff --git a/camel/providers/imap/camel-imap-auth.c b/camel/providers/imap/camel-imap-auth.c
index c510eaf01c..42abd1fa55 100644
--- a/camel/providers/imap/camel-imap-auth.c
+++ b/camel/providers/imap/camel-imap-auth.c
@@ -42,6 +42,10 @@
#include "camel-imap-command.h"
#include "camel-imap-utils.h"
+#include "camel-imap-private.h"
+
+#ifdef HAVE_KRB4
+
static char *
base64_encode_simple (const char *data, int len)
{
@@ -66,7 +70,6 @@ base64_decode_simple (char *data, int len)
(unsigned char *)data, &state, &save);
}
-#ifdef HAVE_KRB4
#define IMAP_KERBEROS_V4_PROTECTION_NONE 1
#define IMAP_KERBEROS_V4_PROTECTION_INTEGRITY 2
#define IMAP_KERBEROS_V4_PROTECTION_PRIVACY 4
@@ -85,14 +88,17 @@ imap_try_kerberos_v4_auth (CamelImapStore *store, CamelException *ex)
des_cblock session;
des_key_schedule schedule;
+ CAMEL_IMAP_STORE_LOCK(store, command_lock);
+
/* The kickoff. */
response = camel_imap_command (store, NULL, ex,
"AUTHENTICATE KERBEROS_V4");
if (!response)
- return FALSE;
+ goto fail;
resp = camel_imap_response_extract_continuation (response, ex);
if (!resp)
- return FALSE;
+ goto fail;
+
data = imap_next_word (resp);
/* First server response is a base64-encoded 32-bit random number
@@ -182,6 +188,7 @@ imap_try_kerberos_v4_auth (CamelImapStore *store, CamelException *ex)
if (!response)
goto lose;
camel_imap_response_free (response);
+ CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
return TRUE;
break_and_lose:
@@ -197,6 +204,8 @@ imap_try_kerberos_v4_auth (CamelImapStore *store, CamelException *ex)
camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
_("Bad authentication response from server."));
}
+fail:
+ CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
return FALSE;
}
#endif /* HAVE_KRB4 */
diff --git a/camel/providers/imap/camel-imap-command.c b/camel/providers/imap/camel-imap-command.c
index b61c9f8cd3..df27fba0fb 100644
--- a/camel/providers/imap/camel-imap-command.c
+++ b/camel/providers/imap/camel-imap-command.c
@@ -67,6 +67,9 @@ static char *imap_command_strdup_vprintf (CamelImapStore *store,
* and quoted strings otherwise. (%S does not support strings that
* contain newlines.)
*
+ * This function assumes you have an exclusive lock on the command
+ * channel/stream.
+ *
* 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().
@@ -120,6 +123,8 @@ camel_imap_command (CamelImapStore *store, CamelFolder *folder,
* This method is for sending continuing responses to the IMAP server
* after camel_imap_command returns a CAMEL_IMAP_PLUS response.
*
+ * This function assumes you have an exclusive lock on the remote stream.
+ *
* Return value: as for camel_imap_command()
**/
CamelImapResponse *
diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c
index 9da5103b68..952e28faa7 100644
--- a/camel/providers/imap/camel-imap-folder.c
+++ b/camel/providers/imap/camel-imap-folder.c
@@ -56,6 +56,7 @@
#include "camel-mime-filter-crlf.h"
#include "camel-exception.h"
#include "camel-mime-utils.h"
+#include "camel-imap-private.h"
#define d(x) x
@@ -69,10 +70,6 @@ static void imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex
static const char *imap_get_full_name (CamelFolder *folder);
static void imap_expunge (CamelFolder *folder, CamelException *ex);
-/* message counts */
-static gint imap_get_message_count (CamelFolder *folder);
-static gint imap_get_unread_message_count (CamelFolder *folder);
-
/* message manipulation */
static CamelMimeMessage *imap_get_message (CamelFolder *folder, const gchar *uid,
CamelException *ex);
@@ -84,10 +81,6 @@ static void imap_move_message_to (CamelFolder *source, const char *uid,
CamelFolder *destination, CamelException *ex);
/* summary info */
-static GPtrArray *imap_get_uids (CamelFolder *folder);
-static GPtrArray *imap_get_summary (CamelFolder *folder);
-static const CamelMessageInfo *imap_get_message_info (CamelFolder *folder, const char *uid);
-
static void imap_update_summary (CamelFolder *folder, int first, int last,
CamelFolderChangeInfo *changes,
CamelException *ex);
@@ -119,27 +112,13 @@ camel_imap_folder_class_init (CamelImapFolderClass *camel_imap_folder_class)
camel_folder_class->expunge = imap_expunge;
camel_folder_class->get_full_name = imap_get_full_name;
- camel_folder_class->get_uids = imap_get_uids;
- camel_folder_class->free_uids = camel_folder_free_nop;
-
- camel_folder_class->get_message_count = imap_get_message_count;
- camel_folder_class->get_unread_message_count = imap_get_unread_message_count;
camel_folder_class->get_message = imap_get_message;
camel_folder_class->append_message = imap_append_message;
camel_folder_class->copy_message_to = imap_copy_message_to;
camel_folder_class->move_message_to = imap_move_message_to;
- camel_folder_class->get_summary = imap_get_summary;
- camel_folder_class->get_message_info = imap_get_message_info;
- camel_folder_class->free_summary = camel_folder_free_nop;
-
camel_folder_class->search_by_expression = imap_search_by_expression;
camel_folder_class->search_free = imap_search_free;
-
- camel_folder_class->get_message_flags = imap_get_message_flags;
- camel_folder_class->set_message_flags = imap_set_message_flags;
- camel_folder_class->get_message_user_flag = imap_get_message_user_flag;
- camel_folder_class->set_message_user_flag = imap_set_message_user_flag;
}
static void
@@ -151,7 +130,11 @@ camel_imap_folder_init (gpointer object, gpointer klass)
folder->has_summary_capability = TRUE;
folder->has_search_capability = TRUE;
- imap_folder->summary = NULL;
+ folder->summary = NULL;
+ imap_folder->priv = g_malloc0(sizeof(*imap_folder->priv));
+#ifdef ENABLE_THREADS
+ imap_folder->priv->search_lock = g_mutex_new();
+#endif
}
CamelType
@@ -188,7 +171,10 @@ camel_imap_folder_new (CamelStore *parent, const char *folder_name,
camel_folder_construct (folder, parent, folder_name, short_name);
+ CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
response = camel_imap_command (imap_store, folder, ex, NULL);
+ CAMEL_IMAP_STORE_UNLOCK(imap_store, command_lock);
+
if (!response) {
camel_object_unref ((CamelObject *)folder);
return NULL;
@@ -213,8 +199,8 @@ camel_imap_folder_new (CamelStore *parent, const char *folder_name,
}
camel_imap_response_free (response);
- imap_folder->summary = camel_imap_summary_new (summary_file, validity);
- if (!imap_folder->summary) {
+ folder->summary = camel_imap_summary_new (summary_file, validity);
+ if (!folder->summary) {
camel_object_unref (CAMEL_OBJECT (folder));
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
_("Could not load summary for %s"),
@@ -236,9 +222,13 @@ imap_finalize (CamelObject *object)
{
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (object);
- camel_object_unref ((CamelObject *)imap_folder->summary);
if (imap_folder->search)
camel_object_unref ((CamelObject *)imap_folder->search);
+
+#ifdef ENABLE_THREADS
+ g_mutex_free(imap_folder->priv->search_lock);
+#endif
+ g_free(imap_folder->priv);
}
static void
@@ -262,9 +252,11 @@ imap_refresh_info (CamelFolder *folder, CamelException *ex)
/* Get UIDs and flags of all messages. */
if (imap_folder->exists) {
+ CAMEL_IMAP_STORE_LOCK(store, command_lock);
response = camel_imap_command (store, folder, ex,
"FETCH 1:%d (UID FLAGS)",
imap_folder->exists);
+ CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
if (!response) {
camel_folder_change_info_free (changes);
return;
@@ -298,18 +290,21 @@ imap_refresh_info (CamelFolder *folder, CamelException *ex)
* the UID in the folder, that it means the message was
* deleted on the server, so we remove it from the summary.
*/
- summary_len = camel_folder_summary_count (imap_folder->summary);
+ summary_len = camel_folder_summary_count (folder->summary);
for (i = 0; i < summary_len && i < imap_folder->exists; i++) {
- info = camel_folder_summary_index (imap_folder->summary, i);
- iinfo = (CamelImapMessageInfo *)info;
-
/* Shouldn't happen, but... */
if (!new[i].uid)
continue;
+ info = camel_folder_summary_index (imap_folder->summary, i);
+ iinfo = (CamelImapMessageInfo *)info;
+
if (strcmp (camel_message_info_uid (info), new[i].uid) != 0) {
camel_folder_change_info_remove_uid (changes, camel_message_info_uid (info));
camel_folder_summary_remove (imap_folder->summary, info);
+ camel_folder_summary_info_free(folder->summary, info);
+ folder_changed = TRUE;
+ g_free (new[i].uid);
i--;
summary_len--;
continue;
@@ -328,14 +323,17 @@ imap_refresh_info (CamelFolder *folder, CamelException *ex)
camel_folder_change_info_change_uid (changes, new[i].uid);
}
+ camel_folder_summary_info_free(folder->summary, info);
+
g_free (new[i].uid);
}
/* Remove any leftover cached summary messages. */
while (summary_len > i + 1) {
- info = camel_folder_summary_index (imap_folder->summary, --summary_len);
+ info = camel_folder_summary_index (folder->summary, --summary_len);
camel_folder_change_info_remove_uid (changes, camel_message_info_uid (info));
- camel_folder_summary_remove (imap_folder->summary, info);
+ camel_folder_summary_remove (folder->summary, info);
+ camel_folder_summary_info_free(folder->summary, info);
}
/* Add any new folder messages. */
@@ -360,40 +358,48 @@ static void
imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
{
CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
- CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
+ /*CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);*/
CamelImapResponse *response;
int i, max;
/* Set the flags on any messages that have changed this session */
- max = camel_folder_summary_count (imap_folder->summary);
+ max = camel_folder_summary_count (folder->summary);
for (i = 0; i < max; i++) {
CamelMessageInfo *info;
- info = camel_folder_summary_index (imap_folder->summary, i);
- if (info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) {
+ info = camel_folder_summary_index (folder->summary, i);
+ if (info && (info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED)) {
char *flags;
flags = imap_create_flag_list (info->flags);
if (flags) {
+ CAMEL_IMAP_STORE_LOCK(store, command_lock);
response = camel_imap_command (
store, folder, ex,
"UID STORE %s FLAGS.SILENT %s",
camel_message_info_uid(info), flags);
+ CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
+
g_free (flags);
- if (!response)
+ if (!response) {
+ camel_folder_summary_info_free(folder->summary, info);
return;
+ }
camel_imap_response_free (response);
}
info->flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED;
}
+ camel_folder_summary_info_free(folder->summary, info);
}
if (expunge) {
+ CAMEL_IMAP_STORE_LOCK(store, command_lock);
response = camel_imap_command (store, folder, ex, "EXPUNGE");
+ CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
camel_imap_response_free (response);
}
- camel_folder_summary_save (imap_folder->summary);
+ camel_folder_summary_save (folder->summary);
}
static void
@@ -417,31 +423,6 @@ imap_get_full_name (CamelFolder *folder)
return folder->full_name;
}
-static gint
-imap_get_message_count (CamelFolder *folder)
-{
- CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
-
- return camel_folder_summary_count (imap_folder->summary);
-}
-
-static gint
-imap_get_unread_message_count (CamelFolder *folder)
-{
- CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
- CamelMessageInfo *info;
- int i, max, count = 0;
-
- max = camel_folder_summary_count (imap_folder->summary);
- for (i = 0; i < max; i++) {
- info = camel_folder_summary_index (imap_folder->summary, i);
- if (!(info->flags & CAMEL_MESSAGE_SEEN))
- count++;
- }
-
- return count;
-}
-
static void
imap_append_message (CamelFolder *folder, CamelMimeMessage *message,
const CamelMessageInfo *info, CamelException *ex)
@@ -476,6 +457,7 @@ imap_append_message (CamelFolder *folder, CamelMimeMessage *message,
camel_object_unref (CAMEL_OBJECT (crlf_filter));
camel_object_unref (CAMEL_OBJECT (memstream));
+ CAMEL_IMAP_STORE_LOCK(store, command_lock);
response = camel_imap_command (store, NULL, ex, "APPEND %S%s%s {%d}",
folder->full_name, flagstr ? " " : "",
flagstr ? flagstr : "", ba->len);
@@ -483,11 +465,13 @@ imap_append_message (CamelFolder *folder, CamelMimeMessage *message,
if (!response) {
g_byte_array_free (ba, TRUE);
+ CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
return;
}
result = camel_imap_response_extract_continuation (response, ex);
if (!result) {
g_byte_array_free (ba, TRUE);
+ CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
return;
}
g_free (result);
@@ -496,6 +480,7 @@ imap_append_message (CamelFolder *folder, CamelMimeMessage *message,
g_byte_array_append (ba, "\0", 3);
response = camel_imap_command_continuation (store, ex, ba->data);
g_byte_array_free (ba, TRUE);
+ CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
if (!response)
return;
camel_imap_response_free (response);
@@ -508,8 +493,11 @@ imap_copy_message_to (CamelFolder *source, const char *uid,
CamelImapStore *store = CAMEL_IMAP_STORE (source->parent_store);
CamelImapResponse *response;
+ CAMEL_IMAP_STORE_LOCK(store, command_lock);
response = camel_imap_command (store, source, ex, "UID COPY %s %S",
uid, destination->full_name);
+ CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
+
camel_imap_response_free (response);
}
@@ -520,8 +508,10 @@ imap_move_message_to (CamelFolder *source, const char *uid,
CamelImapStore *store = CAMEL_IMAP_STORE (source->parent_store);
CamelImapResponse *response;
+ CAMEL_IMAP_STORE_LOCK(store, command_lock);
response = camel_imap_command (store, source, ex, "UID COPY %s %S",
uid, destination->full_name);
+ CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
camel_imap_response_free (response);
if (camel_exception_is_set (ex))
@@ -530,27 +520,6 @@ imap_move_message_to (CamelFolder *source, const char *uid,
camel_folder_delete_message (source, uid);
}
-static GPtrArray *
-imap_get_uids (CamelFolder *folder)
-{
- CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
- const CamelMessageInfo *info;
- GPtrArray *array;
- int i, count;
-
- count = camel_folder_summary_count (imap_folder->summary);
-
- array = g_ptr_array_new ();
- g_ptr_array_set_size (array, count);
-
- for (i = 0; i < count; i++) {
- info = camel_folder_summary_index (imap_folder->summary, i);
- array->pdata[i] = g_strdup (camel_message_info_uid(info));
- }
-
- return array;
-}
-
static CamelMimeMessage *
imap_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex)
{
@@ -561,8 +530,11 @@ imap_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex)
char *result, *mesg, *p;
int len;
+ CAMEL_IMAP_STORE_LOCK(store, command_lock);
response = camel_imap_command (store, folder, ex,
"UID FETCH %s BODY.PEEK[]", uid);
+ CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
+
if (!response)
return NULL;
result = camel_imap_response_extract (response, "FETCH", ex);
@@ -622,7 +594,7 @@ imap_update_summary (CamelFolder *folder, int first, int last,
CamelFolderChangeInfo *changes, CamelException *ex)
{
CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
- CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
+ /*CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);*/
CamelImapResponse *response;
GPtrArray *headers = NULL;
char *q, *summary_specifier;
@@ -630,6 +602,7 @@ imap_update_summary (CamelFolder *folder, int first, int last,
int i;
summary_specifier = imap_protocol_get_summary_specifier (store);
+ CAMEL_IMAP_STORE_LOCK(store, command_lock);
if (first == last) {
response = camel_imap_command (store, folder, ex,
"FETCH %d (%s)", first,
@@ -639,6 +612,7 @@ imap_update_summary (CamelFolder *folder, int first, int last,
"FETCH %d:%d (%s)", first,
last, summary_specifier);
}
+ CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
g_free (summary_specifier);
if (!response)
@@ -683,9 +657,10 @@ imap_update_summary (CamelFolder *folder, int first, int last,
/* We can't just call camel_folder_summary_add_from_parser
* because it will assign the wrong UID, and thus get the
* uid hash table wrong and all that. FIXME some day.
+ * Well you can actually now, because you can override next_uid_string(), but
+ * it hasn't been done yet.
*/
- info = camel_folder_summary_info_new_from_header (
- imap_folder->summary, h);
+ info = camel_folder_summary_info_new_from_header(folder->summary, h);
iinfo = (CamelImapMessageInfo *)info;
header_raw_clear (&h);
uid = g_strndup (uid, q - uid);
@@ -708,42 +683,33 @@ imap_update_summary (CamelFolder *folder, int first, int last,
} else
info->size = strtoul (size + 12, NULL, 10);
- camel_folder_summary_add (imap_folder->summary, info);
+ camel_folder_summary_add (folder->summary, info);
}
camel_imap_response_free (response);
}
static GPtrArray *
-imap_get_summary (CamelFolder *folder)
-{
- CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
-
- return imap_folder->summary->messages;
-}
-
-/* get a single message info, by uid */
-static const CamelMessageInfo *
-imap_get_message_info (CamelFolder *folder, const char *uid)
-{
- CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
-
- return camel_folder_summary_uid (imap_folder->summary, uid);
-}
-
-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);
if (!imap_folder->search)
imap_folder->search = camel_imap_search_new ();
camel_folder_search_set_folder (imap_folder->search, folder);
- camel_folder_search_set_summary (
- imap_folder->search, imap_folder->summary->messages);
+ summary = camel_folder_get_summary(folder);
+ camel_folder_search_set_summary(imap_folder->search, summary);
+ uids = camel_folder_search_execute_expression (imap_folder->search, expression, ex);
+
+ CAMEL_IMAP_FOLDER_UNLOCK(folder, search_lock);
- return camel_folder_search_execute_expression (imap_folder->search,
- expression, ex);
+ camel_folder_free_summary(folder, summary);
}
static void
@@ -753,54 +719,11 @@ imap_search_free (CamelFolder *folder, GPtrArray *uids)
g_return_if_fail (imap_folder->search);
- camel_folder_search_free_result (imap_folder->search, uids);
-}
+ CAMEL_IMAP_FOLDER_LOCK(folder, search_lock);
-static guint32
-imap_get_message_flags (CamelFolder *folder, const char *uid)
-{
- const CamelMessageInfo *info;
-
- info = imap_get_message_info (folder, uid);
- g_return_val_if_fail (info != NULL, 0);
-
- return info->flags;
-}
-
-static void
-imap_set_message_flags (CamelFolder *folder, const char *uid, guint32 flags, guint32 set)
-{
- CamelImapFolder *imap_folder = (CamelImapFolder *)folder;
- CamelMessageInfo *info;
- guint32 new;
-
- info = camel_folder_summary_uid (imap_folder->summary, uid);
- g_return_if_fail (info != NULL);
-
- new = (info->flags & ~flags) | (set & flags);
- if (new == info->flags)
- return;
-
- info->flags = new | CAMEL_MESSAGE_FOLDER_FLAGGED;
- camel_folder_summary_touch (imap_folder->summary);
-
- camel_object_trigger_event (CAMEL_OBJECT (folder), "message_changed",
- (gpointer)uid);
-}
-
-static gboolean
-imap_get_message_user_flag (CamelFolder *folder, const char *uid, const char *name)
-{
- /* FIXME */
- return FALSE;
-}
+ camel_folder_search_free_result (imap_folder->search, uids);
-static void
-imap_set_message_user_flag (CamelFolder *folder, const char *uid, const char *name, gboolean value)
-{
- /* FIXME */
- camel_object_trigger_event (CAMEL_OBJECT (folder), "message_changed",
- (gpointer)uid);
+ CAMEL_IMAP_FOLDER_UNLOCK(folder, search_lock);
}
void
diff --git a/camel/providers/imap/camel-imap-folder.h b/camel/providers/imap/camel-imap-folder.h
index 3183a8816d..cff11255c2 100644
--- a/camel/providers/imap/camel-imap-folder.h
+++ b/camel/providers/imap/camel-imap-folder.h
@@ -44,6 +44,8 @@ extern "C" {
typedef struct {
CamelFolder parent_object;
+ struct _CamelImapFolderPrivate *priv;
+
CamelFolderSearch *search;
CamelFolderSummary *summary;
int exists;
diff --git a/camel/providers/imap/camel-imap-private.h b/camel/providers/imap/camel-imap-private.h
new file mode 100644
index 0000000000..95ec3a5a0b
--- /dev/null
+++ b/camel/providers/imap/camel-imap-private.h
@@ -0,0 +1,74 @@
+/* -*- 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@helixcode.com>
+ *
+ * Copyright 1999, 2000 Helix Code, Inc. (http://www.helixcode.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifndef CAMEL_PRIVATE_H
+#define CAMEL_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 */
+
+#include "config.h"
+
+#ifdef ENABLE_THREADS
+#include "e-util/e-msgport.h"
+#endif
+
+struct _CamelImapStorePrivate {
+#ifdef ENABLE_THREADS
+ EMutex *command_lock; /* for locking the command stream for a complete operation */
+#endif
+};
+
+#ifdef ENABLE_THREADS
+#define CAMEL_IMAP_STORE_LOCK(f, l) (e_mutex_lock(((CamelImapStore *)f)->priv->l))
+#define CAMEL_IMAP_STORE_UNLOCK(f, l) (e_mutex_unlock(((CamelImapStore *)f)->priv->l))
+#else
+#define CAMEL_IMAP_STORE_LOCK(f, l)
+#define CAMEL_IMAP_STORE_UNLOCK(f, l)
+#endif
+
+struct _CamelImapFolderPrivate {
+#ifdef ENABLE_THREADS
+ GMutex *search_lock; /* for locking the search object */
+#endif
+};
+
+#ifdef ENABLE_THREADS
+#define CAMEL_IMAP_FOLDER_LOCK(f, l) (g_mutex_lock(((CamelImapFolder *)f)->priv->l))
+#define CAMEL_IMAP_FOLDER_UNLOCK(f, l) (g_mutex_unlock(((CamelImapFolder *)f)->priv->l))
+#else
+#define CAMEL_IMAP_FOLDER_LOCK(f, l)
+#define CAMEL_IMAP_FOLDER_UNLOCK(f, l)
+#endif
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* CAMEL_H */
+
diff --git a/camel/providers/imap/camel-imap-search.c b/camel/providers/imap/camel-imap-search.c
index 1aa6b55bc5..cec0ee1f89 100644
--- a/camel/providers/imap/camel-imap-search.c
+++ b/camel/providers/imap/camel-imap-search.c
@@ -31,6 +31,7 @@
#include "camel-imap-command.h"
#include "camel-imap-folder.h"
#include "camel-imap-search.h"
+#include "camel-imap-private.h"
static ESExpResult *
imap_body_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv,
@@ -72,10 +73,13 @@ imap_body_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv,
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (s->folder);
char *value = argv[0]->value.string;
CamelImapResponse *response;
- char *result, *p, *lasts = NULL;
+ char *result, *p, *lasts = NULL, *real_uid;
const char *uid;
ESExpResult *r;
CamelMessageInfo *info;
+ GHashTable *uid_hash = NULL;
+
+ CAMEL_IMAP_STORE_LOCK(store, command_lock);
if (s->current) {
uid = camel_message_info_uid (s->current);
@@ -91,6 +95,9 @@ imap_body_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv,
"UID SEARCH BODY \"%s\"",
value);
}
+
+ CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
+
if (!response)
return r;
result = camel_imap_response_extract (response, "SEARCH", NULL);
@@ -105,14 +112,27 @@ imap_body_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv,
break;
}
} else {
- /* FIXME: The strings added to the array must be
- * static...
- */
- info = camel_folder_summary_uid (imap_folder->summary, p);
- g_ptr_array_add (r->value.ptrarray, (char *)camel_message_info_uid (info));
+ /* if we need to setup a hash of summary items, this way we get
+ access to the summary memory which is locked for the duration of
+ the search, and wont vanish on us */
+ if (uid_hash == NULL) {
+ int i;
+
+ uid_hash = g_hash_table_new(g_str_hash, g_str_equal);
+ for (i=0;i<s->summary->len;i++) {
+ info = s->summary->pdata[i];
+ g_hash_table_insert(uid_hash, camel_message_info_uid(info), info);
+ }
+ }
+ if (g_hash_table_lookup_extended(uid_hash, p, &real_uid, &info))
+ g_ptr_array_add (r->value.ptrarray, real_uid);
}
}
+ /* we could probably cache this globally, but its probably not worth it */
+ if (uid_hash)
+ g_hash_table_destroy(uid_hash);
+
return r;
}
diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c
index e3bd61af27..8774d783bd 100644
--- a/camel/providers/imap/camel-imap-store.c
+++ b/camel/providers/imap/camel-imap-store.c
@@ -47,6 +47,8 @@
#include "camel-url.h"
#include "string-utils.h"
+#include "camel-imap-private.h"
+
#define d(x) x
/* Specified in RFC 2060 */
@@ -121,6 +123,10 @@ camel_imap_store_finalize (CamelObject *object)
g_hash_table_foreach_remove (imap_store->subscribed_folders,
free_sub, NULL);
g_hash_table_destroy (imap_store->subscribed_folders);
+#ifdef ENABLE_THREADS
+ e_mutex_destroy(imap_store->priv->command_lock);
+#endif
+ g_free(imap_store->priv);
}
static void
@@ -139,6 +145,11 @@ camel_imap_store_init (gpointer object, gpointer klass)
imap_store->connected = FALSE;
imap_store->subscribed_folders = g_hash_table_new (g_str_hash, g_str_equal);
+
+ imap_store->priv = g_malloc0(sizeof(*imap_store->priv));
+#ifdef ENABLE_THREADS
+ imap_store->priv->command_lock = e_mutex_new(E_MUTEX_REC);
+#endif
}
CamelType
@@ -175,6 +186,7 @@ static struct {
{ NULL, 0 }
};
+/* we have remote-store:connect_lock by now */
static gboolean
connect_to_server (CamelService *service, CamelException *ex)
{
@@ -351,10 +363,12 @@ imap_connect (CamelService *service, CamelException *ex)
}
}
+ CAMEL_IMAP_STORE_LOCK(store, command_lock);
response = camel_imap_command (store, NULL, ex,
"LOGIN %S %S",
service->url->user,
service->url->passwd);
+ CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
if (!response) {
errbuf = g_strdup_printf (_("Unable to authenticate "
"to IMAP server.\n%s\n\n"),
@@ -380,6 +394,8 @@ imap_connect (CamelService *service, CamelException *ex)
namespace++;
else
namespace = "";
+
+ CAMEL_IMAP_STORE_LOCK(store, command_lock);
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.
@@ -396,6 +412,8 @@ imap_connect (CamelService *service, CamelException *ex)
"LIST \"\" %S",
namespace);
}
+ CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
+
if (!response)
return FALSE;
@@ -431,7 +449,11 @@ imap_disconnect (CamelService *service, gboolean clean, CamelException *ex)
if (store->connected && clean) {
/* send the logout command */
+
+ /* NB: this lock probably isn't required */
+ CAMEL_IMAP_STORE_LOCK(store, command_lock);
response = camel_imap_command (store, NULL, ex, "LOGOUT");
+ CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
camel_imap_response_free (response);
}
@@ -440,6 +462,7 @@ imap_disconnect (CamelService *service, gboolean clean, CamelException *ex)
return CAMEL_SERVICE_CLASS (remote_store_class)->disconnect (service, clean, ex);
}
+/* NOTE: Must have imap_store::command_lock before calling this */
static gboolean
imap_folder_exists (CamelImapStore *store, const char *folder_name,
gboolean *selectable, char **short_name,
@@ -481,6 +504,7 @@ imap_folder_exists (CamelImapStore *store, const char *folder_name,
return TRUE;
}
+/* NOTE: Must have imap_store::command_lock before calling this */
static gboolean
imap_create (CamelImapStore *store, const char *folder_name,
CamelException *ex)
@@ -503,18 +527,19 @@ get_folder (CamelStore *store, const char *folder_name, guint32 flags,
char *short_name, *summary_file, *p;
gboolean selectable;
+ /* lock around the whole lot to check/create atomically */
+ CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
if (!imap_folder_exists (imap_store, folder_name,
&selectable, &short_name, ex)) {
- if ((flags & CAMEL_STORE_FOLDER_CREATE) == 0)
- return NULL;
-
- if (!imap_create (imap_store, folder_name, ex))
- return NULL;
-
- if (!imap_folder_exists (imap_store, folder_name,
- &selectable, &short_name, ex))
+ if ((flags & CAMEL_STORE_FOLDER_CREATE) == 0
+ || (!imap_create (imap_store, folder_name, ex))
+ || (!imap_folder_exists (imap_store, folder_name,
+ &selectable, &short_name, ex))) {
+ CAMEL_IMAP_STORE_UNLOCK(imap_store, command_lock);
return NULL;
+ }
}
+ CAMEL_IMAP_STORE_UNLOCK(imap_store, command_lock);
if (!selectable) {
camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
@@ -621,8 +646,10 @@ get_folder_info (CamelStore *store, const char *top, gboolean fast,
else
name = "";
}
+ CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
response = camel_imap_command (imap_store, NULL, ex,
"LIST \"\" %S", name);
+ CAMEL_IMAP_STORE_UNLOCK(imap_store, command_lock);
if (!response)
return FALSE;
list = camel_imap_response_extract (response, "LIST", ex);
@@ -642,10 +669,13 @@ get_folder_info (CamelStore *store, const char *top, gboolean fast,
else
pattern = g_strdup_printf ("%s%c", name,
recursive ? '*' : '%');
+ CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
response = camel_imap_command (imap_store, NULL, ex,
"%s \"\" %S",
subscribed_only ? "LSUB" : "LIST",
pattern);
+ CAMEL_IMAP_STORE_UNLOCK(imap_store, command_lock);
+
g_free (pattern);
if (!response)
return NULL;
@@ -694,10 +724,12 @@ get_folder_info (CamelStore *store, const char *top, gboolean fast,
if (!fi->url)
continue;
+ CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
response = camel_imap_command (
imap_store, NULL, NULL,
"STATUS %S (MESSAGES UNSEEN)",
fi->full_name);
+ CAMEL_IMAP_STORE_UNLOCK(imap_store, command_lock);
if (!response)
continue;
status = camel_imap_response_extract (
@@ -757,6 +789,7 @@ subscribe_folder (CamelStore *store, const char *folder_name,
CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
CamelImapResponse *response;
+ CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
response = camel_imap_command (imap_store, NULL, ex,
"SUBSCRIBE %S", folder_name);
if (response) {
@@ -774,9 +807,11 @@ unsubscribe_folder (CamelStore *store, const char *folder_name,
CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
CamelImapResponse *response;
gpointer key, value;
-
+
+ CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
response = camel_imap_command (imap_store, NULL, ex,
"UNSUBSCRIBE %S", folder_name);
+ CAMEL_IMAP_STORE_UNLOCK(imap_store, command_lock);
if (response) {
g_hash_table_lookup_extended (imap_store->subscribed_folders,
folder_name, &key, &value);
@@ -793,6 +828,8 @@ imap_keepalive (CamelRemoteStore *store)
CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
CamelImapResponse *response;
+ CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
response = camel_imap_command (imap_store, NULL, NULL, "NOOP");
+ CAMEL_IMAP_STORE_UNLOCK(imap_store, command_lock);
camel_imap_response_free (response);
}
diff --git a/camel/providers/imap/camel-imap-store.h b/camel/providers/imap/camel-imap-store.h
index 025e28256a..cd93d8eddf 100644
--- a/camel/providers/imap/camel-imap-store.h
+++ b/camel/providers/imap/camel-imap-store.h
@@ -56,7 +56,8 @@ typedef enum {
typedef struct {
CamelRemoteStore parent_object;
-
+ struct _CamelImapStorePrivate *priv;
+
CamelFolder *current_folder;
guint32 command;