aboutsummaryrefslogtreecommitdiffstats
path: root/camel/providers/imap/camel-imap-message-cache.c
diff options
context:
space:
mode:
authorDan Winship <danw@src.gnome.org>2001-05-01 22:51:36 +0800
committerDan Winship <danw@src.gnome.org>2001-05-01 22:51:36 +0800
commiteb7438182ab5fd969aac96795f67034e21937e35 (patch)
treeaa136f16d6be288b7623cb66a16d260944e61557 /camel/providers/imap/camel-imap-message-cache.c
parentc757cacd08d3650309783172c2dedc0d20092634 (diff)
downloadgsoc2013-evolution-eb7438182ab5fd969aac96795f67034e21937e35.tar
gsoc2013-evolution-eb7438182ab5fd969aac96795f67034e21937e35.tar.gz
gsoc2013-evolution-eb7438182ab5fd969aac96795f67034e21937e35.tar.bz2
gsoc2013-evolution-eb7438182ab5fd969aac96795f67034e21937e35.tar.lz
gsoc2013-evolution-eb7438182ab5fd969aac96795f67034e21937e35.tar.xz
gsoc2013-evolution-eb7438182ab5fd969aac96795f67034e21937e35.tar.zst
gsoc2013-evolution-eb7438182ab5fd969aac96795f67034e21937e35.zip
Support the IMAP UIDPLUS extension (RFC 2359), which lets you
resync after disconnected operation more efficiently, but also makes it possible to do appends and moves/copies more efficiently now. * providers/imap/camel-imap-folder.c (imap_append_message): If the server supports UIDPLUS, grab the APPENDUID response and cache the message into the folder's message cache. (imap_copy_messages_to): Likewise, for COPYUID, copy any message parts we have cached between the source and destination folder caches. (imap_get_message): If the entire message is already in the cache, just return that rather than building it from parts. (imap_update_summary): Fetch just the "UID FLAGS RFC822.SIZE" of the new messages first, then only fetch the headers for messages where we don't already have the headers cached. * providers/imap/camel-imap-message-cache.c: Add gtk-doc comments. (cache_put): Fix refcounting stuff here. (camel_imap_message_cache_insert_stream, camel_imap_message_cache_insert_wrapper): New. (camel_imap_message_cache_get): Fix a bug here so the memory caching actually works. (camel_imap_message_cache_copy): New routine, used by imap_copy_messages_to. * providers/imap/camel-imap-utils.c (imap_uid_set_to_array): Inverse operation of imap_uid_array_to_set. Used to parse COPYUID response. svn path=/trunk/; revision=9635
Diffstat (limited to 'camel/providers/imap/camel-imap-message-cache.c')
-rw-r--r--camel/providers/imap/camel-imap-message-cache.c228
1 files changed, 200 insertions, 28 deletions
diff --git a/camel/providers/imap/camel-imap-message-cache.c b/camel/providers/imap/camel-imap-message-cache.c
index cd96409515..45f8d6db51 100644
--- a/camel/providers/imap/camel-imap-message-cache.c
+++ b/camel/providers/imap/camel-imap-message-cache.c
@@ -33,6 +33,7 @@
#include <string.h>
#include "camel-imap-message-cache.h"
+#include "camel-data-wrapper.h"
#include "camel-exception.h"
#include "camel-stream-fs.h"
@@ -92,18 +93,27 @@ cache_put (CamelImapMessageCache *cache, const char *uid, const char *key,
{
char *hash_key;
GPtrArray *subparts;
- gpointer old_key, old_value;
+ gpointer okey, ostream;
- hash_key = g_strdup (key);
subparts = g_hash_table_lookup (cache->parts, uid);
if (!subparts) {
subparts = g_ptr_array_new ();
g_hash_table_insert (cache->parts, g_strdup (uid), subparts);
- } else if (g_hash_table_lookup_extended (cache->parts, hash_key,
- &old_key, &old_value))
- g_ptr_array_remove (subparts, old_key);
+ }
+
+ if (g_hash_table_lookup_extended (cache->parts, key, &okey, &ostream)) {
+ if (ostream) {
+ camel_object_unhook_event (ostream, "finalize",
+ stream_finalize, cache);
+ g_hash_table_remove (cache->cached, ostream);
+ camel_object_unref (ostream);
+ }
+ hash_key = okey;
+ } else {
+ hash_key = g_strdup (key);
+ g_ptr_array_add (subparts, hash_key);
+ }
- g_ptr_array_add (subparts, hash_key);
g_hash_table_insert (cache->parts, hash_key, stream);
g_hash_table_insert (cache->cached, stream, hash_key);
@@ -113,6 +123,16 @@ cache_put (CamelImapMessageCache *cache, const char *uid, const char *key,
}
}
+/**
+ * camel_imap_message_cache_new:
+ * @path: directory to use for storage
+ * @summary: CamelFolderSummary for the folder we are caching
+ * @ex: a CamelException
+ *
+ * Return value: a new CamelImapMessageCache object using @path for
+ * storage. If cache files already exist in @path, then any that do not
+ * correspond to messages in @summary will be deleted.
+ **/
CamelImapMessageCache *
camel_imap_message_cache_new (const char *path, CamelFolderSummary *summary,
CamelException *ex)
@@ -187,44 +207,145 @@ stream_finalize (CamelObject *stream, gpointer event_data, gpointer user_data)
g_hash_table_insert (cache->parts, key, NULL);
}
-CamelStream *
-camel_imap_message_cache_insert (CamelImapMessageCache *cache, const char *uid,
- const char *part_spec, const char *data,
- int len)
+
+static CamelStream *
+insert_setup (CamelImapMessageCache *cache, const char *uid,
+ const char *part_spec, char **path, char **key)
{
- char *path, *key;
- int fd, status;
CamelStream *stream;
+ int fd;
- path = g_strdup_printf ("%s/%s.%s", cache->path, uid, part_spec);
- key = strrchr (path, '/') + 1;
- stream = g_hash_table_lookup (cache->parts, key);
+ *path = g_strdup_printf ("%s/%s.%s", cache->path, uid, part_spec);
+ *key = strrchr (*path, '/') + 1;
+ stream = g_hash_table_lookup (cache->parts, *key);
if (stream)
camel_object_unref (CAMEL_OBJECT (stream));
- fd = open (path, O_RDWR | O_CREAT | O_TRUNC, 0600);
+ fd = open (*path, O_RDWR | O_CREAT | O_TRUNC, 0600);
if (fd == -1) {
- g_free (path);
+ g_free (*path);
return NULL;
}
- stream = camel_stream_fs_new_with_fd (fd);
- status = camel_stream_write (stream, data, len);
- camel_stream_reset (stream);
+ return camel_stream_fs_new_with_fd (fd);
+}
- if (status == -1) {
- unlink (path);
- g_free (path);
- camel_object_unref (CAMEL_OBJECT (stream));
- return NULL;
- }
+static CamelStream *
+insert_abort (char *path, CamelStream *stream)
+{
+ unlink (path);
+ g_free (path);
+ camel_object_unref (CAMEL_OBJECT (stream));
+ return NULL;
+}
+static CamelStream *
+insert_finish (CamelImapMessageCache *cache, const char *uid,
+ char *path, char *key, CamelStream *stream)
+{
+ camel_stream_reset (stream);
cache_put (cache, uid, key, stream);
+ printf ("caching %s\n", path);
g_free (path);
return stream;
}
+/**
+ * camel_imap_message_cache_insert:
+ * @cache: the cache
+ * @uid: UID of the message data to cache
+ * @part_spec: the IMAP part_spec of the data
+ * @data: the data
+ * @len: length of @data
+ *
+ * Caches the provided data into @cache.
+ *
+ * Return value: a CamelStream containing the cached data, which the
+ * caller must unref.
+ **/
+CamelStream *
+camel_imap_message_cache_insert (CamelImapMessageCache *cache, const char *uid,
+ const char *part_spec, const char *data,
+ int len)
+{
+ char *path, *key;
+ CamelStream *stream;
+
+ stream = insert_setup (cache, uid, part_spec, &path, &key);
+ if (!stream)
+ return NULL;
+ if (camel_stream_write (stream, data, len) == -1)
+ return insert_abort (path, stream);
+ return insert_finish (cache, uid, path, key, stream);
+}
+
+/**
+ * camel_imap_message_cache_insert_stream:
+ * @cache: the cache
+ * @uid: UID of the message data to cache
+ * @part_spec: the IMAP part_spec of the data
+ * @data_stream: the stream to cache
+ *
+ * Caches the provided data into @cache.
+ **/
+void
+camel_imap_message_cache_insert_stream (CamelImapMessageCache *cache,
+ const char *uid, const char *part_spec,
+ CamelStream *data_stream)
+{
+ char *path, *key;
+ CamelStream *stream;
+
+ stream = insert_setup (cache, uid, part_spec, &path, &key);
+ if (!stream)
+ return;
+ if (camel_stream_write_to_stream (data_stream, stream) == -1)
+ insert_abort (path, stream);
+ else {
+ insert_finish (cache, uid, path, key, stream);
+ camel_object_unref (CAMEL_OBJECT (stream));
+ }
+}
+
+/**
+ * camel_imap_message_cache_insert_wrapper:
+ * @cache: the cache
+ * @uid: UID of the message data to cache
+ * @part_spec: the IMAP part_spec of the data
+ * @wrapper: the wrapper to cache
+ *
+ * Caches the provided data into @cache.
+ **/
+void
+camel_imap_message_cache_insert_wrapper (CamelImapMessageCache *cache,
+ const char *uid, const char *part_spec,
+ CamelDataWrapper *wrapper)
+{
+ char *path, *key;
+ CamelStream *stream;
+
+ stream = insert_setup (cache, uid, part_spec, &path, &key);
+ if (!stream)
+ return;
+ if (camel_data_wrapper_write_to_stream (wrapper, stream) == -1)
+ insert_abort (path, stream);
+ else {
+ insert_finish (cache, uid, path, key, stream);
+ camel_object_unref (CAMEL_OBJECT (stream));
+ }
+}
+
+
+/**
+ * camel_imap_message_cache_get:
+ * @cache: the cache
+ * @uid: the UID of the data to get
+ * @part_spec: the part_spec of the data to get
+ *
+ * Return value: a CamelStream containing the cached data (which the
+ * caller must unref), or %NULL if that data is not cached.
+ **/
CamelStream *
camel_imap_message_cache_get (CamelImapMessageCache *cache, const char *uid,
const char *part_spec)
@@ -233,7 +354,7 @@ camel_imap_message_cache_get (CamelImapMessageCache *cache, const char *uid,
char *path, *key;
path = g_strdup_printf ("%s/%s.%s", cache->path, uid, part_spec);
- key = strrchr (path, '/');
+ key = strrchr (path, '/') + 1;
stream = g_hash_table_lookup (cache->parts, key);
if (stream) {
camel_object_ref (CAMEL_OBJECT (stream));
@@ -241,13 +362,22 @@ camel_imap_message_cache_get (CamelImapMessageCache *cache, const char *uid,
}
stream = camel_stream_fs_new_with_name (path, O_RDONLY, 0);
- if (stream)
+ if (stream) {
+ printf ("got %s\n", path);
cache_put (cache, uid, key, stream);
+ }
g_free (path);
return stream;
}
+/**
+ * camel_imap_message_cache_remove:
+ * @cache: the cache
+ * @uid: UID of the data to remove
+ *
+ * Removes all data associated with @uid from @cache.
+ **/
void
camel_imap_message_cache_remove (CamelImapMessageCache *cache, const char *uid)
{
@@ -286,8 +416,50 @@ clear_part (gpointer key, gpointer value, gpointer data)
return TRUE;
}
+/**
+ * camel_imap_message_cache_clear:
+ * @cache: the cache
+ *
+ * Removes all cached data from @cache.
+ **/
void
camel_imap_message_cache_clear (CamelImapMessageCache *cache)
{
g_hash_table_foreach_remove (cache->parts, clear_part, cache);
}
+
+
+/**
+ * camel_imap_message_cache_copy:
+ * @source: the source message cache
+ * @source_uid: UID of a message in @source
+ * @dest: the destination message cache
+ * @dest_uid: UID of the message in @dest
+ *
+ * Copies all cached parts from @source_uid in @source to @dest_uid in
+ * @destination.
+ **/
+void
+camel_imap_message_cache_copy (CamelImapMessageCache *source,
+ const char *source_uid,
+ CamelImapMessageCache *dest,
+ const char *dest_uid)
+{
+ GPtrArray *subparts;
+ CamelStream *stream;
+ char *part;
+ int i;
+
+ subparts = g_hash_table_lookup (source->parts, source_uid);
+ if (!subparts || !subparts->len)
+ return;
+
+ for (i = 0; i < subparts->len; i++) {
+ part = strchr (subparts->pdata[i], '.');
+ if (!part++)
+ continue;
+ stream = camel_imap_message_cache_get (source, source_uid, part);
+ camel_imap_message_cache_insert_stream (dest, dest_uid, part, stream);
+ camel_object_unref (CAMEL_OBJECT (stream));
+ }
+}