imapx_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
{
CamelIMAPXStore *is = (CamelIMAPXStore *)folder->parent_store;
+
+ if (CAMEL_OFFLINE_STORE (is)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
+ return;
+
+ if (is->server && camel_imapx_server_connect (is->server, 1))
+ camel_imapx_server_sync_changes (is->server, folder, ex);
/* Sync twice - make sure deleted flags are written out,
then sync again incase expunge changed anything */
camel_exception_clear(ex);
- if (is->server && camel_imapx_server_connect (is->server, 1))
- camel_imapx_server_sync_changes (is->server, folder, ex);
-
if (is->server && expunge) {
camel_imapx_server_expunge(is->server, folder, ex);
camel_exception_clear(ex);
return NULL;
}
+ if (CAMEL_OFFLINE_STORE (istore)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
+ return NULL;
+
if (istore->server && camel_imapx_server_connect (istore->server, 1)) {
stream = camel_imapx_server_get_message(istore->server, folder, uid, ex);
} else {
return msg;
}
+
+static void
+imapx_transfer_messages_to (CamelFolder *source, GPtrArray *uids,
+ CamelFolder *dest, GPtrArray **transferred_uids,
+ gboolean delete_originals, CamelException *ex)
+{
+ CamelIMAPXStore *istore = (CamelIMAPXStore *) source->parent_store;
+
+ if (CAMEL_OFFLINE_STORE (istore)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
+ return;
+
+ if (istore->server && camel_imapx_server_connect (istore->server, 1))
+ camel_imapx_server_copy_message (istore->server, source, dest, uids, delete_originals, ex);
+
+ imapx_refresh_info (dest, ex);
+}
+
static void
imapx_append_message(CamelFolder *folder, CamelMimeMessage *message, const CamelMessageInfo *info, gchar **appended_uid, CamelException *ex)
{
- CamelIMAPXStore *is = (CamelIMAPXStore *)folder->parent_store;
+ CamelIMAPXStore *istore = (CamelIMAPXStore *)folder->parent_store;
+
+ if (CAMEL_OFFLINE_STORE (istore)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
+ return;
if (appended_uid)
*appended_uid = NULL;
- camel_imapx_server_append_message(is->server, folder, message, info, ex);
+ if (istore->server && camel_imapx_server_connect (istore->server, 1))
+ camel_imapx_server_append_message(istore->server, folder, message, info, ex);
}
gchar *
((CamelFolderClass *)klass)->get_message = imapx_get_message;
((CamelFolderClass *)klass)->append_message = imapx_append_message;
+ ((CamelFolderClass *)klass)->transfer_messages_to = imapx_transfer_messages_to;
((CamelFolderClass *)klass)->get_filename = imapx_get_filename;
}
/* How many message headers to fetch at a time update summary for new messages*/
#define BATCH_FETCH_COUNT 500
+#define MAX_COMMAND_LEN 1000
+
extern gint camel_application_is_exiting;
struct _uidset_state {
enum {
IMAPX_JOB_GET_MESSAGE,
IMAPX_JOB_APPEND_MESSAGE,
+ IMAPX_JOB_COPY_MESSAGE,
IMAPX_JOB_REFRESH_INFO,
IMAPX_JOB_SYNC_CHANGES,
IMAPX_JOB_EXPUNGE,
CamelMessageInfo *info;
} append_message;
struct {
+ CamelFolder *dest;
+ GPtrArray *uids;
+ gboolean delete_originals;
+ gint index;
+ gint last_index;
+ struct _uidset_state uidset;
+ } copy_messages;
+ struct {
gchar *pattern;
guint32 flags;
GHashTable *folders;
static void imapx_job_done (CamelIMAPXJob *job);
static void imapx_run_job (CamelIMAPXServer *is, CamelIMAPXJob *job);
static void imapx_job_fetch_new_messages_start (CamelIMAPXServer *is, CamelIMAPXJob *job);
+static void imapx_command_copy_messages_step_done (CamelIMAPXServer *is, CamelIMAPXCommand *ic);
+static gint imapx_refresh_info_uid_cmp(gconstpointer ap, gconstpointer bp);
typedef struct _CamelIMAPXIdle CamelIMAPXIdle;
struct _CamelIMAPXIdle {
/* ********************************************************************** */
static void
+imapx_command_copy_messages_step_start (CamelIMAPXServer *is, CamelIMAPXJob *job, gint index)
+{
+ CamelIMAPXCommand *ic;
+ GPtrArray *uids = job->u.copy_messages.uids;
+ gint i = index;
+
+ ic = camel_imapx_command_new ("COPY", job->folder->full_name, "UID COPY ");
+ ic->complete = imapx_command_copy_messages_step_done;
+ ic->job = job;
+ job->u.copy_messages.last_index = i;
+
+ for (;i < uids->len; i++) {
+ gint res;
+ const gchar *uid = (gchar *) g_ptr_array_index (uids, i);
+
+ res = imapx_uidset_add (&job->u.copy_messages.uidset, ic, uid);
+ if (res == 1) {
+ camel_imapx_command_add (ic, " %f", job->u.copy_messages.dest->full_name);
+ job->u.copy_messages.index = i;
+ imapx_command_queue (is, ic);
+ return;
+ }
+ }
+
+ job->u.copy_messages.index = i;
+ if (imapx_uidset_done (&job->u.copy_messages.uidset, ic)) {
+ camel_imapx_command_add (ic, " %s", job->u.copy_messages.dest->full_name);
+ imapx_command_queue (is, ic);
+ return;
+ }
+}
+
+static void
+imapx_command_copy_messages_step_done (CamelIMAPXServer *is, CamelIMAPXCommand *ic)
+{
+ CamelIMAPXJob *job = ic->job;
+ gint i = job->u.copy_messages.index;
+ GPtrArray *uids = job->u.copy_messages.uids;
+
+ if (camel_exception_is_set (ic->ex) || ic->status->result != IMAP_OK) {
+ if (!camel_exception_is_set (ic->ex))
+ camel_exception_set (job->ex, 1, "Error copying messages");
+ else
+ camel_exception_xfer (job->ex, ic->ex);
+
+ goto cleanup;
+ }
+
+ if (job->u.copy_messages.delete_originals) {
+ gint j;
+
+ for (j = job->u.copy_messages.last_index; j < i; j++)
+ camel_folder_delete_message (job->folder, uids->pdata [j]);
+ }
+
+ /* TODO copy the summary and cached messages to the new folder. We might need a sorted insert to avoid refreshing the dest folder */
+ if (ic->status->condition == IMAP_COPYUID) {
+
+ }
+
+ if (i < uids->len) {
+ camel_imapx_command_free (ic);
+ imapx_command_copy_messages_step_start (is, job, i);
+ }
+
+cleanup:
+ imapx_job_done (job);
+ camel_imapx_command_free (ic);
+}
+
+static void
+imapx_job_copy_messages_start (CamelIMAPXServer *is, CamelIMAPXJob *job)
+{
+ g_ptr_array_sort (job->u.copy_messages.uids, (GCompareFunc) imapx_refresh_info_uid_cmp);
+ imapx_uidset_init(&job->u.copy_messages.uidset, 0, MAX_COMMAND_LEN);
+ imapx_command_copy_messages_step_start (is, job, 0);
+}
+
+/* ********************************************************************** */
+
+static void
imapx_command_append_message_done (CamelIMAPXServer *is, CamelIMAPXCommand *ic)
{
CamelIMAPXJob *job = ic->job;
}
void
+camel_imapx_server_copy_message (CamelIMAPXServer *is, CamelFolder *source, CamelFolder *dest, GPtrArray *uids, gboolean delete_originals, CamelException *ex)
+{
+ CamelIMAPXJob *job;
+
+ job = g_malloc0(sizeof(*job));
+ job->pri = -60;
+ job->type = IMAPX_JOB_COPY_MESSAGE;
+ job->start = imapx_job_copy_messages_start;
+ job->folder = source;
+ job->u.copy_messages.dest = dest;
+ job->u.copy_messages.uids = uids;
+ job->u.copy_messages.delete_originals = delete_originals;
+
+ camel_object_ref(source);
+ camel_object_ref (dest);
+
+ imapx_run_job (is, job);
+}
+
+void
camel_imapx_server_append_message(CamelIMAPXServer *is, CamelFolder *folder, CamelMimeMessage *message, const CamelMessageInfo *mi, CamelException *ex)
{
gchar *uid = NULL, *tmp = NULL;
#line 3 "camel-imapx-tokens.txt"
struct _imap_keyword {const gchar *name; camel_imapx_id_t id; };
-#define TOTAL_KEYWORDS 35
+#define TOTAL_KEYWORDS 36
#define MIN_WORD_LENGTH 2
#define MAX_WORD_LENGTH 14
#define MIN_HASH_VALUE 5
inline
#endif
#endif
-static guint
-imap_hash (register const gchar *str, register guint len)
+static unsigned int
+imap_hash (register const char *str, register unsigned int len)
{
- static guchar asso_values[] =
+ static unsigned char asso_values[] =
{
57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
- 57, 57, 57, 57, 57, 25, 15, 5, 20, 0,
- 5, 57, 5, 10, 57, 5, 30, 10, 25, 10,
+ 57, 57, 57, 57, 57, 25, 15, 10, 20, 0,
+ 5, 57, 5, 10, 57, 0, 30, 10, 25, 15,
0, 57, 0, 25, 10, 10, 57, 57, 57, 5,
57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
57, 57, 57, 57, 57, 57
};
- return len + asso_values[(guchar)str[len - 1]] + asso_values[(guchar)str[0]];
+ return len + asso_values[(unsigned char)str[len - 1]] + asso_values[(unsigned char)str[0]];
}
#ifdef __GNUC__
__inline
#endif
struct _imap_keyword *
-imap_tokenise_struct (register const gchar *str, register guint len)
+imap_tokenise_struct (register const char *str, register unsigned int len)
{
static struct _imap_keyword wordlist[] =
{
{""}, {""}, {""}, {""}, {""},
-#line 25 "camel-imapx-tokens.txt"
+#line 26 "camel-imapx-tokens.txt"
{"PARSE", IMAP_PARSE},
{""},
-#line 14 "camel-imapx-tokens.txt"
+#line 15 "camel-imapx-tokens.txt"
{"EXPUNGE", IMAP_EXPUNGE},
-#line 12 "camel-imapx-tokens.txt"
+#line 13 "camel-imapx-tokens.txt"
{"ENVELOPE", IMAP_ENVELOPE},
{""},
-#line 29 "camel-imapx-tokens.txt"
+#line 30 "camel-imapx-tokens.txt"
{"READ-WRITE", IMAP_READ_WRITE},
-#line 32 "camel-imapx-tokens.txt"
+#line 33 "camel-imapx-tokens.txt"
{"RFC822.SIZE", IMAP_RFC822_SIZE},
-#line 27 "camel-imapx-tokens.txt"
+#line 28 "camel-imapx-tokens.txt"
{"PREAUTH", IMAP_PREAUTH},
-#line 31 "camel-imapx-tokens.txt"
+#line 32 "camel-imapx-tokens.txt"
{"RFC822.HEADER", IMAP_RFC822_HEADER},
-#line 28 "camel-imapx-tokens.txt"
+#line 29 "camel-imapx-tokens.txt"
{"READ-ONLY", IMAP_READ_ONLY},
-#line 15 "camel-imapx-tokens.txt"
+#line 16 "camel-imapx-tokens.txt"
{"FETCH", IMAP_FETCH},
-#line 30 "camel-imapx-tokens.txt"
+#line 31 "camel-imapx-tokens.txt"
{"RECENT", IMAP_RECENT},
-#line 24 "camel-imapx-tokens.txt"
+#line 25 "camel-imapx-tokens.txt"
{"OK", IMAP_OK},
#line 10 "camel-imapx-tokens.txt"
{"BYE", IMAP_BYE},
-#line 35 "camel-imapx-tokens.txt"
+#line 36 "camel-imapx-tokens.txt"
{"TRYCREATE", IMAP_TRYCREATE},
-#line 11 "camel-imapx-tokens.txt"
- {"CAPABILITY", IMAP_CAPABILITY},
-#line 33 "camel-imapx-tokens.txt"
+ {""},
+#line 34 "camel-imapx-tokens.txt"
{"RFC822.TEXT", IMAP_RFC822_TEXT},
-#line 17 "camel-imapx-tokens.txt"
+#line 18 "camel-imapx-tokens.txt"
{"INTERNALDATE", IMAP_INTERNALDATE},
{""},
#line 8 "camel-imapx-tokens.txt"
{"BODY", IMAP_BODY},
- {""},
-#line 37 "camel-imapx-tokens.txt"
+#line 11 "camel-imapx-tokens.txt"
+ {"CAPABILITY", IMAP_CAPABILITY},
+#line 38 "camel-imapx-tokens.txt"
{"UIDVALIDITY", IMAP_UIDVALIDITY},
-#line 39 "camel-imapx-tokens.txt"
+#line 40 "camel-imapx-tokens.txt"
{"UIDNEXT", IMAP_UIDNEXT},
#line 9 "camel-imapx-tokens.txt"
{"BODYSTRUCTURE", IMAP_BODYSTRUCTURE},
{""}, {""},
-#line 13 "camel-imapx-tokens.txt"
+#line 14 "camel-imapx-tokens.txt"
{"EXISTS", IMAP_EXISTS},
-#line 22 "camel-imapx-tokens.txt"
+#line 23 "camel-imapx-tokens.txt"
{"NEWNAME", IMAP_NEWNAME},
-#line 36 "camel-imapx-tokens.txt"
+#line 37 "camel-imapx-tokens.txt"
{"UID", IMAP_UID},
-#line 21 "camel-imapx-tokens.txt"
+#line 22 "camel-imapx-tokens.txt"
{"NAMESPACE", IMAP_NAMESPACE},
-#line 16 "camel-imapx-tokens.txt"
+#line 17 "camel-imapx-tokens.txt"
{"FLAGS", IMAP_FLAGS},
{""},
-#line 23 "camel-imapx-tokens.txt"
- {"NO", IMAP_NO},
+#line 12 "camel-imapx-tokens.txt"
+ {"COPYUID", IMAP_COPYUID},
#line 7 "camel-imapx-tokens.txt"
{"BAD", IMAP_BAD},
-#line 26 "camel-imapx-tokens.txt"
+#line 27 "camel-imapx-tokens.txt"
{"PERMANENTFLAGS", IMAP_PERMANENTFLAGS},
#line 5 "camel-imapx-tokens.txt"
{"ALERT", IMAP_ALERT},
-#line 38 "camel-imapx-tokens.txt"
+#line 39 "camel-imapx-tokens.txt"
{"UNSEEN", IMAP_UNSEEN},
- {""},
-#line 20 "camel-imapx-tokens.txt"
+#line 24 "camel-imapx-tokens.txt"
+ {"NO", IMAP_NO},
+#line 21 "camel-imapx-tokens.txt"
{"MESSAGES", IMAP_MESSAGES},
-#line 18 "camel-imapx-tokens.txt"
+#line 19 "camel-imapx-tokens.txt"
{"LIST", IMAP_LIST},
{""}, {""}, {""}, {""},
-#line 19 "camel-imapx-tokens.txt"
+#line 20 "camel-imapx-tokens.txt"
{"LSUB", IMAP_LSUB},
{""}, {""}, {""}, {""},
#line 6 "camel-imapx-tokens.txt"
{"APPENDUID", IMAP_APPENDUID},
{""},
-#line 34 "camel-imapx-tokens.txt"
+#line 35 "camel-imapx-tokens.txt"
{"STATUS", IMAP_STATUS}
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
{
- register gint key = imap_hash (str, len);
+ register int key = imap_hash (str, len);
if (key <= MAX_HASH_VALUE && key >= 0)
{
- register const gchar *s = wordlist[key].name;
+ register const char *s = wordlist[key].name;
if (*str == *s && !strcmp (str + 1, s + 1))
return &wordlist[key];
return sinfo;
}
+
+static void
+generate_uids_from_sequence (GPtrArray *uids, guint32 end_uid)
+{
+ guint32 uid = GPOINTER_TO_UINT (g_ptr_array_index (uids, uids->len - 1));
+
+ uid++;
+ while (uid <= end_uid) {
+ g_ptr_array_add (uids, GUINT_TO_POINTER (uid));
+ uid++;
+ }
+}
+
+static GPtrArray *
+imap_parse_uids (CamelIMAPXStream *is, CamelException *ex)
+{
+ GPtrArray *uids = g_ptr_array_new ();
+ gboolean is_prev_number = FALSE, sequence = FALSE;
+ guchar *token;
+ guint len;
+ gint tok;
+
+ tok = camel_imapx_stream_token (is, &token, &len, ex);
+ while (tok != ']'|| !(is_prev_number && tok == IMAP_TOK_INT)) {
+ if (tok == ',') {
+ is_prev_number = FALSE;
+ sequence = FALSE;
+ } else if (tok == ':') {
+ sequence = TRUE;
+ is_prev_number = FALSE;
+ } else {
+ guint32 uid = strtoul ((char *) token, NULL, 10);
+
+ is_prev_number = TRUE;
+ sequence = FALSE;
+
+ if (sequence)
+ generate_uids_from_sequence (uids, uid);
+ else
+ g_ptr_array_add (uids, GUINT_TO_POINTER (uid));
+ }
+ camel_imapx_stream_token (is, &token, &len, ex);
+ }
+
+ if (is_prev_number && tok == IMAP_TOK_INT)
+ camel_imapx_stream_ungettoken (is, tok, token, len);
+
+ return uids;
+}
+
/* rfc 2060 section 7.1 Status Responses */
/* shoudl this start after [ or before the [? token_unget anyone? */
struct _status_info *
sinfo->u.appenduid.uidvalidity = camel_imapx_stream_number(is, ex);
sinfo->u.appenduid.uid = camel_imapx_stream_number(is, ex);
break;
+ case IMAP_COPYUID:
+ sinfo->u.copyuid.uidvalidity = camel_imapx_stream_number(is, ex);
+ sinfo->u.copyuid.uids = imap_parse_uids (is, ex);
+ sinfo->u.copyuid.copied_uids = imap_parse_uids (is, ex);
+ break;
case IMAP_NEWNAME:
/* the rfc doesn't specify the bnf for this */
camel_imapx_stream_astring(is, &token, ex);
case IMAP_NEWNAME:
g_free(sinfo->u.newname.oldname);
g_free(sinfo->u.newname.newname);
+ break;
+ case IMAP_COPYUID:
+ g_ptr_array_free (sinfo->u.copyuid.uids, FALSE);
+ g_ptr_array_free (sinfo->u.copyuid.copied_uids, FALSE);
+ break;
default:
break;
}