diff options
Diffstat (limited to 'camel/providers/imap/camel-imap-command.c')
-rw-r--r-- | camel/providers/imap/camel-imap-command.c | 96 |
1 files changed, 65 insertions, 31 deletions
diff --git a/camel/providers/imap/camel-imap-command.c b/camel/providers/imap/camel-imap-command.c index 36f88917a8..3c36dbfb03 100644 --- a/camel/providers/imap/camel-imap-command.c +++ b/camel/providers/imap/camel-imap-command.c @@ -3,10 +3,10 @@ /* * Authors: - * Dan Winship <danw@helixcode.com> - * Jeffrey Stedfast <fejj@helixcode.com> + * Dan Winship <danw@ximian.com> + * Jeffrey Stedfast <fejj@ximian.com> * - * Copyright 2000 Helix Code, Inc. (www.helixcode.com) + * Copyright 2000, 2001 Ximian, Inc. * * 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 @@ -37,6 +37,7 @@ #include "camel-imap-utils.h" #include "camel-imap-folder.h" #include "camel-imap-store.h" +#include "camel-imap-private.h" #include <camel/camel-exception.h> static char *imap_read_untagged (CamelImapStore *store, char *line, @@ -70,8 +71,10 @@ 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. + * On success, the store's command_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 @@ -84,6 +87,8 @@ camel_imap_command (CamelImapStore *store, CamelFolder *folder, gchar *cmdbuf; va_list ap; + CAMEL_IMAP_STORE_LOCK (store, command_lock); + /* Check for current folder */ if (folder && (!fmt || folder != store->current_folder)) { CamelImapResponse *response; @@ -94,16 +99,27 @@ camel_imap_command (CamelImapStore *store, CamelFolder *folder, } response = camel_imap_command (store, NULL, ex, "SELECT %S", folder->full_name); - if (!response) + if (!response) { + CAMEL_IMAP_STORE_UNLOCK (store, command_lock); return NULL; + } store->current_folder = folder; camel_object_ref (CAMEL_OBJECT (folder)); camel_imap_folder_selected (folder, response, ex); - if (!fmt) + if (!fmt) { + /* This undoes the level of locking we did, + * but not the level of locking associated with + * "response". + */ + CAMEL_IMAP_STORE_UNLOCK (store, command_lock); return response; + } - camel_imap_response_free (response); + /* Contrariwise, this undoes "response"s lock, + * but not our own. + */ + camel_imap_response_free (store, response); } /* Send the command */ @@ -115,8 +131,10 @@ camel_imap_command (CamelImapStore *store, CamelFolder *folder, "A%.5d %s\r\n", store->command++, cmdbuf); g_free (cmdbuf); - if (camel_exception_is_set (ex)) + if (camel_exception_is_set (ex)) { + CAMEL_IMAP_STORE_UNLOCK (store, command_lock); return NULL; + } /* Read the response. */ return imap_read_response (store, ex); @@ -133,15 +151,18 @@ camel_imap_command (CamelImapStore *store, CamelFolder *folder, * * This function assumes you have an exclusive lock on the remote stream. * - * Return value: as for camel_imap_command() + * Return value: as for camel_imap_command(). On failure, the store's + * command_lock will be released. **/ CamelImapResponse * camel_imap_command_continuation (CamelImapStore *store, CamelException *ex, const char *cmdbuf) { if (camel_remote_store_send_string (CAMEL_REMOTE_STORE (store), ex, - "%s\r\n", cmdbuf) < 0) + "%s\r\n", cmdbuf) < 0) { + CAMEL_IMAP_STORE_UNLOCK (store, command_lock); return NULL; + } return imap_read_response (store, ex); } @@ -155,8 +176,10 @@ imap_read_response (CamelImapStore *store, CamelException *ex) /* Read first line */ if (camel_remote_store_recv_line (CAMEL_REMOTE_STORE (store), - &respbuf, ex) < 0) + &respbuf, ex) < 0) { + CAMEL_IMAP_STORE_UNLOCK (store, command_lock); return NULL; + } response = g_new0 (CamelImapResponse, 1); response->folder = store->current_folder; @@ -186,7 +209,7 @@ imap_read_response (CamelImapStore *store, CamelException *ex) } if (!respbuf || camel_exception_is_set (ex)) { - camel_imap_response_free (response); + camel_imap_response_free (store, response); return NULL; } @@ -208,7 +231,7 @@ imap_read_response (CamelImapStore *store, CamelException *ex) camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, _("Unexpected response from IMAP " "server: %s"), respbuf); - camel_imap_response_free (response); + camel_imap_response_free (store, response); return NULL; } @@ -216,7 +239,7 @@ imap_read_response (CamelImapStore *store, CamelException *ex) camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, _("IMAP command failed: %s"), retcode ? retcode : _("Unknown error")); - camel_imap_response_free (response); + camel_imap_response_free (store, response); return NULL; } @@ -347,13 +370,14 @@ imap_read_untagged (CamelImapStore *store, char *line, CamelException *ex) /** * camel_imap_response_free: - * @response: a CamelImapResponse: + * @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. + * EXPUNGE and EXISTS responses in it. Releases @store's command_lock. **/ void -camel_imap_response_free (CamelImapResponse *response) +camel_imap_response_free (CamelImapStore *store, CamelImapResponse *response) { int i, number, exists = 0; GArray *expunged = NULL; @@ -397,40 +421,47 @@ camel_imap_response_free (CamelImapResponse *response) } g_free (response); + CAMEL_IMAP_STORE_UNLOCK (store, command_lock); } /** - * camel_imap_response_free: + * 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. + * responses. Releases @store's command lock. **/ void -camel_imap_response_free_without_processing (CamelImapResponse *response) +camel_imap_response_free_without_processing (CamelImapStore *store, + CamelImapResponse *response) { if (response->folder) { camel_object_unref (CAMEL_OBJECT (response->folder)); response->folder = NULL; } - camel_imap_response_free (response); + 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. + * doesn't contain the right information, the function will set @ex + * and return %NULL. Either way, @response will be freed and the + * store's command_lock released. * * Return value: the desired response string, which the caller must free. **/ char * -camel_imap_response_extract (CamelImapResponse *response, const char *type, +camel_imap_response_extract (CamelImapStore *store, + CamelImapResponse *response, + const char *type, CamelException *ex) { int len = strlen (type), i; @@ -457,24 +488,26 @@ camel_imap_response_extract (CamelImapResponse *response, const char *type, "%s information"), type); } - camel_imap_response_free (response); + 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 and return %NULL. Either way, - * @response will be freed. + * response, the function will set @ex, release @store's command_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 (CamelImapResponse *response, +camel_imap_response_extract_continuation (CamelImapStore *store, + CamelImapResponse *response, CamelException *ex) { char *status; @@ -482,14 +515,15 @@ camel_imap_response_extract_continuation (CamelImapResponse *response, if (response->status && !strncmp (response->status, "+ ", 2)) { status = response->status; response->status = NULL; - camel_imap_response_free (response); + CAMEL_IMAP_STORE_LOCK (store, command_lock); + 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 (response); + camel_imap_response_free (store, response); return NULL; } |