diff options
author | Jeffrey Stedfast <fejj@ximian.com> | 2004-03-29 05:12:22 +0800 |
---|---|---|
committer | Jeffrey Stedfast <fejj@src.gnome.org> | 2004-03-29 05:12:22 +0800 |
commit | 53167c89e32be8da8b3dcad4224664a1e0c445f0 (patch) | |
tree | 43cdbf61d37825e765ca45c3ee84c0a01305e9ec /camel | |
parent | a893ddb0aff692547219fcfdefa5c014d1c46425 (diff) | |
download | gsoc2013-evolution-53167c89e32be8da8b3dcad4224664a1e0c445f0.tar.gz gsoc2013-evolution-53167c89e32be8da8b3dcad4224664a1e0c445f0.tar.zst gsoc2013-evolution-53167c89e32be8da8b3dcad4224664a1e0c445f0.zip |
New source files implementing the CamelFolder class for the new IMAP4
2004-03-28 Jeffrey Stedfast <fejj@ximian.com>
* providers/imap4/camel-imap-folder.[c,h]: New source files
implementing the CamelFolder class for the new IMAP4
implementation.
svn path=/trunk/; revision=25215
Diffstat (limited to 'camel')
-rw-r--r-- | camel/ChangeLog | 4 | ||||
-rw-r--r-- | camel/providers/imap4/Makefile.am | 2 | ||||
-rw-r--r-- | camel/providers/imap4/camel-imap-folder.c | 768 | ||||
-rw-r--r-- | camel/providers/imap4/camel-imap-folder.h | 66 |
4 files changed, 840 insertions, 0 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog index adf5c82cde..1b0d58dca6 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,5 +1,9 @@ 2004-03-28 Jeffrey Stedfast <fejj@ximian.com> + * providers/imap4/camel-imap-folder.[c,h]: New source files + implementing the CamelFolder class for the new IMAP4 + implementation. + * providers/imap4/camel-imap-summary.[c,h]: New source files implementing the CamelFolderSummary class for the new IMAP4 implementation. diff --git a/camel/providers/imap4/Makefile.am b/camel/providers/imap4/Makefile.am index fb514aacbb..b94c8f9564 100644 --- a/camel/providers/imap4/Makefile.am +++ b/camel/providers/imap4/Makefile.am @@ -21,6 +21,8 @@ libcamelimap4_la_SOURCES = \ camel-imap-command.h \ camel-imap-engine.c \ camel-imap-engine.h \ + camel-imap-folder.c \ + camel-imap-folder.h \ camel-imap-provider.c \ camel-imap-specials.c \ camel-imap-specials.h \ diff --git a/camel/providers/imap4/camel-imap-folder.c b/camel/providers/imap4/camel-imap-folder.c new file mode 100644 index 0000000000..04af9f3cb8 --- /dev/null +++ b/camel/providers/imap4/camel-imap-folder.c @@ -0,0 +1,768 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* Camel + * Copyright (C) 1999-2004 Jeffrey Stedfast + * + * 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 Street #330, Boston, MA 02111-1307, USA. + */ + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <time.h> + +#include <camel/camel-file-utils.h> +#include <camel/camel-mime-message.h> +#include <camel/camel-stream-mem.h> +#include <camel/camel-stream-filter.h> +#include <camel/camel-mime-filter-crlf.h> + +#include "camel-imap-utils.h" +#include "camel-imap-store.h" +#include "camel-imap-engine.h" +#include "camel-imap-folder.h" +#include "camel-imap-stream.h" +#include "camel-imap-command.h" +#include "camel-imap-summary.h" + +#define d(x) x + +static void camel_imap_folder_class_init (CamelIMAPFolderClass *klass); +static void camel_imap_folder_init (CamelIMAPFolder *folder, CamelIMAPFolderClass *klass); +static void camel_imap_folder_finalize (CamelObject *object); + +static void imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex); +static void imap_expunge (CamelFolder *folder, CamelException *ex); +static CamelMimeMessage *imap_get_message (CamelFolder *folder, const char *uid, CamelException *ex); +static void imap_append_message (CamelFolder *folder, CamelMimeMessage *message, + const CamelMessageInfo *info, char **appended_uid, CamelException *ex); +static void imap_transfer_messages_to (CamelFolder *src, GPtrArray *uids, CamelFolder *dest, + GPtrArray **transferred_uids, gboolean delete_originals, CamelException *ex); + + +static CamelFolderClass *parent_class = NULL; + + +CamelType +camel_imap_folder_get_type (void) +{ + static CamelType type = 0; + + if (!type) { + type = camel_type_register (CAMEL_TYPE_IMAP_FOLDER, + "CamelIMAPFolder", + sizeof (CamelIMAPFolder), + sizeof (CamelIMAPFolderClass), + (CamelObjectClassInitFunc) camel_imap_folder_class_init, + NULL, + (CamelObjectInitFunc) camel_imap_folder_init, + (CamelObjectFinalizeFunc) camel_imap_folder_finalize); + } + + return type; +} + +static void +camel_imap_folder_class_init (CamelIMAPFolderClass *klass) +{ + CamelFolderClass *folder_class = (CamelFolderClass *) klass; + + parent_class = (CamelFolderClass *) camel_type_get_global_classfuncs (CAMEL_FOLDER_TYPE); + + folder_class->sync = imap_sync; + folder_class->expunge = imap_expunge; + folder_class->get_message = imap_get_message; + folder_class->append_message = imap_append_message; + folder_class->transfer_messages_to = imap_transfer_messages_to; +} + +static void +camel_imap_folder_init (CamelIMAPFolder *folder, CamelIMAPFolderClass *klass) +{ + folder->utf7_name = NULL; +} + +static void +camel_imap_folder_finalize (CamelObject *object) +{ + CamelIMAPFolder *folder = (CamelIMAPFolder *) object; + + g_free (folder->utf7_name); +} + + +static struct { + const char *name; + guint32 flag; +} imap_flags[] = { + { "\\Answered", CAMEL_MESSAGE_ANSWERED }, + { "\\Deleted", CAMEL_MESSAGE_DELETED }, + { "\\Draft", CAMEL_MESSAGE_DRAFT }, + { "\\Flagged", CAMEL_MESSAGE_FLAGGED }, + /*{ "Forwarded", CAMEL_MESSAGE_FORWARDED },*/ + { "\\Seen", CAMEL_MESSAGE_SEEN }, +}; + +static int +imap_get_uid_set (CamelIMAPEngine *engine, CamelFolderSummary *summary, GPtrArray *infos, int cur, size_t linelen, char **set) +{ + CamelMessageInfo *info; + guint32 this, prev, next; + gboolean range = FALSE; + GString *uidset; + int scount, i; + size_t len; + + if (engine->maxlentype == CAMEL_IMAP_ENGINE_MAXLEN_LINE) + len = engine->maxlen - linelen; + else + len = engine->maxlen; + + i = cur + 1; + info = (CamelMessageInfo *) infos->pdata[cur]; + fflush (stdout); + uidset = g_string_new (""); + g_string_append (uidset, camel_message_info_uid (info)); + + if (!(i < infos->len)) + goto done; + + scount = summary->messages->len; + + /* init this info */ + for (this = 0; this < scount; this++) { + if (info == summary->messages->pdata[this]) + break; + } + + /* init next info */ + info = (CamelMessageInfo *) infos->pdata[i]; + for (next = this; next < scount; next++) { + if (info == summary->messages->pdata[next]) + break; + } + + for ( ; i < infos->len && uidset->len < len; i++) { + prev = this; + this = next; + + if (i + 1 < infos->len) { + info = infos->pdata[i + 1]; + for (next = this; next < scount; next++) { + if (info == summary->messages->pdata[next]) + break; + } + } else { + next = scount; + } + + if (this == (next - 1) || this == (prev + 1)) { + range = TRUE; + } else { + if (range) { + info = (CamelMessageInfo *) summary->messages->pdata[prev]; + g_string_append_printf (uidset, ":%s", camel_message_info_uid (info)); + range = FALSE; + } + + info = infos->pdata[i]; + g_string_append_printf (uidset, ",%s", camel_message_info_uid (info)); + } + } + + if (range) { + info = (CamelMessageInfo *) summary->messages->pdata[this]; + g_string_append_printf (uidset, ":%s", camel_message_info_uid (info)); + } + + done: + + *set = uidset->str; + g_string_free (uidset, FALSE); + + return (i - cur); +} + +static int +imap_sync_flag (CamelFolder *folder, GPtrArray *infos, char onoff, const char *flag, CamelException *ex) +{ + CamelIMAPEngine *engine = ((CamelIMAPStore *) folder->parent_store)->engine; + CamelIMAPCommand *ic; + int i, id, retval = 0; + char *set = NULL; + + for (i = 0; i < infos->len; ) { + i += imap_get_uid_set (engine, folder->summary, infos, i, 30 + strlen (flag), &set); + + ic = camel_imap_engine_queue (engine, folder, "UID STORE %s %cFLAGS.SILENT (%s)\r\n", set, onoff, flag); + while ((id = camel_imap_engine_iterate (engine)) < ic->id && id != -1) + ; + + g_free (set); + + if (id == -1 || ic->status != CAMEL_IMAP_COMMAND_COMPLETE) { + camel_exception_xfer (ex, &ic->ex); + camel_imap_command_unref (ic); + + return -1; + } + + switch (ic->result) { + case CAMEL_IMAP_RESULT_NO: + /* FIXME: would be good to save the NO reason into the err message */ + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Cannot sync flags to folder `%s': Unknown"), + folder->full_name); + retval = -1; + break; + case CAMEL_IMAP_RESULT_BAD: + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Cannot sync flags to folder `%s': Bad command"), + folder->full_name); + retval = -1; + break; + } + + camel_imap_command_unref (ic); + + if (retval == -1) + return -1; + } + + return 0; +} + +static int +imap_sync_changes (CamelFolder *folder, GPtrArray *sync, CamelException *ex) +{ + CamelIMAPMessageInfo *iinfo; + GPtrArray *on_set, *off_set; + CamelMessageInfo *info; + flags_diff_t diff; + int retval = 0; + int i, j; + + on_set = g_ptr_array_new (); + off_set = g_ptr_array_new (); + + /* construct commands to sync system and user flags */ + for (i = 0; i < G_N_ELEMENTS (imap_flags); i++) { + if (!(imap_flags[i].flag & folder->permanent_flags)) + continue; + + for (j = 0; j < sync->len; j++) { + iinfo = (CamelIMAPMessageInfo *) info = sync->pdata[j]; + camel_imap_flags_diff (&diff, iinfo->server_flags, info->flags); + if (diff.changed & imap_flags[i].flag) { + if (diff.bits & imap_flags[i].flag) { + g_ptr_array_add (on_set, info); + } else { + g_ptr_array_add (off_set, info); + } + } + } + + if (on_set->len > 0) { + if ((retval = imap_sync_flag (folder, on_set, '+', imap_flags[i].name, ex)) == -1) + break; + + g_ptr_array_set_size (on_set, 0); + } + + if (off_set->len > 0) { + if ((retval = imap_sync_flag (folder, off_set, '-', imap_flags[i].name, ex)) == -1) + break; + + g_ptr_array_set_size (off_set, 0); + } + } + + g_ptr_array_free (on_set, TRUE); + g_ptr_array_free (off_set, TRUE); + + if (retval == -1) + return-1; + + for (i = 0; i < sync->len; i++) { + iinfo = (CamelIMAPMessageInfo *) info = sync->pdata[i]; + info->flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED; + iinfo->server_flags = info->flags & folder->permanent_flags; + } + + return 0; +} + +static void +imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex) +{ + CamelIMAPEngine *engine = ((CamelIMAPStore *) folder->parent_store)->engine; + CamelIMAPMessageInfo *iinfo; + CamelMessageInfo *info; + CamelIMAPCommand *ic; + flags_diff_t diff; + GPtrArray *sync; + int id, max, i; + int retval; + + /* gather a list of changes to sync to the server */ + sync = g_ptr_array_new (); + max = camel_folder_summary_count (folder->summary); + for (i = 0; i < max; i++) { + iinfo = (CamelIMAPMessageInfo *) info = camel_folder_summary_index (folder->summary, i); + expunge = expunge && (info->flags & CAMEL_MESSAGE_DELETED); + if (info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) { + camel_imap_flags_diff (&diff, iinfo->server_flags, info->flags); + diff.changed &= folder->permanent_flags; + + /* weed out flag changes that we can't sync to the server */ + if (!diff.changed) + camel_folder_summary_info_free (folder->summary, info); + else + g_ptr_array_add (sync, info); + } else { + camel_folder_summary_info_free (folder->summary, info); + } + } + + if (sync->len > 0) { + retval = imap_sync_changes (folder, sync, ex); + + for (i = 0; i < sync->len; i++) + camel_folder_summary_info_free (folder->summary, sync->pdata[i]); + + g_ptr_array_free (sync, TRUE); + + if (retval == -1) + return; + } else { + g_ptr_array_free (sync, TRUE); + } + + if (expunge) { + ic = camel_imap_engine_queue (engine, folder, "EXPUNGE\r\n"); + while ((id = camel_imap_engine_iterate (engine)) < ic->id && id != -1) + ; + + switch (ic->result) { + case CAMEL_IMAP_RESULT_NO: + /* FIXME: would be good to save the NO reason into the err message */ + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Cannot expunge folder `%s': Unknown"), + folder->full_name); + break; + case CAMEL_IMAP_RESULT_BAD: + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Cannot expunge folder `%s': Bad command"), + folder->full_name); + break; + } + + camel_imap_command_unref (ic); + } + + camel_folder_summary_save (folder->summary); +} + +static void +imap_expunge (CamelFolder *folder, CamelException *ex) +{ + imap_sync (folder, TRUE, ex); +} + + +static int +untagged_fetch (CamelIMAPEngine *engine, CamelIMAPCommand *ic, guint32 index, camel_imap_token_t *token, CamelException *ex) +{ + CamelStream *fstream, *stream = ic->user_data; + CamelMimeFilter *crlf; + int left = 2; + + if (camel_imap_engine_next_token (engine, token, ex) == -1) + return -1; + + /* parse the FETCH response list */ + if (token->token != '(') { + camel_imap_utils_set_unexpected_token_error (ex, engine, token); + return -1; + } + + do { + if (camel_imap_engine_next_token (engine, token, ex) == -1) + goto exception; + + if (token->token != CAMEL_IMAP_TOKEN_ATOM) + goto unexpected; + + if (!strcmp (token->v.atom, "BODY[]")) { + if (camel_imap_engine_next_token (engine, token, ex) == -1) + goto exception; + + if (token->token != CAMEL_IMAP_TOKEN_LITERAL) + goto unexpected; + + fstream = (CamelStream *) camel_stream_filter_new_with_stream (stream); + crlf = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_DECODE, CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY); + camel_stream_filter_add ((CamelStreamFilter *) fstream, crlf); + camel_object_unref (crlf); + + camel_stream_write_to_stream ((CamelStream *) engine->istream, fstream); + camel_stream_flush (fstream); + camel_object_unref (fstream); + + left--; + } else if (!strcmp (token->v.atom, "UID")) { + if (camel_imap_engine_next_token (engine, token, ex) == -1) + goto exception; + + if (token->token != CAMEL_IMAP_TOKEN_NUMBER || token->v.number == 0) + goto unexpected; + + left--; + } else { + /* wtf? */ + fprintf (stderr, "huh? %s?...\n", token->v.atom); + } + } while (left); + + if (camel_imap_engine_next_token (engine, token, ex) == -1) + goto exception; + + if (token->token != ')') { + fprintf (stderr, "expected ')' to close untagged FETCH response\n"); + goto unexpected; + } + + return 0; + + unexpected: + + camel_imap_utils_set_unexpected_token_error (ex, engine, token); + + exception: + + return -1; +} + +static CamelMimeMessage * +imap_get_message (CamelFolder *folder, const char *uid, CamelException *ex) +{ + CamelIMAPEngine *engine = ((CamelIMAPStore *) folder->parent_store)->engine; + CamelMimeMessage *message = NULL; + CamelIMAPCommand *ic; + CamelStream *stream; + int id; + + ic = camel_imap_engine_queue (engine, folder, "UID FETCH %s BODY.PEEK[]\r\n", uid); + camel_imap_command_register_untagged (ic, "FETCH", untagged_fetch); + ic->user_data = stream = camel_stream_mem_new (); + + while ((id = camel_imap_engine_iterate (engine)) < ic->id && id != -1) + ; + + if (id == -1 || ic->status != CAMEL_IMAP_COMMAND_COMPLETE) { + camel_exception_xfer (ex, &ic->ex); + camel_imap_command_unref (ic); + camel_object_unref (stream); + return NULL; + } + + switch (ic->result) { + case CAMEL_IMAP_RESULT_OK: + camel_stream_reset (stream); + message = camel_mime_message_new (); + camel_data_wrapper_construct_from_stream ((CamelDataWrapper *) message, stream); + break; + case CAMEL_IMAP_RESULT_NO: + /* FIXME: would be good to save the NO reason into the err message */ + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Cannot get message %s from folder `%s': No such message"), + uid, folder->full_name); + break; + case CAMEL_IMAP_RESULT_BAD: + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Cannot get message %s from folder `%s': Bad command"), + uid, folder->full_name); + break; + } + + camel_imap_command_unref (ic); + + camel_object_unref (stream); + + return message; +} + +static char *tm_months[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +static void +imap_append_message (CamelFolder *folder, CamelMimeMessage *message, + const CamelMessageInfo *info, char **appended_uid, CamelException *ex) +{ + CamelIMAPEngine *engine = ((CamelIMAPStore *) folder->parent_store)->engine; + CamelIMAPSummary *summary = (CamelIMAPSummary *) folder->summary; + CamelIMAPRespCode *resp; + CamelIMAPCommand *ic; + CamelFolderInfo *fi; + CamelException lex; + char flags[100], *p; + char date[50]; + struct tm tm; + int id, i; + + /* construct the option flags list */ + if (info->flags & folder->permanent_flags) { + p = g_stpcpy (flags, " ("); + + for (i = 0; i < G_N_ELEMENTS (imap_flags); i++) { + if ((info->flags & imap_flags[i].flag) & folder->permanent_flags) { + p = g_stpcpy (p, imap_flags[i].name); + *p++ = ' '; + } + } + + p[-1] = ')'; + *p = '\0'; + } else { + flags[0] = '\0'; + } + + /* construct the optional date_time string */ + if (info->date_received != (time_t) -1) { + int tzone; + +#ifdef HAVE_LOCALTIME_R + localtime_r (&info->date_received, &tm); +#else + memcpy (&tm, localtime (&info->date_received), sizeof (tm)); +#endif + +#if defined (HAVE_TM_GMTOFF) + tzone = -tm.tm_gmtoff; +#elif defined (HAVE_TIMEZONE) + if (tm.tm_isdst > 0) { +#if defined (HAVE_ALTZONE) + tzone = altzone; +#else /* !defined (HAVE_ALTZONE) */ + tzone = (timezone - 3600); +#endif + } else { + tzone = timezone; + } +#else +#error Neither HAVE_TIMEZONE nor HAVE_TM_GMTOFF defined. Rerun autoheader, autoconf, etc. +#endif + + sprintf (date, " \"%02d-%s-%04d %02d:%02d:%02d %+05d\"", + tm.tm_mday, tm_months[tm.tm_mon], tm.tm_year + 1900, + tm.tm_hour, tm.tm_min, tm.tm_sec, tzone); + } else { + date[0] = '\0'; + } + + retry: + + if (engine->capa & CAMEL_IMAP_CAPABILITY_UIDPLUS) + ic = camel_imap_engine_queue (engine, NULL, "UID APPEND %F%s%s %L\r\n", flags, date, message); + else + ic = camel_imap_engine_queue (engine, NULL, "APPEND %F%s%s %L\r\n", flags, date, message); + + while ((id = camel_imap_engine_iterate (engine)) < ic->id && id != -1) + ; + + if (id == -1 || ic->status != CAMEL_IMAP_COMMAND_COMPLETE) { + camel_exception_xfer (ex, &ic->ex); + camel_imap_command_unref (ic); + return; + } + + switch (ic->result) { + case CAMEL_IMAP_RESULT_OK: + if (!(engine->capa & CAMEL_IMAP_CAPABILITY_UIDPLUS)) + break; + + if (!appended_uid) + break; + + for (i = 0; i < ic->resp_codes->len; i++) { + resp = ic->resp_codes->pdata[i]; + if (resp->code == CAMEL_IMAP_RESP_CODE_APPENDUID) { + if (resp->v.appenduid.uidvalidity == summary->uidvalidity) + *appended_uid = g_strdup_printf ("%u", resp->v.appenduid.uid); + break; + } + } + break; + case CAMEL_IMAP_RESULT_NO: + /* FIXME: can we give the user any more information? */ + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Cannot append message to folder `%s': Unknown error"), + folder->full_name); + + for (i = 0; i < ic->resp_codes->len; i++) { + resp = ic->resp_codes->pdata[i]; + if (resp->code == CAMEL_IMAP_RESP_CODE_TRYCREATE) { + char *parent_name, *p; + + parent_name = g_alloca (strlen (folder->full_name) + 1); + if (!(p = strrchr (parent_name, '/'))) + *parent_name = '\0'; + else + *p = '\0'; + + if (!(fi = camel_store_create_folder (folder->parent_store, parent_name, folder->name, &lex))) { + camel_exception_clear (&lex); + break; + } + + camel_store_free_folder_info (folder->parent_store, fi); + camel_imap_command_unref (ic); + camel_exception_clear (ex); + goto retry; + } + } + + break; + case CAMEL_IMAP_RESULT_BAD: + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Cannot append message to folder `%s': Bad command"), + folder->full_name); + + break; + default: + g_assert_not_reached (); + } + + camel_imap_command_unref (ic); +} + + +static int +info_uid_sort (const CamelMessageInfo **info0, const CamelMessageInfo **info1) +{ + guint32 uid0, uid1; + + uid0 = strtoul (camel_message_info_uid (*info0), NULL, 10); + uid1 = strtoul (camel_message_info_uid (*info1), NULL, 10); + + if (uid0 == uid1) + return 0; + + return uid0 < uid1 ? -1 : 1; +} + +static void +imap_transfer_messages_to (CamelFolder *src, GPtrArray *uids, CamelFolder *dest, + GPtrArray **transferred_uids, gboolean delete_originals, CamelException *ex) +{ + CamelIMAPEngine *engine = ((CamelIMAPStore *) src->parent_store)->engine; + int i, j, n, id, dest_namelen; + CamelMessageInfo *info; + CamelIMAPCommand *ic; + GPtrArray *infos; + char *set; + + infos = g_ptr_array_new (); + for (i = 0; i < uids->len; i++) { + if (!(info = camel_folder_summary_uid (src->summary, uids->pdata[i]))) + continue; + + g_ptr_array_add (infos, info); + } + + if (infos->len == 0) { + g_ptr_array_free (infos, TRUE); + return; + } + + g_ptr_array_sort (infos, (GCompareFunc) info_uid_sort); + + dest_namelen = strlen (camel_imap_folder_utf7_name ((CamelIMAPFolder *) dest)); + + for (i = 0; i < infos->len; i += n) { + n = imap_get_uid_set (engine, src->summary, infos, i, 10 + dest_namelen, &set); + + ic = camel_imap_engine_queue (engine, src, "UID COPY %s %F\r\n", set, dest); + while ((id = camel_imap_engine_iterate (engine)) < ic->id && id != -1) + ; + + g_free (set); + + if (id == -1 || ic->status != CAMEL_IMAP_COMMAND_COMPLETE) { + camel_exception_xfer (ex, &ic->ex); + camel_imap_command_unref (ic); + g_free (set); + goto done; + } + + switch (ic->result) { + case CAMEL_IMAP_RESULT_NO: + /* FIXME: would be good to save the NO reason into the err message */ + if (delete_originals) { + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Cannot move messages from folder `%s' to folder `%s': Unknown"), + src->full_name, dest->full_name); + } else { + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Cannot copy messages from folder `%s' to folder `%s': Unknown"), + src->full_name, dest->full_name); + } + + goto done; + case CAMEL_IMAP_RESULT_BAD: + if (delete_originals) { + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Cannot move messages from folder `%s' to folder `%s': Bad command"), + src->full_name, dest->full_name); + } else { + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Cannot copy messages from folder `%s' to folder `%s': Bad command"), + src->full_name, dest->full_name); + } + + goto done; + } + + camel_imap_command_unref (ic); + + if (delete_originals) { + for (j = i; j < n; j++) { + info = infos->pdata[j]; + camel_folder_set_message_flags (src, camel_message_info_uid (info), + CAMEL_MESSAGE_DELETED, CAMEL_MESSAGE_DELETED); + } + + camel_folder_summary_touch (src->summary); + } + } + + done: + + for (i = 0; i < infos->len; i++) + camel_folder_summary_info_free (src->summary, infos->pdata[i]); + g_ptr_array_free (infos, TRUE); +} diff --git a/camel/providers/imap4/camel-imap-folder.h b/camel/providers/imap4/camel-imap-folder.h new file mode 100644 index 0000000000..a4f4e55528 --- /dev/null +++ b/camel/providers/imap4/camel-imap-folder.h @@ -0,0 +1,66 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* Camel + * Copyright (C) 1999-2004 Jeffrey Stedfast + * + * 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 Street #330, Boston, MA 02111-1307, USA. + */ + + +#ifndef __CAMEL_IMAP_FOLDER_H__ +#define __CAMEL_IMAP_FOLDER_H__ + +#include <camel/camel-store.h> +#include <camel/camel-folder.h> + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + +#define CAMEL_TYPE_IMAP_FOLDER (camel_imap_folder_get_type ()) +#define CAMEL_IMAP_FOLDER(obj) (CAMEL_CHECK_CAST ((obj), CAMEL_TYPE_IMAP_FOLDER, CamelIMAPFolder)) +#define CAMEL_IMAP_FOLDER_CLASS(klass) (CAMEL_CHECK_CLASS_CAST ((klass), CAMEL_TYPE_IMAP_FOLDER, CamelIMAPFolderClass)) +#define CAMEL_IS_IMAP_FOLDER(obj) (CAMEL_CHECK_TYPE ((obj), CAMEL_TYPE_IMAP_FOLDER)) +#define CAMEL_IS_IMAP_FOLDER_CLASS(klass) (CAMEL_CHECK_CLASS_TYPE ((klass), CAMEL_TYPE_IMAP_FOLDER)) +#define CAMEL_IMAP_FOLDER_GET_CLASS(obj) (CAMEL_CHECK_GET_CLASS ((obj), CAMEL_TYPE_IMAP_FOLDER, CamelIMAPFolderClass)) + +typedef struct _CamelIMAPFolder CamelIMAPFolder; +typedef struct _CamelIMAPFolderClass CamelIMAPFolderClass; + +struct _CamelIMAPFolder { + CamelFolder parent_object; + + char *cachedir; + char *utf7_name; +}; + +struct _CamelIMAPFolderClass { + CamelFolderClass parent_class; + +}; + + +CamelType camel_imap_folder_get_type (void); + +CamelFolder *camel_imap_folder_new (CamelStore *store, const char *full_name, gboolean query, CamelException *ex); +CamelFolder *camel_imap_folder_new_utf7_name (CamelStore *store, const char *utf7_name, CamelException *ex); + +const char *camel_imap_folder_utf7_name (CamelIMAPFolder *folder); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __CAMEL_IMAP_FOLDER_H__ */ |