evolution-data-server r8750 - trunk/camel/providers/imap4
- From: fejj svn gnome org
- To: svn-commits-list gnome org
- Subject: evolution-data-server r8750 - trunk/camel/providers/imap4
- Date: Wed, 7 May 2008 01:20:12 +0100 (BST)
Author: fejj
Date: Wed May 7 00:20:12 2008
New Revision: 8750
URL: http://svn.gnome.org/viewvc/evolution-data-server?rev=8750&view=rev
Log:
2008-05-06 Jeffrey Stedfast <fejj novell com>
* camel-imap4-command.c (camel_imap4_command_reset): Reset the
user_data using the user-specified reset function.
* camel-imap4-summary.c: Ported incremental summary flushing over
from libspruce.
Modified:
trunk/camel/providers/imap4/ChangeLog
trunk/camel/providers/imap4/camel-imap4-command.c
trunk/camel/providers/imap4/camel-imap4-command.h
trunk/camel/providers/imap4/camel-imap4-summary.c
Modified: trunk/camel/providers/imap4/camel-imap4-command.c
==============================================================================
--- trunk/camel/providers/imap4/camel-imap4-command.c (original)
+++ trunk/camel/providers/imap4/camel-imap4-command.c Wed May 7 00:20:12 2008
@@ -319,20 +319,27 @@
((EDListNode *) ic)->prev = NULL;
ic->untagged = g_hash_table_new (g_str_hash, g_str_equal);
ic->status = CAMEL_IMAP4_COMMAND_QUEUED;
+ ic->result = CAMEL_IMAP4_RESULT_NONE;
ic->resp_codes = g_ptr_array_new ();
ic->engine = engine;
ic->ref_count = 1;
ic->parts = parts;
ic->part = parts;
-
+ ic->reset = NULL;
+ ic->plus = NULL;
+ ic->tag = NULL;
+ ic->id = -1;
+
camel_exception_init (&ic->ex);
-
+
+ ic->user_data = NULL;
+
if (imap4_folder) {
camel_object_ref (imap4_folder);
ic->folder = imap4_folder;
} else
ic->folder = NULL;
-
+
return ic;
}
@@ -341,11 +348,11 @@
{
CamelIMAP4Command *command;
va_list args;
-
+
va_start (args, format);
command = camel_imap4_command_newv (engine, folder, format, args);
va_end (args);
-
+
return command;
}
@@ -366,30 +373,30 @@
{
CamelIMAP4CommandPart *part, *next;
int i;
-
+
if (ic == NULL)
return;
-
+
ic->ref_count--;
if (ic->ref_count == 0) {
if (ic->folder)
camel_object_unref (ic->folder);
-
+
g_free (ic->tag);
-
+
for (i = 0; i < ic->resp_codes->len; i++) {
CamelIMAP4RespCode *resp_code;
-
+
resp_code = ic->resp_codes->pdata[i];
camel_imap4_resp_code_free (resp_code);
}
g_ptr_array_free (ic->resp_codes, TRUE);
-
+
g_hash_table_foreach (ic->untagged, (GHFunc) g_free, NULL);
g_hash_table_destroy (ic->untagged);
-
+
camel_exception_clear (&ic->ex);
-
+
part = ic->parts;
while (part != NULL) {
g_free (part->buffer);
@@ -405,15 +412,15 @@
camel_object_unref (part->literal->literal.wrapper);
break;
}
-
+
g_free (part->literal);
}
-
+
next = part->next;
g_free (part);
part = next;
}
-
+
g_free (ic);
}
}
@@ -426,20 +433,20 @@
CamelDataWrapper *wrapper;
CamelMimeFilter *crlf;
char *string;
-
+
if (literal->type == CAMEL_IMAP4_LITERAL_STRING) {
string = literal->literal.string;
if (camel_stream_write (stream, string, strlen (string)) == -1)
return -1;
-
+
return 0;
}
-
+
crlf = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_ENCODE, CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY);
ostream = (CamelStream *) camel_stream_filter_new_with_stream (stream);
camel_stream_filter_add ((CamelStreamFilter *) ostream, crlf);
camel_object_unref (crlf);
-
+
/* write the literal */
switch (literal->type) {
case CAMEL_IMAP4_LITERAL_STREAM:
@@ -453,21 +460,21 @@
goto exception;
break;
}
-
+
camel_object_unref (ostream);
ostream = NULL;
-
+
#if 0
if (camel_stream_write (stream, "\r\n", 2) == -1)
return -1;
#endif
-
+
return 0;
exception:
-
+
camel_object_unref (ostream);
-
+
return -1;
}
@@ -509,76 +516,76 @@
camel_imap4_token_t token;
unsigned char *linebuf;
size_t len;
-
+
g_assert (ic->part != NULL);
-
+
if (ic->part == ic->parts) {
ic->tag = g_strdup_printf ("%c%.5u", engine->tagprefix, engine->tag++);
camel_stream_printf (engine->ostream, "%s ", ic->tag);
d(fprintf (stderr, "sending: %s ", ic->tag));
}
-
+
if (camel_debug ("imap4:command")) {
int sending = ic->part != ic->parts;
unsigned char *eoln, *eob;
-
+
linebuf = ic->part->buffer;
eob = linebuf + ic->part->buflen;
-
+
do {
eoln = linebuf;
while (eoln < eob && *eoln != '\n')
eoln++;
-
+
if (eoln < eob)
eoln++;
-
+
if (sending)
fwrite ("sending: ", 1, 10, stderr);
fwrite (linebuf, 1, eoln - linebuf, stderr);
-
+
linebuf = eoln + 1;
sending = 1;
} while (linebuf < eob);
}
-
+
linebuf = ic->part->buffer;
len = ic->part->buflen;
-
+
if (camel_stream_write (engine->ostream, linebuf, len) == -1) {
camel_exception_setv (&ic->ex, CAMEL_EXCEPTION_SYSTEM,
_("Failed sending command to IMAP server %s: %s"),
engine->url->host, g_strerror (errno));
goto exception;
}
-
+
if (camel_stream_flush (engine->ostream) == -1) {
camel_exception_setv (&ic->ex, CAMEL_EXCEPTION_SYSTEM,
_("Failed sending command to IMAP server %s: %s"),
engine->url->host, g_strerror (errno));
goto exception;
}
-
+
/* now we need to read the response(s) from the IMAP4 server */
-
+
do {
if (camel_imap4_engine_next_token (engine, &token, &ic->ex) == -1)
goto exception;
-
+
if (token.token == '+') {
/* we got a continuation response from the server */
literal = ic->part->literal;
-
+
if (camel_imap4_engine_line (engine, &linebuf, &len, &ic->ex) == -1)
goto exception;
-
+
if (literal) {
if (imap4_literal_write_to_stream (literal, engine->ostream) == -1)
goto exception;
-
+
g_free (linebuf);
linebuf = NULL;
-
+
break;
} else if (ic->plus) {
/* command expected a '+' response - probably AUTHENTICATE? */
@@ -586,13 +593,13 @@
g_free (linebuf);
return -1;
}
-
+
/* now we need to wait for a "<tag> OK/NO/BAD" response */
} else {
/* FIXME: error?? */
g_assert_not_reached ();
}
-
+
g_free (linebuf);
linebuf = NULL;
} else if (token.token == '*') {
@@ -602,10 +609,10 @@
} else if (token.token == CAMEL_IMAP4_TOKEN_ATOM && !strcmp (token.v.atom, ic->tag)) {
/* we got "<tag> OK/NO/BAD" */
d(fprintf (stderr, "got %s response\n", token.v.atom));
-
+
if (camel_imap4_engine_next_token (engine, &token, &ic->ex) == -1)
goto exception;
-
+
if (token.token == CAMEL_IMAP4_TOKEN_ATOM) {
if (!strcmp (token.v.atom, "OK"))
result = CAMEL_IMAP4_RESULT_OK;
@@ -613,15 +620,15 @@
result = CAMEL_IMAP4_RESULT_NO;
else if (!strcmp (token.v.atom, "BAD"))
result = CAMEL_IMAP4_RESULT_BAD;
-
+
if (result == CAMEL_IMAP4_RESULT_NONE) {
d(fprintf (stderr, "expected OK/NO/BAD but got %s\n", token.v.atom));
goto unexpected;
}
-
+
if (camel_imap4_engine_next_token (engine, &token, &ic->ex) == -1)
goto exception;
-
+
if (token.token == '[') {
/* we have a response code */
camel_imap4_stream_unget_token (engine->istream, &token);
@@ -638,10 +645,10 @@
unexpected_token (&token);
fprintf (stderr, "\n");
}
-
+
goto unexpected;
}
-
+
break;
} else {
if (camel_debug ("imap4:command")) {
@@ -649,23 +656,23 @@
unexpected_token (&token);
fprintf (stderr, "\n");
}
-
+
unexpected:
-
+
/* no fucking clue what we got... */
if (camel_imap4_engine_line (engine, &linebuf, &len, &ic->ex) == -1)
goto exception;
-
+
camel_exception_setv (&ic->ex, CAMEL_EXCEPTION_SYSTEM,
_("Unexpected response from IMAP4 server %s: %s"),
engine->url->host, linebuf);
-
+
g_free (linebuf);
-
+
goto exception;
}
} while (1);
-
+
/* status should always be ACTIVE here... */
if (ic->status == CAMEL_IMAP4_COMMAND_ACTIVE) {
ic->part = ic->part->next;
@@ -675,13 +682,13 @@
return 1;
}
}
-
+
return 0;
-
+
exception:
-
+
ic->status = CAMEL_IMAP4_COMMAND_ERROR;
-
+
return -1;
}
@@ -690,16 +697,19 @@
camel_imap4_command_reset (CamelIMAP4Command *ic)
{
int i;
-
+
for (i = 0; i < ic->resp_codes->len; i++)
camel_imap4_resp_code_free (ic->resp_codes->pdata[i]);
g_ptr_array_set_size (ic->resp_codes, 0);
-
+
+ if (ic->reset && ic->user_data)
+ ic->reset (ic, ic->user_data);
+
ic->status = CAMEL_IMAP4_COMMAND_QUEUED;
ic->result = CAMEL_IMAP4_RESULT_NONE;
ic->part = ic->parts;
g_free (ic->tag);
ic->tag = NULL;
-
+
camel_exception_clear (&ic->ex);
}
Modified: trunk/camel/providers/imap4/camel-imap4-command.h
==============================================================================
--- trunk/camel/providers/imap4/camel-imap4-command.h (original)
+++ trunk/camel/providers/imap4/camel-imap4-command.h Wed May 7 00:20:12 2008
@@ -53,6 +53,8 @@
struct _camel_imap4_token_t *token,
CamelException *ex);
+typedef void (* CamelIMAP4CommandReset) (CamelIMAP4Command *ic, void *user_data);
+
enum {
CAMEL_IMAP4_LITERAL_STRING,
CAMEL_IMAP4_LITERAL_STREAM,
@@ -72,7 +74,7 @@
struct _CamelIMAP4CommandPart *next;
unsigned char *buffer;
size_t buflen;
-
+
CamelIMAP4Literal *literal;
} CamelIMAP4CommandPart;
@@ -92,32 +94,33 @@
struct _CamelIMAP4Command {
EDListNode node;
-
+
struct _CamelIMAP4Engine *engine;
-
+
unsigned int ref_count:26;
unsigned int status:3;
unsigned int result:3;
int id;
-
+
char *tag;
-
+
GPtrArray *resp_codes;
-
+
struct _CamelIMAP4Folder *folder;
CamelException ex;
-
+
/* command parts - logical breaks in the overall command based on literals */
CamelIMAP4CommandPart *parts;
-
+
/* current part */
CamelIMAP4CommandPart *part;
-
+
/* untagged handlers */
GHashTable *untagged;
-
+
/* '+' callback/data */
CamelIMAP4PlusCallback plus;
+ CamelIMAP4CommandReset reset;
void *user_data;
};
Modified: trunk/camel/providers/imap4/camel-imap4-summary.c
==============================================================================
--- trunk/camel/providers/imap4/camel-imap4-summary.c (original)
+++ trunk/camel/providers/imap4/camel-imap4-summary.c Wed May 7 00:20:12 2008
@@ -1,6 +1,6 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* Camel
- * Copyright (C) 1999-2007 Novell, Inc. (www.novell.com)
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
* Authors: Jeffrey Stedfast <fejj novell com>
*
@@ -54,6 +54,8 @@
#define CAMEL_IMAP4_SUMMARY_VERSION 3
+#define IMAP_SAVE_INCREMENT 1024
+
static void camel_imap4_summary_class_init (CamelIMAP4SummaryClass *klass);
static void camel_imap4_summary_init (CamelIMAP4Summary *summary, CamelIMAP4SummaryClass *klass);
static void camel_imap4_summary_finalize (CamelObject *object);
@@ -484,105 +486,105 @@
decode_envelope (CamelIMAP4Engine *engine, CamelMessageInfo *info, camel_imap4_token_t *token, CamelException *ex)
{
CamelIMAP4MessageInfo *iinfo = (CamelIMAP4MessageInfo *) info;
+ char *nstring, *msgid;
guint8 *digest;
gsize length;
- char *nstring, *msgid;
-
+
length = g_checksum_type_get_length (G_CHECKSUM_MD5);
digest = g_alloca (length);
-
+
if (camel_imap4_engine_next_token (engine, token, ex) == -1)
return -1;
-
+
if (token->token != '(') {
camel_imap4_utils_set_unexpected_token_error (ex, engine, token);
return -1;
}
-
+
if (envelope_decode_date (engine, &iinfo->info.date_sent, ex) == -1)
goto exception;
-
+
/* subject */
if (envelope_decode_nstring (engine, &nstring, TRUE, ex) == -1)
goto exception;
iinfo->info.subject = camel_pstring_strdup (nstring);
g_free(nstring);
-
+
/* from */
if (envelope_decode_addresses (engine, &nstring, ex) == -1)
goto exception;
iinfo->info.from = camel_pstring_strdup (nstring);
g_free(nstring);
-
+
/* sender */
if (envelope_decode_addresses (engine, &nstring, ex) == -1)
goto exception;
g_free (nstring);
-
+
/* reply-to */
if (envelope_decode_addresses (engine, &nstring, ex) == -1)
goto exception;
g_free (nstring);
-
+
/* to */
if (envelope_decode_addresses (engine, &nstring, ex) == -1)
goto exception;
iinfo->info.to = camel_pstring_strdup (nstring);
g_free(nstring);
-
+
/* cc */
if (envelope_decode_addresses (engine, &nstring, ex) == -1)
goto exception;
iinfo->info.cc = camel_pstring_strdup (nstring);
g_free(nstring);
-
+
/* bcc */
if (envelope_decode_addresses (engine, &nstring, ex) == -1)
goto exception;
g_free (nstring);
-
+
/* in-reply-to */
if (envelope_decode_nstring (engine, &nstring, FALSE, ex) == -1)
goto exception;
-
+
if (nstring != NULL) {
if (!iinfo->info.references)
iinfo->info.references = decode_references (NULL, nstring);
-
+
g_free (nstring);
}
-
+
/* message-id */
if (envelope_decode_nstring (engine, &nstring, FALSE, ex) == -1)
goto exception;
-
+
if (nstring != NULL) {
if ((msgid = camel_header_msgid_decode (nstring))) {
GChecksum *checksum;
-
+
checksum = g_checksum_new (G_CHECKSUM_MD5);
g_checksum_update (checksum, (guchar *) msgid, -1);
g_checksum_get_digest (checksum, digest, &length);
g_checksum_free (checksum);
-
+
memcpy (iinfo->info.message_id.id.hash, digest, sizeof (CamelSummaryMessageID));
g_free (msgid);
}
g_free (nstring);
}
-
+
if (camel_imap4_engine_next_token (engine, token, ex) == -1)
return -1;
-
+
if (token->token != ')') {
camel_imap4_utils_set_unexpected_token_error (ex, engine, token);
goto exception;
}
-
+
return 0;
-
+
exception:
-
+
return -1;
}
@@ -596,9 +598,9 @@
{
register const unsigned char *inptr = (const unsigned char *) *in;
int *val, colons = 0;
-
+
*hour = *min = *sec = 0;
-
+
val = hour;
for ( ; *inptr && !isspace ((int) *inptr); inptr++) {
if (*inptr == ':') {
@@ -618,9 +620,9 @@
else
*val = (*val * 10) + (*inptr - '0');
}
-
+
*in = inptr;
-
+
return TRUE;
}
@@ -656,68 +658,70 @@
struct tm tm;
time_t date;
char *buf;
-
+
memset ((void *) &tm, 0, sizeof (struct tm));
-
+
tm.tm_mday = strtoul (inptr, &buf, 10);
if (buf == inptr || *buf != '-')
return (time_t) -1;
-
+
inptr = buf + 1;
if (inptr[3] != '-')
return (time_t) -1;
-
+
for (n = 0; n < 12; n++) {
if (!g_ascii_strncasecmp (inptr, tm_months[n], 3))
break;
}
-
+
if (n >= 12)
return (time_t) -1;
-
+
tm.tm_mon = n;
-
+
inptr += 4;
-
+
n = strtoul (inptr, &buf, 10);
if (buf == inptr || *buf != ' ')
return (time_t) -1;
-
+
tm.tm_year = n - 1900;
-
+
inptr = buf + 1;
if (!decode_time (&inptr, &hour, &min, &sec))
return (time_t) -1;
-
+
tm.tm_hour = hour;
tm.tm_min = min;
tm.tm_sec = sec;
-
+
n = strtol (inptr, NULL, 10);
-
+
date = mktime_utc (&tm);
-
+
/* date is now GMT of the time we want, but not offset by the timezone ... */
-
+
/* this should convert the time to the GMT equiv time */
date -= ((n / 100) * 60 * 60) + (n % 100) * 60;
-
+
return date;
}
enum {
- IMAP4_FETCH_ENVELOPE = (1 << 1),
- IMAP4_FETCH_FLAGS = (1 << 2),
- IMAP4_FETCH_INTERNALDATE = (1 << 3),
- IMAP4_FETCH_RFC822SIZE = (1 << 4),
- IMAP4_FETCH_UID = (1 << 5),
+ IMAP4_FETCH_ENVELOPE = (1 << 0),
+ IMAP4_FETCH_FLAGS = (1 << 1),
+ IMAP4_FETCH_INTERNALDATE = (1 << 2),
+ IMAP4_FETCH_RFC822SIZE = (1 << 3),
+ IMAP4_FETCH_UID = (1 << 4),
+
+ IMAP4_FETCH_SAVED = (1 << 7),
};
#define IMAP4_FETCH_ALL (IMAP4_FETCH_ENVELOPE | IMAP4_FETCH_FLAGS | IMAP4_FETCH_INTERNALDATE | IMAP4_FETCH_RFC822SIZE | IMAP4_FETCH_UID)
struct imap4_envelope_t {
CamelMessageInfo *info;
- guint changed;
+ guint8 changed;
};
struct imap4_fetch_all_t {
@@ -725,10 +729,11 @@
CamelFolderSummary *summary;
GHashTable *uid_hash;
GPtrArray *added;
- guint32 total;
guint32 count;
+ guint32 total;
guint32 first;
- guint32 need;
+ guint8 need;
+ guint8 all;
};
static void
@@ -736,15 +741,15 @@
{
struct imap4_envelope_t *envelope;
int i;
-
+
for (i = 0; i < fetch->added->len; i++) {
if (!(envelope = fetch->added->pdata[i]))
continue;
-
+
camel_message_info_free (envelope->info);
g_free (envelope);
}
-
+
g_ptr_array_free (fetch->added, TRUE);
g_hash_table_destroy (fetch->uid_hash);
camel_folder_change_info_free (fetch->changes);
@@ -756,7 +761,7 @@
{
CamelSession *session = ((CamelService *) summary->folder->parent_store)->session;
char *warning;
-
+
warning = g_strdup_printf ("IMAP server did not respond with an untagged FETCH response "
"for message #%lu. This is illegal according to rfc3501 (and "
"the older rfc2060). You will need to contact your\n"
@@ -764,58 +769,83 @@
"Hint: If your IMAP server is Courier-IMAP, it is likely that this "
"message is simply unreadable by the IMAP server and will need "
"to be given read permissions.", msg);
-
+
camel_session_alert_user (session, CAMEL_SESSION_ALERT_WARNING, warning, FALSE);
g_free (warning);
}
+/**
+ * imap4_fetch_all_add:
+ * @fetch: FETCH ALL state
+ * @complete: %TRUE if the FETCH command is complete or %FALSE otherwise
+ *
+ * Adds all newly acquired envelopes to the summary. Stops at the
+ * first incomplete envelope.
+ **/
static void
-imap4_fetch_all_add (struct imap4_fetch_all_t *fetch)
+imap4_fetch_all_add (struct imap4_fetch_all_t *fetch, gboolean complete)
{
- CamelFolderChangeInfo *changes = NULL;
struct imap4_envelope_t *envelope;
+ CamelFolderChangeInfo *changes;
CamelMessageInfo *info;
guint32 i;
-
+
changes = fetch->changes;
for (i = 0; i < fetch->added->len; i++) {
if (!(envelope = fetch->added->pdata[i])) {
- courier_imap_is_a_piece_of_shit (fetch->summary, i + fetch->first);
+ if (complete)
+ courier_imap_is_a_piece_of_shit (fetch->summary, i + fetch->first);
break;
}
-
- if (envelope->changed != IMAP4_FETCH_ALL) {
- d(fprintf (stderr, "Hmmm, IMAP4 server didn't give us everything for message %d\n", i + 1));
- camel_message_info_free (envelope->info);
- g_free (envelope);
- continue;
+
+ if ((envelope->changed & IMAP4_FETCH_ALL) != IMAP4_FETCH_ALL) {
+ if (complete) {
+ d(fprintf (stderr, "Hmmm, IMAP4 server didn't give us everything for message %d\n",
+ fetch->first + i));
+ }
+
+ break;
}
-
- if ((info = camel_folder_summary_uid (fetch->summary, camel_message_info_uid (envelope->info)))) {
+
+ if (!(envelope->changed & IMAP4_FETCH_SAVED)) {
+ if ((info = camel_folder_summary_uid (fetch->summary, camel_message_info_uid (envelope->info)))) {
+ camel_message_info_free (info);
+ continue;
+ }
+
+ if ((((CamelMessageInfoBase *) envelope->info)->flags & CAMEL_IMAP4_MESSAGE_RECENT))
+ camel_folder_change_info_recent_uid (changes, camel_message_info_uid (envelope->info));
+
+ camel_folder_change_info_add_uid (changes, camel_message_info_uid (envelope->info));
+ camel_folder_summary_add (fetch->summary, envelope->info);
+ envelope->changed |= IMAP4_FETCH_SAVED;
+ }
+ }
+
+ if (complete) {
+ for (i = 0; i < fetch->added->len; i++) {
+ if (!(envelope = fetch->added->pdata[i]))
+ continue;
+
camel_message_info_free (envelope->info);
- camel_message_info_free (info);
g_free (envelope);
- continue;
}
-
- camel_folder_change_info_add_uid (changes, camel_message_info_uid (envelope->info));
-
- if ((((CamelMessageInfoBase *) envelope->info)->flags & CAMEL_IMAP4_MESSAGE_RECENT))
- camel_folder_change_info_recent_uid (changes, camel_message_info_uid (envelope->info));
-
- camel_folder_summary_add (fetch->summary, envelope->info);
- g_free (envelope);
+
+ g_ptr_array_free (fetch->added, TRUE);
+ g_hash_table_destroy (fetch->uid_hash);
}
-
- g_ptr_array_free (fetch->added, TRUE);
- g_hash_table_destroy (fetch->uid_hash);
-
+
if (camel_folder_change_info_changed (changes))
camel_object_trigger_event (fetch->summary->folder, "folder_changed", changes);
- camel_folder_change_info_free (changes);
-
- g_free (fetch);
+
+ if (complete) {
+ camel_folder_change_info_free (changes);
+ g_free (fetch);
+ } else {
+ camel_folder_summary_save (fetch->summary);
+ camel_folder_change_info_clear (changes);
+ }
}
static void
@@ -827,9 +857,9 @@
CamelMessageInfo *info;
guint32 flags;
int total, i;
-
+
changes = fetch->changes;
-
+
total = camel_folder_summary_count (fetch->summary);
for (i = 0; i < total; i++) {
info = camel_folder_summary_index (fetch->summary, i);
@@ -843,34 +873,34 @@
/* update it with the new flags */
new_iinfo = (CamelIMAP4MessageInfo *) envelope->info;
iinfo = (CamelIMAP4MessageInfo *) info;
-
+
flags = iinfo->info.flags;
iinfo->info.flags = camel_imap4_merge_flags (iinfo->server_flags, iinfo->info.flags, new_iinfo->server_flags);
iinfo->server_flags = new_iinfo->server_flags;
if (iinfo->info.flags != flags)
camel_folder_change_info_change_uid (changes, camel_message_info_uid (info));
}
-
+
camel_message_info_free (info);
}
-
+
for (i = 0; i < fetch->added->len; i++) {
if (!(envelope = fetch->added->pdata[i])) {
courier_imap_is_a_piece_of_shit (fetch->summary, i + fetch->first);
continue;
}
-
+
camel_message_info_free (envelope->info);
g_free (envelope);
}
-
+
g_ptr_array_free (fetch->added, TRUE);
g_hash_table_destroy (fetch->uid_hash);
-
+
if (camel_folder_change_info_changed (changes))
camel_object_trigger_event (fetch->summary->folder, "folder_changed", changes);
camel_folder_change_info_free (changes);
-
+
g_free (fetch);
}
@@ -884,83 +914,96 @@
CamelIMAP4MessageInfo *iinfo;
CamelMessageInfo *info;
guint32 changed = 0;
- const char *iuid;
- char uid[12];
-
+ char uid[16];
+
if (index < fetch->first) {
- /* we already have this message envelope cached -
- * server is probably notifying us of a FLAGS change
- * by another client? */
- g_assert (index < summary->messages->len);
- iinfo = (CamelIMAP4MessageInfo *)(info = summary->messages->pdata[index - 1]);
- g_assert (info != NULL);
+ /* This can happen if the connection to the
+ * server was dropped in a previous attempt at
+ * this FETCH (ALL) command and some other
+ * client expunged messages in the range
+ * before fetch->first in the period between
+ * our previous attempt and now. */
+ size_t movelen = added->len * sizeof (void *);
+ size_t extra = index - fetch->first;
+ void *dest;
+
+ g_assert (fetch->all);
+
+ g_ptr_array_set_size (added, added->len + extra);
+ dest = ((char *) added->pdata) + (extra * sizeof (void *));
+ memmove (dest, added->pdata, movelen);
+ fetch->total += extra;
+ fetch->first = index;
+ } else if (index > (added->len + (fetch->first - 1))) {
+ size_t extra = index - (added->len + (fetch->first - 1));
+ g_ptr_array_set_size (added, added->len + extra);
+ fetch->total += extra;
+ }
+
+ if (!(envelope = added->pdata[index - fetch->first])) {
+ info = camel_folder_summary_info_new (summary);
+ iinfo = (CamelIMAP4MessageInfo *) info;
+ envelope = g_new (struct imap4_envelope_t, 1);
+ added->pdata[index - fetch->first] = envelope;
+ envelope->info = info;
+ envelope->changed = 0;
} else {
- if (index > (added->len + fetch->first - 1))
- g_ptr_array_set_size (added, index - fetch->first + 1);
-
- if (!(envelope = added->pdata[index - fetch->first])) {
- iinfo = (CamelIMAP4MessageInfo *) (info = camel_message_info_new (summary));
- envelope = g_new (struct imap4_envelope_t, 1);
- added->pdata[index - fetch->first] = envelope;
- envelope->info = info;
- envelope->changed = 0;
- } else {
- iinfo = (CamelIMAP4MessageInfo *) (info = envelope->info);
- }
+ info = envelope->info;
+ iinfo = (CamelIMAP4MessageInfo *) info;
}
-
+
if (camel_imap4_engine_next_token (engine, token, ex) == -1)
return -1;
-
+
/* parse the FETCH response list */
if (token->token != '(') {
camel_imap4_utils_set_unexpected_token_error (ex, engine, token);
return -1;
}
-
+
do {
if (camel_imap4_engine_next_token (engine, token, ex) == -1)
goto exception;
-
+
if (token->token == ')' || token->token == '\n')
break;
-
+
if (token->token != CAMEL_IMAP4_TOKEN_ATOM)
goto unexpected;
-
+
if (!strcmp (token->v.atom, "ENVELOPE")) {
if (envelope) {
if (decode_envelope (engine, info, token, ex) == -1)
goto exception;
-
+
changed |= IMAP4_FETCH_ENVELOPE;
} else {
CamelMessageInfo *tmp;
int rv;
-
+
g_warning ("Hmmm, server is sending us ENVELOPE data for a message we didn't ask for (message %lu)\n",
index);
tmp = camel_message_info_new (summary);
rv = decode_envelope (engine, tmp, token, ex);
camel_message_info_free(tmp);
-
+
if (rv == -1)
goto exception;
}
} else if (!strcmp (token->v.atom, "FLAGS")) {
guint32 server_flags = 0;
-
+
if (camel_imap4_parse_flags_list (engine, &server_flags, ex) == -1)
return -1;
-
+
iinfo->info.flags = camel_imap4_merge_flags (iinfo->server_flags, iinfo->info.flags, server_flags);
iinfo->server_flags = server_flags;
-
+
changed |= IMAP4_FETCH_FLAGS;
} else if (!strcmp (token->v.atom, "INTERNALDATE")) {
if (camel_imap4_engine_next_token (engine, token, ex) == -1)
goto exception;
-
+
switch (token->token) {
case CAMEL_IMAP4_TOKEN_NIL:
iinfo->info.date_received = (time_t) -1;
@@ -972,25 +1015,25 @@
default:
goto unexpected;
}
-
+
changed |= IMAP4_FETCH_INTERNALDATE;
} else if (!strcmp (token->v.atom, "RFC822.SIZE")) {
if (camel_imap4_engine_next_token (engine, token, ex) == -1)
goto exception;
-
+
if (token->token != CAMEL_IMAP4_TOKEN_NUMBER)
goto unexpected;
-
+
iinfo->info.size = token->v.number;
-
+
changed |= IMAP4_FETCH_RFC822SIZE;
} else if (!strcmp (token->v.atom, "UID")) {
if (camel_imap4_engine_next_token (engine, token, ex) == -1)
goto exception;
-
+
if (token->token != CAMEL_IMAP4_TOKEN_NUMBER || token->v.number == 0)
goto unexpected;
-
+
sprintf (uid, "%lu", token->v.number);
iuid = camel_message_info_uid (info);
if (iuid != NULL && iuid[0] != '\0') {
@@ -1013,22 +1056,22 @@
const char *refs, *str;
char *mlist;
size_t n;
-
+
/* '(' */
if (camel_imap4_engine_next_token (engine, token, ex) == -1)
goto exception;
-
+
if (token->token != '(')
goto unexpected;
-
+
/* header name list */
do {
if (camel_imap4_engine_next_token (engine, token, ex) == -1)
goto exception;
-
+
if (token->token == ')')
break;
-
+
switch (token->token) {
case CAMEL_IMAP4_TOKEN_ATOM:
case CAMEL_IMAP4_TOKEN_QSTRING:
@@ -1036,44 +1079,44 @@
case CAMEL_IMAP4_TOKEN_LITERAL:
if (camel_imap4_engine_literal (engine, &literal, &n, ex) == -1)
return -1;
-
+
g_free (literal);
break;
default:
goto unexpected;
}
-
+
/* we don't care what the list was... */
} while (1);
-
+
/* ']' */
if (camel_imap4_engine_next_token (engine, token, ex) == -1)
goto exception;
-
+
if (token->token != ']')
goto unexpected;
-
+
/* literal */
if (camel_imap4_engine_next_token (engine, token, ex) == -1)
goto exception;
-
+
if (token->token != CAMEL_IMAP4_TOKEN_LITERAL)
goto unexpected;
-
+
parser = camel_mime_parser_new ();
camel_mime_parser_init_with_stream (parser, (CamelStream *) engine->istream);
-
+
switch (camel_mime_parser_step (parser, NULL, NULL)) {
case CAMEL_MIME_PARSER_STATE_HEADER:
case CAMEL_MIME_PARSER_STATE_MESSAGE:
case CAMEL_MIME_PARSER_STATE_MULTIPART:
h = camel_mime_parser_headers_raw (parser);
-
+
/* find our mailing-list header */
mlist = camel_header_raw_check_mailing_list (&h);
iinfo->info.mlist = camel_pstring_strdup (mlist);
g_free (mlist);
-
+
/* check if we possibly have attachments */
if ((str = camel_header_raw_find (&h, "Content-Type", NULL))) {
content_type = camel_content_type_decode (str);
@@ -1082,7 +1125,7 @@
iinfo->info.flags |= CAMEL_MESSAGE_ATTACHMENTS;
camel_content_type_unref (content_type);
}
-
+
/* check for References: */
g_free (iinfo->info.references);
refs = camel_header_raw_find (&h, "References", NULL);
@@ -1091,33 +1134,48 @@
default:
break;
}
-
+
camel_object_unref (parser);
} else {
/* wtf? */
d(fprintf (stderr, "huh? %s?...\n", token->v.atom));
}
} while (1);
-
+
if (envelope) {
envelope->changed |= changed;
- if ((envelope->changed & fetch->need) == fetch->need)
- camel_operation_progress (NULL, (++fetch->count * 100.0f) / fetch->total);
+
+ if ((envelope->changed & fetch->need) == fetch->need) {
+ fetch->count++;
+
+ /* if we're doing a FETCH ALL and fetch->count
+ * is a multiple of the IMAP_SAVE_INCREMENT,
+ * sync the newly fetched envelopes to the
+ * summary and to disk as a convenience to
+ * users on flaky networks which might drop
+ * our connection to the IMAP server at any
+ * time, thus forcing us to reconnect and lose
+ * our summary fetching state. */
+ if (fetch->all && (fetch->count % IMAP_SAVE_INCREMENT) == 0)
+ imap4_fetch_all_add (fetch, FALSE);
+
+ camel_operation_progress (NULL, (fetch->count * 100.0f) / fetch->total);
+ }
} else if (changed & IMAP4_FETCH_FLAGS) {
camel_folder_change_info_change_uid (fetch->changes, camel_message_info_uid (info));
}
-
+
if (token->token != ')')
goto unexpected;
-
+
return 0;
-
+
unexpected:
-
+
camel_imap4_utils_set_unexpected_token_error (ex, engine, token);
-
+
exception:
-
+
return -1;
}
@@ -1127,6 +1185,70 @@
#define BASE_HEADER_FIELDS "Content-Type References In-Reply-To"
#define MORE_HEADER_FIELDS BASE_HEADER_FIELDS " " MAILING_LIST_HEADERS
+static void
+imap4_fetch_all_reset (CamelIMAP4Command *ic, struct imap4_fetch_all_t *fetch)
+{
+ CamelIMAP4Summary *imap_summary = (CamelIMAP4Summary *) fetch->summary;
+ CamelFolder *folder = fetch->summary->folder;
+ struct imap_envelope_t *envelope;
+ SpruceMessageInfo *info;
+ guint32 seqid, iuid;
+ const char *query;
+ char uid[32];
+ int scount;
+ int i;
+
+ /* sync everything we've gotten so far to the summary */
+ imap4_fetch_all_add (fetch, FALSE);
+
+ for (i = 0; i < fetch->added->len; i++) {
+ if (!(envelope = fetch->added->pdata[i]))
+ continue;
+
+ camel_message_info_free (envelope->info);
+ fetch->added->pdata[i] = NULL;
+ g_free (envelope);
+ }
+
+ scount = camel_folder_summary_count (fetch->summary);
+ seqid = scount + 1;
+
+ if (seqid > fetch->first) {
+ /* if we get here, then it means that we managed to
+ * collect some summary info before the connection
+ * with the imap server dropped. Update our FETCH
+ * command state to begin fetching where we left off
+ * rather than at the beginning. */
+ info = camel_folder_summary_index (fetch->summary, scount - 1);
+ iuid = strtoul (camel_message_info_uid (info), NULL, 10);
+ d(fprintf (stderr, "last known summary id = %d, uid = %s, iuid = %u\n", scount, info->uid, iuid));
+ camel_message_info_free (info);
+ sprintf (uid, "%u", iuid + 1);
+
+ fetch->total = imap_summary->exists - scount;
+ g_ptr_array_set_size (fetch->added, fetch->total);
+ fetch->first = seqid;
+
+ /* now we hack the SpruceIMAPCommand structure... */
+ if (((CamelIMAP4Folder *) folder)->enable_mlist)
+ query = "UID FETCH %s:* (" IMAP4_ALL " BODY.PEEK[HEADER.FIELDS (" MORE_HEADER_FIELDS ")])\r\n";
+ else
+ query = "UID FETCH %s:* (" IMAP4_ALL " BODY.PEEK[HEADER.FIELDS (" BASE_HEADER_FIELDS ")])\r\n";
+
+ g_free (ic->part->buffer);
+ ic->part->buffer = g_strdup_printf (query, uid);
+ ic->part->buflen = strlen (ic->part->buffer);
+
+ d(fprintf (stderr, "*** RESETTING FETCH-ALL STATE. New command => %s", ic->part->buffer));
+ } else {
+ /* we didn't manage to fetch any new info before the
+ * connection dropped... */
+ }
+
+ camel_folder_change_info_clear (fetch->changes);
+ g_hash_table_remove_all (fetch->uid_hash);
+}
+
static CamelIMAP4Command *
imap4_summary_fetch_all (CamelFolderSummary *summary, guint32 seqid, const char *uid)
{
@@ -1137,9 +1259,9 @@
CamelIMAP4Command *ic;
const char *query;
guint32 total;
-
+
engine = ((CamelIMAP4Store *) folder->parent_store)->engine;
-
+
total = (imap4_summary->exists - seqid) + 1;
fetch = g_new (struct imap4_fetch_all_t, 1);
fetch->uid_hash = g_hash_table_new (g_str_hash, g_str_equal);
@@ -1150,15 +1272,17 @@
fetch->need = IMAP4_FETCH_ALL;
fetch->total = total;
fetch->count = 0;
-
+ fetch->all = TRUE;
+
if (((CamelIMAP4Folder *) folder)->enable_mlist)
query = "UID FETCH %s:* (" IMAP4_ALL " BODY.PEEK[HEADER.FIELDS (" MORE_HEADER_FIELDS ")])\r\n";
else
query = "UID FETCH %s:* (" IMAP4_ALL " BODY.PEEK[HEADER.FIELDS (" BASE_HEADER_FIELDS ")])\r\n";
-
+
ic = camel_imap4_engine_queue (engine, folder, query, uid);
-
+
camel_imap4_command_register_untagged (ic, "FETCH", untagged_fetch_all);
+ ic->reset = (CamelIMAP4CommandReset) imap4_fetch_all_reset;
ic->user_data = fetch;
return ic;
@@ -1178,12 +1302,13 @@
engine = ((CamelIMAP4Store *) folder->parent_store)->engine;
scount = camel_folder_summary_count (summary);
+
info[0] = camel_folder_summary_index (summary, 0);
if (scount > 1)
info[1] = camel_folder_summary_index (summary, scount - 1);
else
info[1] = NULL;
-
+
total = imap4_summary->exists < scount ? imap4_summary->exists : scount;
fetch = g_new (struct imap4_fetch_all_t, 1);
fetch->uid_hash = g_hash_table_new (g_str_hash, g_str_equal);
@@ -1194,7 +1319,8 @@
fetch->need = IMAP4_FETCH_UID | IMAP4_FETCH_FLAGS;
fetch->total = total;
fetch->count = 0;
-
+ fetch->all = FALSE;
+
if (info[1] != NULL) {
ic = camel_imap4_engine_queue (engine, folder, "UID FETCH %s:%s (FLAGS)\r\n",
camel_message_info_uid (info[0]),
@@ -1204,12 +1330,12 @@
ic = camel_imap4_engine_queue (engine, folder, "UID FETCH %s:* (FLAGS)\r\n",
camel_message_info_uid (info[0]));
}
-
+
camel_message_info_free (info[0]);
-
+
camel_imap4_command_register_untagged (ic, "FETCH", untagged_fetch_all);
ic->user_data = fetch;
-
+
return ic;
}
@@ -1436,26 +1562,26 @@
guint32 iuid, seqid = 0;
int scount, id;
char uid[16];
-
+
g_return_val_if_fail (CAMEL_IS_IMAP4_SUMMARY (summary), -1);
-
+
/* FIXME: what do we do if replaying the journal fails? */
camel_offline_journal_replay (journal, NULL);
-
+
if (imap4_folder->enable_mlist && !(summary->flags & CAMEL_IMAP4_SUMMARY_HAVE_MLIST)) {
/* need to refetch all summary info to get info->mlist */
imap4_summary_clear (summary, FALSE);
}
-
+
summary->flags = (summary->flags & ~CAMEL_IMAP4_SUMMARY_HAVE_MLIST);
if (imap4_folder->enable_mlist)
summary->flags |= CAMEL_IMAP4_SUMMARY_HAVE_MLIST;
else
summary->flags ^= CAMEL_IMAP4_SUMMARY_HAVE_MLIST;
-
+
engine = ((CamelIMAP4Store *) summary->folder->parent_store)->engine;
scount = camel_folder_summary_count (summary);
-
+
if (imap4_summary->uidvalidity_changed) {
/* need to refetch everything */
g_assert (scount == 0);
@@ -1465,11 +1591,11 @@
* have since been expunged from the server by another
* client */
ic = imap4_summary_fetch_flags (summary);
-
+
camel_operation_start (NULL, _("Scanning for changed messages"));
while ((id = camel_imap4_engine_iterate (engine)) < ic->id && id != -1)
;
-
+
if (id == -1 || ic->status != CAMEL_IMAP4_COMMAND_COMPLETE) {
camel_imap4_journal_readd_failed ((CamelIMAP4Journal *) journal);
imap4_fetch_all_free (ic->user_data);
@@ -1478,11 +1604,11 @@
camel_operation_end (NULL);
return -1;
}
-
+
imap4_fetch_all_update (ic->user_data);
camel_imap4_command_unref (ic);
camel_operation_end (NULL);
-
+
scount = camel_folder_summary_count (summary);
if (imap4_summary->exists < scount) {
/* broken server? wtf? this should never happen... */
@@ -1501,7 +1627,7 @@
/* need to fetch new envelopes */
first = scount + 1;
}
-
+
if (seqid != 0 && seqid <= imap4_summary->exists) {
if (scount > 0) {
info = camel_folder_summary_index (summary, scount - 1);
@@ -1511,13 +1637,13 @@
} else {
strcpy (uid, "1");
}
-
+
ic = imap4_summary_fetch_all (summary, seqid, uid);
-
+
camel_operation_start (NULL, _("Fetching envelopes of new messages"));
while ((id = camel_imap4_engine_iterate (engine)) < ic->id && id != -1)
;
-
+
if (id == -1 || ic->status != CAMEL_IMAP4_COMMAND_COMPLETE) {
camel_imap4_journal_readd_failed ((CamelIMAP4Journal *) journal);
imap4_fetch_all_free (ic->user_data);
@@ -1526,16 +1652,16 @@
camel_operation_end (NULL);
return -1;
}
-
- imap4_fetch_all_add (ic->user_data);
+
+ imap4_fetch_all_add (ic->user_data, TRUE);
camel_imap4_command_unref (ic);
camel_operation_end (NULL);
}
-
+
imap4_summary->update_flags = FALSE;
imap4_summary->uidvalidity_changed = FALSE;
-
+
camel_imap4_journal_readd_failed ((CamelIMAP4Journal *) journal);
-
+
return 0;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]