diff options
author | Dan Winship <danw@src.gnome.org> | 2001-05-01 22:51:36 +0800 |
---|---|---|
committer | Dan Winship <danw@src.gnome.org> | 2001-05-01 22:51:36 +0800 |
commit | eb7438182ab5fd969aac96795f67034e21937e35 (patch) | |
tree | aa136f16d6be288b7623cb66a16d260944e61557 /camel/providers/imap/camel-imap-message-cache.c | |
parent | c757cacd08d3650309783172c2dedc0d20092634 (diff) | |
download | gsoc2013-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.c | 228 |
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)); + } +} |