aboutsummaryrefslogtreecommitdiffstats
path: root/camel
diff options
context:
space:
mode:
Diffstat (limited to 'camel')
-rw-r--r--camel/ChangeLog50
-rw-r--r--camel/camel-folder-summary.c9
-rw-r--r--camel/camel-folder-summary.h1
-rw-r--r--camel/camel-mime-utils.c5
-rw-r--r--camel/camel-session.c27
-rw-r--r--camel/providers/imap/Makefile.am2
-rw-r--r--camel/providers/imap/camel-imap-command.c36
-rw-r--r--camel/providers/imap/camel-imap-folder.c760
-rw-r--r--camel/providers/imap/camel-imap-folder.h15
-rw-r--r--camel/providers/imap/camel-imap-store.c33
-rw-r--r--camel/providers/imap/camel-imap-store.h2
-rw-r--r--camel/providers/imap/camel-imap-summary.c147
-rw-r--r--camel/providers/imap/camel-imap-summary.h63
13 files changed, 609 insertions, 541 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog
index b38c4bc322..15d9a4ed0b 100644
--- a/camel/ChangeLog
+++ b/camel/ChangeLog
@@ -1,3 +1,52 @@
+2000-10-12 Dan Winship <danw@helixcode.com>
+
+ * providers/imap/camel-imap-summary.c: Simple subclass of
+ CamelFolderSummary that also keeps a UIDVALIDITY value (and
+ doesn't, for the moment, build content info).
+
+ * providers/imap/camel-imap-folder.c:
+ (various): Use a CamelImapSummary to store/fetch summary info.
+ (camel_imap_folder_new): Take a path to a file to use for the
+ summary. Set the folder's permanent_flags correctly according to
+ the server response. Read in the summary (checking the
+ UIDVALIDITY) and update it if it's out of date.
+ (imap_refresh_info): Just fetch UIDs and flags. If the UIDs all
+ match, update the flags as needed and be done with it. Otherwise,
+ delete messages that have been expunged from the server and fetch
+ full summary info for any new messages.
+ (imap_sync): Save the summary to disk.
+ (imap_update_summary): Renamed from imap_get_summary_internal. Can
+ now be told to get summary for only a subset of messages. Use
+ camel-mime-utils functions rather than rolling our own header
+ parsing.
+ (imap_get_message_info_internal): Merged into imap_update_summary.
+ (imap_set_message_flags): Don't marked the message FOLDER_FLAGGED
+ if we're not actually changing the value of any of the flags.
+ (camel_imap_folder_changed): Deal with EXISTS rather than RECENT.
+
+ * providers/imap/camel-imap-store.c (imap_connect): Call
+ camel_session_get_storage_path and save the value.
+ (get_folder): Create a local directory to store summary
+ information and pass a summary file name to camel_imap_folder_new.
+ Don't call camel_folder_refresh_info from here any more since
+ camel_imap_folder_new does it again.
+
+ * providers/imap/camel-imap-command.c (camel_imap_command): Add a
+ special case to this to make it possible to get the repsonses from
+ a SELECT and still have store->current_folder be updated
+ correctly.
+ (imap_read_response): parse EXISTS rather than RECENT
+
+ * camel-session.c (camel_session_get_storage_path): Use
+ e_mkdir_hier.
+
+ * camel-folder-summary.c (camel_folder_summary_remove_index): New
+ function.
+
+ * camel-mime-utils.c (header_raw_append_parse): fix this.
+ (camel-mime-parser.c doesn't use this code because of the MEMPOOL
+ optimization, so nothing was ever actually calling it before.)
+
2000-10-11 Not Zed <NotZed@HelixCode.com>
* camel-mime-part.h (struct _CamelMimePart): Removed
@@ -71,7 +120,6 @@
* providers/nntp/camel-nntp-newsrc.c: robustification and bug
fixes.
->>>>>>> 1.527
2000-10-06 Jeffrey Stedfast <fejj@helixcode.com>
* camel-folder-summary.c (camel_summary_format_address): Decode
diff --git a/camel/camel-folder-summary.c b/camel/camel-folder-summary.c
index d3881f5857..f68c2a7970 100644
--- a/camel/camel-folder-summary.c
+++ b/camel/camel-folder-summary.c
@@ -521,6 +521,15 @@ void camel_folder_summary_remove_uid(CamelFolderSummary *s, const char *uid)
}
}
+void camel_folder_summary_remove_index(CamelFolderSummary *s, int index)
+{
+ CamelMessageInfo *oldinfo;
+
+ oldinfo = camel_folder_summary_index (s, index);
+ if (oldinfo)
+ camel_folder_summary_remove(s, oldinfo);
+}
+
int
camel_folder_summary_encode_uint32(FILE *out, guint32 value)
{
diff --git a/camel/camel-folder-summary.h b/camel/camel-folder-summary.h
index 77d8abfb68..95b394c69f 100644
--- a/camel/camel-folder-summary.h
+++ b/camel/camel-folder-summary.h
@@ -181,6 +181,7 @@ CamelMessageInfo *camel_folder_summary_add_from_parser(CamelFolderSummary *, Cam
/* removes a summary item, doesn't fix content offsets */
void camel_folder_summary_remove(CamelFolderSummary *s, CamelMessageInfo *info);
void camel_folder_summary_remove_uid(CamelFolderSummary *s, const char *uid);
+void camel_folder_summary_remove_index(CamelFolderSummary *s, int);
/* remove all items */
void camel_folder_summary_clear(CamelFolderSummary *s);
diff --git a/camel/camel-mime-utils.c b/camel/camel-mime-utils.c
index 92e33228c3..22b6dfcff0 100644
--- a/camel/camel-mime-utils.c
+++ b/camel/camel-mime-utils.c
@@ -2583,14 +2583,13 @@ header_raw_append_parse(struct _header_raw **list, const char *header, int offse
in = header;
while (is_fieldname(*in) || *in==':')
in++;
- fieldlen = in-header;
+ fieldlen = in-header-1;
while (is_lwsp(*in))
in++;
- if (fieldlen == 0 || *in != ':') {
+ if (fieldlen == 0 || header[fieldlen] != ':') {
printf("Invalid header line: '%s'\n", header);
return;
}
- in++;
name = alloca(fieldlen+1);
memcpy(name, header, fieldlen);
name[fieldlen] = 0;
diff --git a/camel/camel-session.c b/camel/camel-session.c
index 3e6630a9c8..6f6896c885 100644
--- a/camel/camel-session.c
+++ b/camel/camel-session.c
@@ -354,26 +354,13 @@ camel_session_get_storage_path (CamelSession *session, CamelService *service,
if (access (path, F_OK) == 0)
return path;
- p = path + strlen (session->storage_path);
- do {
- p = strchr (p + 1, '/');
- if (p)
- *p = '\0';
- if (access (path, F_OK) == -1) {
- if (mkdir (path, S_IRWXU) == -1) {
- camel_exception_setv (ex,
- CAMEL_EXCEPTION_SYSTEM,
- "Could not create "
- "directory %s:\n%s",
- path,
- g_strerror (errno));
- g_free (path);
- return NULL;
- }
- }
- if (p)
- *p = '/';
- } while (p);
+ if (e_mkdir_hier (path, S_IRWXU) == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ "Could not create directory %s:\n%s",
+ path, g_strerror (errno));
+ g_free (path);
+ return NULL;
+ }
return path;
}
diff --git a/camel/providers/imap/Makefile.am b/camel/providers/imap/Makefile.am
index 15e1b850e8..d4e4db8327 100644
--- a/camel/providers/imap/Makefile.am
+++ b/camel/providers/imap/Makefile.am
@@ -24,12 +24,14 @@ libcamelimap_la_SOURCES = \
camel-imap-folder.c \
camel-imap-provider.c \
camel-imap-store.c \
+ camel-imap-summary.c \
camel-imap-utils.c
libcamelimapinclude_HEADERS = \
camel-imap-command.h \
camel-imap-folder.h \
camel-imap-store.h \
+ camel-imap-summary.h \
camel-imap-utils.h
libcamelimap_la_LDFLAGS = -version-info 0:0:0
diff --git a/camel/providers/imap/camel-imap-command.c b/camel/providers/imap/camel-imap-command.c
index 70b6ea8149..ea1f3aaccf 100644
--- a/camel/providers/imap/camel-imap-command.c
+++ b/camel/providers/imap/camel-imap-command.c
@@ -48,9 +48,13 @@ static CamelImapResponse *imap_read_response (CamelImapStore *store,
* @ex: a CamelException
* @fmt: a printf-style format string, followed by arguments
*
- * This camel method sends the IMAP command specified by @fmt and the
- * following arguments to the IMAP store specified by @store. It then
- * reads the server's response(s) and parses the final result.
+ * This function makes sure that @folder (if non-%NULL) is the
+ * currently-selected folder on @store and then sends the IMAP command
+ * specified by @fmt and the following arguments. It then reads the
+ * server's response(s) and parses the final result.
+ *
+ * As a special case, if @fmt is %NULL, it will just select @folder
+ * and return the response from doing so.
*
* Return value: %NULL if an error occurred (in which case @ex will
* be set). Otherwise, a CamelImapResponse describing the server's
@@ -64,23 +68,25 @@ camel_imap_command (CamelImapStore *store, CamelFolder *folder,
va_list ap;
/* Check for current folder */
- if (folder && folder != store->current_folder) {
+ if (folder && (!fmt || folder != store->current_folder)) {
char *folder_path;
CamelImapResponse *response;
folder_path = camel_imap_store_folder_path (store,
folder->full_name);
+ store->current_folder = NULL;
response = camel_imap_command (store, NULL, ex,
"SELECT \"%s\"", folder_path);
g_free (folder_path);
- if (!response) {
- store->current_folder = NULL;
+ if (!response)
return NULL;
- }
- camel_imap_response_free (response);
-
store->current_folder = folder;
+
+ if (!fmt)
+ return response;
+
+ camel_imap_response_free (response);
}
/* Send the command */
@@ -126,7 +132,7 @@ static CamelImapResponse *
imap_read_response (CamelImapStore *store, CamelException *ex)
{
CamelImapResponse *response;
- int number, recent = 0;
+ int number, exists = 0;
GArray *expunged = NULL;
char *respbuf, *retcode, *p;
@@ -149,10 +155,10 @@ imap_read_response (CamelImapStore *store, CamelException *ex)
* it ourselves.
*/
number = strtoul (respbuf + 2, &p, 10);
- if (p != respbuf + 2) {
+ if (p != respbuf + 2 && store->current_folder) {
p = imap_next_word (p);
- if (!g_strcasecmp (p, "RECENT")) {
- recent = number;
+ if (!g_strcasecmp (p, "EXISTS")) {
+ exists = number;
g_free (respbuf);
goto next;
} else if (!g_strcasecmp (p, "EXPUNGE")) {
@@ -174,8 +180,8 @@ imap_read_response (CamelImapStore *store, CamelException *ex)
}
/* Update the summary */
- if (store->current_folder && (recent > 0 || expunged)) {
- camel_imap_folder_changed (store->current_folder, recent,
+ if (store->current_folder && (exists > 0 || expunged)) {
+ camel_imap_folder_changed (store->current_folder, exists,
expunged, NULL);
}
if (expunged)
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);
}
diff --git a/camel/providers/imap/camel-imap-folder.h b/camel/providers/imap/camel-imap-folder.h
index 41170ce698..724ce7ab3e 100644
--- a/camel/providers/imap/camel-imap-folder.h
+++ b/camel/providers/imap/camel-imap-folder.h
@@ -44,10 +44,8 @@ extern "C" {
typedef struct {
CamelFolder parent_object;
- CamelFolderSearch *search; /* used to run searches */
-
- GPtrArray *summary;
- GHashTable *summary_hash;
+ CamelFolderSummary *summary;
+ int exists;
} CamelImapFolder;
@@ -60,10 +58,13 @@ typedef struct {
/* public methods */
-CamelFolder *camel_imap_folder_new (CamelStore *parent, const char *folder_name);
+CamelFolder *camel_imap_folder_new (CamelStore *parent,
+ const char *folder_name,
+ const char *summary_file,
+ CamelException *ex);
-void camel_imap_folder_changed (CamelFolder *folder, gint recent, GArray *expunged,
- CamelException *ex);
+void camel_imap_folder_changed (CamelFolder *folder, int exists,
+ GArray *expunged, CamelException *ex);
/* Standard Camel function */
CamelType camel_imap_folder_get_type (void);
diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c
index 723cfe8d19..1042160868 100644
--- a/camel/providers/imap/camel-imap-store.c
+++ b/camel/providers/imap/camel-imap-store.c
@@ -29,6 +29,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <errno.h>
#include <gal/util/e-util.h>
@@ -198,6 +199,12 @@ imap_connect (CamelService *service, CamelException *ex)
store->command = 0;
g_free (store->dir_sep);
store->dir_sep = g_strdup ("/"); /* default dir sep */
+ if (!store->storage_path) {
+ store->storage_path =
+ camel_session_get_storage_path (session, service, ex);
+ if (camel_exception_is_set (ex))
+ return FALSE;
+ }
/* Read the greeting, if any. */
if (camel_remote_store_recv_line (CAMEL_REMOTE_STORE (service), &buf, ex) < 0) {
@@ -410,9 +417,9 @@ get_folder (CamelStore *store, const char *folder_name, gboolean create, CamelEx
{
CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
CamelFolder *new_folder;
- char *folder_path;
+ char *folder_path, *summary_file, *p;
gboolean selectable;
-
+
folder_path = camel_imap_store_folder_path (imap_store, folder_name);
if (!imap_folder_exists (imap_store, folder_path, &selectable, ex)) {
if (!create) {
@@ -431,14 +438,26 @@ get_folder (CamelStore *store, const char *folder_name, gboolean create, CamelEx
g_free (folder_path);
return NULL;
}
+
+ summary_file = g_strdup_printf ("%s/%s/#summary",
+ imap_store->storage_path,
+ folder_path);
+ p = strrchr (summary_file, '/');
+ *p = '\0';
+ if (e_mkdir_hier (summary_file, S_IRWXU) == 0) {
+ *p = '/';
+ new_folder = camel_imap_folder_new (store, folder_name,
+ summary_file, ex);
+ } else {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ "Could not create directory %s: %s",
+ summary_file, g_strerror (errno));
+ }
+ g_free (summary_file);
g_free (folder_path);
- new_folder = camel_imap_folder_new (store, folder_name);
- camel_folder_refresh_info (new_folder, ex);
- if (camel_exception_is_set (ex)) {
- camel_object_unref (CAMEL_OBJECT (new_folder));
+ if (camel_exception_is_set (ex))
return NULL;
- }
return new_folder;
}
diff --git a/camel/providers/imap/camel-imap-store.h b/camel/providers/imap/camel-imap-store.h
index 3382a8940b..a211457dbe 100644
--- a/camel/providers/imap/camel-imap-store.h
+++ b/camel/providers/imap/camel-imap-store.h
@@ -56,7 +56,7 @@ typedef struct {
CamelImapServerLevel server_level;
gboolean has_status_capability;
- gchar *dir_sep;
+ gchar *dir_sep, *storage_path;
} CamelImapStore;
diff --git a/camel/providers/imap/camel-imap-summary.c b/camel/providers/imap/camel-imap-summary.c
new file mode 100644
index 0000000000..ebdf8b9842
--- /dev/null
+++ b/camel/providers/imap/camel-imap-summary.c
@@ -0,0 +1,147 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors:
+ * Michael Zucchi <notzed@helixcode.com>
+ * Dan Winship <danw@helixcode.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include "camel-imap-summary.h"
+#include <camel/camel-mime-message.h>
+
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define CAMEL_IMAP_SUMMARY_VERSION (0x1000)
+
+static int summary_header_load (CamelFolderSummary *, FILE *);
+static int summary_header_save (CamelFolderSummary *, FILE *);
+
+static void camel_imap_summary_class_init (CamelImapSummaryClass *klass);
+static void camel_imap_summary_init (CamelImapSummary *obj);
+
+static CamelFolderSummaryClass *camel_imap_summary_parent;
+
+CamelType
+camel_imap_summary_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register(
+ camel_folder_summary_get_type(), "CamelImapSummary",
+ sizeof (CamelImapSummary),
+ sizeof (CamelImapSummaryClass),
+ (CamelObjectClassInitFunc) camel_imap_summary_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_imap_summary_init,
+ NULL);
+ }
+
+ return type;
+}
+
+static void
+camel_imap_summary_class_init (CamelImapSummaryClass *klass)
+{
+ CamelFolderSummaryClass *cfs_class = (CamelFolderSummaryClass *) klass;
+
+ camel_imap_summary_parent = CAMEL_FOLDER_SUMMARY_CLASS (camel_type_get_global_classfuncs (camel_folder_summary_get_type()));
+
+ cfs_class->summary_header_load = summary_header_load;
+ cfs_class->summary_header_save = summary_header_save;
+}
+
+static void
+camel_imap_summary_init (CamelImapSummary *obj)
+{
+ CamelFolderSummary *s = (CamelFolderSummary *)obj;
+
+ /* subclasses need to set the right instance data sizes */
+ s->message_info_size = sizeof(CamelImapMessageInfo);
+ s->content_info_size = sizeof(CamelImapMessageContentInfo);
+
+ /* and a unique file version */
+ s->version += CAMEL_IMAP_SUMMARY_VERSION;
+}
+
+/**
+ * camel_imap_summary_new:
+ * @filename: the file to store the summary in.
+ * @validity: the current UIDVALIDITY value of the folder
+ *
+ * This will create a new CamelImapSummary object and read in the
+ * summary data from disk, if it exists and has the right UIDVALIDITY
+ * value.
+ *
+ * Return value: A new CamelImapSummary object.
+ **/
+CamelFolderSummary *
+camel_imap_summary_new (const char *filename, guint32 validity)
+{
+ CamelFolderSummary *summary = CAMEL_FOLDER_SUMMARY (
+ camel_object_new (camel_imap_summary_get_type ()));
+ CamelImapSummary *imap_summary = (CamelImapSummary *)summary;
+
+ camel_folder_summary_set_build_content (summary, FALSE);
+ camel_folder_summary_set_filename (summary, filename);
+
+ if (camel_folder_summary_load (summary) == -1) {
+ if (errno == ENOENT) {
+ imap_summary->validity = validity;
+ return summary;
+ } else {
+ camel_object_unref ((CamelObject *)summary);
+ return NULL;
+ }
+ }
+ if (imap_summary->validity != validity) {
+ camel_folder_summary_clear (summary);
+ imap_summary->validity = validity;
+ }
+
+ return summary;
+}
+
+
+static int
+summary_header_load (CamelFolderSummary *s, FILE *in)
+{
+ CamelImapSummary *ims = CAMEL_IMAP_SUMMARY (s);
+
+ if (camel_imap_summary_parent->summary_header_load (s, in) == -1)
+ return -1;
+
+ return camel_folder_summary_decode_uint32 (in, &ims->validity);
+}
+
+static int
+summary_header_save (CamelFolderSummary *s, FILE *out)
+{
+ CamelImapSummary *ims = CAMEL_IMAP_SUMMARY(s);
+
+ if (camel_imap_summary_parent->summary_header_save (s, out) == -1)
+ return -1;
+
+ return camel_folder_summary_encode_uint32 (out, ims->validity);
+}
diff --git a/camel/providers/imap/camel-imap-summary.h b/camel/providers/imap/camel-imap-summary.h
new file mode 100644
index 0000000000..0b844fdd7e
--- /dev/null
+++ b/camel/providers/imap/camel-imap-summary.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors:
+ * Michael Zucchi <notzed@helixcode.com>
+ * Dan Winship <danw@helixcode.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifndef _CAMEL_IMAP_SUMMARY_H
+#define _CAMEL_IMAP_SUMMARY_H
+
+#include <camel/camel-folder-summary.h>
+#include <camel/camel-exception.h>
+
+#define CAMEL_IMAP_SUMMARY(obj) CAMEL_CHECK_CAST (obj, camel_imap_summary_get_type (), CamelImapSummary)
+#define CAMEL_IMAP_SUMMARY_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_imap_summary_get_type (), CamelImapSummaryClass)
+#define CAMEL_IS_IMAP_SUMMARY(obj) CAMEL_CHECK_TYPE (obj, camel_imap_summary_get_type ())
+
+typedef struct _CamelImapSummary CamelImapSummary;
+typedef struct _CamelImapSummaryClass CamelImapSummaryClass;
+
+typedef struct _CamelImapMessageContentInfo {
+ CamelMessageContentInfo info;
+
+} CamelImapMessageContentInfo;
+
+typedef struct _CamelImapMessageInfo {
+ CamelMessageInfo info;
+
+} CamelImapMessageInfo;
+
+struct _CamelImapSummary {
+ CamelFolderSummary parent;
+
+ guint32 validity;
+};
+
+struct _CamelImapSummaryClass {
+ CamelFolderSummaryClass parent_class;
+
+};
+
+guint camel_imap_summary_get_type (void);
+CamelFolderSummary *camel_imap_summary_new (const char *filename,
+ guint32 validity);
+
+#endif /* ! _CAMEL_IMAP_SUMMARY_H */
+