aboutsummaryrefslogtreecommitdiffstats
path: root/camel/providers/imapp/camel-imapp-driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'camel/providers/imapp/camel-imapp-driver.c')
-rw-r--r--camel/providers/imapp/camel-imapp-driver.c748
1 files changed, 748 insertions, 0 deletions
diff --git a/camel/providers/imapp/camel-imapp-driver.c b/camel/providers/imapp/camel-imapp-driver.c
new file mode 100644
index 0000000000..f9daced770
--- /dev/null
+++ b/camel/providers/imapp/camel-imapp-driver.c
@@ -0,0 +1,748 @@
+
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "camel-imapp-driver.h"
+#include "camel-imapp-utils.h"
+#include "camel-imapp-folder.h"
+#include "camel-imapp-engine.h"
+#include "camel-imapp-summary.h"
+#include "camel-imapp-exception.h"
+
+#include <camel/camel-stream-mem.h>
+#include <camel/camel-stream-null.h>
+
+#include <camel/camel-folder-summary.h>
+#include <camel/camel-store.h>
+#include <camel/camel-mime-utils.h>
+#include <camel/camel-sasl.h>
+
+#define d(x) x
+
+static int driver_resp_fetch(CamelIMAPPEngine *ie, guint32 id, CamelIMAPPDriver *sdata);
+static int driver_resp_expunge(CamelIMAPPEngine *ie, guint32 id, CamelIMAPPDriver *sdata);
+static int driver_resp_exists(CamelIMAPPEngine *ie, guint32 id, CamelIMAPPDriver *sdata);
+static int driver_resp_list(CamelIMAPPEngine *ie, guint32 id, CamelIMAPPDriver *sdata);
+
+static void driver_status(CamelIMAPPEngine *ie, struct _status_info *sinfo, CamelIMAPPDriver *sdata);
+
+static void
+class_init(CamelIMAPPDriverClass *ieclass)
+{
+}
+
+static void
+object_init(CamelIMAPPDriver *ie, CamelIMAPPDriverClass *ieclass)
+{
+ ie->summary = g_ptr_array_new();
+ e_dlist_init(&ie->body_fetch);
+ e_dlist_init(&ie->body_fetch_done);
+}
+
+static void
+object_finalise(CamelIMAPPDriver *ie, CamelIMAPPDriverClass *ieclass)
+{
+ if (ie->folder)
+ camel_object_unref((CamelObject *)ie->folder);
+ if (ie->engine)
+ camel_object_unref((CamelObject *)ie->engine);
+ if (ie->summary)
+ g_ptr_array_free(ie->summary, TRUE);
+}
+
+CamelType
+camel_imapp_driver_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (
+ camel_object_get_type (),
+ "CamelIMAPPDriver",
+ sizeof (CamelIMAPPDriver),
+ sizeof (CamelIMAPPDriverClass),
+ (CamelObjectClassInitFunc) class_init,
+ NULL,
+ (CamelObjectInitFunc) object_init,
+ (CamelObjectFinalizeFunc) object_finalise);
+
+ /* blah ... could just use it in object setup? */
+ /* TEMPORARY */
+ camel_exception_setup();
+ }
+
+ return type;
+}
+
+CamelIMAPPDriver *
+camel_imapp_driver_new(CamelIMAPPStream *stream)
+{
+ CamelIMAPPDriver *driver;
+ CamelIMAPPEngine *ie;
+
+ driver = CAMEL_IMAPP_DRIVER (camel_object_new (CAMEL_IMAPP_DRIVER_TYPE));
+ ie = driver->engine = camel_imapp_engine_new(stream);
+
+ camel_imapp_engine_add_handler(ie, "FETCH", (CamelIMAPPEngineFunc)driver_resp_fetch, driver);
+ camel_imapp_engine_add_handler(ie, "EXPUNGE", (CamelIMAPPEngineFunc)driver_resp_expunge, driver);
+ camel_imapp_engine_add_handler(ie, "EXISTS", (CamelIMAPPEngineFunc)driver_resp_exists, driver);
+ camel_imapp_engine_add_handler(ie, "LIST", (CamelIMAPPEngineFunc)driver_resp_list, driver);
+ camel_object_hook_event(ie, "status", (CamelObjectEventHookFunc)driver_status, driver);
+
+ return driver;
+}
+
+void
+camel_imapp_driver_set_sasl_factory(CamelIMAPPDriver *id, CamelIMAPPSASLFunc get_sasl, void *sasl_data)
+{
+ id->get_sasl = get_sasl;
+ id->get_sasl_data = sasl_data;
+}
+
+void
+camel_imapp_driver_set_login_query(CamelIMAPPDriver *id, CamelIMAPPLoginFunc get_login, void *login_data)
+{
+ id->get_login = get_login;
+ id->get_login_data = login_data;
+}
+
+void
+camel_imapp_driver_login(CamelIMAPPDriver *id)
+/* throws SERVICE_CANT_AUTHENTICATE, SYSTEM_IO */
+{
+ CamelIMAPPCommand * volatile ic = NULL;
+
+ /* connect? */
+ /* camel_imapp_engine_connect() */
+ /* or above? */
+
+ CAMEL_TRY {
+ CamelSasl *sasl;
+
+ if (id->get_sasl
+ && (sasl = id->get_sasl(id, id->get_sasl_data))) {
+ ic = camel_imapp_engine_command_new(id->engine, "AUTHENTICATE", NULL, "AUTHENTICATE %A", sasl);
+ camel_object_unref(sasl);
+ } else {
+ char *user, *pass;
+
+ g_assert(id->get_login);
+ id->get_login(id, &user, &pass, id->get_login_data);
+ ic = camel_imapp_engine_command_new(id->engine, "LOGIN", NULL, "LOGIN %s %s", user, pass);
+ g_free(user);
+ g_free(pass);
+ }
+
+ camel_imapp_engine_command_queue(id->engine, ic);
+ while (camel_imapp_engine_iterate(id->engine, ic) > 0)
+ ;
+
+ if (ic->status->result != IMAP_OK)
+ camel_exception_throw(CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE, "Login failed: %s", ic->status->text);
+ camel_imapp_engine_command_free(id->engine, ic);
+ } CAMEL_CATCH(ex) {
+ if (ic)
+ camel_imapp_engine_command_free(id->engine, ic);
+ camel_exception_throw_ex(ex);
+ } CAMEL_DONE;
+}
+
+void
+camel_imapp_driver_select(CamelIMAPPDriver *id, struct _CamelIMAPPFolder *folder)
+{
+ CamelIMAPPSelectResponse *sr;
+ CamelIMAPPCommand * volatile ic = NULL;
+ CamelIMAPPCommand * volatile ic2 = NULL;
+ guint32 count;
+ CamelFolderSummary *summary;
+
+ if (id->folder) {
+ if (folder == id->folder)
+ return;
+ camel_imapp_driver_sync(id, FALSE, id->folder);
+ if (camel_folder_change_info_changed(id->folder->changes)) {
+ camel_object_trigger_event(id->folder, "folder_changed", id->folder->changes);
+ camel_folder_change_info_clear(id->folder->changes);
+ }
+ camel_object_unref(id->folder);
+ id->folder = NULL;
+ }
+
+ summary = ((CamelFolder *)folder)->summary;
+
+ ic = camel_imapp_engine_command_new(id->engine, "SELECT", NULL, "SELECT %t", folder->raw_name);
+ camel_imapp_engine_command_queue(id->engine, ic);
+ while (camel_imapp_engine_iterate(id->engine, ic)>0)
+ ;
+ camel_imapp_engine_command_free(id->engine, ic);
+
+ id->folder = folder;
+ camel_object_ref(folder);
+
+ count = camel_folder_summary_count(summary);
+ if (count > 0 && count <= id->exists) {
+ ic = camel_imapp_engine_command_new(id->engine, "FETCH", NULL,
+ "FETCH 1:%u (UID FLAGS)", count);
+ camel_imapp_engine_command_queue(id->engine, ic);
+ if (count < id->exists) {
+ ic2 = camel_imapp_engine_command_new(id->engine, "FETCH", NULL,
+ "FETCH %u:* (UID FLAGS ENVELOPE)", count+1);
+ camel_imapp_engine_command_queue(id->engine, ic2);
+ } else {
+ ic2 = NULL;
+ }
+
+ while (camel_imapp_engine_iterate(id->engine, ic2?ic2:ic)>0)
+ ;
+
+ camel_imapp_engine_command_free(id->engine, ic);
+ if (ic2)
+ camel_imapp_engine_command_free(id->engine, ic2);
+ } else {
+ ic = camel_imapp_engine_command_new(id->engine, "FETCH", NULL,
+ "FETCH 1:* (UID FLAGS ENVELOPE)");
+ camel_imapp_engine_command_queue(id->engine, ic);
+ while (camel_imapp_engine_iterate(id->engine, ic)>0)
+ ;
+ camel_imapp_engine_command_free(id->engine, ic);
+ }
+
+ /* TODO: need to set exists/etc in summary */
+ folder->exists = id->exists;
+ folder->uidvalidity = id->uidvalidity;
+
+ printf("saving summary '%s'\n", summary->summary_path);
+ camel_folder_summary_save(summary);
+
+ if (camel_folder_change_info_changed(id->folder->changes)) {
+ camel_object_trigger_event(id->folder, "folder_changed", id->folder->changes);
+ camel_folder_change_info_clear(id->folder->changes);
+ }
+}
+
+static void
+imapp_driver_check(CamelIMAPPDriver *id)
+{
+ guint32 count;
+ CamelIMAPPCommand *ic;
+
+ /* FIXME: exception handling */
+
+ if (id->folder->exists != id->exists) {
+ count = camel_folder_summary_count(((CamelFolder *)id->folder)->summary);
+ if (count < id->exists) {
+ printf("fetching new messages\n");
+ ic = camel_imapp_engine_command_new(id->engine, "FETCH", NULL,
+ "FETCH %u:* (UID FLAGS ENVELOPE)", count+1);
+ camel_imapp_engine_command_queue(id->engine, ic);
+ while (camel_imapp_engine_iterate(id->engine, ic)>0)
+ ;
+ camel_imapp_engine_command_free(id->engine, ic);
+ } else if (count > id->exists) {
+ printf("folder shrank with no expunge notificaitons!? uh, dunno what to do\n");
+ }
+ }
+
+ printf("checking for change info changes\n");
+ if (camel_folder_change_info_changed(id->folder->changes)) {
+ printf("got somechanges! added=%d changed=%d removed=%d\n",
+ id->folder->changes->uid_added->len,
+ id->folder->changes->uid_changed->len,
+ id->folder->changes->uid_removed->len);
+ camel_object_trigger_event(id->folder, "folder_changed", id->folder->changes);
+ camel_folder_change_info_clear(id->folder->changes);
+ }
+}
+
+void
+camel_imapp_driver_update(CamelIMAPPDriver *id, CamelIMAPPFolder *folder)
+{
+ if (id->folder == folder) {
+ CamelIMAPPCommand *ic;
+
+ /* this will automagically update flags & expunge items */
+ ic = camel_imapp_engine_command_new(id->engine, "NOOP", NULL, "NOOP");
+ camel_imapp_engine_command_queue(id->engine, ic);
+ while (camel_imapp_engine_iterate(id->engine, ic)>0)
+ ;
+ camel_imapp_engine_command_free(id->engine, ic);
+
+ imapp_driver_check(id);
+ } else {
+ camel_imapp_driver_select(id, folder);
+ }
+}
+
+/* FIXME: this is basically a copy of the same in camel-imapp-utils.c */
+static struct {
+ char *name;
+ guint32 flag;
+} flag_table[] = {
+ { "\\ANSWERED", CAMEL_MESSAGE_ANSWERED },
+ { "\\DELETED", CAMEL_MESSAGE_DELETED },
+ { "\\DRAFT", CAMEL_MESSAGE_DRAFT },
+ { "\\FLAGGED", CAMEL_MESSAGE_FLAGGED },
+ { "\\SEEN", CAMEL_MESSAGE_SEEN },
+ /* { "\\RECENT", CAMEL_IMAPP_MESSAGE_RECENT }, */
+};
+
+/*
+ flags 00101000
+ sflags 01001000
+ ^ 01100000
+~flags 11010111
+& 01000000
+
+&flags 00100000
+*/
+
+static void
+imapp_write_flags(CamelIMAPPDriver *id, guint32 orset, gboolean on, CamelFolderSummary *summary)
+{
+ guint32 i, j, count;
+ CamelIMAPPMessageInfo *info;
+ CamelIMAPPCommand *ic = NULL;
+ struct _uidset_state ss;
+ GSList *commands = NULL;
+
+ /* FIXME: exception handling */
+
+ count = camel_folder_summary_count(summary);
+ for (j=0;j<sizeof(flag_table)/sizeof(flag_table[0]);j++) {
+ int flush;
+
+ if ((orset & flag_table[j].flag) == 0)
+ continue;
+
+ printf("checking/storing %s flags '%s'\n", on?"on":"off", flag_table[j].name);
+
+ flush = 0;
+ imapp_uidset_init(&ss, id->engine);
+ for (i=0;i<count;i++) {
+ info = (CamelIMAPPMessageInfo *)camel_folder_summary_index(summary, i);
+ if (info) {
+ guint32 flags = info->info.flags & CAMEL_IMAPP_SERVER_FLAGS;
+ guint32 sflags = info->server_flags & CAMEL_IMAPP_SERVER_FLAGS;
+
+ if ( (on && (((flags ^ sflags) & flags) & flag_table[j].flag))
+ || (!on && (((flags ^ sflags) & ~flags) & flag_table[j].flag))) {
+ if (ic == NULL)
+ ic = camel_imapp_engine_command_new(id->engine, "STORE", NULL, "UID STORE ");
+ flush = imapp_uidset_add(&ss, ic, camel_message_info_uid(info));
+ }
+ camel_folder_summary_info_free(summary, (CamelMessageInfo *)info);
+ }
+
+ if (i == count-1 && ic != NULL)
+ flush |= imapp_uidset_done(&ss, ic);
+
+ if (flush) {
+ flush = 0;
+ camel_imapp_engine_command_add(id->engine, ic, " %tFLAGS.SILENT (%t)", on?"+":"-", flag_table[j].name);
+ camel_imapp_engine_command_queue(id->engine, ic);
+ commands = g_slist_prepend(commands, ic);
+ ic = NULL;
+ }
+ }
+ }
+
+ /* flush off any requests we may have outstanding */
+ /* TODO: for max benefit, should have this routine do both on and off flags in one go */
+ while (commands) {
+ GSList *next = commands->next;
+
+ ic = commands->data;
+ g_slist_free_1(commands);
+ commands = next;
+
+ while (camel_imapp_engine_iterate(id->engine, ic)>0)
+ ;
+ camel_imapp_engine_command_free(id->engine, ic);
+ }
+}
+
+void
+camel_imapp_driver_sync(CamelIMAPPDriver *id, gboolean expunge, CamelIMAPPFolder *folder)
+{
+ CamelFolderSummary *summary;
+ guint i, count, on_orset, off_orset;
+ CamelIMAPPMessageInfo *info;
+ CamelIMAPPCommand *ic;
+
+ /* FIXME: exception handling */
+
+ camel_imapp_driver_update(id, folder);
+
+ summary = ((CamelFolder *)folder)->summary;
+ count = camel_folder_summary_count(summary);
+ /* find out which flags have turned on, which have tunred off */
+ off_orset = on_orset = 0;
+ for (i=0;i<count;i++) {
+ guint32 flags, sflags;
+
+ info = (CamelIMAPPMessageInfo *)camel_folder_summary_index(summary, i);
+ if (info == NULL)
+ continue;
+ flags = info->info.flags & CAMEL_IMAPP_SERVER_FLAGS;
+ sflags = info->server_flags & CAMEL_IMAPP_SERVER_FLAGS;
+ if (flags != sflags) {
+ off_orset |= ( flags ^ sflags ) & ~flags;
+ on_orset |= (flags ^ sflags) & flags;
+ }
+ camel_folder_summary_info_free(summary, (CamelMessageInfo *)info);
+ }
+
+ if (on_orset || off_orset) {
+ /* turn on or off all messages matching */
+ if (on_orset)
+ imapp_write_flags(id, on_orset, TRUE, summary);
+ if (off_orset)
+ imapp_write_flags(id, off_orset, FALSE, summary);
+
+ /* success (no exception), make sure we match what we're supposed to */
+ for (i=0;i<count;i++) {
+ guint32 flags, sflags;
+
+ info = (CamelIMAPPMessageInfo *)camel_folder_summary_index(summary, i);
+ if (info == NULL)
+ continue;
+ info->server_flags = info->info.flags & CAMEL_IMAPP_SERVER_FLAGS;
+ camel_folder_summary_info_free(summary, (CamelMessageInfo *)info);
+ }
+ camel_folder_summary_touch(summary);
+ /* could save summary here, incase of failure? */
+ }
+
+ if (expunge) {
+ ic = camel_imapp_engine_command_new(id->engine, "EXPUNGE", NULL, "EXPUNGE");
+ camel_imapp_engine_command_queue(id->engine, ic);
+ while (camel_imapp_engine_iterate(id->engine, ic)>0)
+ ;
+ camel_imapp_engine_command_free(id->engine, ic);
+ }
+
+ printf("saving summary '%s'\n", summary->summary_path);
+ camel_folder_summary_save(summary);
+
+ if (camel_folder_change_info_changed(id->folder->changes)) {
+ camel_object_trigger_event(id->folder, "folder_changed", id->folder->changes);
+ camel_folder_change_info_clear(id->folder->changes);
+ }
+}
+
+struct _fetch_data {
+ struct _fetch_data *next;
+ struct _fetch_data *prev;
+
+ CamelStream *data;
+ const char *uid;
+ const char *section;
+};
+
+CamelStream *
+camel_imapp_driver_fetch(CamelIMAPPDriver *id, CamelIMAPPFolder *folder, const char *uid, const char *section)
+{
+ struct _fetch_data fd;
+ CamelIMAPPCommand *ic;
+
+ fd.data = NULL;
+ fd.uid = uid;
+ fd.section = section;
+ e_dlist_addtail(&id->body_fetch, (EDListNode *)&fd);
+
+ CAMEL_TRY {
+ camel_imapp_driver_select(id, folder);
+
+ ic = camel_imapp_engine_command_new(id->engine, "FETCH", NULL, "UID FETCH %t (BODY.PEEK[%t])", uid, section);
+ camel_imapp_engine_command_queue(id->engine, ic);
+ while (camel_imapp_engine_iterate(id->engine, ic)>0)
+ ;
+ camel_imapp_engine_command_free(id->engine, ic);
+ imapp_driver_check(id);
+ } CAMEL_CATCH(e) {
+ /* FIXME: do exception properly */
+ } CAMEL_DONE;
+
+ e_dlist_remove((EDListNode *)&fd);
+
+ return fd.data;
+}
+
+GPtrArray *
+camel_imapp_driver_list(CamelIMAPPDriver *id, const char *name, guint32 flags)
+{
+ CamelIMAPPCommand *ic;
+ GPtrArray *res;
+
+ g_assert(id->list_commands == NULL);
+ g_assert(id->list_result == NULL);
+
+ /* FIXME: make sure we only have a single list running at a time */
+ /* sem_wait(id->list_sem); */
+
+ /* FIXME: namespace stuff (done in store code?) */
+
+ /* FIXME: if name != "", we need to also do list "name.%" (. == sep) */
+
+ id->list_result = g_ptr_array_new();
+ id->list_flags = flags;
+ ic = camel_imapp_engine_command_new(id->engine, "LIST", NULL, "LIST \"\" %f", name[0]?name:"%");
+ camel_imapp_engine_command_queue(id->engine, ic);
+ while (ic) {
+ while (camel_imapp_engine_iterate(id->engine, ic)>0)
+ ;
+ camel_imapp_engine_command_free(id->engine, ic);
+
+ if (id->list_commands) {
+ GSList *top = id->list_commands;
+
+ id->list_commands = top->next;
+ ic = top->data;
+ g_slist_free_1(top);
+ } else {
+ ic = NULL;
+ }
+ }
+
+ res = id->list_result;
+ id->list_result = NULL;
+
+ /* sem_post(id->list_sem); */
+
+ return res;
+}
+
+static int
+driver_resp_list(CamelIMAPPEngine *ie, guint32 idx, CamelIMAPPDriver *id)
+{
+ struct _list_info *linfo;
+
+ /* FIXME: exceptions */
+
+ linfo = imap_parse_list(ie->stream);
+ printf("store list: '%s' ('%c')\n", linfo->name, linfo->separator);
+ if (id->list_result) {
+ if ((linfo->flags & CAMEL_FOLDER_NOINFERIORS) == 0
+ && (id->list_flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE)
+ && linfo->separator) {
+ int depth = 0;
+ char *p = linfo->name;
+ char c = linfo->separator;
+
+ /* this is expensive ... but if we've listed this deep we're going slow anyway */
+ while (*p && depth < 10) {
+ if (*p == c)
+ depth++;
+ p++;
+ }
+
+ if (depth < 10
+ && (linfo->name[0] == 0 || linfo->name[strlen(linfo->name)-1] != c)) {
+ CamelIMAPPCommand *ic;
+
+ ic = camel_imapp_engine_command_new(id->engine, "LIST", NULL, "LIST \"\" %t%c%%", linfo->name, c);
+ id->list_commands = g_slist_prepend(id->list_commands, ic);
+ camel_imapp_engine_command_queue(id->engine, ic);
+ }
+ }
+ /* FIXME: dont add to list if name ends in separator */
+ g_ptr_array_add(id->list_result, linfo);
+ } else {
+ g_warning("unexpected list response\n");
+ imap_free_list(linfo);
+ }
+
+ return camel_imapp_engine_skip(ie);
+}
+
+/* ********************************************************************** */
+
+static void
+driver_status(CamelIMAPPEngine *ie, struct _status_info *sinfo, CamelIMAPPDriver *sdata)
+{
+ printf("got status response ...\n");
+ switch(sinfo->condition) {
+ case IMAP_READ_WRITE:
+ printf("folder is read-write\n");
+ break;
+ case IMAP_READ_ONLY:
+ printf("folder is read-only\n");
+ break;
+ case IMAP_UIDVALIDITY:
+ sdata->uidvalidity = sinfo->u.uidvalidity;
+ break;
+#if 0
+ /* not defined yet ... */
+ case IMAP_UIDNEXT:
+ printf("got uidnext for folder: %d\n", sinfo->u.uidnext);
+ break;
+#endif
+ case IMAP_UNSEEN:
+ sdata->unseen = sinfo->u.unseen;
+ break;
+ case IMAP_PERMANENTFLAGS:
+ sdata->permanentflags = sinfo->u.permanentflags;
+ break;
+ case IMAP_ALERT:
+ printf("ALERT!: %s\n", sinfo->text);
+ break;
+ case IMAP_PARSE:
+ printf("PARSE: %s\n", sinfo->text);
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+driver_resp_exists(CamelIMAPPEngine *ie, guint32 id, CamelIMAPPDriver *sdata)
+{
+ /* should this be an event instead? */
+
+ sdata->exists = id;
+
+ return camel_imapp_engine_skip(ie);
+}
+
+static int
+driver_resp_expunge(CamelIMAPPEngine *ie, guint32 id, CamelIMAPPDriver *sdata)
+{
+ printf("got expunge response %u\n", id);
+ if (sdata->folder != NULL) {
+ CamelMessageInfo *info;
+ CamelFolderSummary *summary = ((CamelFolder *)sdata->folder)->summary;
+
+ info = camel_folder_summary_index(summary, id-1);
+ if (info) {
+ printf("expunging msg %d\n", id);
+ camel_folder_summary_remove(summary, info);
+ camel_folder_summary_info_free(summary, info);
+ camel_folder_change_info_remove_uid(sdata->folder->changes, camel_message_info_uid(info));
+ } else {
+ printf("can not find msg %u from expunge\n", id);
+ }
+ }
+
+ return camel_imapp_engine_skip(ie);
+}
+
+static int
+driver_resp_fetch(CamelIMAPPEngine *ie, guint32 id, CamelIMAPPDriver *sdata)
+{
+ struct _fetch_info *finfo = NULL;
+ CamelMessageInfo *info, *uinfo;
+ unsigned int i;
+ CamelFolderSummary *summary;
+
+ printf("got fetch response %d\n", id);
+
+ if (sdata->folder == NULL)
+ goto done;
+
+ summary = ((CamelFolder *)sdata->folder)->summary;
+
+ finfo = imap_parse_fetch(ie->stream);
+ imap_dump_fetch(finfo);
+
+ info = camel_folder_summary_index(summary, id-1);
+ if (info == NULL) {
+ if (finfo->uid == NULL) {
+ printf("got fetch response for currently unknown message %u\n", id);
+ goto done;
+ }
+ uinfo = camel_folder_summary_uid(summary, finfo->uid);
+ if (uinfo) {
+ /* we have a problem ... index mismatch */
+ printf("index mismatch, uid '%s' not at index '%u'\n",
+ finfo->uid, id);
+ camel_folder_summary_info_free(summary, uinfo);
+ }
+ /* pad out the summary till we have enough indexes */
+ for (i=camel_folder_summary_count(summary);i<id;i++) {
+ info = camel_folder_summary_info_new(summary);
+ if (i == id-1) {
+ printf("inserting new info @ %u\n", i);
+ camel_message_info_set_uid(info, g_strdup(finfo->uid));
+ } else {
+ char uidtmp[32];
+
+ sprintf(uidtmp, "blank-%u", i);
+ camel_message_info_set_uid(info, g_strdup(uidtmp));
+ printf("inserting empty uid %s\n", uidtmp);
+ }
+
+ camel_folder_summary_add(summary, info);
+ }
+ info = camel_folder_summary_index(summary, id-1);
+ g_assert(info != NULL);
+ } else {
+ if (finfo->uid) {
+ /* FIXME: need to handle blank-* uids, somehow */
+ while (info && strcmp(camel_message_info_uid(info), finfo->uid) != 0) {
+ printf("index mismatch, uid '%s' not at index '%u', got '%s' instead (removing)\n",
+ finfo->uid, id, camel_message_info_uid(info));
+
+ camel_folder_change_info_remove_uid(sdata->folder->changes, camel_message_info_uid(info));
+ camel_folder_summary_remove(summary, info);
+ camel_folder_summary_info_free(summary, info);
+ info = camel_folder_summary_index(summary, id-1);
+ }
+ } else {
+ printf("got info for unknown message %u\n", id);
+ }
+ }
+
+ if (info) {
+ if (finfo->got & FETCH_MINFO) {
+ /* if we only use ENVELOPE? */
+ camel_message_info_set_subject(info, g_strdup(camel_message_info_subject(finfo->minfo)));
+ camel_message_info_set_from(info, g_strdup(camel_message_info_from(finfo->minfo)));
+ camel_message_info_set_to(info, g_strdup(camel_message_info_to(finfo->minfo)));
+ camel_message_info_set_cc(info, g_strdup(camel_message_info_cc(finfo->minfo)));
+ info->date_sent = finfo->minfo->date_sent;
+ camel_folder_change_info_add_uid(sdata->folder->changes, camel_message_info_uid(info));
+ printf("adding change info uid '%s'\n", camel_message_info_uid(info));
+ }
+
+ if (finfo->got & FETCH_FLAGS) {
+ if ((info->flags & CAMEL_IMAPP_SERVER_FLAGS) != (finfo->flags & CAMEL_IMAPP_SERVER_FLAGS)) {
+ camel_folder_change_info_change_uid(sdata->folder->changes, camel_message_info_uid(info));
+ info->flags = (info->flags & ~(CAMEL_IMAPP_SERVER_FLAGS)) | (finfo->flags & CAMEL_IMAPP_SERVER_FLAGS);
+ camel_folder_summary_touch(summary);
+ }
+ ((CamelIMAPPMessageInfo *)info)->server_flags = finfo->flags & CAMEL_IMAPP_SERVER_FLAGS;
+ }
+
+ if ((finfo->got & (FETCH_BODY|FETCH_UID)) == (FETCH_BODY|FETCH_UID)) {
+ struct _fetch_data *fd, *fn;
+
+ fd = (struct _fetch_data *)sdata->body_fetch.head;
+ fn = fd->next;
+ while (fn) {
+ if (!strcmp(finfo->uid, fd->uid) && !strcmp(finfo->section, fd->section)) {
+ if (fd->data)
+ camel_object_unref(fd->data);
+ fd->data = finfo->body;
+ camel_object_ref(fd->data);
+ e_dlist_remove((EDListNode *)fd);
+ e_dlist_addtail(&sdata->body_fetch_done, (EDListNode *)fd);
+ break;
+ }
+ fd = fn;
+ fn = fn->next;
+ }
+ }
+
+ camel_folder_summary_info_free(summary, info);
+ } else {
+ printf("dont know what to do with message\n");
+ }
+ done:
+ imap_free_fetch(finfo);
+
+ return camel_imapp_engine_skip(ie);
+}