From 0d074947b910663afcd24fd740bb26a6ae7fc56d Mon Sep 17 00:00:00 2001 From: Jeffrey Stedfast Date: Sat, 12 Aug 2000 01:36:31 +0000 Subject: New convenience function for multi-transactional commands (opening 2000-08-11 Jeffrey Stedfast * providers/imap/camel-imap-store.c (camel_imap_command_preliminary): New convenience function for multi-transactional commands (opening request) (camel_imap_command_continuation): New convenience function for multi-transactional commands (followup data) svn path=/trunk/; revision=4762 --- camel/ChangeLog | 8 ++ camel/providers/imap/camel-imap-folder.c | 53 ++++----- camel/providers/imap/camel-imap-store.c | 177 +++++++++++++++++++++++++++++++ camel/providers/imap/camel-imap-store.h | 12 ++- 4 files changed, 217 insertions(+), 33 deletions(-) diff --git a/camel/ChangeLog b/camel/ChangeLog index 8576606d12..e4ba89390a 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,3 +1,11 @@ +2000-08-11 Jeffrey Stedfast + + * providers/imap/camel-imap-store.c + (camel_imap_command_preliminary): New convenience function for + multi-transactional commands (opening request) + (camel_imap_command_continuation): New convenience function for + multi-transactional commands (followup data) + 2000-08-11 Christopher James Lahey * providers/mh/camel-mh-folder.c: Fixed a warning. diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c index a752bee56f..894b7a0865 100644 --- a/camel/providers/imap/camel-imap-folder.c +++ b/camel/providers/imap/camel-imap-folder.c @@ -141,12 +141,12 @@ camel_imap_folder_init (gpointer object, gpointer klass) { CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (object); CamelFolder *folder = CAMEL_FOLDER (object); - + folder->can_hold_messages = TRUE; folder->can_hold_folders = TRUE; folder->has_summary_capability = TRUE; - folder->has_search_capability = FALSE; /* FIXME: this should be TRUE but it's not yet implemented */ - + folder->has_search_capability = TRUE; + imap_folder->summary = NULL; imap_folder->summary_hash = NULL; imap_folder->lsub = NULL; @@ -213,7 +213,7 @@ imap_summary_free (GPtrArray **summary) g_free (info); info = NULL; } - + g_ptr_array_free (array, TRUE); *summary = NULL; } @@ -238,10 +238,10 @@ imap_finalize (CamelObject *object) gint max, i; imap_folder_summary_free (imap_folder); - + if (imap_folder->lsub) { max = imap_folder->lsub->len; - + for (i = 0; i < max; i++) { g_free (imap_folder->lsub->pdata[i]); imap_folder->lsub->pdata[i] = NULL; @@ -261,13 +261,13 @@ imap_init (CamelFolder *folder, CamelStore *parent_store, CamelFolder *parent_fo parent_class->init (folder, parent_store, parent_folder, name, separator, path_begins_with_sep, ex); if (camel_exception_get_id (ex)) return; - + /* we assume that the parent init method checks for the existance of @folder */ folder->can_hold_messages = TRUE; folder->can_hold_folders = TRUE; folder->has_summary_capability = TRUE; - folder->has_search_capability = TRUE; /* FIXME: this should be TRUE 'cept it ain't implemented yet */ + folder->has_search_capability = TRUE; /* some IMAP daemons support user-flags * * I would not, however, rely on this feature as * @@ -301,7 +301,7 @@ imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex) max = imap_folder->summary->len; for (i = 0; i < max; i++) { CamelMessageInfo *info; - + info = (CamelMessageInfo *) g_ptr_array_index (imap_folder->summary, i); if (info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) { char *flags; @@ -347,9 +347,9 @@ imap_expunge (CamelFolder *folder, CamelException *ex) CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder); gchar *node, *result; gint i, status, recent = -1; - + g_return_if_fail (folder != NULL); - + imap_sync (folder, FALSE, ex); status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder, @@ -365,7 +365,7 @@ imap_expunge (CamelFolder *folder, CamelException *ex) g_free (result); return; } - + /* determine which messages were successfully expunged */ node = result; for (i = 0; node; i++) { @@ -438,8 +438,6 @@ imap_expunge (CamelFolder *folder, CamelException *ex) } g_free (result); - - /*imap_folder_summary_free (imap_folder);*/ camel_imap_folder_changed (folder, recent, ex); } @@ -527,13 +525,13 @@ imap_get_unread_message_count (CamelFolder *folder) CamelMessageInfo *info; GPtrArray *infolist; gint i, count = 0; - + g_return_val_if_fail (folder != NULL, 0); - + /* If we don't have a message count, return 0 */ if (!imap_folder->summary) return 0; - + infolist = imap_get_summary (folder); for (i = 0; i < infolist->len; i++) { @@ -541,7 +539,7 @@ imap_get_unread_message_count (CamelFolder *folder) if (!(info->flags & CAMEL_MESSAGE_SEEN)) count++; } - + return count; } @@ -553,21 +551,12 @@ imap_append_message (CamelFolder *folder, CamelMimeMessage *message, const Camel CamelStreamMem *mem; gchar *result, *folder_path, *dir_sep, *flagstr = NULL; gint status; - + g_return_if_fail (folder != NULL); g_return_if_fail (message != NULL); - + /* write the message to a CamelStreamMem so we can get it's size */ - mem = CAMEL_STREAM_MEM (camel_stream_mem_new ()); - if (camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), CAMEL_STREAM (mem)) == -1) { - CamelService *service = CAMEL_SERVICE (folder->parent_store); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - "Could not APPEND message to IMAP server %s: %s.", - service->url->host, - g_strerror (errno)); - - return; - } + mem = CAMEL_STREAM_MEM (CAMEL_DATA_WRAPPER (message)->stream); mem->buffer = g_byte_array_append (mem->buffer, g_strdup ("\r\n"), 3); @@ -1516,7 +1505,7 @@ imap_set_message_flags (CamelFolder *folder, const char *uid, guint32 flags, gui info->flags = (info->flags & ~flags) | (set & flags) | CAMEL_MESSAGE_FOLDER_FLAGGED; /*gtk_signal_emit_by_name (GTK_OBJECT (folder), "message_changed", uid);*/ - camel_object_trigger_event (CAMEL_OBJECT (folder), "message_changed", (char *) uid); + camel_object_trigger_event (CAMEL_OBJECT (folder), "message_changed", (gpointer *) uid); } static gboolean @@ -1529,7 +1518,7 @@ static void imap_set_message_user_flag (CamelFolder *folder, const char *uid, const char *name, gboolean value) { /*gtk_signal_emit_by_name (GTK_OBJECT (folder), "message_changed", uid);*/ - camel_object_trigger_event (CAMEL_OBJECT (folder), "message_changed", (char *) uid); + camel_object_trigger_event (CAMEL_OBJECT (folder), "message_changed", (gpointer *) uid); } void diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c index 374107250d..6eb03e9db4 100644 --- a/camel/providers/imap/camel-imap-store.c +++ b/camel/providers/imap/camel-imap-store.c @@ -968,3 +968,180 @@ camel_imap_command_extended (CamelImapStore *store, CamelFolder *folder, char ** return status; } + +/** + * camel_imap_command_preliminary: Send a preliminary command to the + * IMAP server. + * @store: the IMAP store + * @ret: a pointer to return the full server response in + * @cmdid: a pointer to return the command identifier (for use in + * camel_imap_command_continuation) + * @fmt: a printf-style format string, followed by arguments + * + * This camel method sends a preliminary IMAP command specified by + * @fmt and the following arguments to the IMAP store specified by + * @store. This function is meant for use with multi-transactional + * IMAP communications like Kerberos authentication and APPEND. + * + * If the caller passed a non-NULL pointer for @ret, + * camel_imap_command_preliminary will set it to point to a buffer + * containing the rest of the response from the IMAP server. The + * caller function is responsible for freeing @ret. + * + * Return value: one of CAMEL_IMAP_PLUS or CAMEL_IMAP_FAIL + * + * Note: on success (CAMEL_IMAP_PLUS), you will need to follow up with + * a camel_imap_command_continuation call. + **/ +gint +camel_imap_command_preliminary (CamelImapStore *store, char **ret, char **cmdid, char *fmt, ...) +{ + gchar *cmdbuf, *respbuf; + gint status = CAMEL_IMAP_OK; + va_list app; + + /* Create the command */ + *cmdid = g_strdup_printf ("A%.5d", store->command++); + va_start (app, fmt); + cmdbuf = g_strdup_vprintf (fmt, app); + va_end (app); + + d(fprintf (stderr, "sending : %s %s\r\n", *cmdid, cmdbuf)); + + if (camel_stream_printf (store->ostream, "%s %s\r\n", *cmdid, cmdbuf) == -1) { + g_free (cmdbuf); + + if (ret) + *ret = g_strdup (strerror (errno)); + + return CAMEL_IMAP_FAIL; + } + g_free (cmdbuf); + + respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (store->istream)); + + if (respbuf) { + switch (*respbuf) { + case '+': + status = CAMEL_IMAP_PLUS; + break; + default: + status = camel_imap_status (*cmdid, respbuf); + } + + if (ret) + *ret = g_strdup (imap_next_word (respbuf)); + } else { + status = CAMEL_IMAP_FAIL; + if (ret) + *ret = NULL; + } + + return status; +} + +/** + * camel_imap_command_continuation: Handle another transaction with the IMAP + * server and possibly get a multi-line response. + * @store: the IMAP store + * @cmdid: The command identifier returned from camel_imap_command_preliminary + * @ret: a pointer to return the full server response in + * @cstream: a CamelStream containing a continuation response. + * + * This method is for sending continuing responses to the IMAP server. Meant + * to be used as a followup to camel_imap_command_preliminary. + * + * Return value: one of CAMEL_IMAP_PLUS (command requires additional data), + * CAMEL_IMAP_OK (command executed successfully), + * CAMEL_IMAP_NO (operational error message), + * CAMEL_IMAP_BAD (error message from the server), or + * CAMEL_IMAP_FAIL (a protocol-level error occurred, and Camel is uncertain + * of the result of the command.) + **/ +gint +camel_imap_command_continuation (CamelImapStore *store, char *cmdid, char **ret, CamelStream *cstream) +{ + gint len = 0, status = CAMEL_IMAP_OK; + gchar *respbuf; + GPtrArray *data; + int i; + + d(fprintf (stderr, "sending continuation stream\r\n")); + + if (camel_stream_write_to_stream (cstream, store->ostream) == -1) { + *ret = g_strdup (strerror (errno)); + + return CAMEL_IMAP_FAIL; + } + + data = g_ptr_array_new (); + + while (TRUE) { + CamelStreamBuffer *stream = CAMEL_STREAM_BUFFER (store->istream); + + respbuf = camel_stream_buffer_read_line (stream); + if (!respbuf || *respbuf == '+' || !strncmp (respbuf, cmdid, strlen (cmdid))) { + /* IMAP's last response starts with our command id */ + d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)")); + + break; + } + + d(fprintf (stderr, "received: %s\n", respbuf)); + + g_ptr_array_add (data, respbuf); + len += strlen (respbuf) + 1; + } + + if (respbuf) { + switch (*respbuf) { + case '+': + status = CAMEL_IMAP_PLUS; + break; + default: + g_ptr_array_add (data, respbuf); + len += strlen (respbuf) + 1; + + status = camel_imap_status (cmdid, respbuf); + } + } else { + status = CAMEL_IMAP_FAIL; + } + + if (status == CAMEL_IMAP_OK || status == CAMEL_IMAP_PLUS) { + char *p; + + *ret = g_malloc0 (len + 1); + + for (i = 0, p = *ret; i < data->len; i++) { + char *ptr, *datap; + + datap = (char *) data->pdata[i]; + ptr = (*datap == '.') ? datap + 1 : datap; + len = strlen (ptr); + memcpy (p, ptr, len); + p += len; + *p++ = '\n'; + } + *p = '\0'; + } else { + if (status != CAMEL_IMAP_FAIL && respbuf) { + char *word; + + word = imap_next_word (respbuf); + + if (*respbuf == '-') + *ret = g_strdup (word); + else + *ret = g_strdup (imap_next_word (word)); + } else { + *ret = NULL; + } + } + + for (i = 0; i < data->len; i++) + g_free (data->pdata[i]); + g_ptr_array_free (data, TRUE); + + return status; +} diff --git a/camel/providers/imap/camel-imap-store.h b/camel/providers/imap/camel-imap-store.h index a860fb84bd..ce572ff45d 100644 --- a/camel/providers/imap/camel-imap-store.h +++ b/camel/providers/imap/camel-imap-store.h @@ -75,11 +75,21 @@ void camel_imap_store_close (CamelImapStore *store, gboolean expunge, CamelExcep /* support functions */ -enum { CAMEL_IMAP_OK = 0, CAMEL_IMAP_NO, CAMEL_IMAP_BAD, CAMEL_IMAP_FAIL }; +enum { + CAMEL_IMAP_OK = 0, + CAMEL_IMAP_NO, + CAMEL_IMAP_BAD, + CAMEL_IMAP_PLUS, + CAMEL_IMAP_FAIL +}; gint camel_imap_command (CamelImapStore *store, CamelFolder *folder, char **ret, char *fmt, ...); gint camel_imap_command_extended (CamelImapStore *store, CamelFolder *folder, char **ret, char *fmt, ...); +/* multi-transactional commands... */ +gint camel_imap_command_preliminary (CamelImapStore *store, char **ret, char **cmdid, char *fmt, ...); +gint camel_imap_command_continuation (CamelImapStore *store, char *cmdid, char **ret, CamelStream *cstream); + /* Standard Camel function */ CamelType camel_imap_store_get_type (void); -- cgit