diff options
-rw-r--r-- | camel/ChangeLog | 50 | ||||
-rw-r--r-- | camel/camel-folder-summary.c | 9 | ||||
-rw-r--r-- | camel/camel-folder-summary.h | 1 | ||||
-rw-r--r-- | camel/camel-mime-utils.c | 5 | ||||
-rw-r--r-- | camel/camel-session.c | 27 | ||||
-rw-r--r-- | camel/providers/imap/Makefile.am | 2 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-command.c | 36 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-folder.c | 760 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-folder.h | 15 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-store.c | 33 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-store.h | 2 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-summary.c | 147 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-summary.h | 63 |
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 */ + |