+2004-12-14 Jeffrey Stedfast <fejj@novell.com>
+
+ * providers/imap4/camel-imap4-journal.[c,h]: New source files
+ implementing a basic journal.
+
+ * providers/imap4/camel-imap4-summary.c
+ (camel_imap4_summary_flush_updates): Replay the journal.
+
+ * providers/imap4/camel-imap4-folder.c
+ (camel_imap4_folder_finalize): Write/unref the journal.
+ (camel_imap4_folder_new): Create a journal object.
+ (imap4_append_message): Journal the message append if we're in
+ offline mode.
+ (imap4_transfer_messages_to): Implement offline copy/move support
+ using the new journal code.
+
2004-12-09 Jeffrey Stedfast <fejj@novell.com>
* providers/imap4/camel-imap4-folder.c (imap4_append_message):
camel-imap4-engine.h \
camel-imap4-folder.c \
camel-imap4-folder.h \
+ camel-imap4-journal.c \
+ camel-imap4-journal.h \
camel-imap4-provider.c \
camel-imap4-search.c \
camel-imap4-search.h \
#include "camel-imap4-store.h"
#include "camel-imap4-engine.h"
#include "camel-imap4-folder.h"
+#include "camel-imap4-journal.h"
#include "camel-imap4-stream.h"
#include "camel-imap4-command.h"
#include "camel-imap4-summary.h"
folder->sync_offline = FALSE;
folder->utf7_name = NULL;
folder->cachedir = NULL;
+ folder->journal = NULL;
folder->search = NULL;
}
if (folder->cache)
camel_object_unref (folder->cache);
+ if (folder->journal) {
+ camel_imap4_journal_write (folder->journal, NULL);
+ camel_object_unref (folder->journal);
+ }
+
g_free (folder->utf7_name);
g_free (folder->cachedir);
}
int i, count = 0;
guint32 tag;
- for (i = 0; i <args->argc; i++) {
+ for (i = 0; i < args->argc; i++) {
CamelArgGet *arg = &args->argv[i];
tag = arg->tag;
static char *
-imap_get_summary_filename (const char *path)
+imap4_get_summary_filename (const char *path)
{
/* /path/to/imap/summary */
return g_build_filename (path, "summary", NULL);
}
static char *
-imap_build_filename (const char *toplevel_dir, const char *full_name)
+imap4_get_journal_filename (const char *path)
+{
+ /* /path/to/imap/journal */
+ return g_build_filename (path, "journal", NULL);
+}
+
+static char *
+imap4_build_filename (const char *toplevel_dir, const char *full_name)
{
const char *inptr = full_name;
int subdirs = 0;
}
static char *
-imap_store_build_filename (void *store, const char *full_name)
+imap4_store_build_filename (void *store, const char *full_name)
{
- CamelIMAP4Store *imap_store = (CamelIMAP4Store *) store;
+ CamelIMAP4Store *imap4_store = (CamelIMAP4Store *) store;
char *toplevel_dir;
char *path;
- toplevel_dir = g_strdup_printf ("%s/folders", imap_store->storage_path);
- path = imap_build_filename (toplevel_dir, full_name);
+ toplevel_dir = g_strdup_printf ("%s/folders", imap4_store->storage_path);
+ path = imap4_build_filename (toplevel_dir, full_name);
g_free (toplevel_dir);
return path;
CamelFolder *
camel_imap4_folder_new (CamelStore *store, const char *full_name, CamelException *ex)
{
- CamelIMAP4Folder *imap_folder;
+ CamelIMAP4Folder *imap4_folder;
char *utf7_name, *name, *p;
CamelFolder *folder;
char *path;
utf7_name = camel_utf8_utf7 (utf7_name);
- folder = (CamelFolder *) (imap_folder = (CamelIMAP4Folder *) camel_object_new (CAMEL_TYPE_IMAP4_FOLDER));
+ folder = (CamelFolder *) (imap4_folder = (CamelIMAP4Folder *) camel_object_new (CAMEL_TYPE_IMAP4_FOLDER));
camel_folder_construct (folder, store, full_name, name);
- imap_folder->utf7_name = utf7_name;
+ imap4_folder->utf7_name = utf7_name;
folder->summary = camel_imap4_summary_new (folder);
- imap_folder->cachedir = imap_store_build_filename (store, folder->full_name);
- camel_mkdir (imap_folder->cachedir, 0777);
+ imap4_folder->cachedir = imap4_store_build_filename (store, folder->full_name);
+ camel_mkdir (imap4_folder->cachedir, 0777);
- imap_folder->cache = camel_data_cache_new (imap_folder->cachedir, 0, NULL);
+ imap4_folder->cache = camel_data_cache_new (imap4_folder->cachedir, 0, NULL);
- path = imap_get_summary_filename (imap_folder->cachedir);
+ path = imap4_get_summary_filename (imap4_folder->cachedir);
camel_folder_summary_set_filename (folder->summary, path);
g_free (path);
- imap_folder->search = camel_imap4_search_new (((CamelIMAP4Store *) store)->engine, imap_folder->cachedir);
+ path = imap4_get_journal_filename (imap4_folder->cachedir);
+ imap4_folder->journal = camel_imap4_journal_new (imap4_folder, path);
+ g_free (path);
+
+ imap4_folder->search = camel_imap4_search_new (((CamelIMAP4Store *) store)->engine, imap4_folder->cachedir);
if (camel_session_is_online (((CamelService *) store)->session)) {
/* we don't care if the summary loading fails here */
}
} else {
/* wtf? */
- fprintf (stderr, "huh? %s?...\n", token->v.atom);
+ d(fprintf (stderr, "huh? %s?...\n", token->v.atom));
}
} while (1);
if (token->token != ')') {
- fprintf (stderr, "expected ')' to close untagged FETCH response\n");
+ d(fprintf (stderr, "expected ')' to close untagged FETCH response\n"));
goto unexpected;
}
{
CamelIMAP4Engine *engine = ((CamelIMAP4Store *) folder->parent_store)->engine;
CamelSession *session = ((CamelService *) folder->parent_store)->session;
- CamelIMAP4Folder *imap_folder = (CamelIMAP4Folder *) folder;
+ CamelIMAP4Folder *imap4_folder = (CamelIMAP4Folder *) folder;
CamelMimeMessage *message = NULL;
CamelStream *stream, *cache;
CamelIMAP4Command *ic;
CAMEL_SERVICE_LOCK (folder->parent_store, connect_lock);
- if (imap_folder->cache && (stream = camel_data_cache_get (imap_folder->cache, "cache", uid, ex))) {
+ if (imap4_folder->cache && (stream = camel_data_cache_get (imap4_folder->cache, "cache", uid, ex))) {
message = camel_mime_message_new ();
if (camel_data_wrapper_construct_from_stream ((CamelDataWrapper *) message, stream) == -1) {
camel_stream_reset (stream);
/* cache the message locally */
- if (imap_folder->cache && (cache = camel_data_cache_add (imap_folder->cache, "cache", uid, NULL))) {
+ if (imap4_folder->cache && (cache = camel_data_cache_add (imap4_folder->cache, "cache", uid, NULL))) {
if (camel_stream_write_to_stream (stream, cache) == -1
|| camel_stream_flush (cache) == -1)
- camel_data_cache_remove (imap_folder->cache, "cache", uid, NULL);
+ camel_data_cache_remove (imap4_folder->cache, "cache", uid, NULL);
camel_object_unref (cache);
}
*appended_uid = NULL;
if (!camel_session_is_online (session)) {
- camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot append messages to IMAP folders in offline mode."));
+ camel_imap4_journal_append (((CamelIMAP4Folder *) folder)->journal, message, info, ex);
return;
}
GPtrArray *infos;
char *set;
- if (!camel_session_is_online (session)) {
- if (move)
- camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Cannot move messages to or from IMAP folders in offline mode."));
- else
- camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Cannot copy messages to or from IMAP folders in offline mode."));
-
- return;
- }
+ if (transferred_uids)
+ *transferred_uids = NULL;
infos = g_ptr_array_new ();
for (i = 0; i < uids->len; i++) {
CAMEL_SERVICE_LOCK (src->parent_store, connect_lock);
+ /* check for offline operation */
+ if (!camel_session_is_online (session)) {
+ CamelMimeMessage *message;
+
+ for (i = 0; i < infos->len; i++) {
+ info = infos->pdata[i];
+
+ if (!(message = imap4_get_message (src, camel_message_info_uid (info), ex)))
+ break;
+
+ camel_imap4_journal_append (((CamelIMAP4Folder *) dest)->journal, message, info, ex);
+ camel_object_unref (message);
+
+ if (camel_exception_is_set (ex))
+ break;
+
+ if (move)
+ camel_folder_set_message_flags (src, camel_message_info_uid (info),
+ CAMEL_MESSAGE_DELETED, CAMEL_MESSAGE_DELETED);
+ }
+
+ goto done;
+ }
+
dest_namelen = strlen (camel_imap4_folder_utf7_name ((CamelIMAP4Folder *) dest));
for (i = 0; i < infos->len; i += n) {
done:
for (i = 0; i < infos->len; i++)
- camel_message_info_free(infos->pdata[i]);
+ camel_message_info_free (infos->pdata[i]);
g_ptr_array_free (infos, TRUE);
CAMEL_SERVICE_LOCK (src->parent_store, connect_lock);
typedef struct _CamelIMAP4Folder CamelIMAP4Folder;
typedef struct _CamelIMAP4FolderClass CamelIMAP4FolderClass;
+struct _CamelIMAP4Journal;
+
enum {
CAMEL_IMAP4_FOLDER_ARG_SYNC_OFFLINE = CAMEL_FOLDER_ARG_LAST,
CAMEL_IMAP4_FOLDER_ARG_LAST = CAMEL_FOLDER_ARG_LAST + 0x100
unsigned int sync_offline:1;
CamelFolderSearch *search;
+
+ struct _CamelIMAP4Journal *journal;
CamelDataCache *cache;
char *cachedir;
--- /dev/null
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@novell.com>
+ *
+ * Copyright 2004 Novell, Inc. (www.novell.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 Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <camel/camel-i18n.h>
+#include <camel/camel-folder.h>
+#include <camel/camel-file-utils.h>
+#include <camel/camel-folder-summary.h>
+#include <camel/camel-data-cache.h>
+
+#include "camel-imap4-folder.h"
+#include "camel-imap4-journal.h"
+
+
+#define d(x) x
+
+
+static void camel_imap4_journal_class_init (CamelIMAP4JournalClass *klass);
+static void camel_imap4_journal_init (CamelIMAP4Journal *journal, CamelIMAP4JournalClass *klass);
+static void camel_imap4_journal_finalize (CamelObject *object);
+
+
+static CamelObjectClass *parent_class = NULL;
+
+
+CamelType
+camel_imap4_journal_get_type (void)
+{
+ static CamelType type = 0;
+
+ if (!type) {
+ type = camel_type_register (camel_object_get_type (),
+ "CamelIMAP4Journal",
+ sizeof (CamelIMAP4Journal),
+ sizeof (CamelIMAP4JournalClass),
+ (CamelObjectClassInitFunc) camel_imap4_journal_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_imap4_journal_init,
+ (CamelObjectFinalizeFunc) camel_imap4_journal_finalize);
+ }
+
+ return type;
+}
+
+static void
+camel_imap4_journal_class_init (CamelIMAP4JournalClass *klass)
+{
+ parent_class = camel_type_get_global_classfuncs (CAMEL_OBJECT_TYPE);
+}
+
+static void
+camel_imap4_journal_init (CamelIMAP4Journal *journal, CamelIMAP4JournalClass *klass)
+{
+ journal->folder = NULL;
+ journal->filename = NULL;
+ e_dlist_init (&journal->queue);
+}
+
+static void
+camel_imap4_journal_finalize (CamelObject *object)
+{
+ CamelIMAP4Journal *journal = (CamelIMAP4Journal *) object;
+ CamelIMAP4JournalEntry *entry;
+
+ g_free (journal->filename);
+
+ while ((entry = (CamelIMAP4JournalEntry *) e_dlist_remhead (&journal->queue))) {
+ g_free (entry->v.append_uid);
+ g_free (entry);
+ }
+}
+
+
+static CamelIMAP4JournalEntry *
+imap4_journal_entry_load (FILE *in)
+{
+ CamelIMAP4JournalEntry *entry;
+
+ entry = g_malloc0 (sizeof (CamelIMAP4JournalEntry));
+
+ if (camel_file_util_decode_uint32 (in, &entry->type) == -1)
+ goto exception;
+
+ switch (entry->type) {
+ case CAMEL_IMAP4_JOURNAL_ENTRY_APPEND:
+ if (camel_file_util_decode_string (in, &entry->v.append_uid) == -1)
+ goto exception;
+
+ break;
+ default:
+ goto exception;
+ }
+
+ return entry;
+
+ exception:
+
+ switch (entry->type) {
+ case CAMEL_IMAP4_JOURNAL_ENTRY_APPEND:
+ g_free (entry->v.append_uid);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ g_free (entry);
+
+ return NULL;
+}
+
+
+CamelIMAP4Journal *
+camel_imap4_journal_new (CamelIMAP4Folder *folder, const char *filename)
+{
+ CamelIMAP4Journal *journal;
+ EDListNode *entry;
+ FILE *fp;
+
+ g_return_val_if_fail (CAMEL_IS_IMAP4_FOLDER (folder), NULL);
+
+ journal = (CamelIMAP4Journal *) camel_object_new (camel_imap4_journal_get_type ());
+ journal->filename = g_strdup (filename);
+ journal->folder = folder;
+
+ if ((fp = fopen (filename, "r"))) {
+ while ((entry = (EDListNode *) imap4_journal_entry_load (fp)))
+ e_dlist_addtail (&journal->queue, entry);
+
+ fclose (fp);
+ }
+
+ return journal;
+}
+
+
+void
+camel_imap4_journal_set_filename (CamelIMAP4Journal *journal, const char *filename)
+{
+ g_return_if_fail (CAMEL_IS_IMAP4_JOURNAL (journal));
+
+ g_free (journal->filename);
+ journal->filename = g_strdup (filename);
+}
+
+
+static int
+imap4_journal_entry_write (CamelIMAP4JournalEntry *entry, FILE *out)
+{
+ if (camel_file_util_encode_uint32 (out, entry->type) == -1)
+ return -1;
+
+ switch (entry->type) {
+ case CAMEL_IMAP4_JOURNAL_ENTRY_APPEND:
+ if (camel_file_util_encode_string (out, entry->v.append_uid))
+ return -1;
+
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ return 0;
+}
+
+
+int
+camel_imap4_journal_write (CamelIMAP4Journal *journal, CamelException *ex)
+{
+ CamelIMAP4JournalEntry *entry;
+ EDListNode *node;
+ FILE *fp;
+ int fd;
+
+ if ((fd = open (journal->filename, O_CREAT | O_TRUNC | O_WRONLY, 0666)) == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot write IMAP4 offline journal: %s"),
+ g_strerror (errno));
+ return -1;
+ }
+
+ fp = fdopen (fd, "w");
+ node = journal->queue.head;
+ while (node->next) {
+ entry = (CamelIMAP4JournalEntry *) node;
+ if (imap4_journal_entry_write (entry, fp) == -1)
+ goto exception;
+ node = node->next;
+ }
+
+ if (fsync (fd) == -1)
+ goto exception;
+
+ fclose (fp);
+
+ return 0;
+
+ exception:
+
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot write IMAP4 offline journal: %s"),
+ g_strerror (errno));
+
+ fclose (fp);
+
+ return -1;
+}
+
+
+static int
+imap4_journal_entry_play_append (CamelIMAP4Journal *journal, CamelIMAP4JournalEntry *entry, CamelException *ex)
+{
+ CamelIMAP4Folder *imap4_folder = journal->folder;
+ CamelFolder *folder = (CamelFolder *) imap4_folder;
+ CamelMimeMessage *message;
+ CamelMessageInfo *info;
+ CamelStream *stream;
+ CamelException lex;
+
+ /* if the message isn't in the cache, the user went behind our backs so "not our problem" */
+ if (!imap4_folder->cache || !(stream = camel_data_cache_get (imap4_folder->cache, "cache", entry->v.append_uid, ex)))
+ goto done;
+
+ message = camel_mime_message_new ();
+ if (camel_data_wrapper_construct_from_stream ((CamelDataWrapper *) message, stream) == -1) {
+ camel_object_unref (message);
+ camel_object_unref (stream);
+ goto done;
+ }
+
+ camel_object_unref (stream);
+
+ if (!(info = camel_folder_summary_uid (folder->summary, entry->v.append_uid))) {
+ /* info not in the summary, either because the summary
+ * got corrupted or because the previous time this
+ * journal was replay'd, it failed [1] */
+ info = camel_message_info_new (NULL);
+ }
+
+ camel_exception_init (&lex);
+ camel_folder_append_message (folder, message, info, NULL, &lex);
+ camel_message_info_free (info);
+ camel_object_unref (message);
+
+ if (camel_exception_is_set (&lex)) {
+ /* [1] remove the summary even if we fail or the next
+ * summary downsync will break because info indexes
+ * will be wrong
+ *
+ * FIXME: we really need to save these info's to a
+ * temp location and then restore them after the
+ * summary downsync finishes. */
+ camel_folder_summary_remove_uid (folder->summary, entry->v.append_uid);
+ camel_exception_xfer (ex, &lex);
+ return -1;
+ }
+
+ done:
+
+ camel_folder_summary_remove_uid (folder->summary, entry->v.append_uid);
+ camel_data_cache_remove (journal->folder->cache, "cache", entry->v.append_uid, NULL);
+
+ return 0;
+}
+
+static int
+imap4_journal_entry_play (CamelIMAP4Journal *journal, CamelIMAP4JournalEntry *entry, CamelException *ex)
+{
+ switch (entry->type) {
+ case CAMEL_IMAP4_JOURNAL_ENTRY_APPEND:
+ return imap4_journal_entry_play_append (journal, entry, ex);
+ default:
+ g_assert_not_reached ();
+ return -1;
+ }
+}
+
+
+int
+camel_imap4_journal_replay (CamelIMAP4Journal *journal, CamelException *ex)
+{
+ EDListNode *node, *next;
+ CamelException lex;
+ int failed = 0;
+
+ camel_exception_init (&lex);
+
+ node = journal->queue.head;
+ while (node->next) {
+ next = node->next;
+ if (imap4_journal_entry_play (journal, (CamelIMAP4JournalEntry *) node, &lex) == -1) {
+ if (failed == 0)
+ camel_exception_xfer (ex, &lex);
+ camel_exception_clear (&lex);
+ failed++;
+ } else {
+ e_dlist_remove (node);
+ }
+ node = next;
+ }
+
+ if (failed > 0)
+ return -1;
+
+ return 0;
+}
+
+
+void
+camel_imap4_journal_append (CamelIMAP4Journal *journal, CamelMimeMessage *message, CamelMessageInfo *mi, CamelException *ex)
+{
+ CamelFolder *folder = (CamelFolder *) journal->folder;
+ CamelIMAP4JournalEntry *entry;
+ CamelStream *cache;
+ guint32 nextuid;
+ char *uid;
+
+ if (journal->folder->cache == NULL) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot append message in offline mode: cache unavailable"));
+ return;
+ }
+
+ nextuid = camel_folder_summary_next_uid (folder->summary);
+ uid = g_strdup_printf ("-%u", nextuid);
+
+ if (!(cache = camel_data_cache_add (journal->folder->cache, "cache", uid, ex))) {
+ folder->summary->nextuid--;
+ g_free (uid);
+ return;
+ }
+
+ if (camel_data_wrapper_write_to_stream ((CamelDataWrapper *) message, cache) == -1
+ || camel_stream_flush (cache) == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot append message in offline mode: %s"),
+ g_strerror (errno));
+ camel_data_cache_remove (journal->folder->cache, "cache", uid, NULL);
+ folder->summary->nextuid--;
+ camel_object_unref (cache);
+ g_free (uid);
+ return;
+ }
+
+ camel_object_unref (cache);
+
+ entry = g_new (CamelIMAP4JournalEntry, 1);
+ entry->type = CAMEL_IMAP4_JOURNAL_ENTRY_APPEND;
+ entry->v.append_uid = uid;
+
+ e_dlist_addtail (&journal->queue, (EDListNode *) entry);
+}
--- /dev/null
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@novell.com>
+ *
+ * Copyright 2004 Novell, Inc. (www.novell.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 Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifndef __CAMEL_IMAP4_JOURNAL_H__
+#define __CAMEL_IMAP4_JOURNAL_H__
+
+#include <stdarg.h>
+
+#include <glib.h>
+
+#include <libedataserver/e-msgport.h>
+#include <camel/camel-mime-message.h>
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+#define CAMEL_TYPE_IMAP4_JOURNAL (camel_imap4_journal_get_type ())
+#define CAMEL_IMAP4_JOURNAL(obj) (CAMEL_CHECK_CAST ((obj), CAMEL_TYPE_IMAP4_JOURNAL, CamelIMAP4Journal))
+#define CAMEL_IMAP4_JOURNAL_CLASS(klass) (CAMEL_CHECK_CLASS_CAST ((klass), CAMEL_TYPE_IMAP4_JOURNAL, CamelIMAP4JournalClass))
+#define CAMEL_IS_IMAP4_JOURNAL(obj) (CAMEL_CHECK_TYPE ((obj), CAMEL_TYPE_IMAP4_JOURNAL))
+#define CAMEL_IS_IMAP4_JOURNAL_CLASS(klass) (CAMEL_CHECK_CLASS_TYPE ((klass), CAMEL_TYPE_IMAP4_JOURNAL))
+#define CAMEL_IMAP4_JOURNAL_GET_CLASS(obj) (CAMEL_CHECK_GET_CLASS ((obj), CAMEL_TYPE_IMAP4_JOURNAL, CamelIMAP4JournalClass))
+
+typedef struct _CamelIMAP4Journal CamelIMAP4Journal;
+typedef struct _CamelIMAP4JournalClass CamelIMAP4JournalClass;
+typedef struct _CamelIMAP4JournalEntry CamelIMAP4JournalEntry;
+
+struct _CamelIMAP4Folder;
+
+enum {
+ CAMEL_IMAP4_JOURNAL_ENTRY_APPEND,
+};
+
+struct _CamelIMAP4JournalEntry {
+ EDListNode node;
+
+ int type;
+
+ union {
+ char *append_uid;
+ } v;
+};
+
+struct _CamelIMAP4Journal {
+ CamelObject parent_object;
+
+ struct _CamelIMAP4Folder *folder;
+ char *filename;
+ EDList queue;
+};
+
+struct _CamelIMAP4JournalClass {
+ CamelObjectClass parent_class;
+
+};
+
+
+CamelType camel_imap4_journal_get_type (void);
+
+CamelIMAP4Journal *camel_imap4_journal_new (struct _CamelIMAP4Folder *folder, const char *filename);
+
+void camel_imap4_journal_set_filename (CamelIMAP4Journal *journal, const char *filename);
+
+int camel_imap4_journal_write (CamelIMAP4Journal *journal, CamelException *ex);
+
+int camel_imap4_journal_replay (CamelIMAP4Journal *journal, CamelException *ex);
+
+/* interfaces for adding a journal entry */
+void camel_imap4_journal_append (CamelIMAP4Journal *journal, CamelMimeMessage *message, CamelMessageInfo *mi, CamelException *ex);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __CAMEL_IMAP4_JOURNAL_H__ */
#include "camel-imap4-folder.h"
#include "camel-imap4-stream.h"
#include "camel-imap4-command.h"
+#include "camel-imap4-journal.h"
#include "camel-imap4-utils.h"
#include "camel-imap4-summary.h"
g_return_val_if_fail (CAMEL_IS_IMAP4_SUMMARY (summary), -1);
+ /* FIXME: what do we do if replaying the journal fails? */
+ camel_imap4_journal_replay (((CamelIMAP4Folder *) summary->folder)->journal, NULL);
+
engine = ((CamelIMAP4Store *) summary->folder->parent_store)->engine;
scount = camel_folder_summary_count (summary);