aboutsummaryrefslogtreecommitdiffstats
path: root/camel/providers/imap/camel-imap-folder.c
diff options
context:
space:
mode:
Diffstat (limited to 'camel/providers/imap/camel-imap-folder.c')
-rw-r--r--camel/providers/imap/camel-imap-folder.c760
1 files changed, 273 insertions, 487 deletions
diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c
index 970f622b16..fcb6cba5a2 100644
--- a/camel/providers/imap/camel-imap-folder.c
+++ b/camel/providers/imap/camel-imap-folder.c
@@ -1,4 +1,4 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*- */
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* camel-imap-folder.c: Abstract class for an imap folder */
/*
@@ -33,6 +33,7 @@
#include <errno.h>
#include <string.h>
#include <fcntl.h>
+#include <ctype.h>
#include <gal/util/e-util.h>
@@ -40,6 +41,7 @@
#include "camel-imap-command.h"
#include "camel-imap-store.h"
#include "camel-imap-stream.h"
+#include "camel-imap-summary.h"
#include "camel-imap-utils.h"
#include "string-utils.h"
#include "camel-stream.h"
@@ -66,7 +68,6 @@ static void imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex
static void imap_expunge (CamelFolder *folder, CamelException *ex);
/* message counts */
-static gint imap_get_message_count_internal (CamelFolder *folder, CamelException *ex);
static gint imap_get_message_count (CamelFolder *folder);
static gint imap_get_unread_message_count (CamelFolder *folder);
@@ -82,10 +83,12 @@ static void imap_move_message_to (CamelFolder *source, const char *uid,
/* summary info */
static GPtrArray *imap_get_uids (CamelFolder *folder);
-static GPtrArray *imap_get_summary_internal (CamelFolder *folder, CamelException *ex);
static GPtrArray *imap_get_summary (CamelFolder *folder);
static const CamelMessageInfo *imap_get_message_info (CamelFolder *folder, const char *uid);
+static void imap_update_summary (CamelFolder *folder, int first, int last,
+ CamelException *ex);
+
/* searching */
static GPtrArray *imap_search_by_expression (CamelFolder *folder, const char *expression, CamelException *ex);
@@ -143,17 +146,6 @@ camel_imap_folder_init (gpointer object, gpointer klass)
folder->has_search_capability = TRUE;
imap_folder->summary = NULL;
- imap_folder->summary_hash = NULL;
-
- /* some IMAP daemons support user-flags *
- * I would not, however, rely on this feature as *
- * most IMAP daemons do not support all the features */
- folder->permanent_flags = CAMEL_MESSAGE_SEEN |
- CAMEL_MESSAGE_ANSWERED |
- CAMEL_MESSAGE_FLAGGED |
- CAMEL_MESSAGE_DELETED |
- CAMEL_MESSAGE_DRAFT |
- CAMEL_MESSAGE_USER;
}
CamelType
@@ -176,11 +168,17 @@ camel_imap_folder_get_type (void)
}
CamelFolder *
-camel_imap_folder_new (CamelStore *parent, const char *folder_name)
+camel_imap_folder_new (CamelStore *parent, const char *folder_name,
+ const char *summary_file, CamelException *ex)
{
+ CamelImapStore *imap_store = CAMEL_IMAP_STORE (parent);
CamelFolder *folder = CAMEL_FOLDER (camel_object_new (camel_imap_folder_get_type ()));
- const char *dir_sep, *short_name;
-
+ CamelImapFolder *imap_folder = (CamelImapFolder *)folder;
+ CamelImapResponse *response;
+ const char *dir_sep, *short_name, *resp;
+ guint32 validity = 0;
+ int i;
+
dir_sep = CAMEL_IMAP_STORE (parent)->dir_sep;
short_name = strrchr (folder_name, *dir_sep);
if (short_name)
@@ -188,34 +186,48 @@ camel_imap_folder_new (CamelStore *parent, const char *folder_name)
else
short_name = folder_name;
camel_folder_construct (folder, parent, folder_name, short_name);
-
- return folder;
-}
-static void
-imap_summary_free (GPtrArray **summary)
-{
- GPtrArray *array = *summary;
- gint i;
-
- if (array) {
- for (i = 0; i < array->len; i++)
- camel_message_info_free (array->pdata[i]);
-
- g_ptr_array_free (array, TRUE);
- *summary = NULL;
+ imap_folder->summary = camel_imap_summary_new (summary_file, validity);
+ if (!imap_folder->summary) {
+ camel_object_unref (CAMEL_OBJECT (folder));
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ "Could not load summary for %s",
+ folder_name);
+ return NULL;
}
-}
-static void
-imap_folder_summary_free (CamelImapFolder *imap_folder)
-{
- if (imap_folder->summary_hash) {
- g_hash_table_destroy (imap_folder->summary_hash);
- imap_folder->summary_hash = NULL;
+ response = camel_imap_command (imap_store, folder, ex, NULL);
+ if (!response) {
+ camel_object_unref ((CamelObject *)folder);
+ return NULL;
}
-
- imap_summary_free (&imap_folder->summary);
+
+ for (i = 0; i < response->untagged->len; i++) {
+ resp = response->untagged->pdata[i] + 2;
+ if (!g_strncasecmp (resp, "FLAGS ", 6)) {
+ folder->permanent_flags =
+ imap_parse_flag_list (resp + 6);
+ } else if (!g_strncasecmp (resp, "OK [PERMANENTFLAGS ", 19)) {
+ folder->permanent_flags =
+ imap_parse_flag_list (resp + 19);
+ } else if (!g_strncasecmp (resp, "OK [UIDVALIDITY ", 16)) {
+ validity = strtoul (resp + 16, NULL, 10);
+ } else if (isdigit ((unsigned char)*resp)) {
+ unsigned long num = strtoul (resp, (char **)&resp, 10);
+
+ if (!g_strncasecmp (resp, " EXISTS", 7))
+ imap_folder->exists = num;
+ }
+ }
+ camel_imap_response_free (response);
+
+ imap_refresh_info (folder, ex);
+ if (camel_exception_is_set (ex)) {
+ camel_object_unref (CAMEL_OBJECT (folder));
+ return NULL;
+ }
+
+ return folder;
}
static void
@@ -223,116 +235,139 @@ imap_finalize (CamelObject *object)
{
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (object);
- imap_folder_summary_free (imap_folder);
+ camel_object_unref ((CamelObject *)imap_folder->summary);
}
static void
imap_refresh_info (CamelFolder *folder, CamelException *ex)
{
- imap_get_summary_internal (folder, ex);
-}
-
-static void
-imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
-{
CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
CamelImapResponse *response;
- gint i, max;
-
- if (expunge) {
- imap_expunge (folder, ex);
+ struct {
+ char *uid;
+ guint32 flags;
+ } *new;
+ char *resp, *uid, *p, *flags;
+ int i, seq, summary_len;
+ CamelMessageInfo *info;
+
+ if (imap_folder->exists == 0) {
+ camel_folder_summary_clear (imap_folder->summary);
return;
}
-
- /* Set the flags on any messages that have changed this session */
- if (imap_folder->summary) {
- max = imap_folder->summary->len;
- for (i = 0; i < max; i++) {
- CamelMessageInfo *info;
-
- info = g_ptr_array_index (imap_folder->summary, i);
- if (info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) {
- char *flags;
-
- flags = imap_create_flag_list (info->flags);
- if (flags) {
- response = camel_imap_command (
- store, folder, ex,
- "UID STORE %s FLAGS.SILENT %s",
- info->uid, flags);
- g_free (flags);
- if (!response)
- return;
- camel_imap_response_free (response);
- }
- info->flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED;
- }
+
+ /* Get UIDs and flags of all messages. */
+ response = camel_imap_command (store, folder, ex,
+ "FETCH 1:%d (UID FLAGS)",
+ imap_folder->exists);
+ if (!response)
+ return;
+
+ new = g_malloc0 (imap_folder->exists * sizeof (*new));
+ for (i = 0; i < response->untagged->len; i++) {
+ resp = response->untagged->pdata[i];
+
+ seq = strtoul (resp + 2, &resp, 10);
+ if (g_strncasecmp (resp, " FETCH ", 7) != 0)
+ continue;
+
+ uid = e_strstrcase (resp, "UID ");
+ if (uid) {
+ uid += 4;
+ strtoul (uid, &p, 10);
+ new[seq - 1].uid = g_strndup (uid, p - uid);
+ }
+
+ flags = e_strstrcase (resp, "FLAGS ");
+ if (flags) {
+ flags += 6;
+ new[seq - 1].flags = imap_parse_flag_list (flags);
}
}
+
+ /* Theoretically, the UIDs could get arbitrarily reordered,
+ * but that won't normally happen. We assume that if we find a
+ * UID in the summary that doesn't correspond to the UID in
+ * the folder, that it means the message was deleted on the
+ * server, so we remove it from the summary.
+ */
+ summary_len = camel_folder_summary_count (imap_folder->summary);
+ for (i = 0; i < summary_len && i < imap_folder->exists; i++) {
+ info = camel_folder_summary_index (imap_folder->summary, i);
+
+ /* Shouldn't happen, but... */
+ if (!new[i].uid)
+ continue;
+
+ if (strcmp (info->uid, new[i].uid) != 0) {
+ camel_folder_summary_remove (imap_folder->summary,
+ info);
+ i--;
+ summary_len--;
+ continue;
+ }
+
+ /* Update summary flags */
+ info->flags = new[i].flags;
+
+ g_free (new[i].uid);
+ }
+
+ if (i < imap_folder->exists) {
+ /* Fetch full summary for the remaining messages. */
+ imap_update_summary (folder, i + 1, imap_folder->exists, ex);
+ }
+
+ for (; i < imap_folder->exists; i++)
+ g_free (new[i].uid);
+ g_free (new);
}
static void
-imap_expunge (CamelFolder *folder, CamelException *ex)
+imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
{
CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
+ CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
CamelImapResponse *response;
+ int i, max;
- imap_sync (folder, FALSE, ex);
- response = camel_imap_command (store, folder, ex, "EXPUNGE");
- camel_imap_response_free (response);
-}
+ /* Set the flags on any messages that have changed this session */
+ max = camel_folder_summary_count (imap_folder->summary);
+ for (i = 0; i < max; i++) {
+ CamelMessageInfo *info;
-static gint
-imap_get_message_count_internal (CamelFolder *folder, CamelException *ex)
-{
- CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
- char *result, *msg_count, *folder_path;
- CamelImapResponse *response;
- int count = 0;
-
- folder_path = camel_imap_store_folder_path (store, folder->full_name);
- if (store->has_status_capability)
- response = camel_imap_command (store, folder, ex,
- "STATUS \"%s\" (MESSAGES)",
- folder_path);
- else
- response = camel_imap_command (store, folder, ex,
- "EXAMINE \"%s\"", folder_path);
- g_free (folder_path);
- if (!response)
- return 0;
-
- /* parse out the message count */
- if (store->has_status_capability) {
- /* should come in the form: "* STATUS <folder> (MESSAGES <count>)" */
- result = camel_imap_response_extract (response, "STATUS", NULL);
- if (result) {
- if ((msg_count = strstr (result, "MESSAGES")) != NULL) {
- msg_count = imap_next_word (msg_count);
-
- /* we should now be pointing to the message count */
- count = atoi (msg_count);
+ info = camel_folder_summary_index (imap_folder->summary, i);
+ if (info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) {
+ char *flags;
+
+ flags = imap_create_flag_list (info->flags);
+ if (flags) {
+ response = camel_imap_command (
+ store, folder, ex,
+ "UID STORE %s FLAGS.SILENT %s",
+ info->uid, flags);
+ g_free (flags);
+ if (!response)
+ return;
+ camel_imap_response_free (response);
}
- g_free (result);
- }
- } else {
- /* should come in the form: "* <count> EXISTS" */
- result = camel_imap_response_extract (response, "EXISTS", NULL);
- if (result) {
- if ((msg_count = strstr (result, "EXISTS")) != NULL) {
- for ( ; msg_count > result && *msg_count != '*'; msg_count--);
-
- msg_count = imap_next_word (msg_count);
-
- /* we should now be pointing to the message count */
- count = atoi (msg_count);
- }
- g_free (result);
+ info->flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED;
}
}
-
- return count;
+
+ if (expunge) {
+ response = camel_imap_command (store, folder, ex, "EXPUNGE");
+ camel_imap_response_free (response);
+ }
+
+ camel_folder_summary_save (imap_folder->summary);
+}
+
+static void
+imap_expunge (CamelFolder *folder, CamelException *ex)
+{
+ imap_sync (folder, TRUE, ex);
}
static gint
@@ -340,10 +375,7 @@ imap_get_message_count (CamelFolder *folder)
{
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
- if (imap_folder->summary)
- return imap_folder->summary->len;
- else
- return 0;
+ return camel_folder_summary_count (imap_folder->summary);
}
static gint
@@ -351,23 +383,15 @@ imap_get_unread_message_count (CamelFolder *folder)
{
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
CamelMessageInfo *info;
- GPtrArray *infolist;
- gint i, count = 0;
-
- g_return_val_if_fail (folder != NULL, 0);
-
- /* If we don't have a message count, return 0 */
- if (!imap_folder->summary)
- return 0;
-
- infolist = imap_folder->summary;
-
- for (i = 0; i < infolist->len; i++) {
- info = (CamelMessageInfo *) g_ptr_array_index (infolist, i);
+ int i, max, count = 0;
+
+ max = camel_folder_summary_count (imap_folder->summary);
+ for (i = 0; i < max; i++) {
+ info = camel_folder_summary_index (imap_folder->summary, i);
if (!(info->flags & CAMEL_MESSAGE_SEEN))
count++;
}
-
+
return count;
}
@@ -472,22 +496,21 @@ imap_move_message_to (CamelFolder *source, const char *uid,
static GPtrArray *
imap_get_uids (CamelFolder *folder)
{
+ CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
const CamelMessageInfo *info;
- GPtrArray *array, *infolist;
- gint i, count;
-
- infolist = imap_get_summary (folder);
-
- count = infolist ? infolist->len : 0;
-
+ GPtrArray *array;
+ int i, count;
+
+ count = camel_folder_summary_count (imap_folder->summary);
+
array = g_ptr_array_new ();
g_ptr_array_set_size (array, count);
-
+
for (i = 0; i < count; i++) {
- info = g_ptr_array_index (infolist, i);
+ info = camel_folder_summary_index (imap_folder->summary, i);
array->pdata[i] = g_strdup (info->uid);
}
-
+
return array;
}
@@ -533,37 +556,6 @@ imap_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex)
return msg;
}
-/* This probably shouldn't go here...but it will for now */
-static gchar *
-get_header_field (gchar *header, gchar *field)
-{
- gchar *part, *index, *p, *q;
-
- index = (char *) e_strstrcase (header, field);
- if (index == NULL)
- return NULL;
-
- p = index + strlen (field) + 1;
- for (q = p; *q; q++)
- if (*q == '\n' && (*(q + 1) != ' ' && *(q + 1) != '\t'))
- break;
-
- part = g_strndup (p, (gint)(q - p));
-
- /* it may be wrapped on multiple lines, so lets strip out \n's */
- for (p = part; *p; ) {
- if (*p == '\n')
- memmove (p, p + 1, strlen (p));
- else
- p++;
- }
-
- return part;
-}
-
-static char *header_fields[] = { "subject", "from", "to", "cc", "date",
- "received", "message-id", "references",
- "in-reply-to", "" };
/**
* imap_protocol_get_summary_specifier
*
@@ -591,271 +583,103 @@ imap_protocol_get_summary_specifier (CamelImapStore *store)
headers_wanted, sect_end);
}
-static GPtrArray *
-imap_get_summary_internal (CamelFolder *folder, CamelException *ex)
+static void
+imap_update_summary (CamelFolder *folder, int first, int last,
+ CamelException *ex)
{
- /* This ALWAYS updates the summary except on fail */
CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
CamelImapResponse *response;
- GPtrArray *summary = NULL, *headers = NULL;
- GHashTable *hash = NULL;
- int num, i, j;
- char *q;
- const char *received;
- char *summary_specifier;
- struct _header_raw *h = NULL, *tail = NULL;
-
- num = imap_get_message_count_internal (folder, ex);
-
- /* sync any previously set/changed message flags */
- imap_sync (folder, FALSE, ex);
-
- if (num == 0) {
- /* clean up any previous summary data */
- imap_folder_summary_free (imap_folder);
-
- imap_folder->summary = g_ptr_array_new ();
- imap_folder->summary_hash = g_hash_table_new (g_str_hash, g_str_equal);
-
- return imap_folder->summary;
- }
-
+ GPtrArray *headers = NULL;
+ char *q, *summary_specifier;
+ struct _header_raw *h = NULL;
+ int i;
+
+ /* If the range we're updating overlaps with the range we already
+ * know about, then fetch just flags + uids first. If uids
+ * aren't "right", reorder them. Update flags appropriately.
+ * If that returned unknown UIDs, or we're updating unknown
+ * sequence numbers, do the full fetch for those.
+ */
+
summary_specifier = imap_protocol_get_summary_specifier (store);
- if (num == 1) {
+ if (first == last) {
response = camel_imap_command (store, folder, ex,
- "FETCH 1 (%s)",
+ "FETCH %d (%s)", first,
summary_specifier);
} else {
response = camel_imap_command (store, folder, ex,
- "FETCH 1:%d (%s)", num,
- summary_specifier);
+ "FETCH %d:%d (%s)", first,
+ last, summary_specifier);
}
g_free (summary_specifier);
-
- if (!response) {
- if (!imap_folder->summary) {
- imap_folder->summary = g_ptr_array_new ();
- imap_folder->summary_hash = g_hash_table_new (g_str_hash, g_str_equal);
- }
-
- return imap_folder->summary;
- }
- headers = response->untagged;
- /* initialize our new summary-to-be */
- summary = g_ptr_array_new ();
- hash = g_hash_table_new (g_str_hash, g_str_equal);
-
+ if (!response)
+ return;
+
+ headers = response->untagged;
for (i = 0; i < headers->len; i++) {
CamelMessageInfo *info;
char *uid, *flags, *header;
-
- info = g_malloc0 (sizeof (CamelMessageInfo));
-
- /* lets grab the UID... */
+
+ /* Grab the UID... */
if (!(uid = strstr (headers->pdata[i], "UID "))) {
d(fprintf (stderr, "Cannot get a uid for %d\n\n%s\n\n", i+1, (char *) headers->pdata[i]));
- g_free (info);
- break;
- }
-
- for (uid += 4; *uid && (*uid < '0' || *uid > '9'); uid++); /* advance to <uid> */
- for (q = uid; *q && *q >= '0' && *q <= '9'; q++); /* find the end of the <uid> */
- info->uid = g_strndup (uid, (gint)(q - uid));
- /*d(fprintf (stderr, "*** info->uid = %s\n", info->uid));*/
-
- /* now lets grab the FLAGS */
- if (!(flags = strstr (headers->pdata[i], "FLAGS "))) {
- d(fprintf (stderr, "We didn't seem to get any flags for %d...\n", i));
- g_free (info->uid);
- g_free (info);
break;
}
-
- for (flags += 6; *flags && *flags != '('; flags++); /* advance to <flags> */
- info->flags = imap_parse_flag_list (flags);
-
+
+ for (uid += 4; *uid && (*uid < '0' || *uid > '9'); uid++)
+ ;
+ for (q = uid; *q && *q >= '0' && *q <= '9'; q++)
+ ;
+
/* construct the header list */
/* fast-forward to beginning of header info... */
- for (header = headers->pdata[i]; *header && *header != '\n'; header++);
+ header = strchr (headers->pdata[i], '\n') + 1;
h = NULL;
- for (j = 0; *header_fields[j]; j++) {
- struct _header_raw *raw;
- char *field, *value;
-
- field = g_strdup_printf ("\n%s:", header_fields[j]);
- value = get_header_field (header, field);
- g_free (field);
- if (!value)
- continue;
-
- raw = g_malloc0 (sizeof (struct _header_raw));
- raw->next = NULL;
- raw->name = g_strdup (header_fields[j]);
- raw->value = value;
- raw->offset = -1;
-
- if (!h) {
- h = raw;
- tail = h;
- } else {
- tail->next = raw;
- tail = raw;
- }
- }
-
- /* construct the CamelMessageInfo */
- info->subject = camel_folder_summary_format_string (h, "subject");
- info->from = camel_folder_summary_format_address (h, "from");
- info->to = camel_folder_summary_format_address (h, "to");
- info->cc = camel_folder_summary_format_address (h, "cc");
- info->user_flags = NULL;
- info->date_sent = header_decode_date (header_raw_find (&h, "date", NULL), NULL);
- received = header_raw_find (&h, "received", NULL);
- if (received)
- received = strrchr (received, ';');
- if (received)
- info->date_received = header_decode_date (received + 1, NULL);
- else
- info->date_received = 0;
- info->message_id = header_msgid_decode (header_raw_find (&h, "message-id", NULL));
- /* if we have a references, use that, otherwise, see if we have an in-reply-to
- header, with parsable content, otherwise *shrug* */
- info->references = header_references_decode (header_raw_find (&h, "references", NULL));
- if (info->references == NULL)
- info->references = header_references_decode (header_raw_find (&h, "in-reply-to", NULL));
-
+ do {
+ char *line;
+ int len;
+
+ len = strcspn (header, "\n");
+ while (header[len + 1] == ' ' ||
+ header[len + 1] == '\t')
+ len += 1 + strcspn (header + len + 1, "\n");
+ line = g_strndup (header, len);
+ header_raw_append_parse (&h, line, -1);
+ g_free (line);
+
+ header += len;
+ } while (*header++ == '\n' && *header != '\n');
+
+ /* We can't just call camel_folder_summary_add_from_parser
+ * because it will assign the wrong UID, and thus get the
+ * uid hash table wrong and all that. FIXME some day.
+ */
+ info = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(imap_folder->summary)))->message_info_new(imap_folder->summary, h);
header_raw_clear (&h);
-
- g_ptr_array_add (summary, info);
- g_hash_table_insert (hash, info->uid, info);
+ info->uid = g_strndup (uid, q - uid);
+
+ /* now lets grab the FLAGS */
+ if (!(flags = strstr (headers->pdata[i], "FLAGS "))) {
+ d(fprintf (stderr, "We didn't seem to get any flags for %d...\n", i));
+ } else {
+ for (flags += 6; *flags && *flags != '('; flags++)
+ ;
+ info->flags = imap_parse_flag_list (flags);
+ }
+
+ camel_folder_summary_add (imap_folder->summary, info);
}
camel_imap_response_free (response);
-
- /* clean up any previous summary data */
- imap_folder_summary_free (imap_folder);
-
- imap_folder->summary = summary;
- imap_folder->summary_hash = hash;
-
- return imap_folder->summary;
}
static GPtrArray *
imap_get_summary (CamelFolder *folder)
{
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
-
- return imap_folder->summary;
-}
-
-/* get a single message info from the server */
-static CamelMessageInfo *
-imap_get_message_info_internal (CamelFolder *folder, guint id, CamelException *ex)
-{
- CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
- CamelImapResponse *response;
- CamelMessageInfo *info = NULL;
- struct _header_raw *h, *tail = NULL;
- const char *received;
- char *result, *uid, *flags, *header, *q;
- char *summary_specifier;
- int j;
-
- /* we don't have a cached copy, so fetch it */
- summary_specifier = imap_protocol_get_summary_specifier (store);
- response = camel_imap_command (store, folder, ex,
- "FETCH %d (%s)", id, summary_specifier);
- g_free (summary_specifier);
- if (!response)
- return NULL;
- result = camel_imap_response_extract (response, "FETCH", ex);
- if (!result)
- return NULL;
-
- /* lets grab the UID... */
- if (!(uid = (char *) e_strstrcase (result, "UID "))) {
- d(fprintf (stderr, "Cannot get a uid for %d\n\n%s\n\n", id, result));
- g_free (result);
- return NULL;
- }
-
- for (uid += 4; *uid && (*uid < '0' || *uid > '9'); uid++); /* advance to <uid> */
- for (q = uid; *q && *q >= '0' && *q <= '9'; q++); /* find the end of the <uid> */
- uid = g_strndup (uid, (gint)(q - uid));
-
- info = g_malloc0 (sizeof (CamelMessageInfo));
- info->uid = uid;
- d(fprintf (stderr, "*** info->uid = %s\n", info->uid));
-
- /* now lets grab the FLAGS */
- if (!(flags = strstr (q, "FLAGS "))) {
- d(fprintf (stderr, "We didn't seem to get any flags for %s...\n", uid));
- g_free (info->uid);
- g_free (info);
- g_free (result);
- return NULL;
- }
-
- for (flags += 6; *flags && *flags != '('; flags++); /* advance to <flags> */
- info->flags = imap_parse_flag_list (flags);
-
- /* construct the header list */
- /* fast-forward to beginning of header info... */
- for (header = q; *header && *header != '\n'; header++);
- h = NULL;
- for (j = 0; *header_fields[j]; j++) {
- struct _header_raw *raw;
- char *field, *value;
-
- field = g_strdup_printf ("\n%s:", header_fields[j]);
- value = get_header_field (header, field);
- g_free (field);
- if (!value)
- continue;
-
- raw = g_malloc0 (sizeof (struct _header_raw));
- raw->next = NULL;
- raw->name = g_strdup (header_fields[j]);
- raw->value = value;
- raw->offset = -1;
-
- if (!h) {
- h = raw;
- tail = h;
- } else {
- tail->next = raw;
- tail = raw;
- }
- }
-
- /* construct the CamelMessageInfo */
- info->subject = camel_folder_summary_format_string (h, "subject");
- info->from = camel_folder_summary_format_address (h, "from");
- info->to = camel_folder_summary_format_address (h, "to");
- info->cc = camel_folder_summary_format_address (h, "cc");
- info->user_flags = NULL;
- info->date_sent = header_decode_date (header_raw_find (&h, "date", NULL), NULL);
- received = header_raw_find (&h, "received", NULL);
- if (received)
- received = strrchr (received, ';');
- if (received)
- info->date_received = header_decode_date (received + 1, NULL);
- else
- info->date_received = 0;
- info->message_id = header_msgid_decode (header_raw_find (&h, "message-id", NULL));
- /* if we have a references, use that, otherwise, see if we have an in-reply-to
- header, with parsable content, otherwise *shrug* */
- info->references = header_references_decode (header_raw_find (&h, "references", NULL));
- if (info->references == NULL)
- info->references = header_references_decode (header_raw_find (&h, "in-reply-to", NULL));
-
- header_raw_clear (&h);
- g_free (result);
-
- return info;
+ return imap_folder->summary->messages;
}
/* get a single message info, by uid */
@@ -864,10 +688,7 @@ imap_get_message_info (CamelFolder *folder, const char *uid)
{
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
- if (imap_folder->summary)
- return g_hash_table_lookup (imap_folder->summary_hash, uid);
-
- return NULL;
+ return camel_folder_summary_uid (imap_folder->summary, uid);
}
static GPtrArray *
@@ -936,94 +757,59 @@ imap_get_message_flags (CamelFolder *folder, const char *uid)
static void
imap_set_message_flags (CamelFolder *folder, const char *uid, guint32 flags, guint32 set)
{
+ CamelImapFolder *imap_folder = (CamelImapFolder *)folder;
CamelMessageInfo *info;
-
- info = (CamelMessageInfo*)imap_get_message_info (folder, uid);
+
+ info = camel_folder_summary_uid (imap_folder->summary, uid);
g_return_if_fail (info != NULL);
-
+
+ if ((info->flags & set) == flags)
+ return;
+
info->flags = (info->flags & ~flags) | (set & flags) | CAMEL_MESSAGE_FOLDER_FLAGGED;
-
- camel_object_trigger_event (CAMEL_OBJECT (folder), "message_changed", (gpointer *) uid);
+ camel_folder_summary_touch (imap_folder->summary);
+
+ camel_object_trigger_event (CAMEL_OBJECT (folder), "message_changed",
+ (gpointer)uid);
}
static gboolean
imap_get_message_user_flag (CamelFolder *folder, const char *uid, const char *name)
{
+ /* FIXME */
return FALSE;
}
static void
imap_set_message_user_flag (CamelFolder *folder, const char *uid, const char *name, gboolean value)
{
- camel_object_trigger_event (CAMEL_OBJECT (folder), "message_changed", (gpointer *) uid);
+ /* FIXME */
+ camel_object_trigger_event (CAMEL_OBJECT (folder), "message_changed",
+ (gpointer)uid);
}
void
-camel_imap_folder_changed (CamelFolder *folder, gint recent, GArray *expunged, CamelException *ex)
+camel_imap_folder_changed (CamelFolder *folder, int exists,
+ GArray *expunged, CamelException *ex)
{
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
-
+
if (expunged) {
- gint i, id;
-
+ int i, id;
+
for (i = 0; i < expunged->len; i++) {
id = g_array_index (expunged, int, i);
d(fprintf (stderr, "Expunging message %d from the summary (i = %d)\n", id + i, i));
-
- if (id <= imap_folder->summary->len) {
- CamelMessageInfo *info;
-
- info = (CamelMessageInfo *) imap_folder->summary->pdata[id - 1];
-
- /* remove from the lookup table and summary */
- g_hash_table_remove (imap_folder->summary_hash, info->uid);
- g_ptr_array_remove_index (imap_folder->summary, id - 1);
-
- camel_message_info_free (info);
- } else {
- /* Hopefully this should never happen */
- d(fprintf (stderr, "imap expunge-error: message %d is out of range\n", id));
- }
+ camel_folder_summary_remove_index (imap_folder->summary, id - 1);
}
}
-
- if (recent > 0) {
- CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
- CamelMessageInfo *info;
- gint i, j, last, slast;
-
- if (!imap_folder->summary) {
- imap_folder->summary = g_ptr_array_new ();
- imap_folder->summary_hash = g_hash_table_new (g_str_hash, g_str_equal);
- }
-
- last = imap_folder->summary->len + 1;
- slast = imap_get_message_count_internal (folder, ex);
- fprintf (stderr, "calculated next message is: %d\n", last);
- fprintf (stderr, "server says %d mesgs total\n", slast);
- slast -= (recent - 1);
- fprintf (stderr, "based on total, new guess is: %d\n", slast);
-
- for (i = slast, j = 0; j < recent; i++, j++) {
- info = imap_get_message_info_internal (folder, i, ex);
- if (info) {
- if (!imap_get_message_info (folder, info->uid)) {
- /* add to our summary */
- g_ptr_array_add (imap_folder->summary, info);
- g_hash_table_insert (imap_folder->summary_hash, info->uid, info);
- } else {
- /* we already have a record of it */
- camel_message_info_free (info);
- d(fprintf (stderr, "we already had message %d!!\n", i));
- }
- } else {
- /* our hack failed so now we need to do it the old fashioned way */
- /*imap_get_summary_internal (folder, ex);*/
- d(fprintf (stderr, "*** we tried to get message %d but failed\n", i));
- break;
- }
- }
+
+ if (exists > imap_folder->exists) {
+ int old = imap_folder->exists;
+
+ imap_folder->exists = exists;
+ imap_update_summary (folder, old + 1, exists, ex);
}
- camel_object_trigger_event (CAMEL_OBJECT (folder), "folder_changed", GINT_TO_POINTER (0));
+ camel_object_trigger_event (CAMEL_OBJECT (folder), "folder_changed", NULL);
}