summaryrefslogtreecommitdiff
path: root/camel/providers/imapx
diff options
context:
space:
mode:
authorFederico Mena Quintero <federico@novell.com>2010-09-24 11:43:50 -0500
committerFederico Mena Quintero <federico@novell.com>2010-09-24 11:43:50 -0500
commitd4f0f65a53f0163e410a06684ac4c3404f5fd989 (patch)
tree80a3c43b1053bc9f658b12fe1d05c4fe69b6c4fc /camel/providers/imapx
parent192ec4d20f07fb5cf71e02ce5b7ea90eaa99595a (diff)
parent4eef23360571d75a6cf83fecbc47cf0784e78267 (diff)
downloadevolution-data-server-d4f0f65a53f0163e410a06684ac4c3404f5fd989.tar.gz
Merge branch 'gnome-2-30' into camel-socks-proxycamel-socks-proxy
Diffstat (limited to 'camel/providers/imapx')
-rw-r--r--camel/providers/imapx/camel-imapx-folder.c80
-rw-r--r--camel/providers/imapx/camel-imapx-folder.h19
-rw-r--r--camel/providers/imapx/camel-imapx-provider.c25
-rw-r--r--camel/providers/imapx/camel-imapx-server.c586
-rw-r--r--camel/providers/imapx/camel-imapx-server.h23
-rw-r--r--camel/providers/imapx/camel-imapx-store.c159
-rw-r--r--camel/providers/imapx/camel-imapx-store.h20
-rw-r--r--camel/providers/imapx/camel-imapx-stream.c18
-rw-r--r--camel/providers/imapx/camel-imapx-stream.h14
-rw-r--r--camel/providers/imapx/camel-imapx-summary.c49
-rw-r--r--camel/providers/imapx/camel-imapx-summary.h4
-rw-r--r--camel/providers/imapx/camel-imapx-utils.c54
-rw-r--r--camel/providers/imapx/camel-imapx-utils.h22
-rw-r--r--camel/providers/imapx/camel-imapx-view-summary.c16
-rw-r--r--camel/providers/imapx/camel-imapx-view-summary.h16
-rw-r--r--camel/providers/imapx/test-imapx.c19
16 files changed, 800 insertions, 324 deletions
diff --git a/camel/providers/imapx/camel-imapx-folder.c b/camel/providers/imapx/camel-imapx-folder.c
index 3d9b0c048..87b49d06f 100644
--- a/camel/providers/imapx/camel-imapx-folder.c
+++ b/camel/providers/imapx/camel-imapx-folder.c
@@ -1,24 +1,23 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* camel-imap-folder.c : class for a imap folder */
-
/*
* Authors: Michael Zucchi <notzed@ximian.com>
*
- * Copyright (C) 2002 Ximian, Inc. (www.ximian.com)
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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.
+ * 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
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
@@ -129,25 +128,33 @@ static void
imapx_refresh_info (CamelFolder *folder, CamelException *ex)
{
CamelIMAPXStore *istore = (CamelIMAPXStore *)folder->parent_store;
+ CamelIMAPXServer *server;
if (CAMEL_OFFLINE_STORE (istore)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
return;
camel_service_connect((CamelService *)istore, ex);
- if (istore->server && camel_imapx_server_connect (istore->server, TRUE, ex))
- camel_imapx_server_refresh_info(istore->server, folder, ex);
+ server = camel_imapx_store_get_server(istore, ex);
+ if (server) {
+ camel_imapx_server_refresh_info(server, folder, ex);
+ camel_object_unref(server);
+ }
}
static void
imapx_expunge (CamelFolder *folder, CamelException *ex)
{
CamelIMAPXStore *is = (CamelIMAPXStore *)folder->parent_store;
+ CamelIMAPXServer *server;
if (CAMEL_OFFLINE_STORE (is)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
return;
- if (is->server && camel_imapx_server_connect (is->server, TRUE, ex))
- camel_imapx_server_expunge(is->server, folder, ex);
+ server = camel_imapx_store_get_server(is, ex);
+ if (server) {
+ camel_imapx_server_expunge(server, folder, ex);
+ camel_object_unref(server);
+ }
}
@@ -155,6 +162,7 @@ static void
imapx_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
{
CamelIMAPXStore *is = (CamelIMAPXStore *)folder->parent_store;
+ CamelIMAPXServer *server;
CamelException eex = CAMEL_EXCEPTION_INITIALISER;
if (CAMEL_OFFLINE_STORE (is)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
@@ -163,17 +171,21 @@ imapx_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
if (!ex)
ex = &eex;
- if (is->server && camel_imapx_server_connect (is->server, TRUE, ex))
- camel_imapx_server_sync_changes (is->server, folder, ex);
+ server = camel_imapx_store_get_server(is, ex);
+ if (!server)
+ return;
+
+ camel_imapx_server_sync_changes (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 && expunge) {
- camel_imapx_server_expunge(is->server, folder, ex);
+ if (expunge) {
+ camel_imapx_server_expunge(server, folder, ex);
camel_exception_clear(ex);
}
+ camel_object_unref(server);
}
static CamelMimeMessage *
@@ -183,6 +195,7 @@ imapx_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex)
CamelStream *stream = NULL;
CamelIMAPXStore *istore = (CamelIMAPXStore *)folder->parent_store;
CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) folder;
+ CamelIMAPXServer *server;
const gchar *path = NULL;
gboolean offline_message = FALSE;
@@ -203,9 +216,12 @@ imapx_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex)
if (CAMEL_OFFLINE_STORE (istore)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
return NULL;
- if (istore->server && camel_imapx_server_connect (istore->server, TRUE, ex)) {
- stream = camel_imapx_server_get_message(istore->server, folder, uid, ex);
+ server = camel_imapx_store_get_server(istore, ex);
+ if (server) {
+ stream = camel_imapx_server_get_message(server, folder, uid, ex);
+ camel_object_unref(server);
} else {
+ /* It should _always_ be set */
if (!camel_exception_is_set (ex))
camel_exception_setv(ex, 1, "not authenticated");
return NULL;
@@ -231,12 +247,16 @@ static void
imapx_sync_message (CamelFolder *folder, const gchar *uid, CamelException *ex)
{
CamelIMAPXStore *istore = (CamelIMAPXStore *)folder->parent_store;
+ CamelIMAPXServer *server;
if (CAMEL_OFFLINE_STORE (istore)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
return;
- if (istore->server && camel_imapx_server_connect (istore->server, TRUE, ex))
- camel_imapx_server_sync_message (istore->server, folder, uid, ex);
+ server = camel_imapx_store_get_server(istore, ex);
+ if (server) {
+ camel_imapx_server_sync_message (server, folder, uid, ex);
+ camel_object_unref(server);
+ }
}
static void
@@ -245,12 +265,16 @@ imapx_transfer_messages_to (CamelFolder *source, GPtrArray *uids,
gboolean delete_originals, CamelException *ex)
{
CamelIMAPXStore *istore = (CamelIMAPXStore *) source->parent_store;
+ CamelIMAPXServer *server;
if (CAMEL_OFFLINE_STORE (istore)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
return;
- if (istore->server && camel_imapx_server_connect (istore->server, TRUE, ex))
- camel_imapx_server_copy_message (istore->server, source, dest, uids, delete_originals, ex);
+ server = camel_imapx_store_get_server(istore, ex);
+ if (server) {
+ camel_imapx_server_copy_message (server, source, dest, uids, delete_originals, ex);
+ camel_object_unref(server);
+ }
imapx_refresh_info (dest, ex);
}
@@ -259,6 +283,7 @@ static void
imapx_append_message(CamelFolder *folder, CamelMimeMessage *message, const CamelMessageInfo *info, gchar **appended_uid, CamelException *ex)
{
CamelIMAPXStore *istore = (CamelIMAPXStore *)folder->parent_store;
+ CamelIMAPXServer *server;
if (CAMEL_OFFLINE_STORE (istore)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
return;
@@ -266,8 +291,11 @@ imapx_append_message(CamelFolder *folder, CamelMimeMessage *message, const Camel
if (appended_uid)
*appended_uid = NULL;
- if (istore->server && camel_imapx_server_connect (istore->server, TRUE, ex))
- camel_imapx_server_append_message(istore->server, folder, message, info, ex);
+ server = camel_imapx_store_get_server(istore, ex);
+ if (server) {
+ camel_imapx_server_append_message(server, folder, message, info, ex);
+ camel_object_unref(server);
+ }
}
gchar *
diff --git a/camel/providers/imapx/camel-imapx-folder.h b/camel/providers/imapx/camel-imapx-folder.h
index ae7144a23..5371a0da4 100644
--- a/camel/providers/imapx/camel-imapx-folder.h
+++ b/camel/providers/imapx/camel-imapx-folder.h
@@ -4,21 +4,21 @@
/*
* Authors: Michael Zucchi <notzed@ximian.com>
*
- * Copyright (C) 2002 Ximian, Inc. (www.ximian.com)
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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.
+ * 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
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef CAMEL_IMAPX_FOLDER_H
@@ -48,6 +48,7 @@ typedef struct _CamelIMAPXFolder {
guint32 exists_on_server;
guint32 unread_on_server;
guint64 modseq_on_server;
+ guint64 uidvalidity_on_server;
guint32 uidnext_on_server;
/* hash table of UIDs to ignore as recent when updating folder */
diff --git a/camel/providers/imapx/camel-imapx-provider.c b/camel/providers/imapx/camel-imapx-provider.c
index 01f547d73..c704ed0f4 100644
--- a/camel/providers/imapx/camel-imapx-provider.c
+++ b/camel/providers/imapx/camel-imapx-provider.c
@@ -1,26 +1,25 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* camel-pop3-provider.c: pop3 provider registration code */
-
/*
* Authors :
* Dan Winship <danw@ximian.com>
* Michael Zucchi <notzed@ximian.com>
*
- * Copyright (C) 2002 Ximian, Inc. (www.ximian.com)
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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.
+ * 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
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
@@ -40,8 +39,12 @@ static guint imapx_url_hash (gconstpointer key);
static gint imapx_url_equal (gconstpointer a, gconstpointer b);
CamelProviderConfEntry imapx_conf_entries[] = {
- { CAMEL_PROVIDER_CONF_SECTION_START, "mailcheck", NULL,
+ { CAMEL_PROVIDER_CONF_SECTION_START, "mailcheck", NULL,
N_("Checking for New Mail") },
+/* Not for stable branch -- new string. Set it with gconf-editor instead
+ { CAMEL_PROVIDER_CONF_CHECKBOX, "use_qresync", NULL,
+ N_("Use _Quick Resync if the server supports it"), "1" },
+*/
{ CAMEL_PROVIDER_CONF_CHECKBOX, "use_idle", NULL,
N_("Use I_dle if the server supports it"), "1" },
{ CAMEL_PROVIDER_CONF_CHECKBOX, "check_all", NULL,
diff --git a/camel/providers/imapx/camel-imapx-server.c b/camel/providers/imapx/camel-imapx-server.c
index 5f3437836..768a4ff44 100644
--- a/camel/providers/imapx/camel-imapx-server.c
+++ b/camel/providers/imapx/camel-imapx-server.c
@@ -1,3 +1,21 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
#ifdef HAVE_CONFIG_H
#include <config.h>
@@ -139,7 +157,7 @@ struct _CamelIMAPXCommand {
const gchar *name; /* command name/type (e.g. FETCH) */
- gchar *select; /* folder to select */
+ CamelFolder *select; /* folder to select */
struct _status_info *status; /* status for command, indicates it is complete if != NULL */
@@ -161,7 +179,7 @@ struct _CamelIMAPXCommand {
struct _CamelIMAPXJob *job;
};
-CamelIMAPXCommand *camel_imapx_command_new(CamelIMAPXServer *is, const gchar *name, const gchar *select, const gchar *fmt, ...);
+CamelIMAPXCommand *camel_imapx_command_new(CamelIMAPXServer *is, const gchar *name, CamelFolder *select, const gchar *fmt, ...);
void camel_imapx_command_add(CamelIMAPXCommand *ic, const gchar *fmt, ...);
void camel_imapx_command_free(CamelIMAPXCommand *ic);
void camel_imapx_command_close(CamelIMAPXCommand *ic);
@@ -170,6 +188,7 @@ static gboolean imapx_is_command_queue_empty (CamelIMAPXServer *is);
/* states for the connection? */
enum {
IMAPX_DISCONNECTED,
+ IMAPX_SHUTDOWN,
IMAPX_CONNECTED,
IMAPX_AUTHENTICATED,
IMAPX_INITIALISED,
@@ -263,6 +282,8 @@ struct _CamelIMAPXJob {
/* used for biulding uidset stuff */
gint index;
gint last_index;
+ gboolean update_unseen;
+ gboolean dummy_exception;
struct _uidset_state uidset;
/* changes during refresh */
CamelFolderChangeInfo *changes;
@@ -273,6 +294,7 @@ struct _CamelIMAPXJob {
guint32 off_set;
GArray *on_user; /* imapx_flag_change */
GArray *off_user;
+ gint unread_change;
} sync_changes;
struct {
gchar *path;
@@ -307,6 +329,7 @@ struct _CamelIMAPXJob {
} u;
};
+static CamelIMAPXJob *imapx_match_active_job (CamelIMAPXServer *is, guint32 type, const gchar *uid);
static void imapx_job_done (CamelIMAPXServer *is, CamelIMAPXJob *job);
static void imapx_run_job (CamelIMAPXServer *is, CamelIMAPXJob *job);
static void imapx_job_fetch_new_messages_start (CamelIMAPXServer *is, CamelIMAPXJob *job);
@@ -501,7 +524,7 @@ imapx_command_add_part(CamelIMAPXCommand *ic, camel_imapx_command_part_t type, g
}
if (type & CAMEL_IMAPX_COMMAND_LITERAL_PLUS) {
- if (ic->is->cinfo && ic->is->cinfo->capa & IMAPX_CAPABILITY_LITERALPLUS) {
+ if (ic->is->cinfo->capa & IMAPX_CAPABILITY_LITERALPLUS) {
camel_stream_printf((CamelStream *)ic->mem, "{%u+}", ob_size);
} else {
type &= ~CAMEL_IMAPX_COMMAND_LITERAL_PLUS;
@@ -716,7 +739,7 @@ imapx_command_addv(CamelIMAPXCommand *ic, const gchar *fmt, va_list ap)
}
CamelIMAPXCommand *
-camel_imapx_command_new(CamelIMAPXServer *is, const gchar *name, const gchar *select, const gchar *fmt, ...)
+camel_imapx_command_new(CamelIMAPXServer *is, const gchar *name, CamelFolder *select, const gchar *fmt, ...)
{
CamelIMAPXCommand *ic;
static gint tag = 0;
@@ -726,7 +749,7 @@ camel_imapx_command_new(CamelIMAPXServer *is, const gchar *name, const gchar *se
ic->tag = tag++;
ic->name = name;
ic->mem = (CamelStreamMem *)camel_stream_mem_new();
- ic->select = g_strdup(select);
+ ic->select = select;
ic->is = is;
camel_dlist_init(&ic->parts);
ic->ex = camel_exception_new ();
@@ -765,8 +788,7 @@ camel_imapx_command_free(CamelIMAPXCommand *ic)
if (ic->mem)
camel_object_unref((CamelObject *)ic->mem);
imapx_free_status(ic->status);
- g_free(ic->select);
-
+
while ((cp = ((CamelIMAPXCommandPart *)camel_dlist_remhead(&ic->parts)))) {
g_free(cp->data);
if (cp->ob) {
@@ -844,6 +866,21 @@ imapx_command_start (CamelIMAPXServer *imap, CamelIMAPXCommand *ic)
return TRUE;
}
+static gboolean duplicate_fetch_or_refresh(CamelIMAPXServer *is, CamelIMAPXCommand *ic)
+{
+ if (!ic->job)
+ return FALSE;
+
+ if (!(ic->job->type & (IMAPX_JOB_FETCH_NEW_MESSAGES|IMAPX_JOB_REFRESH_INFO)))
+ return FALSE;
+
+ if (imapx_match_active_job (is, IMAPX_JOB_FETCH_NEW_MESSAGES|IMAPX_JOB_REFRESH_INFO, NULL)) {
+ c(printf("Not yet sending duplicate fetch/refresh %s command\n", ic->name));
+ return TRUE;
+ }
+
+ return FALSE;
+}
/* See if we can start another task yet.
If we're waiting for a literal, we cannot proceed.
@@ -881,7 +918,7 @@ imapx_command_start_next(CamelIMAPXServer *is, CamelException *ex)
nc = ic->next;
while (nc && is->literal == NULL && count < MAX_COMMANDS && ic->pri >= pri) {
c(printf("-- %3d '%s'?\n", (gint)ic->pri, ic->name));
- if (ic->select == NULL) {
+ if (!ic->select) {
c(printf("--> starting '%s'\n", ic->name));
pri = ic->pri;
camel_dlist_remove((CamelDListNode *)ic);
@@ -905,7 +942,9 @@ imapx_command_start_next(CamelIMAPXServer *is, CamelException *ex)
if (imapx_in_idle (is) && !camel_dlist_empty (&is->queue)) {
/* if imapx_stop_idle() returns FALSE, it was only
pending and we can go ahead and send a new command
- immediately. If it returns TRUE, we must wait. */
+ immediately. If it returns TRUE, either it sent the
+ DONE to exit IDLE mode, or there was an error.
+ Either way, we do nothing more right now. */
if (imapx_stop_idle (is, ex)) {
c(printf ("waiting for idle to stop \n"));
return;
@@ -925,8 +964,9 @@ imapx_command_start_next(CamelIMAPXServer *is, CamelException *ex)
}
/* See if any queued jobs on this select first */
- if (is->select) {
- c(printf("- we're selected on '%s', current jobs?\n", is->select));
+ if (is->select_folder) {
+ c(printf("- we're selected on '%s', current jobs?\n",
+ camel_folder_get_full_name(is->select_folder)));
for (ic = (CamelIMAPXCommand *)is->active.head;ic->next;ic=ic->next) {
c(printf("- %3d '%s'\n", (gint)ic->pri, ic->name));
if (ic->pri > pri)
@@ -944,7 +984,8 @@ imapx_command_start_next(CamelIMAPXServer *is, CamelException *ex)
nc = ic->next;
while (nc && is->literal == NULL && count < MAX_COMMANDS && ic->pri >= pri) {
c(printf("-- %3d '%s'?\n", (gint)ic->pri, ic->name));
- if (ic->select == NULL || strcmp(ic->select, is->select) == 0) {
+ if (!ic->select || ((ic->select == is->select_folder) &&
+ !duplicate_fetch_or_refresh(is, ic))) {
c(printf("--> starting '%s'\n", ic->name));
pri = ic->pri;
camel_dlist_remove((CamelDListNode *)ic);
@@ -968,14 +1009,17 @@ imapx_command_start_next(CamelIMAPXServer *is, CamelException *ex)
/* If we need to select a folder for the first command, do it now, once
it is complete it will re-call us if it succeeded */
- if (ic->job->folder) {
- imapx_select(is, ic->job->folder, FALSE, ex);
+ if (ic->select) {
+ c(printf("Selecting folder '%s' for command '%s'(%p)\n",
+ camel_folder_get_full_name(ic->select), ic->name, ic));
+ imapx_select(is, ic->select, FALSE, ex);
} else {
pri = ic->pri;
nc = ic->next;
count = 0;
while (nc && is->literal == NULL && count < MAX_COMMANDS && ic->pri >= pri) {
- if (ic->select == NULL || (is->select && strcmp(ic->select, is->select))) {
+ if (!ic->select || (ic->select == is->select_folder &&
+ !duplicate_fetch_or_refresh(is, ic))) {
c(printf("* queueing job %3d '%s'\n", (gint)ic->pri, ic->name));
pri = ic->pri;
camel_dlist_remove((CamelDListNode *)ic);
@@ -1013,6 +1057,15 @@ imapx_command_queue(CamelIMAPXServer *is, CamelIMAPXCommand *ic)
QUEUE_LOCK(is);
+ if (is->state == IMAPX_SHUTDOWN) {
+ c(printf("refuse to queue job on disconnected server\n"));
+ camel_exception_set(ic->ex, 1, "Server disconnected");
+ QUEUE_UNLOCK(is);
+ if (ic->complete)
+ ic->complete(is, ic);
+ return;
+ }
+
scan = (CamelIMAPXCommand *)is->queue.head;
if (scan->next == NULL)
camel_dlist_addtail(&is->queue, (CamelDListNode *)ic);
@@ -1058,20 +1111,19 @@ found:
}
static gboolean
-imapx_job_matches (const gchar *folder_name, CamelIMAPXJob *job, guint32 type, const gchar *uid)
+imapx_job_matches (CamelFolder *folder, CamelIMAPXJob *job, guint32 type, const gchar *uid)
{
switch (job->type) {
case IMAPX_JOB_GET_MESSAGE:
- if (folder_name && strcmp(job->folder->full_name, folder_name) == 0
- && strcmp(job->u.get_message.uid, uid) == 0)
+ if (folder == job->folder &&
+ strcmp(job->u.get_message.uid, uid) == 0)
return TRUE;
break;
case IMAPX_JOB_FETCH_NEW_MESSAGES:
case IMAPX_JOB_REFRESH_INFO:
case IMAPX_JOB_SYNC_CHANGES:
case IMAPX_JOB_EXPUNGE:
- if (folder_name
- && strcmp(job->folder->full_name, folder_name) == 0)
+ if (folder == job->folder)
return TRUE;
break;
case IMAPX_JOB_LIST:
@@ -1095,7 +1147,7 @@ imapx_match_active_job (CamelIMAPXServer *is, guint32 type, const gchar *uid)
if (!job || !(job->type & type))
continue;
- if (imapx_job_matches (is->select, job, type, uid))
+ if (imapx_job_matches (is->select_folder, job, type, uid))
goto found;
}
job = NULL;
@@ -1105,7 +1157,7 @@ found:
}
static CamelIMAPXJob *
-imapx_is_job_in_queue (CamelIMAPXServer *is, const gchar *folder_name, guint32 type, const gchar *uid)
+imapx_is_job_in_queue (CamelIMAPXServer *is, CamelFolder *folder, guint32 type, const gchar *uid)
{
CamelDListNode *node;
CamelIMAPXJob *job = NULL;
@@ -1119,7 +1171,7 @@ imapx_is_job_in_queue (CamelIMAPXServer *is, const gchar *folder_name, guint32 t
if (!job || !(job->type & type))
continue;
- if (imapx_job_matches (folder_name, job, type, uid)) {
+ if (imapx_job_matches (folder, job, type, uid)) {
found = TRUE;
break;
}
@@ -1134,12 +1186,12 @@ imapx_is_job_in_queue (CamelIMAPXServer *is, const gchar *folder_name, guint32 t
}
static void
-imapx_expunge_uid_from_summary(CamelIMAPXServer *imap, gchar *uid)
+imapx_expunge_uid_from_summary(CamelIMAPXServer *imap, gchar *uid, gboolean unsolicited)
{
CamelMessageInfo *mi;
CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *)imap->select_folder;
- if (ifolder->exists_on_server)
+ if (unsolicited && ifolder->exists_on_server)
ifolder->exists_on_server--;
if (imap->changes == NULL)
@@ -1147,7 +1199,7 @@ imapx_expunge_uid_from_summary(CamelIMAPXServer *imap, gchar *uid)
mi = camel_folder_summary_uid (imap->select_folder->summary, uid);
if (mi) {
- imapx_update_summary_for_removed_message (mi, imap->select_folder);
+ imapx_update_summary_for_removed_message (mi, imap->select_folder, unsolicited);
camel_message_info_free (mi);
}
@@ -1221,21 +1273,40 @@ imapx_untagged(CamelIMAPXServer *imap, CamelException *ex)
if (!uid)
break;
- imapx_expunge_uid_from_summary(imap, uid);
+ imapx_expunge_uid_from_summary(imap, uid, TRUE);
}
break;
}
case IMAPX_VANISHED: {
- GPtrArray *uids = imapx_parse_uids(imap->stream, ex);
+ GPtrArray *uids;
+ gboolean unsolicited = TRUE;
int i;
+ guint len;
+ guchar *token;
+ gint tok;
+
+ tok = camel_imapx_stream_token (imap->stream, &token, &len, ex);
+ if (camel_exception_is_set(ex))
+ return -1;
+ if (tok == '(') {
+ unsolicited = FALSE;
+ while (tok != ')') {
+ /* We expect this to be 'EARLIER' */
+ tok = camel_imapx_stream_token(imap->stream, &token, &len, ex);
+ if (camel_exception_is_set(ex))
+ return -1;
+ }
+ } else
+ camel_imapx_stream_ungettoken(imap->stream, tok, token, len);
+ uids = imapx_parse_uids(imap->stream, ex);
if (camel_exception_is_set(ex))
return -1;
for (i = 0; i < uids->len; i++) {
gchar *uid = g_strdup_printf("%u", GPOINTER_TO_UINT(g_ptr_array_index (uids, i)));
c(printf("vanished: %s\n", uid));
- imapx_expunge_uid_from_summary(imap, uid);
+ imapx_expunge_uid_from_summary(imap, uid, unsolicited);
}
g_ptr_array_free (uids, FALSE);
break;
@@ -1343,9 +1414,11 @@ imapx_untagged(CamelIMAPXServer *imap, CamelException *ex)
if (uid) {
mi = camel_folder_summary_uid (folder->summary, uid);
- if (mi)
- changed = imapx_update_message_info_flags (mi, finfo->flags, finfo->user_flags, folder);
- else {
+ if (mi) {
+ /* It's unsolicited _unless_ imap->select_pending (i.e. during
+ a QRESYNC SELECT */
+ changed = imapx_update_message_info_flags (mi, finfo->flags, finfo->user_flags, folder, !imap->select_pending);
+ } else {
/* This (UID + FLAGS for previously unknown message) might
happen during a SELECT (QRESYNC). We should use it. */
c(printf("flags changed for unknown uid %s\n.", uid));
@@ -1395,6 +1468,7 @@ imapx_untagged(CamelIMAPXServer *imap, CamelException *ex)
guint32 server_flags;
CamelFlag *server_user_flags;
CamelMessageInfoBase *binfo;
+ gboolean free_user_flags = FALSE;
mi->uid = camel_pstring_strdup (finfo->uid);
@@ -1433,6 +1507,24 @@ imapx_untagged(CamelIMAPXServer *imap, CamelException *ex)
server_user_flags = finfo->user_flags;
/* free user_flags ? */
finfo->user_flags = NULL;
+ free_user_flags = TRUE;
+ }
+
+ /* If the message is a really new one -- equal or higher than what
+ we know as UIDNEXT for the folder, then it came in since we last
+ fetched UIDNEXT and UNREAD count. We'll update UIDNEXT in the
+ command completion, but update UNREAD count now according to the
+ message SEEN flag */
+ if (!(server_flags & CAMEL_MESSAGE_SEEN)) {
+ CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *)job->folder;
+ unsigned long long uidl = strtoull(mi->uid, NULL, 10);
+
+ if (uidl >= ifolder->uidnext_on_server) {
+ c(printf("Updating unread count for new message %s\n", mi->uid));
+ ((CamelIMAPXFolder *)job->folder)->unread_on_server++;
+ } else {
+ c(printf("Not updating unread count for new message %s\n", mi->uid));
+ }
}
binfo = (CamelMessageInfoBase *) mi;
@@ -1450,10 +1542,15 @@ imapx_untagged(CamelIMAPXServer *imap, CamelException *ex)
g_hash_table_remove (ifolder->ignore_recent, mi->uid);
}
- if (job->op)
- camel_operation_progress (job->op, (camel_folder_summary_count (job->folder->summary)
- * 100)/ifolder->exists_on_server?:1);
+ if (job->op) {
+ int cnt = (camel_folder_summary_count (job->folder->summary) * 100 )/ifolder->exists_on_server;
+ camel_operation_progress (job->op, cnt?cnt:1);
+ }
}
+
+ if (free_user_flags && server_user_flags)
+ camel_flag_list_free (&server_user_flags);
+
}
}
}
@@ -1513,6 +1610,7 @@ imapx_untagged(CamelIMAPXServer *imap, CamelException *ex)
ifolder->exists_on_server = sinfo->messages;
ifolder->modseq_on_server = sinfo->highestmodseq;
ifolder->uidnext_on_server = sinfo->uidnext;
+ ifolder->uidvalidity_on_server = sinfo->uidvalidity;
} else {
c(printf("Received STATUS for unknown folder '%s'\n", sinfo->name));
}
@@ -1530,7 +1628,8 @@ imapx_untagged(CamelIMAPXServer *imap, CamelException *ex)
c(printf("BYE: %s\n", token));
camel_exception_setv(ex, 1, "IMAP server said BYE: %s", token);
}
- break;
+ imap->state = IMAPX_SHUTDOWN;
+ return -1;
}
case IMAPX_PREAUTH:
c(printf("preauthenticated\n"));
@@ -1549,11 +1648,7 @@ imapx_untagged(CamelIMAPXServer *imap, CamelException *ex)
case IMAPX_CLOSED:
c(printf("previously selected folder is now closed\n"));
if (imap->select_pending && !imap->select_folder) {
- const gchar *full_name;
imap->select_folder = imap->select_pending;
- full_name = camel_folder_get_full_name (imap->select_folder);
-
- imap->select = g_strdup(full_name);
}
break;
case IMAPX_READ_WRITE:
@@ -1587,10 +1682,11 @@ imapx_untagged(CamelIMAPXServer *imap, CamelException *ex)
break;
case IMAPX_CAPABILITY:
if (sinfo->u.cinfo) {
- if (imap->cinfo)
- imapx_free_capability(imap->cinfo);
+ struct _capability_info *cinfo = imap->cinfo;
imap->cinfo = sinfo->u.cinfo;
sinfo->u.cinfo = NULL;
+ if (cinfo)
+ imapx_free_capability(cinfo);
c(printf("got capability flags %08x\n", imap->cinfo->capa));
}
break;
@@ -1631,7 +1727,10 @@ imapx_continuation(CamelIMAPXServer *imap, CamelException *ex, gboolean litplus)
/* IDLE got cancelled after we sent the command, while
we were waiting for this continuation. Send DONE
immediately. */
- imapx_command_idle_stop(imap, ex);
+ if (!imapx_command_idle_stop (imap, ex)) {
+ IDLE_UNLOCK(imap->idle);
+ return -1;
+ }
imap->idle->state = IMAPX_IDLE_OFF;
} else {
c(printf("idle starts in wrong state %d\n",
@@ -1685,7 +1784,7 @@ imapx_continuation(CamelIMAPXServer *imap, CamelException *ex, gboolean litplus)
c(printf("got auth continuation, feeding token '%s' back to auth mech\n", resp));
camel_stream_write((CamelStream *)imap->stream, resp, strlen(resp));
-
+ g_free(resp);
/* we want to keep getting called until we get a status reponse from the server
ignore what sasl tells us */
newliteral = ic;
@@ -1899,6 +1998,10 @@ imapx_job_done (CamelIMAPXServer *is, CamelIMAPXJob *job)
if (job->noreply) {
camel_exception_clear(job->ex);
+ if (job->type == IMAPX_JOB_FETCH_NEW_MESSAGES &&
+ job->u.refresh_info.dummy_exception)
+ camel_exception_free (job->ex);
+
g_free(job);
} else
camel_msgport_reply((CamelMsg *) job);
@@ -1954,6 +2057,11 @@ imapx_command_idle_stop (CamelIMAPXServer *is, CamelException *ex)
{
if (!is->stream || camel_stream_printf((CamelStream *)is->stream, "%s", "DONE\r\n") == -1) {
camel_exception_set (ex, 1, "Unable to issue DONE");
+ c(printf("Failed to issue DONE to terminate IDLE\n"));
+ is->state = IMAPX_SHUTDOWN;
+ if (is->op)
+ camel_operation_cancel(is->op);
+ is->parser_quit = TRUE;
return FALSE;
}
@@ -1986,7 +2094,7 @@ imapx_job_idle_start(CamelIMAPXServer *is, CamelIMAPXJob *job)
CamelIMAPXCommand *ic;
CamelIMAPXCommandPart *cp;
- ic = camel_imapx_command_new (is, "IDLE", job->folder->full_name, "IDLE");
+ ic = camel_imapx_command_new (is, "IDLE", job->folder, "IDLE");
ic->job = job;
ic->pri = job->pri;
ic->complete = imapx_command_idle_done;
@@ -2026,7 +2134,8 @@ camel_imapx_server_idle (CamelIMAPXServer *is, CamelFolder *folder, CamelExcepti
}
static void
-imapx_server_fetch_new_messages (CamelIMAPXServer *is, CamelFolder *folder, gboolean async, CamelException *ex)
+imapx_server_fetch_new_messages (CamelIMAPXServer *is, CamelFolder *folder, gboolean async,
+ gboolean update_unseen, CamelException *ex)
{
CamelIMAPXJob *job;
@@ -2035,8 +2144,13 @@ imapx_server_fetch_new_messages (CamelIMAPXServer *is, CamelFolder *folder, gboo
job->start = imapx_job_fetch_new_messages_start;
job->folder = folder;
job->noreply = async;
+ if (!ex) {
+ job->u.refresh_info.dummy_exception = TRUE;
+ ex = camel_exception_new ();
+ }
job->ex = ex;
job->u.refresh_info.changes = camel_folder_change_info_new();
+ job->u.refresh_info.update_unseen = update_unseen;
job->op = camel_operation_registered ();
if (imapx_register_job (is, job))
@@ -2074,7 +2188,7 @@ imapx_idle_thread (gpointer data)
if (!camel_exception_is_set (ex) && ifolder->exists_on_server >
camel_folder_summary_count (((CamelFolder *) ifolder)->summary) && imapx_is_command_queue_empty (is))
- imapx_server_fetch_new_messages (is, is->select_folder, TRUE, ex);
+ imapx_server_fetch_new_messages (is, is->select_folder, TRUE, TRUE, ex);
if (camel_exception_is_set (ex)) {
e(printf ("Caught exception in idle thread: %s \n", ex->desc));
@@ -2114,9 +2228,13 @@ imapx_stop_idle (CamelIMAPXServer *is, CamelException *ex)
break;
case IMAPX_IDLE_STARTED:
- imapx_command_idle_stop (is, ex);
- idle->state = IMAPX_IDLE_OFF;
+ /* We set 'stopped' even if sending DONE fails, to ensure that
+ our caller doesn't try to submit its own command. */
stopped = TRUE;
+ if (!imapx_command_idle_stop (is, ex))
+ break;
+
+ idle->state = IMAPX_IDLE_OFF;
c(printf("Stopping idle after %ld seconds\n",
(long)(now - idle->started)));
case IMAPX_IDLE_PENDING:
@@ -2208,7 +2326,7 @@ imapx_in_idle (CamelIMAPXServer *is)
static gboolean
imapx_idle_supported (CamelIMAPXServer *is)
{
- return (is->cinfo && is->cinfo->capa & IMAPX_CAPABILITY_IDLE && is->use_idle);
+ return (is->cinfo->capa & IMAPX_CAPABILITY_IDLE && is->use_idle);
}
// end IDLE
@@ -2216,7 +2334,6 @@ imapx_idle_supported (CamelIMAPXServer *is)
static void
imapx_command_select_done (CamelIMAPXServer *is, CamelIMAPXCommand *ic)
{
-
if (camel_exception_is_set (ic->ex) || ic->status->result != IMAPX_OK) {
CamelDList failed;
CamelIMAPXCommand *cw, *cn;
@@ -2230,7 +2347,9 @@ imapx_command_select_done (CamelIMAPXServer *is, CamelIMAPXCommand *ic)
if (is->select_pending) {
while (cn) {
- if (cw->select && strcmp(cw->select, is->select_pending->full_name) == 0) {
+ if (cw->select && cw->select == is->select_pending) {
+ c(printf("Cancelling command '%s'(%p) for folder '%s'\n",
+ cw->name, cw, camel_folder_get_full_name(cw->select)));
camel_dlist_remove((CamelDListNode *)cw);
camel_dlist_addtail(&failed, (CamelDListNode *)cw);
}
@@ -2247,7 +2366,13 @@ imapx_command_select_done (CamelIMAPXServer *is, CamelIMAPXCommand *ic)
while (cn) {
if (ic->status)
cw->status = imapx_copy_status(ic->status);
- camel_exception_setv (cw->ex, 1, "select %s failed", cw->select);
+ if (camel_exception_is_set(ic->ex))
+ camel_exception_xfer (cw->ex, ic->ex);
+ else {
+ camel_exception_setv (cw->ex, 1, "SELECT %s failed: %s",
+ camel_folder_get_full_name(cw->select),
+ ic->status->text?ic->status->text:"<unknown reason>");
+ }
cw->complete(is, cw);
cw = cn;
cn = cn->next;
@@ -2257,11 +2382,9 @@ imapx_command_select_done (CamelIMAPXServer *is, CamelIMAPXCommand *ic)
camel_object_unref(is->select_pending);
/* A [CLOSED] status may have caused us to assume that it had happened */
- if (is->select) {
- g_free(is->select);
- is->select = NULL;
+ if (is->select_folder)
is->select_folder = NULL;
- }
+
is->state = IMAPX_INITIALISED;
} else {
CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) is->select_pending;
@@ -2270,12 +2393,17 @@ imapx_command_select_done (CamelIMAPXServer *is, CamelIMAPXCommand *ic)
if (!is->select_folder) {
/* This could have been done earlier by a [CLOSED] status */
is->select_folder = is->select_pending;
- is->select = g_strdup(is->select_folder->full_name);
}
is->state = IMAPX_SELECTED;
ifolder->exists_on_server = is->exists;
ifolder->modseq_on_server = is->highestmodseq;
- ifolder->uidnext_on_server = is->uidnext;
+ if (ifolder->uidnext_on_server < is->uidnext) {
+ imapx_server_fetch_new_messages (is, is->select_pending, TRUE, TRUE, NULL);
+ /* We don't do this right now because we want the new messages to
+ update the unseen count. */
+ //ifolder->uidnext_on_server = is->uidnext;
+ }
+ ifolder->uidvalidity_on_server = is->uidvalidity;
#if 0
/* This must trigger a complete index rebuild! */
if (is->uidvalidity && is->uidvalidity != ((CamelIMAPXSummary *)is->select_folder->summary)->uidvalidity)
@@ -2314,7 +2442,7 @@ imapx_select (CamelIMAPXServer *is, CamelFolder *folder, gboolean forced, CamelE
if (is->select_pending)
return;
- if (is->select && strcmp(is->select, folder->full_name) == 0 && !forced)
+ if (is->select_folder == folder && !forced)
return;
if (!camel_dlist_empty(&is->active))
@@ -2323,15 +2451,12 @@ imapx_select (CamelIMAPXServer *is, CamelFolder *folder, gboolean forced, CamelE
is->select_pending = folder;
camel_object_ref(folder);
if (is->select_folder) {
- g_free(is->select);
camel_object_unref(is->select_folder);
- is->select = NULL;
is->select_folder = NULL;
} else {
/* If no folder was selected, we won't get a [CLOSED] status
so just point select_folder at the new folder immediately */
is->select_folder = is->select_pending;
- is->select = g_strdup(is->select_folder->full_name);
}
is->uidvalidity = 0;
@@ -2347,6 +2472,66 @@ imapx_select (CamelIMAPXServer *is, CamelFolder *folder, gboolean forced, CamelE
is->state = IMAPX_INITIALISED;
ic = camel_imapx_command_new(is, "SELECT", NULL, "SELECT %f", folder);
+
+ if (is->use_qresync) {
+ CamelIMAPXSummary *isum = (CamelIMAPXSummary *)folder->summary;
+ CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *)folder;
+ gint total = camel_folder_summary_count(folder->summary);
+ const gchar *uid = "1";
+
+ if (total)
+ uid = camel_folder_summary_uid_from_index (folder->summary, 0);
+
+ if (isum->modseq && ifolder->uidvalidity_on_server) {
+ c(printf("SELECT QRESYNC %ld %ld\n", ifolder->uidvalidity_on_server, isum->modseq));
+ camel_imapx_command_add(ic, " (QRESYNC (%ld %ld %s:*", ifolder->uidvalidity_on_server, isum->modseq, uid);
+
+ if (total > 10) {
+ int i;
+ GString *seqs, *uids;
+
+ seqs = g_string_new(" ");
+ uids = g_string_new(")");
+
+ /* Include some seq/uid pairs to avoid a huge VANISHED list
+ (see RFC5162 §3.1). Work backwards exponentially from the
+ end of the mailbox, starting with the message 9 from the
+ end, then 27 from the end, then 81 from the end... */
+ i = 3;
+ do {
+ gchar buf[10];
+
+ i *= 3;
+ if (i > total)
+ i = total;
+
+ if (i != 9) { /* If not the first time */
+ g_string_prepend(seqs, ",");
+ g_string_prepend(uids, ",");
+ }
+
+ /* IMAP sequence numbers are one higher than the corresponding
+ indices in our folder summary -- they start from one, while
+ the summary starts from zero. */
+ sprintf(buf, "%d", total - i + 1);
+ g_string_prepend(seqs, buf);
+ g_string_prepend(uids, camel_folder_summary_uid_from_index(folder->summary, total - i));
+ } while (i < total);
+
+ g_string_prepend(seqs, " (");
+
+ c(printf("adding QRESYNC seq/uidset %s%s\n", seqs->str, uids->str));
+ camel_imapx_command_add(ic, seqs->str);
+ camel_imapx_command_add(ic, uids->str);
+
+ g_string_free(seqs, TRUE);
+ g_string_free(uids, TRUE);
+
+ }
+ camel_imapx_command_add(ic, "))");
+ }
+ }
+
ic->complete = imapx_command_select_done;
imapx_command_start (is, ic);
}
@@ -2701,7 +2886,7 @@ imapx_reconnect (CamelIMAPXServer *is, CamelException *ex)
goto preauthed;
if (!authtype && service->url->authmech) {
- if (is->cinfo && !g_hash_table_lookup (is->cinfo->auth_types, service->url->authmech)) {
+ if (!g_hash_table_lookup (is->cinfo->auth_types, service->url->authmech)) {
camel_exception_setv (
ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
_("IMAP server %s does not support requested "
@@ -2828,6 +3013,19 @@ imapx_reconnect (CamelIMAPXServer *is, CamelException *ex)
if (camel_exception_is_set (ex))
goto exception;
}
+ if (((CamelIMAPXStore *)is->store)->rec_options & IMAPX_USE_QRESYNC &&
+ is->cinfo->capa & IMAPX_CAPABILITY_QRESYNC) {
+ ic = camel_imapx_command_new (is, "ENABLE", NULL, "ENABLE CONDSTORE QRESYNC");
+ imapx_command_run (is, ic);
+ camel_exception_xfer (ex, ic->ex);
+ camel_imapx_command_free (ic);
+
+ if (camel_exception_is_set (ex))
+ goto exception;
+
+ is->use_qresync = TRUE;
+ } else
+ is->use_qresync = FALSE;
if (((CamelIMAPXStore *) is->store)->summary->namespaces == NULL) {
CamelIMAPXNamespaceList *nsl = NULL;
@@ -2890,7 +3088,7 @@ imapx_command_fetch_message_done(CamelIMAPXServer *is, CamelIMAPXCommand *ic)
if (job->op)
camel_operation_progress (job->op, (job->u.get_message.fetch_offset *100)/job->u.get_message.size);
- ic = camel_imapx_command_new(is, "FETCH", job->folder->full_name,
+ ic = camel_imapx_command_new(is, "FETCH", job->folder,
"UID FETCH %t (BODY.PEEK[]", job->u.get_message.uid);
camel_imapx_command_add(ic, "<%u.%u>", job->u.get_message.fetch_offset, MULTI_SIZE);
camel_imapx_command_add(ic, ")");
@@ -2956,7 +3154,7 @@ imapx_job_get_message_start (CamelIMAPXServer *is, CamelIMAPXJob *job)
if (job->u.get_message.use_multi_fetch) {
for (i=0; i < 3 && job->u.get_message.fetch_offset < job->u.get_message.size;i++) {
- ic = camel_imapx_command_new(is, "FETCH", job->folder->full_name,
+ ic = camel_imapx_command_new(is, "FETCH", job->folder,
"UID FETCH %t (BODY.PEEK[]", job->u.get_message.uid);
camel_imapx_command_add(ic, "<%u.%u>", job->u.get_message.fetch_offset, MULTI_SIZE);
camel_imapx_command_add(ic, ")");
@@ -2968,7 +3166,7 @@ imapx_job_get_message_start (CamelIMAPXServer *is, CamelIMAPXJob *job)
imapx_command_queue(is, ic);
}
} else {
- ic = camel_imapx_command_new(is, "FETCH", job->folder->full_name,
+ ic = camel_imapx_command_new(is, "FETCH", job->folder,
"UID FETCH %t (BODY.PEEK[])", job->u.get_message.uid);
ic->complete = imapx_command_fetch_message_done;
ic->job = job;
@@ -2987,7 +3185,7 @@ imapx_command_copy_messages_step_start (CamelIMAPXServer *is, CamelIMAPXJob *job
GPtrArray *uids = job->u.copy_messages.uids;
gint i = index;
- ic = camel_imapx_command_new (is, "COPY", job->folder->full_name, "UID COPY ");
+ ic = camel_imapx_command_new (is, "COPY", job->folder, "UID COPY ");
ic->complete = imapx_command_copy_messages_step_done;
ic->job = job;
ic->pri = job->pri;
@@ -3097,7 +3295,7 @@ imapx_command_append_message_done (CamelIMAPXServer *is, CamelIMAPXCommand *ic)
if (!camel_exception_is_set (ic->ex) && ic->status->result == IMAPX_OK) {
if (ic->status->condition == IMAPX_APPENDUID) {
c(printf("Got appenduid %d %d\n", (gint)ic->status->u.appenduid.uidvalidity, (gint)ic->status->u.appenduid.uid));
- if (ic->status->u.appenduid.uidvalidity == is->uidvalidity) {
+ if (ic->status->u.appenduid.uidvalidity == ifolder->uidvalidity_on_server) {
CamelFolderChangeInfo *changes;
gchar *uid;
@@ -3109,7 +3307,10 @@ imapx_command_append_message_done (CamelIMAPXServer *is, CamelIMAPXCommand *ic)
/* should we update the message count ? */
camel_folder_summary_add (job->folder->summary, mi);
-
+ imapx_set_message_info_flags_for_new_message (mi,
+ ((CamelMessageInfoBase *)job->u.append_message.info)->flags,
+ ((CamelMessageInfoBase *)job->u.append_message.info)->user_flags,
+ job->folder);
changes = camel_folder_change_info_new ();
camel_folder_change_info_add_uid (changes, mi->uid);
camel_object_trigger_event (CAMEL_OBJECT (job->folder), "folder_changed",
@@ -3224,6 +3425,8 @@ imapx_index_next (GPtrArray *uids, CamelFolderSummary *s, guint index)
static void
imapx_command_step_fetch_done(CamelIMAPXServer *is, CamelIMAPXCommand *ic)
{
+ CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *)ic->job->folder;
+ CamelIMAPXSummary *isum = (CamelIMAPXSummary *)ic->job->folder->summary;
CamelIMAPXJob *job = ic->job;
gint i = job->u.refresh_info.index;
GArray *infos = job->u.refresh_info.infos;
@@ -3248,7 +3451,7 @@ imapx_command_step_fetch_done(CamelIMAPXServer *is, CamelIMAPXCommand *ic)
if (i<infos->len) {
camel_imapx_command_free (ic);
- ic = camel_imapx_command_new(is, "FETCH", job->folder->full_name, "UID FETCH ");
+ ic = camel_imapx_command_new(is, "FETCH", job->folder, "UID FETCH ");
ic->complete = imapx_command_step_fetch_done;
ic->job = job;
ic->pri = job->pri - 1;
@@ -3277,10 +3480,27 @@ imapx_command_step_fetch_done(CamelIMAPXServer *is, CamelIMAPXCommand *ic)
}
}
+ if (camel_folder_summary_count(job->folder->summary)) {
+ gchar *uid = camel_folder_summary_uid_from_index (job->folder->summary,
+ camel_folder_summary_count(job->folder->summary) - 1);
+ unsigned long long uidl = strtoull(uid, NULL, 10);
+ g_free(uid);
+
+ uidl++;
+
+ if (uidl > ifolder->uidnext_on_server) {
+ c(printf("Updating uidnext_on_server for '%s' to %lld\n",
+ camel_folder_get_full_name(job->folder), uidl));
+ ifolder->uidnext_on_server = uidl;
+ }
+ }
+ isum->uidnext = ifolder->uidnext_on_server;
+
cleanup:
for (i=0;i<infos->len;i++) {
struct _refresh_info *r = &g_array_index(infos, struct _refresh_info, i);
+ camel_flag_list_free (&r->server_user_flags);
g_free(r->uid);
}
g_array_free(job->u.refresh_info.infos, TRUE);
@@ -3374,7 +3594,7 @@ imapx_job_scan_changes_done(CamelIMAPXServer *is, CamelIMAPXCommand *ic)
if (s_minfo && uid_cmp(s_minfo->uid, r->uid, s) == 0) {
info = (CamelIMAPXMessageInfo *)s_minfo;
- if (imapx_update_message_info_flags ((CamelMessageInfo *) info, r->server_flags, r->server_user_flags, job->folder))
+ if (imapx_update_message_info_flags ((CamelMessageInfo *) info, r->server_flags, r->server_user_flags, job->folder, FALSE))
camel_folder_change_info_change_uid (job->u.refresh_info.changes, camel_message_info_uid (s_minfo));
r->exists = TRUE;
} else
@@ -3416,7 +3636,7 @@ imapx_job_scan_changes_done(CamelIMAPXServer *is, CamelIMAPXCommand *ic)
mi = camel_folder_summary_uid (job->folder->summary, uid);
if (mi) {
- imapx_update_summary_for_removed_message (mi, job->folder);
+ imapx_update_summary_for_removed_message (mi, job->folder, FALSE);
camel_message_info_free (mi);
}
@@ -3442,7 +3662,9 @@ imapx_job_scan_changes_done(CamelIMAPXServer *is, CamelIMAPXCommand *ic)
if (fetch_new) {
camel_operation_start (job->op, _("Fetching summary information for new messages in %s"), job->folder->name);
imapx_uidset_init(&job->u.refresh_info.uidset, BATCH_FETCH_COUNT, 0);
- /* command will be free'ed in step_fetch_done */
+ /* These are new messages which arrived since we last knew the unseen count;
+ update it as they arrive. */
+ job->u.refresh_info.update_unseen = TRUE;
imapx_command_step_fetch_done(is, ic);
return;
}
@@ -3456,6 +3678,7 @@ imapx_job_scan_changes_done(CamelIMAPXServer *is, CamelIMAPXCommand *ic)
for (i=0;i<infos->len;i++) {
struct _refresh_info *r = &g_array_index(infos, struct _refresh_info, i);
+ camel_flag_list_free (&r->server_user_flags);
g_free(r->uid);
}
@@ -3473,9 +3696,11 @@ imapx_job_scan_changes_start(CamelIMAPXServer *is, CamelIMAPXJob *job)
{
CamelIMAPXCommand *ic;
- camel_operation_start (job->op, _("Scanning for changed messages in %s"), job->folder->name);
+ camel_operation_start (
+ job->op, _("Scanning for changed messages in %s"),
+ job->folder->name);
- ic = camel_imapx_command_new (is, "FETCH", job->folder->full_name,
+ ic = camel_imapx_command_new (is, "FETCH", job->folder,
"UID FETCH 1:* (UID FLAGS)");
ic->job = job;
ic->complete = imapx_job_scan_changes_done;
@@ -3497,7 +3722,6 @@ imapx_command_fetch_new_messages_done (CamelIMAPXServer *is, CamelIMAPXCommand *
camel_exception_xfer (ic->job->ex, ic->ex);
goto exception;
}
- isum->uidnext = ifolder->uidnext_on_server;
if (camel_folder_change_info_changed(ic->job->u.refresh_info.changes)) {
imapx_update_store_summary (ic->job->folder);
@@ -3506,6 +3730,23 @@ imapx_command_fetch_new_messages_done (CamelIMAPXServer *is, CamelIMAPXCommand *
camel_folder_change_info_clear(ic->job->u.refresh_info.changes);
}
+ if (camel_folder_summary_count(ic->job->folder->summary)) {
+ gchar *uid = camel_folder_summary_uid_from_index (ic->job->folder->summary,
+ camel_folder_summary_count(ic->job->folder->summary) - 1);
+ unsigned long long uidl = strtoull(uid, NULL, 10);
+ g_free(uid);
+
+ uidl++;
+
+ if (uidl > ifolder->uidnext_on_server) {
+ c(printf("Updating uidnext_on_server for '%s' to %lld\n",
+ camel_folder_get_full_name(ic->job->folder), uidl));
+ ifolder->uidnext_on_server = uidl;
+ }
+ }
+
+ isum->uidnext = ifolder->uidnext_on_server;
+
exception:
if (ic->job->noreply)
camel_folder_change_info_free(ic->job->u.refresh_info.changes);
@@ -3529,22 +3770,26 @@ imapx_job_fetch_new_messages_start (CamelIMAPXServer *is, CamelIMAPXJob *job)
total = camel_folder_summary_count (folder->summary);
diff = ifolder->exists_on_server - total;
- if (total > 0)
+ if (total > 0) {
+ unsigned long long uidl;
uid = camel_folder_summary_uid_from_index (folder->summary, total - 1);
- else
+ uidl = strtoull(uid, NULL, 10);
+ g_free(uid);
+ uid = g_strdup_printf("%lld", uidl+1);
+ } else
uid = g_strdup ("1");
camel_operation_start (job->op, _("Fetching summary information for new messages in %s"), folder->name);
if (diff > BATCH_FETCH_COUNT) {
- ic = camel_imapx_command_new (is, "FETCH", job->folder->full_name,
+ ic = camel_imapx_command_new (is, "FETCH", job->folder,
"UID FETCH %s:* (UID FLAGS)", uid);
imapx_uidset_init(&job->u.refresh_info.uidset, BATCH_FETCH_COUNT, 0);
job->u.refresh_info.infos = g_array_new (0, 0, sizeof(struct _refresh_info));
ic->pri = job->pri;
ic->complete = imapx_command_step_fetch_done;
} else {
- ic = camel_imapx_command_new (is, "FETCH", job->folder->full_name,
+ ic = camel_imapx_command_new (is, "FETCH", job->folder,
"UID FETCH %s:* (RFC822.SIZE RFC822.HEADER FLAGS)", uid);
ic->pri = job->pri;
ic->complete = imapx_command_fetch_new_messages_done;
@@ -3565,6 +3810,7 @@ imapx_job_refresh_info_start (CamelIMAPXServer *is, CamelIMAPXJob *job)
CamelException *ex = job->ex;
gboolean need_rescan = FALSE;
gboolean is_selected = FALSE;
+ gboolean can_qresync = FALSE;
/* Sync changes first, else unread count will not
match. Need to think about better ways for this */
@@ -3574,7 +3820,7 @@ imapx_job_refresh_info_start (CamelIMAPXServer *is, CamelIMAPXJob *job)
#if 0 /* There are issues with this still; continue with the buggy behaviour
where we issue STATUS on the current folder, for now...*/
- if (is->select && !strcmp(folder->full_name, is->select))
+ if (is->select_folder == folder)
is_selected = TRUE;
#endif
total = camel_folder_summary_count (folder->summary);
@@ -3619,10 +3865,10 @@ imapx_job_refresh_info_start (CamelIMAPXServer *is, CamelIMAPXJob *job)
}
}
} else {
- if (is->cinfo && is->cinfo->capa & IMAPX_CAPABILITY_CONDSTORE)
- ic = camel_imapx_command_new (is, "STATUS", NULL, "STATUS %f (MESSAGES UNSEEN UIDNEXT HIGHESTMODSEQ)", folder);
+ if (is->cinfo->capa & IMAPX_CAPABILITY_CONDSTORE)
+ ic = camel_imapx_command_new (is, "STATUS", NULL, "STATUS %f (MESSAGES UNSEEN UIDVALIDITY UIDNEXT HIGHESTMODSEQ)", folder);
else
- ic = camel_imapx_command_new (is, "STATUS", NULL, "STATUS %f (MESSAGES UNSEEN UIDNEXT)", folder);
+ ic = camel_imapx_command_new (is, "STATUS", NULL, "STATUS %f (MESSAGES UNSEEN UIDVALIDITY UIDNEXT)", folder);
ic->job = job;
ic->pri = job->pri;
@@ -3650,6 +3896,9 @@ imapx_job_refresh_info_start (CamelIMAPXServer *is, CamelIMAPXJob *job)
}
+ if (is->use_qresync && isum->modseq && ifolder->uidvalidity_on_server)
+ can_qresync = TRUE;
+
e(printf("folder %s is %sselected, total %u / %u, unread %u / %u, modseq %llu / %llu, uidnext %u / %u: will %srescan\n",
folder->full_name, is_selected?"": "not ", total, ifolder->exists_on_server,
folder->summary->unread_count, ifolder->unread_on_server,
@@ -3664,17 +3913,43 @@ imapx_job_refresh_info_start (CamelIMAPXServer *is, CamelIMAPXJob *job)
if (!total)
need_rescan = FALSE;
- imapx_server_fetch_new_messages (is, folder, FALSE, job->ex);
+ imapx_server_fetch_new_messages (is, folder, FALSE, FALSE, job->ex);
if (camel_exception_is_set (job->ex))
goto done;
+
+ /* If QRESYNC-capable we'll have got all flags changes in SELECT */
+ if (can_qresync)
+ goto qresync_done;
}
- /* Refetch flags for the entire folder */
- if (need_rescan) {
- imapx_job_scan_changes_start (is, job);
- return;
+ if (!need_rescan)
+ goto done;
+
+ if (can_qresync) {
+ /* Actually we only want to select it; no need for the NOOP */
+ camel_imapx_server_noop(is, folder, ex);
+ qresync_done:
+ isum->modseq = ifolder->modseq_on_server;
+ total = camel_folder_summary_count(job->folder->summary);
+ if (total != ifolder->exists_on_server ||
+ folder->summary->unread_count != ifolder->unread_on_server ||
+ (isum->modseq != ifolder->modseq_on_server)) {
+ c(printf("Eep, after QRESYNC we're out of sync. total %u / %u, unread %u / %u, modseq %" G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT "\n",
+ total, ifolder->exists_on_server,
+ folder->summary->unread_count, ifolder->unread_on_server,
+ isum->modseq, ifolder->modseq_on_server));
+ } else {
+ c(printf("OK, after QRESYNC we're still in sync. total %u / %u, unread %u / %u, modseq %" G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT "\n",
+ total, ifolder->exists_on_server,
+ folder->summary->unread_count, ifolder->unread_on_server,
+ isum->modseq, ifolder->modseq_on_server));
+ goto done;
+ }
}
+ imapx_job_scan_changes_start (is, job);
+ return;
+
done:
imapx_job_done (is, job);
}
@@ -3707,7 +3982,7 @@ imapx_command_expunge_done (CamelIMAPXServer *is, CamelIMAPXCommand *ic)
CamelMessageInfo *mi = camel_folder_summary_uid (folder->summary, uid);
if (mi) {
- imapx_update_summary_for_removed_message (mi, folder);
+ imapx_update_summary_for_removed_message (mi, folder, FALSE);
camel_message_info_free (mi);
}
@@ -3739,7 +4014,7 @@ imapx_job_expunge_start(CamelIMAPXServer *is, CamelIMAPXJob *job)
imapx_server_sync_changes (is, job->folder, job->pri, job->ex);
/* TODO handle UIDPLUS capability */
- ic = camel_imapx_command_new(is, "EXPUNGE", job->folder->full_name, "EXPUNGE");
+ ic = camel_imapx_command_new(is, "EXPUNGE", job->folder, "EXPUNGE");
ic->job = job;
ic->pri = job->pri;
ic->complete = imapx_command_expunge_done;
@@ -3894,7 +4169,7 @@ imapx_job_delete_folder_start (CamelIMAPXServer *is, CamelIMAPXJob *job)
job->folder = camel_store_get_folder(is->store, "INBOX", 0, job->ex);
/* make sure to-be-deleted folder is not selected by selecting INBOX for this operation */
- ic = camel_imapx_command_new (is, "DELETE", "INBOX", "DELETE %s", encoded_fname);
+ ic = camel_imapx_command_new (is, "DELETE", job->folder, "DELETE %s", encoded_fname);
ic->pri = job->pri;
ic->job = job;
ic->complete = imapx_command_delete_folder_done;
@@ -3930,7 +4205,7 @@ imapx_job_rename_folder_start (CamelIMAPXServer *is, CamelIMAPXJob *job)
en_ofname = imapx_encode_folder_name ((CamelIMAPXStore *) is->store, job->u.rename_folder.ofolder_name);
en_nfname = imapx_encode_folder_name ((CamelIMAPXStore *) is->store, job->u.rename_folder.nfolder_name);
- ic = camel_imapx_command_new (is, "RENAME", "INBOX", "RENAME %s %s", en_ofname, en_nfname);
+ ic = camel_imapx_command_new (is, "RENAME", job->folder, "RENAME %s %s", en_ofname, en_nfname);
ic->pri = job->pri;
ic->job = job;
ic->complete = imapx_command_rename_folder_done;
@@ -3961,10 +4236,7 @@ imapx_job_noop_start(CamelIMAPXServer *is, CamelIMAPXJob *job)
{
CamelIMAPXCommand *ic;
- if (job->folder)
- ic = camel_imapx_command_new (is, "NOOP", job->folder->full_name, "NOOP");
- else
- ic = camel_imapx_command_new (is, "NOOP", NULL, "NOOP");
+ ic = camel_imapx_command_new (is, "NOOP", job->folder, "NOOP");
ic->job = job;
ic->complete = imapx_command_noop_done;
@@ -3987,7 +4259,9 @@ static struct {
{ "\\DRAFT", CAMEL_MESSAGE_DRAFT },
{ "\\FLAGGED", CAMEL_MESSAGE_FLAGGED },
{ "\\SEEN", CAMEL_MESSAGE_SEEN },
- { "\\RECENT", CAMEL_IMAPX_MESSAGE_RECENT }
+ { "\\RECENT", CAMEL_IMAPX_MESSAGE_RECENT },
+ { "JUNK", CAMEL_MESSAGE_JUNK },
+ { "NOTJUNK", CAMEL_MESSAGE_NOTJUNK }
};
/*
@@ -4031,21 +4305,23 @@ imapx_command_sync_changes_done (CamelIMAPXServer *is, CamelIMAPXCommand *ic)
gint i;
for (i=0;i<job->u.sync_changes.changed_uids->len;i++) {
- CamelIMAPXMessageInfo *info = (CamelIMAPXMessageInfo *) camel_folder_summary_uid (job->folder->summary,
+ CamelIMAPXMessageInfo *xinfo = (CamelIMAPXMessageInfo *) camel_folder_summary_uid (job->folder->summary,
job->u.sync_changes.changed_uids->pdata[i]);
- if (!info)
+ if (!xinfo)
continue;
- info->server_flags = ((CamelMessageInfoBase *)info)->flags & CAMEL_IMAPX_SERVER_FLAGS;
- info->info.flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED;
- info->info.dirty = TRUE;
+ xinfo->server_flags = ((CamelMessageInfoBase *)xinfo)->flags & CAMEL_IMAPX_SERVER_FLAGS;
+ xinfo->info.flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED;
+ xinfo->info.dirty = TRUE;
+ camel_flag_list_copy (&xinfo->server_user_flags, &xinfo->info.user_flags);
camel_folder_summary_touch (job->folder->summary);
- camel_message_info_free (info);
-
- /* FIXME: move over user flags too */
+ camel_message_info_free (xinfo);
}
+ /* Apply the changes to server-side unread count; it won't tell
+ us of these changes, of course. */
+ ((CamelIMAPXFolder *)job->folder)->unread_on_server += job->u.sync_changes.unread_change;
}
if (job->commands == 0) {
@@ -4111,7 +4387,7 @@ imapx_job_sync_changes_start(CamelIMAPXServer *is, CamelIMAPXJob *job)
if ( (on && (((flags ^ sflags) & flags) & flag))
|| (!on && (((flags ^ sflags) & ~flags) & flag))) {
if (ic == NULL) {
- ic = camel_imapx_command_new(is, "STORE", job->folder->full_name, "UID STORE ");
+ ic = camel_imapx_command_new(is, "STORE", job->folder, "UID STORE ");
ic->complete = imapx_command_sync_changes_done;
ic->job = job;
ic->pri = job->pri;
@@ -4124,6 +4400,14 @@ imapx_job_sync_changes_start(CamelIMAPXServer *is, CamelIMAPXJob *job)
imapx_command_queue(is, ic);
ic = NULL;
}
+ if (flag == CAMEL_MESSAGE_SEEN) {
+ /* Remember how the server's unread count will change if this
+ command succeeds */
+ if (on)
+ job->u.sync_changes.unread_change--;
+ else
+ job->u.sync_changes.unread_change++;
+ }
camel_message_info_free (info);
}
}
@@ -4139,7 +4423,7 @@ imapx_job_sync_changes_start(CamelIMAPXServer *is, CamelIMAPXJob *job)
CamelIMAPXMessageInfo *info = c->infos->pdata[i];
if (ic == NULL) {
- ic = camel_imapx_command_new(is, "STORE", job->folder->full_name, "UID STORE ");
+ ic = camel_imapx_command_new(is, "STORE", job->folder, "UID STORE ");
ic->complete = imapx_command_sync_changes_done;
ic->job = job;
ic->pri = job->pri;
@@ -4224,7 +4508,7 @@ imapx_parser_thread (gpointer d)
CamelOperation *op;
op = camel_operation_new (NULL, NULL);
- op = camel_operation_register (op);
+ camel_operation_register (op);
is->op = op;
while (!camel_exception_is_set (&ex) && is->stream) {
@@ -4271,7 +4555,7 @@ imapx_parser_thread (gpointer d)
errno = EINTR;
}
- if (camel_application_is_exiting || is->parser_quit) {
+ if (is->parser_quit) {
camel_exception_setv (&ex, CAMEL_EXCEPTION_USER_CANCEL, "Operation Cancelled: %s", g_strerror(errno));
break;
}
@@ -4290,11 +4574,11 @@ imapx_parser_thread (gpointer d)
}
}
- imapx_disconnect (is);
- cancel_all_jobs (is, &ex);
+ QUEUE_LOCK(is);
+ is->state = IMAPX_SHUTDOWN;
+ QUEUE_UNLOCK(is);
- if (imapx_idle_supported (is))
- imapx_exit_idle (is);
+ cancel_all_jobs (is, &ex);
camel_exception_clear (&ex);
@@ -4348,11 +4632,30 @@ imapx_server_init(CamelIMAPXServer *is, CamelIMAPXServerClass *isclass)
static void
imapx_server_finalise(CamelIMAPXServer *is, CamelIMAPXServerClass *isclass)
{
+ e(printf("imapx_server_finalise\n"));
+
+ QUEUE_LOCK(is);
+ is->state = IMAPX_SHUTDOWN;
+ QUEUE_UNLOCK(is);
+
+ is->parser_quit = TRUE;
+ if (is->op)
+ camel_operation_cancel (is->op);
+
+ if (is->parser_thread)
+ g_thread_join (is->parser_thread);
+
+ if (is->cinfo && imapx_idle_supported (is))
+ imapx_exit_idle (is);
+
+ imapx_disconnect (is);
+
g_static_rec_mutex_free(&is->queue_lock);
g_static_rec_mutex_free (&is->ostream_lock);
g_hash_table_destroy (is->uid_eflags);
camel_folder_change_info_free (is->changes);
+
}
CamelType
@@ -4409,11 +4712,6 @@ imapx_disconnect (CamelIMAPXServer *is)
is->select_folder = NULL;
}
- if (is->select) {
- g_free(is->select);
- is->select = NULL;
- }
-
if (is->select_pending) {
camel_object_unref(is->select_pending);
is->select_pending = NULL;
@@ -4433,39 +4731,23 @@ imapx_disconnect (CamelIMAPXServer *is)
/* Client commands */
gboolean
-camel_imapx_server_connect (CamelIMAPXServer *is, gboolean connect, CamelException *ex)
+camel_imapx_server_connect (CamelIMAPXServer *is, CamelException *ex)
{
- gboolean ret = FALSE;
-
- CAMEL_SERVICE_REC_LOCK (is->store, connect_lock);
- if (connect) {
- if (is->state >= IMAPX_INITIALISED) {
- ret = TRUE;
- goto exit;
- }
+ if (is->state == IMAPX_SHUTDOWN)
+ return FALSE;
- g_static_rec_mutex_lock (&is->ostream_lock);
- imapx_reconnect (is, ex);
- g_static_rec_mutex_unlock (&is->ostream_lock);
+ if (is->state >= IMAPX_INITIALISED)
+ return TRUE;
- if (camel_exception_is_set (ex)) {
- ret = FALSE;
- goto exit;
- }
+ g_static_rec_mutex_lock (&is->ostream_lock);
+ imapx_reconnect (is, ex);
+ g_static_rec_mutex_unlock (&is->ostream_lock);
- is->parser_thread = g_thread_create((GThreadFunc) imapx_parser_thread, is, TRUE, NULL);
- ret = TRUE;
- } else {
- is->parser_quit = TRUE;
- camel_operation_cancel (is->op);
- if (is->parser_thread)
- g_thread_join (is->parser_thread);
- ret = TRUE;
- }
+ if (camel_exception_is_set (ex))
+ return FALSE;
-exit:
- CAMEL_SERVICE_REC_UNLOCK (is->store, connect_lock);
- return ret;
+ is->parser_thread = g_thread_create((GThreadFunc) imapx_parser_thread, is, TRUE, NULL);
+ return TRUE;
}
static CamelStream *
@@ -4488,7 +4770,7 @@ imapx_server_get_message (CamelIMAPXServer *is, CamelFolder *folder, CamelOperat
QUEUE_LOCK (is);
- if ((job = imapx_is_job_in_queue (is, folder->full_name, IMAPX_JOB_GET_MESSAGE, uid))) {
+ if ((job = imapx_is_job_in_queue (is, folder, IMAPX_JOB_GET_MESSAGE, uid))) {
flag = g_hash_table_lookup (is->uid_eflags, uid);
if (pri > job->pri)
@@ -4697,7 +4979,7 @@ camel_imapx_server_refresh_info (CamelIMAPXServer *is, CamelFolder *folder, Came
QUEUE_LOCK (is);
- if (imapx_is_job_in_queue (is, folder->full_name, IMAPX_JOB_REFRESH_INFO, NULL)) {
+ if (imapx_is_job_in_queue (is, folder, IMAPX_JOB_REFRESH_INFO, NULL)) {
QUEUE_UNLOCK (is);
return;
}
@@ -4869,7 +5151,7 @@ imapx_server_sync_changes(CamelIMAPXServer *is, CamelFolder *folder, gint pri, C
QUEUE_LOCK (is);
- if ((job = imapx_is_job_in_queue (is, folder->full_name, IMAPX_JOB_SYNC_CHANGES, NULL))) {
+ if ((job = imapx_is_job_in_queue (is, folder, IMAPX_JOB_SYNC_CHANGES, NULL))) {
if (pri > job->pri)
job->pri = pri;
@@ -4921,7 +5203,7 @@ camel_imapx_server_expunge(CamelIMAPXServer *is, CamelFolder *folder, CamelExcep
/* Do we really care to wait for this one to finish? */
QUEUE_LOCK (is);
- if (imapx_is_job_in_queue (is, folder->full_name, IMAPX_JOB_EXPUNGE, NULL)) {
+ if (imapx_is_job_in_queue (is, folder, IMAPX_JOB_EXPUNGE, NULL)) {
QUEUE_UNLOCK (is);
return;
}
diff --git a/camel/providers/imapx/camel-imapx-server.h b/camel/providers/imapx/camel-imapx-server.h
index 22bd7da7a..6b3934815 100644
--- a/camel/providers/imapx/camel-imapx-server.h
+++ b/camel/providers/imapx/camel-imapx-server.h
@@ -1,11 +1,9 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
- * Copyright (C) 2005 Novell Inc.
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
- * Authors:
- * Michael Zucchi <notzed@ximian.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
@@ -13,10 +11,10 @@
* 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.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef _CAMEL_IMAPX_SERVER_H
@@ -74,7 +72,6 @@ struct _CamelIMAPXServer {
/* info on currently selected folder */
struct _CamelFolder *select_folder;
- gchar *select;
struct _CamelFolderChangeInfo *changes;
struct _CamelFolder *select_pending;
guint32 permanentflags;
@@ -102,6 +99,8 @@ struct _CamelIMAPXServer {
struct _CamelIMAPXIdle *idle;
gboolean use_idle;
+ gboolean use_qresync;
+
/* used for storing eflags to syncronize duplicate get_message requests */
GHashTable *uid_eflags;
};
@@ -115,7 +114,7 @@ struct _CamelIMAPXServerClass {
CamelType camel_imapx_server_get_type (void);
CamelIMAPXServer *camel_imapx_server_new(struct _CamelStore *store, struct _CamelURL *url);
-gboolean camel_imapx_server_connect(CamelIMAPXServer *is, gint state, CamelException *ex);
+gboolean camel_imapx_server_connect(CamelIMAPXServer *is, CamelException *ex);
gboolean imapx_connect_to_server (CamelIMAPXServer *is, CamelException *ex);
GPtrArray *camel_imapx_server_list(CamelIMAPXServer *is, const gchar *top, guint32 flags, const gchar *ext, CamelException *ex);
diff --git a/camel/providers/imapx/camel-imapx-store.c b/camel/providers/imapx/camel-imapx-store.c
index 5d12bd2a6..cb9823d56 100644
--- a/camel/providers/imapx/camel-imapx-store.c
+++ b/camel/providers/imapx/camel-imapx-store.c
@@ -1,24 +1,23 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* camel-imap-store.c : class for a imap store */
-
/*
* Authors: Michael Zucchi <notzed@ximian.com>
*
- * Copyright (C) 2000-2002 Ximian, Inc. (www.ximian.com)
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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.
+ * 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
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
@@ -124,6 +123,9 @@ imapx_parse_receiving_options (CamelIMAPXStore *istore, CamelURL *url)
if (camel_url_get_param (url, "use_idle"))
istore->rec_options |= IMAPX_USE_IDLE;
+
+ if (camel_url_get_param (url, "use_qresync"))
+ istore->rec_options |= IMAPX_USE_QRESYNC;
}
static void
@@ -204,16 +206,53 @@ imapx_get_name (CamelService *service, gboolean brief)
service->url->user, service->url->host);
}
+CamelIMAPXServer *
+camel_imapx_store_get_server(CamelIMAPXStore *store, CamelException *ex)
+{
+ CamelIMAPXServer *server = NULL;
+
+ if (camel_operation_cancel_check(NULL)) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
+ _("Operation cancelled"));
+ return NULL;
+ }
+ CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+
+ if (store->server && camel_imapx_server_connect(store->server, ex)) {
+ camel_object_ref(store->server);
+ server = store->server;
+ } else {
+ if (store->server) {
+ camel_object_unref(store->server);
+ store->server = NULL;
+ }
+
+ server = camel_imapx_server_new(CAMEL_STORE(store), CAMEL_SERVICE(store)->url);
+ if (camel_imapx_server_connect(server, ex)) {
+ store->server = server;
+ camel_object_ref(server);
+ } else {
+ camel_object_unref(server);
+ server = NULL;
+ }
+ }
+ CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+ return server;
+}
+
static gboolean
imapx_connect (CamelService *service, CamelException *ex)
{
CamelIMAPXStore *istore = (CamelIMAPXStore *)service;
+ CamelIMAPXServer *server;
- /* We never really are 'connected' or 'disconnected' */
- if (istore->server == NULL)
- istore->server = camel_imapx_server_new((CamelStore *)istore, service->url);
+ server = camel_imapx_store_get_server(istore, ex);
+ if (server) {
+ camel_object_unref(server);
+ return TRUE;
+ }
- return camel_imapx_server_connect (istore->server, TRUE, ex);
+ return FALSE;
}
static gboolean
@@ -223,8 +262,14 @@ imapx_disconnect (CamelService *service, gboolean clean, CamelException *ex)
CAMEL_SERVICE_CLASS (parent_class)->disconnect (service, clean, ex);
- if (istore->server)
- camel_imapx_server_connect(istore->server, FALSE, ex);
+ CAMEL_SERVICE_REC_LOCK (service, connect_lock);
+
+ if (istore->server) {
+ camel_object_unref(istore->server);
+ istore->server = NULL;
+ }
+
+ CAMEL_SERVICE_REC_UNLOCK (service, connect_lock);
return TRUE;
}
@@ -267,12 +312,16 @@ static void
imapx_noop (CamelStore *store, CamelException *ex)
{
CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
+ CamelIMAPXServer *server;
if (CAMEL_OFFLINE_STORE(store)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
return;
- if (istore->server && camel_imapx_server_connect (istore->server, TRUE, ex))
- camel_imapx_server_noop (istore->server, NULL, ex);
+ server = camel_imapx_store_get_server(istore, ex);
+ if (server) {
+ camel_imapx_server_noop (server, NULL, ex);
+ camel_object_unref(server);
+ }
}
static guint
@@ -528,12 +577,17 @@ static void
imapx_subscribe_folder (CamelStore *store, const gchar *folder_name, gboolean emit_signal, CamelException *ex)
{
CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
+ CamelIMAPXServer *server;
if (CAMEL_OFFLINE_STORE(store)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
return;
- if (istore->server && camel_imapx_server_connect (istore->server, TRUE, ex))
- camel_imapx_server_manage_subscription (istore->server, folder_name, TRUE, ex);
+ server = camel_imapx_store_get_server(istore, ex);
+ if (!server)
+ return;
+
+ camel_imapx_server_manage_subscription (server, folder_name, TRUE, ex);
+ camel_object_unref(server);
if (!camel_exception_is_set (ex))
imapx_mark_folder_subscribed (istore, folder_name, emit_signal, ex);
@@ -543,12 +597,17 @@ static void
imapx_unsubscribe_folder (CamelStore *store, const gchar *folder_name, gboolean emit_signal, CamelException *ex)
{
CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
+ CamelIMAPXServer *server;
if (CAMEL_OFFLINE_STORE(store)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
return;
- if (istore->server && camel_imapx_server_connect (istore->server, TRUE, ex))
- camel_imapx_server_manage_subscription (istore->server, folder_name, FALSE, ex);
+ server = camel_imapx_store_get_server(istore, ex);
+ if (!server)
+ return;
+
+ camel_imapx_server_manage_subscription (server, folder_name, FALSE, ex);
+ camel_object_unref(server);
if (!camel_exception_is_set (ex))
imapx_unmark_folder_subscribed (istore, folder_name, emit_signal, ex);
@@ -614,15 +673,19 @@ static void
imapx_delete_folder (CamelStore *store, const gchar *folder_name, CamelException *ex)
{
CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
+ CamelIMAPXServer *server;
if (CAMEL_OFFLINE_STORE (store)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL) {
camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
_("You must be working online to complete this operation"));
return;
}
+ server = camel_imapx_store_get_server(istore, ex);
+ if (!server)
+ return;
- if (istore->server && camel_imapx_server_connect (istore->server, TRUE, ex))
- camel_imapx_server_delete_folder (istore->server, folder_name, ex);
+ camel_imapx_server_delete_folder (server, folder_name, ex);
+ camel_object_unref(server);
if (!camel_exception_is_set (ex))
imapx_delete_folder_from_cache (istore, folder_name, ex);
@@ -665,6 +728,7 @@ static void
imapx_rename_folder (CamelStore *store, const gchar *old, const gchar *new, CamelException *ex)
{
CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
+ CamelIMAPXServer *server;
gchar *oldpath, *newpath, *storage_path;
if (CAMEL_OFFLINE_STORE (store)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL) {
@@ -676,8 +740,11 @@ imapx_rename_folder (CamelStore *store, const gchar *old, const gchar *new, Came
if (istore->rec_options & IMAPX_SUBSCRIPTIONS)
imapx_unsubscribe_folder (store, old, FALSE, ex);
- if (istore->server && camel_imapx_server_connect (istore->server, TRUE, ex))
- camel_imapx_server_rename_folder (istore->server, old, new, ex);
+ server = camel_imapx_store_get_server(istore, ex);
+ if (server) {
+ camel_imapx_server_rename_folder (server, old, new, ex);
+ camel_object_unref(server);
+ }
if (camel_exception_is_set (ex)) {
imapx_subscribe_folder (store, old, FALSE, ex);
@@ -711,6 +778,7 @@ imapx_create_folder (CamelStore *store, const gchar *parent_name, const gchar *f
CamelStoreInfo *si;
CamelIMAPXStoreNamespace *ns;
CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
+ CamelIMAPXServer *server;
gchar *real_name, *full_name, *parent_real;
CamelFolderInfo *fi = NULL;
gchar dir_sep;
@@ -721,7 +789,8 @@ imapx_create_folder (CamelStore *store, const gchar *parent_name, const gchar *f
return NULL;
}
- if (!(istore->server && camel_imapx_server_connect (istore->server, TRUE, ex)))
+ server = camel_imapx_store_get_server(istore, ex);
+ if (!server)
return NULL;
if (!parent_name)
@@ -737,6 +806,7 @@ imapx_create_folder (CamelStore *store, const gchar *parent_name, const gchar *f
camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID_PATH,
_("The folder name \"%s\" is invalid because it contains the character \"%c\""),
folder_name, dir_sep);
+ camel_object_unref(server);
return NULL;
}
@@ -744,6 +814,7 @@ imapx_create_folder (CamelStore *store, const gchar *parent_name, const gchar *f
if (parent_real == NULL) {
camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_STATE,
_("Unknown parent folder: %s"), parent_name);
+ camel_object_unref(server);
return NULL;
}
@@ -751,6 +822,7 @@ imapx_create_folder (CamelStore *store, const gchar *parent_name, const gchar *f
if (si && si->flags & CAMEL_STORE_INFO_FOLDER_NOINFERIORS) {
camel_exception_set (ex, CAMEL_EXCEPTION_FOLDER_INVALID_STATE,
_("The parent folder is not allowed to contain subfolders"));
+ camel_object_unref(server);
return NULL;
}
@@ -761,7 +833,8 @@ imapx_create_folder (CamelStore *store, const gchar *parent_name, const gchar *f
full_name = imapx_concat (istore, parent_real, real_name);
g_free(real_name);
- camel_imapx_server_create_folder (istore->server, full_name, ex);
+ camel_imapx_server_create_folder (server, full_name, ex);
+ camel_object_unref(server);
if (!camel_exception_is_set (ex)) {
CamelIMAPXStoreInfo *si;
@@ -886,7 +959,7 @@ get_folder_info_offline (CamelStore *store, const gchar *top,
}
static void
-add_folders_to_summary (CamelIMAPXStore *istore, GPtrArray *folders, GHashTable *table, gboolean subscribed)
+add_folders_to_summary (CamelIMAPXStore *istore, CamelIMAPXServer *server, GPtrArray *folders, GHashTable *table, gboolean subscribed)
{
gint i = 0;
@@ -909,8 +982,10 @@ add_folders_to_summary (CamelIMAPXStore *istore, GPtrArray *folders, GHashTable
}
si = camel_imapx_store_summary_add_from_full (istore->summary, li->name, li->separator);
- if (!si)
+ if (!si) {
+ camel_object_unref(server);
continue;
+ }
new_flags = (si->info.flags & (CAMEL_STORE_INFO_FOLDER_SUBSCRIBED | CAMEL_STORE_INFO_FOLDER_CHECK_FOR_NEW)) |
(li->flags & ~CAMEL_STORE_INFO_FOLDER_SUBSCRIBED);
@@ -969,15 +1044,16 @@ imapx_get_folders_free(gpointer k, gpointer v, gpointer d)
}
static void
-fetch_folders_for_pattern (CamelIMAPXStore *istore, const gchar *pattern, guint32 flags, const gchar *ext, GHashTable *table, CamelException *ex)
+fetch_folders_for_pattern (CamelIMAPXStore *istore, CamelIMAPXServer *server, const gchar *pattern, guint32 flags,
+ const gchar *ext, GHashTable *table, CamelException *ex)
{
GPtrArray *folders = NULL;
- folders = camel_imapx_server_list (istore->server, pattern, flags, ext, ex);
+ folders = camel_imapx_server_list (server, pattern, flags, ext, ex);
if (camel_exception_is_set (ex))
return;
- add_folders_to_summary (istore, folders, table, (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED));
+ add_folders_to_summary (istore, server, folders, table, (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED));
g_ptr_array_foreach (folders, free_list, folders);
g_ptr_array_free (folders, TRUE);
@@ -1004,9 +1080,14 @@ get_namespaces (CamelIMAPXStore *istore)
static GHashTable *
fetch_folders_for_namespaces (CamelIMAPXStore *istore, const gchar *pattern, gboolean sync, CamelException *ex)
{
+ CamelIMAPXServer *server;
GHashTable *folders = NULL;
GSList *namespaces = NULL, *l;
+ server = camel_imapx_store_get_server(istore, ex);
+ if (!server)
+ return NULL;
+
folders = g_hash_table_new (folder_hash, folder_eq);
namespaces = get_namespaces (istore);
@@ -1030,11 +1111,11 @@ fetch_folders_for_namespaces (CamelIMAPXStore *istore, const gchar *pattern, gbo
if (sync)
flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST;
- if (istore->server->cinfo->capa & IMAPX_CAPABILITY_LIST_EXTENDED)
+ if (server->cinfo->capa & IMAPX_CAPABILITY_LIST_EXTENDED)
list_ext = "RETURN (SUBSCRIBED)";
flags |= CAMEL_STORE_FOLDER_INFO_RECURSIVE;
- fetch_folders_for_pattern (istore, pat, flags, list_ext, folders, ex);
+ fetch_folders_for_pattern (istore, server, pat, flags, list_ext, folders, ex);
if (camel_exception_is_set (ex)) {
g_free (pat);
goto exception;
@@ -1043,7 +1124,7 @@ fetch_folders_for_namespaces (CamelIMAPXStore *istore, const gchar *pattern, gbo
/* If the server doesn't support LIST-EXTENDED then we have to
issue LSUB to list the subscribed folders separately */
flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
- fetch_folders_for_pattern (istore, pat, flags, NULL, folders, ex);
+ fetch_folders_for_pattern (istore, server, pat, flags, NULL, folders, ex);
if (camel_exception_is_set (ex)) {
g_free (pat);
goto exception;
@@ -1052,15 +1133,17 @@ fetch_folders_for_namespaces (CamelIMAPXStore *istore, const gchar *pattern, gbo
g_free (pat);
if (pattern)
- return folders;
+ goto out;
ns = ns->next;
}
}
-
+ out:
+ camel_object_unref(server);
return folders;
exception:
+ camel_object_unref(server);
g_hash_table_destroy (folders);
return NULL;
}
diff --git a/camel/providers/imapx/camel-imapx-store.h b/camel/providers/imapx/camel-imapx-store.h
index fa08ab9e2..93ea68666 100644
--- a/camel/providers/imapx/camel-imapx-store.h
+++ b/camel/providers/imapx/camel-imapx-store.h
@@ -4,21 +4,21 @@
/*
* Authors: Michael Zucchi <notzed@ximian.com>
*
- * Copyright (C) 2002 Ximian, Inc. (www.ximian.com)
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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.
+ * 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
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef CAMEL_IMAPX_STORE_H
@@ -47,6 +47,7 @@ extern "C" {
#define IMAPX_SUBSCRIPTIONS (1 << 5)
#define IMAPX_CHECK_LSUB (1 << 6)
#define IMAPX_USE_IDLE (1 << 7)
+#define IMAPX_USE_QRESYNC (1 << 8)
typedef struct {
CamelOfflineStore parent_object;
@@ -79,6 +80,7 @@ typedef struct {
/* Standard Camel function */
CamelType camel_imapx_store_get_type (void);
+struct _CamelIMAPXServer *camel_imapx_store_get_server(CamelIMAPXStore *store, CamelException *ex);
#ifdef __cplusplus
}
diff --git a/camel/providers/imapx/camel-imapx-stream.c b/camel/providers/imapx/camel-imapx-stream.c
index 2cb68ca03..6fe0fd37a 100644
--- a/camel/providers/imapx/camel-imapx-stream.c
+++ b/camel/providers/imapx/camel-imapx-stream.c
@@ -3,21 +3,21 @@
* Author:
* Michael Zucchi <notzed@ximian.com>
*
- * Copyright 1999, 2000 Ximian, Inc. (www.ximian.com)
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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.
+ * 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
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
diff --git a/camel/providers/imapx/camel-imapx-stream.h b/camel/providers/imapx/camel-imapx-stream.h
index 27138c2ee..5568c3a73 100644
--- a/camel/providers/imapx/camel-imapx-stream.h
+++ b/camel/providers/imapx/camel-imapx-stream.h
@@ -3,8 +3,10 @@
*
* Authors: Michael Zucchi <notzed@ximian.com>
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
@@ -12,10 +14,10 @@
* 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.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef _CAMEL_IMAPX_STREAM_H
diff --git a/camel/providers/imapx/camel-imapx-summary.c b/camel/providers/imapx/camel-imapx-summary.c
index b000c138a..5c6b717ce 100644
--- a/camel/providers/imapx/camel-imapx-summary.c
+++ b/camel/providers/imapx/camel-imapx-summary.c
@@ -40,10 +40,10 @@
#include "camel-imapx-summary.h"
//#include "camel-imap-utils.h"
-#define CAMEL_IMAPX_SUMMARY_VERSION (3)
+#define CAMEL_IMAPX_SUMMARY_VERSION (4)
-#define EXTRACT_FIRST_DIGIT(val) val=strtoul (part, &part, 10);
-#define EXTRACT_DIGIT(val) if (*part) part++; val=strtoul (part, &part, 10);
+#define EXTRACT_FIRST_DIGIT(val) val=strtoull (part, &part, 10);
+#define EXTRACT_DIGIT(val) if (*part) part++; val=strtoull (part, &part, 10);
static gint summary_header_load (CamelFolderSummary *, FILE *);
static gint summary_header_save (CamelFolderSummary *, FILE *);
@@ -239,8 +239,15 @@ summary_header_from_db (CamelFolderSummary *s, CamelFIRecord *mir)
EXTRACT_DIGIT (ims->validity)
}
+ if (ims->version >= 4) {
+ if (part)
+ EXTRACT_DIGIT (ims->uidnext);
+ if (part)
+ EXTRACT_DIGIT (ims->modseq);
+ }
+
if (ims->version > CAMEL_IMAPX_SUMMARY_VERSION) {
- g_warning("Unkown summary version\n");
+ g_warning("Unknown summary version\n");
errno = EINVAL;
return -1;
}
@@ -252,13 +259,19 @@ static gint
summary_header_load (CamelFolderSummary *s, FILE *in)
{
CamelIMAPXSummary *ims = CAMEL_IMAPX_SUMMARY (s);
+ guint32 validity;
+ gint ret;
if (camel_imapx_summary_parent->summary_header_load (s, in) == -1)
return -1;
/* Legacy version */
- if (s->version == 0x30c)
- return camel_file_util_decode_uint32(in, &ims->validity);
+ if (s->version == 0x30c) {
+ ret = camel_file_util_decode_uint32(in, &validity);
+ if (!ret)
+ ims->validity = validity;
+ return ret;
+ }
/* Version 1 */
if (camel_file_util_decode_fixed_int32(in, (gint32 *) &ims->version) == -1)
@@ -272,11 +285,14 @@ summary_header_load (CamelFolderSummary *s, FILE *in)
return -1;
}
- if (camel_file_util_decode_fixed_int32(in, (gint32 *) &ims->validity) == -1)
+ if (camel_file_util_decode_fixed_int32(in, (gint32 *) &validity) == -1)
return -1;
+ ims->validity = validity;
- if (ims->version > CAMEL_IMAPX_SUMMARY_VERSION) {
- g_warning("Unkown summary version\n");
+ /* This is only used for migration; will never be asked to load newer
+ versions of the store format */
+ if (ims->version > 3) {
+ g_warning("Unknown summary version\n");
errno = EINVAL;
return -1;
}
@@ -293,22 +309,17 @@ summary_header_to_db (CamelFolderSummary *s, CamelException *ex)
fir = camel_imapx_summary_parent->summary_header_to_db (s, ex);
if (!fir)
return NULL;
- fir->bdata = g_strdup_printf ("%d %u", CAMEL_IMAPX_SUMMARY_VERSION, ims->validity);
-
+ fir->bdata = g_strdup_printf ("%d %llu %u %llu", CAMEL_IMAPX_SUMMARY_VERSION,
+ (unsigned long long)ims->validity, ims->uidnext,
+ (unsigned long long)ims->modseq);
return fir;
}
static gint
summary_header_save (CamelFolderSummary *s, FILE *out)
{
- CamelIMAPXSummary *ims = CAMEL_IMAPX_SUMMARY(s);
-
- if (camel_imapx_summary_parent->summary_header_save (s, out) == -1)
- return -1;
-
- camel_file_util_encode_fixed_int32(out, CAMEL_IMAPX_SUMMARY_VERSION);
-
- return camel_file_util_encode_fixed_int32(out, ims->validity);
+ g_warning("imapx %s called; should never happen!\n", __func__);
+ return -1;
}
static CamelMessageInfo *
diff --git a/camel/providers/imapx/camel-imapx-summary.h b/camel/providers/imapx/camel-imapx-summary.h
index 0dee06faf..0d641eead 100644
--- a/camel/providers/imapx/camel-imapx-summary.h
+++ b/camel/providers/imapx/camel-imapx-summary.h
@@ -35,6 +35,8 @@
CAMEL_MESSAGE_DELETED | \
CAMEL_MESSAGE_DRAFT | \
CAMEL_MESSAGE_FLAGGED | \
+ CAMEL_MESSAGE_JUNK | \
+ CAMEL_MESSAGE_NOTJUNK | \
CAMEL_MESSAGE_SEEN)
G_BEGIN_DECLS
@@ -58,8 +60,8 @@ struct _CamelIMAPXSummary {
CamelFolderSummary parent;
guint32 version;
- guint32 validity;
guint32 uidnext;
+ guint64 validity;
guint64 modseq;
};
diff --git a/camel/providers/imapx/camel-imapx-utils.c b/camel/providers/imapx/camel-imapx-utils.c
index 274736d58..aab048c1d 100644
--- a/camel/providers/imapx/camel-imapx-utils.c
+++ b/camel/providers/imapx/camel-imapx-utils.c
@@ -1,3 +1,21 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
#include <ctype.h>
#include <errno.h>
@@ -75,6 +93,8 @@ static struct {
{ "\\FLAGGED", CAMEL_MESSAGE_FLAGGED },
{ "\\SEEN", CAMEL_MESSAGE_SEEN },
{ "\\RECENT", CAMEL_IMAPX_MESSAGE_RECENT },
+ { "JUNK", CAMEL_MESSAGE_JUNK },
+ { "NOTJUNK", CAMEL_MESSAGE_NOTJUNK },
{ "\\*", CAMEL_MESSAGE_USER }
};
@@ -87,7 +107,7 @@ imapx_parse_flags(CamelIMAPXStream *stream, guint32 *flagsp, CamelFlag **user_fl
{
gint tok, i;
guint len;
- guchar *token, *p, c;
+ guchar *token;
guint32 flags = 0;
*flagsp = flags;
@@ -96,13 +116,11 @@ imapx_parse_flags(CamelIMAPXStream *stream, guint32 *flagsp, CamelFlag **user_fl
if (tok == '(') {
do {
tok = camel_imapx_stream_token(stream, &token, &len, ex);
- if (tok == IMAPX_TOK_TOKEN) {
- p = token;
- // FIXME: ascii_toupper
- while ((c=*p))
- *p++ = toupper(c);
+ if (tok == IMAPX_TOK_TOKEN || tok == IMAPX_TOK_INT) {
+ gchar *upper = g_ascii_strup ((gchar *) token, len);
+
for (i = 0; i < G_N_ELEMENTS (flag_table); i++)
- if (!strcmp((gchar *)token, flag_table[i].name)) {
+ if (!strcmp(upper, flag_table[i].name)) {
flags |= flag_table[i].flag;
goto found;
}
@@ -114,6 +132,7 @@ imapx_parse_flags(CamelIMAPXStream *stream, guint32 *flagsp, CamelFlag **user_fl
}
found:
tok = tok; /* fixes stupid warning */
+ g_free (upper);
} else if (tok != ')') {
camel_exception_set (ex, 1, "expecting flag");
return;
@@ -219,12 +238,14 @@ imapx_update_user_flags (CamelMessageInfo *info, CamelFlag *server_user_flags)
{
gboolean changed = FALSE;
CamelMessageInfoBase *binfo = (CamelMessageInfoBase *) info;
+ CamelIMAPXMessageInfo *xinfo = (CamelIMAPXMessageInfo *) info;
gboolean set_cal = FALSE;
if (camel_flag_get (&binfo->user_flags, "$has_cal"))
set_cal = TRUE;
changed = camel_flag_list_copy(&binfo->user_flags, &server_user_flags);
+ camel_flag_list_copy (&xinfo->server_user_flags, &server_user_flags);
/* reset the calendar flag if it was set in messageinfo before */
if (set_cal)
@@ -234,9 +255,10 @@ imapx_update_user_flags (CamelMessageInfo *info, CamelFlag *server_user_flags)
}
gboolean
-imapx_update_message_info_flags (CamelMessageInfo *info, guint32 server_flags, CamelFlag *server_user_flags, CamelFolder *folder)
+imapx_update_message_info_flags (CamelMessageInfo *info, guint32 server_flags, CamelFlag *server_user_flags, CamelFolder *folder, gboolean unsolicited)
{
gboolean changed = FALSE;
+ CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *)folder;
CamelIMAPXMessageInfo *xinfo = (CamelIMAPXMessageInfo *) info;
if (server_flags != xinfo->server_flags)
@@ -266,8 +288,11 @@ imapx_update_message_info_flags (CamelMessageInfo *info, guint32 server_flags, C
deleted == 1 ? "deleted" : ( deleted == -1 ? "undeleted" : ""),
junk == 1 ? "junk" : ( junk == -1 ? "unjunked" : "")));
- if (read)
+ if (read) {
folder->summary->unread_count -= read;
+ if (unsolicited)
+ ifolder->unread_on_server -= read;
+ }
if (deleted)
folder->summary->deleted_count += deleted;
if (junk)
@@ -339,9 +364,10 @@ imapx_set_message_info_flags_for_new_message (CamelMessageInfo *info, guint32 se
}
void
-imapx_update_summary_for_removed_message (CamelMessageInfo *info, CamelFolder *folder)
+imapx_update_summary_for_removed_message (CamelMessageInfo *info, CamelFolder *folder, gboolean unsolicited)
{
CamelMessageInfoBase *dinfo = (CamelMessageInfoBase *) info;
+ CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *)folder;
gint unread=0, deleted=0, junk=0;
guint32 flags;
@@ -355,9 +381,11 @@ imapx_update_summary_for_removed_message (CamelMessageInfo *info, CamelFolder *f
if (flags & CAMEL_MESSAGE_JUNK)
junk = 1;
- if (unread)
+ if (unread) {
folder->summary->unread_count--;
-
+ if (unsolicited)
+ ifolder->unread_on_server--;
+ }
if (deleted)
folder->summary->deleted_count--;
if (junk)
@@ -1721,7 +1749,7 @@ imapx_parse_status(CamelIMAPXStream *is, CamelException *ex)
/* ignore anything we dont know about */
do {
tok = camel_imapx_stream_token(is, &token, &len, ex);
- if (tok == '\n') {
+ if (tok == '\n' || tok < 0) {
camel_exception_set (ex, 1, "server response truncated");
imapx_free_status(sinfo);
return NULL;
diff --git a/camel/providers/imapx/camel-imapx-utils.h b/camel/providers/imapx/camel-imapx-utils.h
index 277ec7ffd..ec22116b1 100644
--- a/camel/providers/imapx/camel-imapx-utils.h
+++ b/camel/providers/imapx/camel-imapx-utils.h
@@ -1,3 +1,21 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
#ifndef _CAMEL_IMAPX_UTILS_H
#define _CAMEL_IMAPX_UTILS_H
@@ -69,10 +87,10 @@ enum {
GPtrArray *imapx_parse_uids (struct _CamelIMAPXStream *is, CamelException *ex);
void imapx_parse_flags(struct _CamelIMAPXStream *stream, guint32 *flagsp, struct _CamelFlag **user_flagsp, CamelException *ex);
void imapx_write_flags(CamelStream *stream, guint32 flags, struct _CamelFlag *user_flags, CamelException *ex);
-gboolean imapx_update_message_info_flags (CamelMessageInfo *info, guint32 server_flags, CamelFlag *server_user_flags, CamelFolder *folder);
+gboolean imapx_update_message_info_flags (CamelMessageInfo *info, guint32 server_flags, CamelFlag *server_user_flags, CamelFolder *folder, gboolean unsolicited);
void imapx_set_message_info_flags_for_new_message (CamelMessageInfo *info, guint32 server_flags, CamelFlag *server_user_flags,
CamelFolder *folder);
-void imapx_update_summary_for_removed_message (CamelMessageInfo *info, CamelFolder *folder);
+void imapx_update_summary_for_removed_message (CamelMessageInfo *info, CamelFolder *folder, gboolean unsolicited);
void imapx_update_store_summary (CamelFolder *folder);
/* ********************************************************************** */
diff --git a/camel/providers/imapx/camel-imapx-view-summary.c b/camel/providers/imapx/camel-imapx-view-summary.c
index 20d01f27f..342cda145 100644
--- a/camel/providers/imapx/camel-imapx-view-summary.c
+++ b/camel/providers/imapx/camel-imapx-view-summary.c
@@ -1,11 +1,9 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*-
*
- * Copyright (C) 2005 Novell Inc.
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
- * Authors: Michael Zucchi <notzed@ximian.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
@@ -13,10 +11,10 @@
* 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.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
diff --git a/camel/providers/imapx/camel-imapx-view-summary.h b/camel/providers/imapx/camel-imapx-view-summary.h
index 6a4307fe6..d2022c35e 100644
--- a/camel/providers/imapx/camel-imapx-view-summary.h
+++ b/camel/providers/imapx/camel-imapx-view-summary.h
@@ -1,10 +1,10 @@
/*
- * Copyright (C) 2000 Ximian Inc.
- *
* Authors: Michael Zucchi <notzed@ximian.com>
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
@@ -12,10 +12,10 @@
* 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.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef _CAMEL_IMAPX_VIEW_SUMMARY_H
diff --git a/camel/providers/imapx/test-imapx.c b/camel/providers/imapx/test-imapx.c
index 2f139d766..1c3af52ce 100644
--- a/camel/providers/imapx/test-imapx.c
+++ b/camel/providers/imapx/test-imapx.c
@@ -1,3 +1,22 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
#include <glib.h>
#include "camel-imapx-store.h"
#include "camel-imapx-folder.h"