diff options
author | Not Zed <NotZed@HelixCode.com> | 2000-12-24 08:46:20 +0800 |
---|---|---|
committer | Michael Zucci <zucchi@src.gnome.org> | 2000-12-24 08:46:20 +0800 |
commit | 6de256c2a2b23f30d35e4a2213ad5839bf141d06 (patch) | |
tree | a34d8be64c0718070c4e1ea9548282912f37b387 /camel/providers/imap | |
parent | 6183d89039ba67a7f3869f460c13aff09a548471 (diff) | |
download | gsoc2013-evolution-6de256c2a2b23f30d35e4a2213ad5839bf141d06.tar.gz 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.am | 3 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-auth.c | 15 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-command.c | 5 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-folder.c | 233 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-folder.h | 2 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-private.h | 74 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-search.c | 32 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-store.c | 55 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-store.h | 3 |
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; |