#endif
#include <errno.h>
+#include <glib/gi18n-lib.h>
#include "camel/camel-exception.h"
#include "camel/camel-stream-mem.h"
static CamelFolderClass *parent_class;
CamelFolder *
-camel_imapx_folder_new(CamelStore *store, const gchar *path, const gchar *folder_name)
+camel_imapx_folder_new(CamelStore *store, const gchar *folder_dir, const gchar *folder_name, CamelException *ex)
{
CamelFolder *folder;
CamelIMAPXFolder *ifolder;
const gchar *short_name;
gchar *summary_file;
- d(printf("opening imap folder '%s'\n", path));
+ d(printf("opening imap folder '%s'\n", folder_dir));
short_name = strrchr (folder_name, '/');
if (short_name)
((CamelIMAPXFolder *)folder)->raw_name = g_strdup(folder_name);
- summary_file = g_strdup_printf ("%s/summary", path);
+ summary_file = g_strdup_printf ("%s/summary", folder_dir);
folder->summary = camel_imapx_summary_new(folder, summary_file);
+ if (!folder->summary) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not create folder summary for %s"),
+ short_name);
+ return NULL;
+ }
+
+ ifolder->cache = camel_data_cache_new (folder_dir, 0, ex);
+ if (!ifolder->cache) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not create cache for %s"),
+ short_name);
+ return NULL;
+ }
+
ifolder->search = camel_folder_search_new ();
ifolder->search_lock = g_mutex_new ();
ifolder->exists_on_server = -1;
imapx_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex)
{
CamelMimeMessage *msg = NULL;
- CamelStream *stream;
- CamelIMAPXStore *is = (CamelIMAPXStore *)folder->parent_store;
+ CamelStream *stream = NULL;
+ CamelIMAPXStore *istore = (CamelIMAPXStore *)folder->parent_store;
+ CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) folder;
+ const char *path = NULL;
+ gboolean offline_message = FALSE;
+
+ if (!strchr (uid, '-'))
+ path = "cur";
+ else {
+ path = "new";
+ offline_message = TRUE;
+ }
+
+ stream = camel_data_cache_get (ifolder->cache, path, uid, NULL);
+ if (!stream) {
+ if (offline_message) {
+ camel_exception_setv(ex, 2, "Offline message vanished from disk: %s", uid);
+ return NULL;
+ }
- if (is->server) {
- stream = camel_imapx_server_get_message(is->server, folder, uid, ex);
- if (stream) {
- msg = camel_mime_message_new();
- if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)msg, stream) == -1) {
- camel_exception_setv(ex, 1, "error building message?");
- camel_object_unref(msg);
- msg = NULL;
- }
- camel_object_unref(stream);
+ if (istore->server && camel_imapx_server_connect (istore->server, 1)) {
+ stream = camel_imapx_server_get_message(istore->server, folder, uid, ex);
+ } else {
+ camel_exception_setv(ex, 1, "not authenticated");
+ return NULL;
}
- } else {
- camel_exception_setv(ex, 1, "not ready");
+ }
+
+ if (!camel_exception_is_set (ex)) {
+ msg = camel_mime_message_new();
+ if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)msg, stream) == -1) {
+ camel_exception_setv(ex, 1, "error building message?");
+ camel_object_unref(msg);
+ msg = NULL;
+ }
+ camel_object_unref(stream);
}
return msg;
camel_imapx_server_append_message(is->server, folder, message, info, ex);
}
+gchar *
+imapx_get_filename (CamelFolder *folder, const gchar *uid, CamelException *ex)
+{
+ CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) folder;
+
+ return camel_data_cache_get_filename (ifolder->cache, "cache", uid, NULL);
+}
+
/* Algorithm for selecting a folder:
- If uidvalidity == old uidvalidity
((CamelFolderClass *)klass)->get_message = imapx_get_message;
((CamelFolderClass *)klass)->append_message = imapx_append_message;
+ ((CamelFolderClass *)klass)->get_filename = imapx_get_filename;
}
static void
}
static void
-imap_finalise(CamelObject *object)
+imap_finalize (CamelObject *object)
{
CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) object;
+ camel_object_unref (CAMEL_OBJECT (ifolder->cache));
+
g_mutex_free (ifolder->search_lock);
if (ifolder->search)
camel_object_unref (CAMEL_OBJECT (ifolder->search));
-
}
CamelType
(CamelObjectClassInitFunc)imap_folder_class_init,
NULL,
imap_folder_init,
- (CamelObjectFinalizeFunc)imap_finalise);
+ (CamelObjectFinalizeFunc) imap_finalize);
parent_class = (CamelFolderClass *)camel_folder_get_type();
}
#include <errno.h>
#include <string.h>
#include <glib.h>
+#include <glib/gstdio.h>
// fixme, use own type funcs
#include <ctype.h>
}
#endif
-/* Get a path into the cache, works like maildir, but isn't */
-static gchar *
-imapx_get_path_uid(CamelIMAPXServer *is, CamelFolder *folder, const gchar *bit, const gchar *uid)
-{
- gchar *dir, *path;
-
- // big fixme of course, we need to create the path if it doesn't exist,
- // base it on the server, blah blah
- if (bit == NULL)
- bit = strchr(uid, '-') == NULL?"cur":"new";
- dir = g_strdup_printf("/tmp/imap-cache/%s/%s", folder->full_name, bit);
-
- g_mkdir_with_parents(dir, 0777);
- path = g_strdup_printf("%s/%s", dir, uid);
- g_free(dir);
-
- return path;
-}
-
/* Must hold QUEUE_LOCK */
static gboolean
imapx_command_start (CamelIMAPXServer *imap, CamelIMAPXCommand *ic)
/* ********************************************************************** */
static void
-imapx_command_append_message_done(CamelIMAPXServer *is, CamelIMAPXCommand *ic)
+imapx_command_append_message_done (CamelIMAPXServer *is, CamelIMAPXCommand *ic)
{
CamelIMAPXJob *job = ic->job;
+ CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) job->folder;
CamelMessageInfo *mi;
- gchar *cur;
+ gchar *cur, *old_uid;
/* Append done. If we the server supports UIDPLUS we will get an APPENDUID response
with the new uid. This lets us move the message we have directly to the cache
and also create a correctly numbered MessageInfo, without losing any information.
Otherwise we have to wait for the server to less us know it was appended. */
+ mi = camel_message_info_clone(job->u.append_message.info);
+ old_uid = g_strdup (mi->uid);
+
if (!camel_exception_is_set (ic->ex) && ic->status->result == IMAP_OK) {
if (ic->status->condition == IMAP_APPENDUID) {
printf("Got appenduid %d %d\n", (gint)ic->status->u.appenduid.uidvalidity, (gint)ic->status->u.appenduid.uid);
if (ic->status->u.appenduid.uidvalidity == is->uidvalidity) {
- mi = camel_message_info_clone(job->u.append_message.info);
+ CamelFolderChangeInfo *changes;
+
mi->uid = g_strdup_printf("%u", (guint)ic->status->u.appenduid.uid);
- cur = imapx_get_path_uid(is, job->folder, NULL, mi->uid);
+
+ cur = camel_data_cache_get_filename (ifolder->cache, "cur", mi->uid, NULL);
printf("Moving cache item %s to %s\n", job->u.append_message.path, cur);
- link(job->u.append_message.path, cur);
- g_free(cur);
- camel_folder_summary_add(job->folder->summary, mi);
+ link (job->u.append_message.path, cur);
+
+ /* should we update the message count ? */
+ camel_folder_summary_add (job->folder->summary, mi);
+
+ changes = camel_folder_change_info_new ();
+ camel_folder_change_info_add_uid (changes, mi->uid);
+ camel_object_trigger_event (CAMEL_OBJECT (job->folder), "folder_changed",
+ changes);
+ camel_folder_change_info_free (changes);
+
camel_message_info_free(mi);
+ g_free(cur);
} else {
printf("but uidvalidity changed, uh ...\n");
}
}
- camel_folder_summary_remove(job->folder->summary, job->u.append_message.info);
- // should the folder-summary remove the file ?
- unlink(job->u.append_message.path);
} else {
if (!camel_exception_is_set (ic->ex))
camel_exception_setv(job->ex, 1, "Error appending message: %s", ic->status->text);
camel_exception_xfer (job->ex, ic->ex);
}
+ camel_data_cache_remove (ifolder->cache, "tmp", old_uid, NULL);
+ g_free (old_uid);
camel_message_info_free(job->u.append_message.info);
g_free(job->u.append_message.path);
camel_object_unref(job->folder);
imapx_server_get_message (CamelIMAPXServer *is, CamelFolder *folder, const gchar *uid, gint pri, CamelException *ex)
{
CamelStream *stream;
+ CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) folder;
CamelIMAPXJob *job;
- gchar *tmp, *name;
-
- /* Get a message, we either get it from the local cache,
- Or we ask for it, which will put it in the local cache,
- then return that copy */
-
- /* FIXME: The storage logic should use camel-data-cache,
- which handles concurrent adds properly.
- EXCEPT! It wont handle the 'new' dir directly ... do we care? */
+ gchar *cache_file = NULL;
- name = imapx_get_path_uid (is, folder, NULL, uid);
- stream = camel_stream_fs_new_with_name (name, O_RDONLY, 0);
- if (stream) {
- g_free(name);
- return stream;
- } else if (strchr(uid, '-')) {
- camel_exception_setv(ex, 2, "Offline message vanished from disk: %s", uid);
- g_free(name);
- camel_object_unref(stream);
+ cache_file = camel_data_cache_get_filename (ifolder->cache, "cur", uid, NULL);
+ if (g_file_test (cache_file, G_FILE_TEST_EXISTS)) {
+ camel_exception_set (ex, 1, "cache already exists \n");
+ g_free (cache_file);
+// g_assert_not_reached ();
return NULL;
}
- tmp = imapx_get_path_uid(is, folder, "tmp", uid);
+ stream = camel_data_cache_add (ifolder->cache, "tmp", uid, NULL);
job = g_malloc0(sizeof(*job));
job->pri = pri;
job->start = imapx_job_get_message_start;
job->folder = folder;
job->u.get_message.uid = (gchar *)uid;
- job->u.get_message.stream = camel_stream_fs_new_with_name(tmp, O_WRONLY|O_CREAT|O_TRUNC, 0666);
- if (job->u.get_message.stream == NULL) {
- g_free(tmp);
- tmp = NULL;
+ job->u.get_message.stream = stream;
+ if (job->u.get_message.stream == NULL)
job->u.get_message.stream = camel_stream_mem_new();
- }
+
job->ex = ex;
-
imapx_run_job(is, job);
stream = job->u.get_message.stream;
g_free(job);
if (stream) {
- if (tmp == NULL)
+ if (CAMEL_IS_STREAM_MEM (stream))
camel_stream_reset(stream);
else {
+ char *tmp = camel_data_cache_get_filename (ifolder->cache, "tmp", uid, NULL);
+
if (camel_stream_flush(stream) == 0 && camel_stream_close(stream) == 0) {
- camel_object_unref(stream);
- stream = NULL;
- if (link(tmp, name) == 0)
- stream = camel_stream_fs_new_with_name(name, O_RDONLY, 0);
+ gchar *temp = g_strrstr (cache_file, "/"), *dir;
+
+ dir = g_strndup (cache_file, temp - cache_file);
+ g_mkdir_with_parents (dir, 0700);
+ g_free (dir);
+
+ if (link (tmp, cache_file) == 0)
+ stream = camel_stream_fs_new_with_name(cache_file, O_RDONLY, 0);
+ else {
+ camel_exception_set (ex, 1, "failed to copy the tmp file");
+ g_assert_not_reached ();
+ }
} else {
camel_exception_setv(ex, 1, "closing tmp stream failed: %s", g_strerror(errno));
camel_object_unref(stream);
stream = NULL;
}
- unlink(tmp);
+
+ camel_data_cache_remove (ifolder->cache, "tmp", uid, NULL);
+ g_free (tmp);
}
}
- g_free(tmp);
- g_free(name);
-
+ g_free (cache_file);
return stream;
}
void
camel_imapx_server_append_message(CamelIMAPXServer *is, CamelFolder *folder, CamelMimeMessage *message, const CamelMessageInfo *mi, CamelException *ex)
{
- gchar *uid = NULL, *tmp = NULL, *new = NULL;
+ gchar *uid = NULL, *tmp = NULL;
CamelStream *stream, *filter;
+ CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) folder;
CamelMimeFilter *canon;
CamelIMAPXJob *job;
CamelMessageInfo *info;
job which will asynchronously upload the message at some point in the future,
and fix up the summary to match */
- // FIXME: assign a real uid! start with last known uid, add some maildir-like stuff?
- do {
- static gint nextappend;
-
- g_free(uid);
- g_free(tmp);
- uid = g_strdup_printf("%s-%d", "1000", nextappend++);
- tmp = imapx_get_path_uid(is, folder, "tmp", uid);
- stream = camel_stream_fs_new_with_name(tmp, O_WRONLY|O_CREAT|O_EXCL, 0666);
- } while (stream == NULL && (errno == EINTR || errno == EEXIST));
-
+ /* chen cleanup this later */
+ uid = imapx_get_temp_uid ();
+ stream = camel_data_cache_add (ifolder->cache, "tmp", uid, NULL);
if (stream == NULL) {
camel_exception_setv(ex, 2, "Cannot create spool file: %s", g_strerror((gint) errno));
goto fail;
goto fail;
}
- new = imapx_get_path_uid(is, folder, "new", uid);
- if (link(tmp, new) == -1) {
- camel_exception_setv(ex, 2, "Cannot create spool file: %s", g_strerror(errno));
- goto fail;
- }
-
+ tmp = camel_data_cache_get_filename (ifolder->cache, "tmp", uid, NULL);
info = camel_folder_summary_info_new_from_message((CamelFolderSummary *)folder->summary, message, NULL);
info->uid = uid;
uid = NULL;
- camel_folder_summary_add(folder->summary, info);
// FIXME
job->folder = folder;
camel_object_ref(folder);
job->u.append_message.info = info;
- job->u.append_message.path = new;
- new = NULL;
+ job->u.append_message.path = tmp;
imapx_run_job(is, job);
fail:
unlink(tmp);
g_free(uid);
g_free(tmp);
- g_free(new);
}
#include "camel-imapx-store.h"