[evolution-patches] The POP3 provider as a CamelDisco*
- From: Philip Van Hoof <spam pvanhoof be>
- To: evolution-patches gnome org
- Subject: [evolution-patches] The POP3 provider as a CamelDisco*
- Date: Mon, 18 Jun 2007 23:30:25 +0300
As per request, the diff that could make the POP3 code of Evolution a
CamelDisco*.
--
Philip Van Hoof, software developer
home: me at pvanhoof dot be
gnome: pvanhoof at gnome dot org
http://www.pvanhoof.be/blog
Index: camel-pop3-folder.h
===================================================================
--- camel-pop3-folder.h (revision 7816)
+++ camel-pop3-folder.h (working copy)
@@ -26,7 +26,8 @@
#ifndef CAMEL_POP3_FOLDER_H
#define CAMEL_POP3_FOLDER_H 1
-#include "camel-folder.h"
+#include <camel/camel-folder.h>
+#include <camel/camel-disco-folder.h>
#define CAMEL_POP3_FOLDER_TYPE (camel_pop3_folder_get_type ())
#define CAMEL_POP3_FOLDER(obj) (CAMEL_CHECK_CAST((obj), CAMEL_POP3_FOLDER_TYPE, CamelPOP3Folder))
@@ -47,7 +48,7 @@
} CamelPOP3FolderInfo;
typedef struct {
- CamelFolder parent_object;
+ CamelDiscoFolder parent_object;
GPtrArray *uids;
GHashTable *uids_uid; /* messageinfo by uid */
@@ -55,7 +56,7 @@
} CamelPOP3Folder;
typedef struct {
- CamelFolderClass parent_class;
+ CamelDiscoFolderClass parent_class;
/* Virtual methods */
Index: camel-pop3-stream.h
===================================================================
--- camel-pop3-stream.h (revision 7816)
+++ camel-pop3-stream.h (working copy)
@@ -26,6 +26,13 @@
#include <camel/camel-stream.h>
+#ifdef DEBUG
+#define pop3_debug g_print
+#else
+#define pop3_debug(o,...)
+#endif
+
+
#define CAMEL_POP3_STREAM(obj) CAMEL_CHECK_CAST (obj, camel_pop3_stream_get_type (), CamelPOP3Stream)
#define CAMEL_POP3_STREAM_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_pop3_stream_get_type (), CamelPOP3StreamClass)
#define CAMEL_IS_POP3_STREAM(obj) CAMEL_CHECK_TYPE (obj, camel_pop3_stream_get_type ())
Index: camel-pop3-store.h
===================================================================
--- camel-pop3-store.h (revision 7816)
+++ camel-pop3-store.h (working copy)
@@ -30,6 +30,7 @@
#include <camel/camel-types.h>
#include <camel/camel-store.h>
#include "camel-pop3-engine.h"
+#include <camel/camel-disco-store.h>
#define CAMEL_POP3_STORE_TYPE (camel_pop3_store_get_type ())
#define CAMEL_POP3_STORE(obj) (CAMEL_CHECK_CAST((obj), CAMEL_POP3_STORE_TYPE, CamelPOP3Store))
@@ -39,25 +40,27 @@
G_BEGIN_DECLS
typedef struct {
- CamelStore parent_object;
+ CamelDiscoStore parent_object;
CamelPOP3Engine *engine; /* pop processing engine */
struct _CamelDataCache *cache;
-
guint delete_after;
+ gboolean immediate_delete_after;
+ gchar *storage_path, *base_url;
+ gboolean connected;
+ GStaticRecMutex *eng_lock;
+
} CamelPOP3Store;
typedef struct {
- CamelStoreClass parent_class;
+ CamelDiscoStoreClass parent_class;
} CamelPOP3StoreClass;
-/* public methods */
-void camel_pop3_store_expunge (CamelPOP3Store *store, CamelException *ex);
/* support functions */
enum { CAMEL_POP3_OK, CAMEL_POP3_ERR, CAMEL_POP3_FAIL };
Index: camel-pop3-engine.c
===================================================================
--- camel-pop3-engine.c (revision 7816)
+++ camel-pop3-engine.c (working copy)
@@ -60,6 +60,9 @@
static void
camel_pop3_engine_init(CamelPOP3Engine *pe, CamelPOP3EngineClass *peclass)
{
+ pe->lock = g_new0 (GStaticRecMutex, 1);
+ g_static_rec_mutex_init (pe->lock);
+
e_dlist_init(&pe->active);
e_dlist_init(&pe->queue);
e_dlist_init(&pe->done);
@@ -71,12 +74,19 @@
{
/* FIXME: Also flush/free any outstanding requests, etc */
+ g_static_rec_mutex_lock (pe->lock);
+
if (pe->stream)
camel_object_unref(pe->stream);
g_list_free(pe->auth);
if (pe->apop)
g_free(pe->apop);
+
+ g_static_rec_mutex_unlock (pe->lock);
+
+ g_static_rec_mutex_free (pe->lock);
+ pe->lock = NULL;
}
CamelType
@@ -105,22 +115,29 @@
extern CamelServiceAuthType camel_pop3_apop_authtype;
unsigned char *line, *apop, *apopend;
unsigned int len;
-
+
+
+ g_static_rec_mutex_lock (pe->lock);
+
/* first, read the greeting */
if (camel_pop3_stream_line (pe->stream, &line, &len) == -1
- || strncmp (line, "+OK", 3) != 0)
+ || strncmp ((char *) line, "+OK", 3) != 0) {
+ g_static_rec_mutex_unlock (pe->lock);
return -1;
-
- if ((apop = strchr (line + 3, '<'))
- && (apopend = strchr (apop, '>'))) {
+ }
+
+ if ((apop = (unsigned char *) strchr ((char *) line + 3, '<'))
+ && (apopend = (unsigned char *) strchr ((char *) apop, '>'))) {
apopend[1] = 0;
- pe->apop = g_strdup (apop);
+ pe->apop = g_strdup ((gchar *) apop);
pe->capa = CAMEL_POP3_CAP_APOP;
pe->auth = g_list_append (pe->auth, &camel_pop3_apop_authtype);
}
pe->auth = g_list_prepend (pe->auth, &camel_pop3_password_authtype);
-
+
+ g_static_rec_mutex_unlock (pe->lock);
+
return 0;
}
@@ -141,17 +158,21 @@
pe = (CamelPOP3Engine *)camel_object_new(camel_pop3_engine_get_type ());
+ g_static_rec_mutex_lock (pe->lock);
+
pe->stream = (CamelPOP3Stream *)camel_pop3_stream_new(source);
pe->state = CAMEL_POP3_ENGINE_AUTH;
pe->flags = flags;
if (read_greeting (pe) == -1) {
+ g_static_rec_mutex_unlock (pe->lock);
camel_object_unref (pe);
return NULL;
}
-
+
get_capabilities (pe);
-
+ g_static_rec_mutex_unlock (pe->lock);
+
return pe;
}
@@ -166,8 +187,10 @@
camel_pop3_engine_reget_capabilities (CamelPOP3Engine *engine)
{
g_return_if_fail (CAMEL_IS_POP3_ENGINE (engine));
-
+
+ g_static_rec_mutex_lock (engine->lock);
get_capabilities (engine);
+ g_static_rec_mutex_unlock (engine->lock);
}
@@ -193,19 +216,21 @@
int i;
CamelServiceAuthType *auth;
+ g_static_rec_mutex_lock (pe->lock);
+
dd(printf("cmd_capa\n"));
do {
ret = camel_pop3_stream_line(stream, &line, &len);
if (ret >= 0) {
- if (strncmp(line, "SASL ", 5) == 0) {
+ if (strncmp((char *) line, "SASL ", 5) == 0) {
tok = line+5;
dd(printf("scanning tokens '%s'\n", tok));
while (tok) {
- next = strchr(tok, ' ');
+ next = (unsigned char *) strchr((char *) tok, ' ');
if (next)
*next++ = 0;
- auth = camel_sasl_authtype(tok);
+ auth = camel_sasl_authtype((const char *) tok);
if (auth) {
dd(printf("got auth type '%s'\n", tok));
pe->auth = g_list_prepend(pe->auth, auth);
@@ -216,19 +241,23 @@
}
} else {
for (i=0;i<sizeof(capa)/sizeof(capa[0]);i++) {
- if (strcmp(capa[i].cap, line) == 0)
+ if (strcmp((char *) capa[i].cap, (char *) line) == 0)
pe->capa |= capa[i].flag;
}
}
}
} while (ret>0);
+
+ g_static_rec_mutex_unlock (pe->lock);
}
static void
get_capabilities(CamelPOP3Engine *pe)
{
CamelPOP3Command *pc;
-
+
+ g_static_rec_mutex_lock (pe->lock);
+
if (!(pe->flags & CAMEL_POP3_ENGINE_DISABLE_EXTENSIONS)) {
pc = camel_pop3_engine_command_new(pe, CAMEL_POP3_COMMAND_MULTI, cmd_capa, NULL, "CAPA\r\n");
while (camel_pop3_engine_iterate(pe, pc) > 0)
@@ -247,34 +276,46 @@
camel_pop3_engine_command_free (pe, pc);
}
}
+
+ g_static_rec_mutex_unlock (pe->lock);
+
}
/* returns true if the command was sent, false if it was just queued */
static int
engine_command_queue(CamelPOP3Engine *pe, CamelPOP3Command *pc)
{
+
+ g_static_rec_mutex_lock (pe->lock);
+
if (((pe->capa & CAMEL_POP3_CAP_PIPE) == 0 || (pe->sentlen + strlen(pc->data)) > CAMEL_POP3_SEND_LIMIT)
&& pe->current != NULL) {
e_dlist_addtail(&pe->queue, (EDListNode *)pc);
+ g_static_rec_mutex_unlock (pe->lock);
return FALSE;
- } else {
- /* ??? */
- if (camel_stream_write((CamelStream *)pe->stream, pc->data, strlen(pc->data)) == -1) {
- e_dlist_addtail(&pe->queue, (EDListNode *)pc);
- return FALSE;
- }
+ }
- pe->sentlen += strlen(pc->data);
+ /* TNY TODO: Check online status here, else it will crash
+ Correction, it will not crash but will emit a SIGPIPE */
- pc->state = CAMEL_POP3_COMMAND_DISPATCHED;
+ if (camel_stream_write((CamelStream *)pe->stream, pc->data, strlen(pc->data)) == -1) {
+ e_dlist_addtail(&pe->queue, (EDListNode *)pc);
+ g_static_rec_mutex_unlock (pe->lock);
+ return FALSE;
+ }
- if (pe->current == NULL)
- pe->current = pc;
- else
- e_dlist_addtail(&pe->active, (EDListNode *)pc);
+ pe->sentlen += strlen(pc->data);
- return TRUE;
- }
+ pc->state = CAMEL_POP3_COMMAND_DISPATCHED;
+
+ if (pe->current == NULL)
+ pe->current = pc;
+ else
+ e_dlist_addtail(&pe->active, (EDListNode *)pc);
+
+ g_static_rec_mutex_unlock (pe->lock);
+
+ return TRUE;
}
/* returns -1 on error (sets errno), 0 when no work to do, or >0 if work remaining */
@@ -285,15 +326,19 @@
unsigned int len;
CamelPOP3Command *pc, *pw, *pn;
- if (pcwait && pcwait->state >= CAMEL_POP3_COMMAND_OK)
+ g_static_rec_mutex_lock (pe->lock);
+
+ if (pcwait && pcwait->state >= CAMEL_POP3_COMMAND_OK) {
+ g_static_rec_mutex_unlock (pe->lock);
return 0;
+ }
pc = pe->current;
- if (pc == NULL)
+ if (pc == NULL) {
+ g_static_rec_mutex_unlock (pe->lock);
return 0;
+ }
- /* LOCK */
-
if (camel_pop3_stream_line(pe->stream, &pe->line, &pe->linelen) == -1)
goto ioerror;
@@ -309,9 +354,14 @@
pc->func(pe, pe->stream, pc->func_data);
/* Make sure we get all data before going back to command mode */
- while (camel_pop3_stream_getd(pe->stream, &p, &len) > 0)
- ;
- camel_pop3_stream_set_mode(pe->stream, CAMEL_POP3_STREAM_LINE);
+ if (!pe->partial_happening)
+ while (camel_pop3_stream_getd(pe->stream, &p, &len) > 0)
+ ;
+
+ if (!pe->partial_happening)
+ camel_pop3_stream_set_mode(pe->stream, CAMEL_POP3_STREAM_LINE);
+
+ pe->partial_happening = FALSE;
} else {
pc->state = CAMEL_POP3_COMMAND_OK;
}
@@ -326,16 +376,25 @@
break;
}
- e_dlist_addtail(&pe->done, (EDListNode *)pc);
- pe->sentlen -= strlen(pc->data);
+ if (pc)
+ e_dlist_addtail(&pe->done, (EDListNode *)pc);
+ else
+ g_warning ("Unexpected, pc == NULL");
+ if (pc && pc->data)
+ pe->sentlen -= strlen(pc->data);
+ else
+ g_warning ("Unexpected, pc == NULL");
+
/* Set next command */
pe->current = (CamelPOP3Command *)e_dlist_remhead(&pe->active);
/* check the queue for sending any we can now send also */
pw = (CamelPOP3Command *)pe->queue.head;
pn = pw->next;
- while (pn) {
+
+ while (pn)
+ {
if (((pe->capa & CAMEL_POP3_CAP_PIPE) == 0 || (pe->sentlen + strlen(pw->data)) > CAMEL_POP3_SEND_LIMIT)
&& pe->current != NULL)
break;
@@ -357,12 +416,14 @@
pn = pn->next;
}
- /* UNLOCK */
-
- if (pcwait && pcwait->state >= CAMEL_POP3_COMMAND_OK)
+ if (pcwait && pcwait->state >= CAMEL_POP3_COMMAND_OK) {
+ g_static_rec_mutex_unlock (pe->lock);
return 0;
+ }
+ g_static_rec_mutex_unlock (pe->lock);
return pe->current==NULL?0:1;
+
ioerror:
/* we assume all outstanding commands are gunna fail now */
while ( (pw = (CamelPOP3Command*)e_dlist_remhead(&pe->active)) ) {
@@ -381,6 +442,7 @@
pe->current = NULL;
}
+ g_static_rec_mutex_unlock (pe->lock);
return -1;
}
@@ -408,8 +470,10 @@
void
camel_pop3_engine_command_free(CamelPOP3Engine *pe, CamelPOP3Command *pc)
{
+ g_static_rec_mutex_lock (pe->lock);
if (pe->current != pc)
e_dlist_remove((EDListNode *)pc);
- g_free(pc->data);
+ g_free(pc->data); pc->data = NULL;
g_free(pc);
+ g_static_rec_mutex_unlock (pe->lock);
}
Index: camel-pop3-engine.h
===================================================================
--- camel-pop3-engine.h (revision 7816)
+++ camel-pop3-engine.h (working copy)
@@ -115,6 +115,10 @@
EDList done; /* list of done commands, awaiting free */
CamelPOP3Command *current; /* currently busy (downloading) response */
+ void *store; gboolean partial_happening;
+ gint type; gint param;
+
+ GStaticRecMutex *lock;
};
struct _CamelPOP3EngineClass {
Index: camel-pop3-folder.c
===================================================================
--- camel-pop3-folder.c (revision 7816)
+++ camel-pop3-folder.c (working copy)
@@ -5,7 +5,13 @@
* Authors:
* Dan Winship <danw ximian com>
* Michael Zucchi <notzed ximian com>
+ * Philip Van Hoof <pvanhoof gnome org>
*
+ * This is CamelPop3Store for camel-lite that implements CamelDiscoFolder and
+ * has support for CamelFolderSummary. Its implementation is significantly
+ * different from Camel's upstream version (being used by Evolution): this
+ * version supports offline and online modes.
+ *
* Copyright (C) 2002 Ximian, Inc. (www.ximian.com)
*
* This program is free software; you can redistribute it and/or
@@ -27,6 +33,10 @@
#include <config.h>
#endif
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
#include <errno.h>
#include <stdlib.h>
#include <string.h>
@@ -39,70 +49,41 @@
#include "camel-exception.h"
#include "camel-mime-message.h"
#include "camel-operation.h"
+
#include "camel-pop3-folder.h"
#include "camel-pop3-store.h"
#include "camel-stream-filter.h"
+#include "camel-pop3-stream.h"
#include "camel-stream-mem.h"
+#include "camel-disco-diary.h"
+
#define d(x)
#define CF_CLASS(o) (CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(o)))
static CamelFolderClass *parent_class;
+static CamelDiscoFolderClass *disco_folder_class = NULL;
static void pop3_finalize (CamelObject *object);
static void pop3_refresh_info (CamelFolder *folder, CamelException *ex);
static void pop3_sync (CamelFolder *folder, gboolean expunge, CamelException *ex);
static gint pop3_get_message_count (CamelFolder *folder);
static GPtrArray *pop3_get_uids (CamelFolder *folder);
-static CamelMimeMessage *pop3_get_message (CamelFolder *folder, const char *uid, CamelException *ex);
+static CamelMimeMessage *pop3_get_message (CamelFolder *folder, const char *uid, CamelFolderReceiveType type, gint param, CamelException *ex);
static gboolean pop3_set_message_flags (CamelFolder *folder, const char *uid, guint32 flags, guint32 set);
+static CamelMimeMessage *pop3_get_top (CamelFolder *folder, const char *uid, CamelException *ex);
-static void
-camel_pop3_folder_class_init (CamelPOP3FolderClass *camel_pop3_folder_class)
-{
- CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS(camel_pop3_folder_class);
-
- parent_class = CAMEL_FOLDER_CLASS(camel_folder_get_type());
-
- /* virtual method overload */
- camel_folder_class->refresh_info = pop3_refresh_info;
- camel_folder_class->sync = pop3_sync;
-
- camel_folder_class->get_message_count = pop3_get_message_count;
- camel_folder_class->get_uids = pop3_get_uids;
- camel_folder_class->free_uids = camel_folder_free_shallow;
-
- camel_folder_class->get_message = pop3_get_message;
- camel_folder_class->set_message_flags = pop3_set_message_flags;
-}
-CamelType
-camel_pop3_folder_get_type (void)
+static void
+destroy_lists (CamelPOP3Folder *pop3_folder)
{
- static CamelType camel_pop3_folder_type = CAMEL_INVALID_TYPE;
-
- if (!camel_pop3_folder_type) {
- camel_pop3_folder_type = camel_type_register (CAMEL_FOLDER_TYPE, "CamelPOP3Folder",
- sizeof (CamelPOP3Folder),
- sizeof (CamelPOP3FolderClass),
- (CamelObjectClassInitFunc) camel_pop3_folder_class_init,
- NULL,
- NULL,
- (CamelObjectFinalizeFunc) pop3_finalize);
- }
-
- return camel_pop3_folder_type;
-}
-static void
-pop3_finalize (CamelObject *object)
-{
- CamelPOP3Folder *pop3_folder = CAMEL_POP3_FOLDER (object);
- CamelPOP3FolderInfo **fi = (CamelPOP3FolderInfo **)pop3_folder->uids->pdata;
- CamelPOP3Store *pop3_store = (CamelPOP3Store *)((CamelFolder *)pop3_folder)->parent_store;
- int i;
+ if (pop3_folder->uids != NULL)
+ {
+ CamelPOP3FolderInfo **fi = (CamelPOP3FolderInfo **)pop3_folder->uids->pdata;
+ CamelPOP3Store *pop3_store = (CamelPOP3Store *)((CamelFolder *)pop3_folder)->parent_store;
+ int i;
- if (pop3_folder->uids) {
for (i=0;i<pop3_folder->uids->len;i++,fi++) {
if (fi[0]->cmd) {
while (camel_pop3_engine_iterate(pop3_store->engine, fi[0]->cmd) > 0)
@@ -119,23 +100,70 @@
}
}
+static void
+pop3_finalize (CamelObject *object)
+{
+ CamelPOP3Folder *pop3_folder = CAMEL_POP3_FOLDER (object);
+
+ destroy_lists (pop3_folder);
+
+}
+
+static void
+camel_pop3_summary_set_extra_flags (CamelFolder *folder, CamelMessageInfoBase *mi)
+{
+ CamelPOP3Store *pop3_store = (CamelPOP3Store *)folder->parent_store;
+ camel_data_cache_set_flags (pop3_store->cache, "cache", mi);
+}
+
CamelFolder *
camel_pop3_folder_new (CamelStore *parent, CamelException *ex)
{
CamelFolder *folder;
+ CamelPOP3Store *p3store = (CamelPOP3Store*) parent;
+ gchar *summary_file;
+ CamelPOP3Folder *pop3_folder;
d(printf("opening pop3 INBOX folder\n"));
folder = CAMEL_FOLDER (camel_object_new (CAMEL_POP3_FOLDER_TYPE));
+ pop3_folder = CAMEL_POP3_FOLDER (folder);
+ pop3_folder->uids = NULL;
+
camel_folder_construct (folder, parent, "inbox", "inbox");
-
+
+ summary_file = g_strdup_printf ("%s/summary.mmap", p3store->storage_path);
+ folder->summary = camel_folder_summary_new (folder);
+ folder->summary->set_extra_flags_func = camel_pop3_summary_set_extra_flags;
+ camel_folder_summary_set_build_content (folder->summary, TRUE);
+ camel_folder_summary_set_filename (folder->summary, summary_file);
+
+ if (camel_folder_summary_load (folder->summary) == -1) {
+ camel_folder_summary_clear (folder->summary);
+ camel_folder_summary_touch (folder->summary);
+ camel_folder_summary_save (folder->summary);
+ camel_folder_summary_load (folder->summary);
+ }
+
+ g_free (summary_file);
+
+
/* mt-ok, since we dont have the folder-lock for new() */
- camel_folder_refresh_info (folder, ex);/* mt-ok */
+ /* camel_folder_refresh_info (folder, ex);
if (camel_exception_is_set (ex)) {
camel_object_unref (CAMEL_OBJECT (folder));
folder = NULL;
+ }*/
+
+ if (!folder->summary) {
+ camel_object_unref (CAMEL_OBJECT (folder));
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not load summary for INBOX"));
+ return NULL;
}
+ folder->folder_flags |= CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY;
+
return folder;
}
@@ -164,8 +192,8 @@
while (h) {
if (g_ascii_strcasecmp(h->name, "status") != 0
&& g_ascii_strcasecmp(h->name, "x-status") != 0) {
- md5_update(&md5, h->name, strlen(h->name));
- md5_update(&md5, h->value, strlen(h->value));
+ md5_update(&md5, (const guchar*) h->name, strlen(h->name));
+ md5_update(&md5, (const guchar*) h->value, strlen(h->value));
}
h = h->next;
}
@@ -174,7 +202,7 @@
}
camel_object_unref(mp);
md5_final(&md5, digest);
- fi->uid = camel_base64_encode_simple(digest, 16);
+ fi->uid = camel_base64_encode_simple((const char*) digest, 16);
d(printf("building uid for id '%d' = '%s'\n", fi->id, fi->uid));
}
@@ -192,12 +220,12 @@
do {
ret = camel_pop3_stream_line(stream, &line, &len);
if (ret>=0) {
- if (sscanf(line, "%u %u", &id, &size) == 2) {
- fi = g_malloc0(sizeof(*fi));
+ if (sscanf((char *) line, "%u %u", &id, &size) == 2) {
+ fi = g_malloc0 (sizeof(*fi));
fi->size = size;
fi->id = id;
fi->index = ((CamelPOP3Folder *)folder)->uids->len;
- if ((pop3_store->engine->capa & CAMEL_POP3_CAP_UIDL) == 0)
+ if ((pop3_store->engine && pop3_store->engine->capa & CAMEL_POP3_CAP_UIDL) == 0)
fi->cmd = camel_pop3_engine_command_new(pe, CAMEL_POP3_COMMAND_MULTI, cmd_builduid, fi, "TOP %u 0\r\n", id);
g_ptr_array_add(((CamelPOP3Folder *)folder)->uids, fi);
g_hash_table_insert(((CamelPOP3Folder *)folder)->uids_id, GINT_TO_POINTER(id), fi);
@@ -220,12 +248,12 @@
do {
ret = camel_pop3_stream_line(stream, &line, &len);
if (ret>=0) {
- if (strlen(line) > 1024)
+ if (strlen((char*) line) > 1024)
line[1024] = 0;
- if (sscanf(line, "%u %s", &id, uid) == 2) {
+ if (sscanf((char *) line, "%u %s", &id, uid) == 2) {
fi = g_hash_table_lookup(folder->uids_id, GINT_TO_POINTER(id));
if (fi) {
- camel_operation_progress(NULL, (fi->index+1) * 100 / folder->uids->len);
+ camel_operation_progress(NULL, (fi->index+1) , folder->uids->len);
fi->uid = g_strdup(uid);
g_hash_table_insert(folder->uids_uid, fi->uid, fi);
} else {
@@ -242,23 +270,35 @@
CamelPOP3Store *pop3_store = CAMEL_POP3_STORE (folder->parent_store);
CamelPOP3Folder *pop3_folder = (CamelPOP3Folder *) folder;
CamelPOP3Command *pcl, *pcu = NULL;
- int i;
+ int i, hcnt = 0;
- camel_operation_start (NULL, _("Retrieving POP summary"));
+ if (camel_disco_store_status (CAMEL_DISCO_STORE (pop3_store)) == CAMEL_DISCO_STORE_OFFLINE)
+ return;
+ g_static_rec_mutex_lock (pop3_store->eng_lock);
+ if (pop3_store->engine == NULL)
+ {
+ g_static_rec_mutex_unlock (pop3_store->eng_lock);
+ return;
+ }
+
+ destroy_lists (pop3_folder);
+
pop3_folder->uids = g_ptr_array_new ();
pop3_folder->uids_uid = g_hash_table_new(g_str_hash, g_str_equal);
/* only used during setup */
pop3_folder->uids_id = g_hash_table_new(NULL, NULL);
+ camel_operation_start (NULL, _("Fetching summary information for new messages in folder"));
+
+
pcl = camel_pop3_engine_command_new(pop3_store->engine, CAMEL_POP3_COMMAND_MULTI, cmd_list, folder, "LIST\r\n");
- if (pop3_store->engine->capa & CAMEL_POP3_CAP_UIDL) {
+ if (pop3_store->engine->capa & CAMEL_POP3_CAP_UIDL)
pcu = camel_pop3_engine_command_new(pop3_store->engine, CAMEL_POP3_COMMAND_MULTI, cmd_uidl, folder, "UIDL\r\n");
- }
- while ((i = camel_pop3_engine_iterate(pop3_store->engine, NULL)) > 0)
- ;
+ while ((i = camel_pop3_engine_iterate(pop3_store->engine, NULL)) > 0);
- if (i == -1) {
+ if (i == -1)
+ {
if (errno == EINTR)
camel_exception_setv(ex, CAMEL_EXCEPTION_USER_CANCEL, _("User canceled"));
else
@@ -270,12 +310,76 @@
/* TODO: check every id has a uid & commands returned OK too? */
camel_pop3_engine_command_free(pop3_store->engine, pcl);
-
+
+ /* Update the summary.mmap file */
+
+ camel_folder_summary_prepare_hash (folder->summary);
+
+ for (i=0;i<pop3_folder->uids->len;i++)
+ {
+ CamelPOP3FolderInfo *fi = pop3_folder->uids->pdata[i];
+ CamelMessageInfoBase *mi = NULL;
+ CamelFolderChangeInfo *changes;
+
+ mi = (CamelMessageInfoBase*) camel_folder_summary_uid (folder->summary, fi->uid);
+ if (!mi)
+ {
+ CamelMimeMessage *msg = NULL;
+
+ if (pop3_store->engine && pop3_store->engine->capa & CAMEL_POP3_CAP_TOP)
+ msg = pop3_get_top (folder, fi->uid, NULL);
+ else
+ msg = pop3_get_message (folder, fi->uid, CAMEL_FOLDER_RECEIVE_PARTIAL, -1, NULL);
+
+ if (msg)
+ {
+ mi = (CamelMessageInfoBase*) camel_folder_summary_uid (folder->summary, fi->uid);
+ if (mi) {
+ mi->size = (fi->size);
+ /* TNY TODO: This is a hack! But else we need to parse
+ * BODYSTRUCTURE (and I'm lazy). It needs fixing though. */
+ if (mi->size > 102400)
+ mi->flags |= CAMEL_MESSAGE_ATTACHMENTS;
+ /* ... it does */
+ camel_message_info_free (mi);
+ }
+
+ camel_object_unref (CAMEL_OBJECT (msg));
+
+ hcnt++;
+ if (hcnt > 1000)
+ {
+ /* Periodically save the summary (this reduces
+ memory usage too) */
+ camel_folder_summary_save (folder->summary);
+ hcnt = 0;
+ }
+
+ changes = camel_folder_change_info_new ();
+ camel_folder_change_info_add_uid (changes, fi->uid);
+ if (camel_folder_change_info_changed (changes))
+ camel_object_trigger_event (CAMEL_OBJECT (folder), "folder_changed", changes);
+ camel_folder_change_info_free (changes);
+
+ }
+
+ } else
+ camel_message_info_free (mi);
+
+ camel_operation_progress (NULL, i , pop3_folder->uids->len);
+
+ }
+
+ camel_folder_summary_save (folder->summary);
+
+ camel_folder_summary_kill_hash (folder->summary);
+
if (pop3_store->engine->capa & CAMEL_POP3_CAP_UIDL) {
camel_pop3_engine_command_free(pop3_store->engine, pcu);
} else {
for (i=0;i<pop3_folder->uids->len;i++) {
CamelPOP3FolderInfo *fi = pop3_folder->uids->pdata[i];
+
if (fi->cmd) {
camel_pop3_engine_command_free(pop3_store->engine, fi->cmd);
fi->cmd = NULL;
@@ -287,8 +391,11 @@
/* dont need this anymore */
g_hash_table_destroy(pop3_folder->uids_id);
-
+
camel_operation_end (NULL);
+
+ g_static_rec_mutex_unlock (pop3_store->eng_lock);
+
return;
}
@@ -297,25 +404,32 @@
{
CamelPOP3Folder *pop3_folder;
CamelPOP3Store *pop3_store;
- int i;
- CamelPOP3FolderInfo *fi;
+ int i, max; CamelPOP3FolderInfo *fi;
+ CamelMessageInfoBase *info;
pop3_folder = CAMEL_POP3_FOLDER (folder);
pop3_store = CAMEL_POP3_STORE (folder->parent_store);
+ if (camel_disco_store_status (CAMEL_DISCO_STORE (pop3_store)) == CAMEL_DISCO_STORE_OFFLINE)
+ return;
+
if(pop3_store->delete_after && !expunge)
{
camel_operation_start(NULL, _("Expunging old messages"));
- camel_pop3_delete_old(folder, pop3_store->delete_after,ex);
- }
+ camel_pop3_delete_old(folder, pop3_store->delete_after,ex);
+ }
- if (!expunge) {
+ if (!expunge)
return;
- }
-
+
+ g_static_rec_mutex_lock (pop3_store->eng_lock);
+
camel_operation_start(NULL, _("Expunging deleted messages"));
-
- for (i = 0; i < pop3_folder->uids->len; i++) {
+
+ if (pop3_folder->uids)
+ {
+ for (i = 0; i < pop3_folder->uids->len; i++)
+ {
fi = pop3_folder->uids->pdata[i];
/* busy already? wait for that to finish first */
if (fi->cmd) {
@@ -326,20 +440,15 @@
}
if (fi->flags & CAMEL_MESSAGE_DELETED) {
- fi->cmd = camel_pop3_engine_command_new(pop3_store->engine,
- 0,
- NULL,
- NULL,
- "DELE %u\r\n",
- fi->id);
+ fi->cmd = camel_pop3_engine_command_new(pop3_store->engine, 0, NULL, NULL, "DELE %u\r\n", fi->id);
/* also remove from cache */
if (pop3_store->cache && fi->uid)
camel_data_cache_remove(pop3_store->cache, "cache", fi->uid, NULL);
}
- }
+ }
- for (i = 0; i < pop3_folder->uids->len; i++) {
+ for (i = 0; i < pop3_folder->uids->len; i++) {
fi = pop3_folder->uids->pdata[i];
/* wait for delete commands to finish */
if (fi->cmd) {
@@ -348,64 +457,90 @@
camel_pop3_engine_command_free(pop3_store->engine, fi->cmd);
fi->cmd = NULL;
}
- camel_operation_progress(NULL, (i+1) * 100 / pop3_folder->uids->len);
+ camel_operation_progress(NULL, (i+1) , pop3_folder->uids->len);
+ }
}
+ max = camel_folder_summary_count (folder->summary);
+ for (i = 0; i < max; i++)
+ {
+ if (!(info = (CamelMessageInfoBase*) camel_folder_summary_index (folder->summary, i)))
+ continue;
+
+ if (info->flags & CAMEL_MESSAGE_DELETED)
+ {
+ struct _CamelPOP3Command *cmd;
+ cmd = camel_pop3_engine_command_new(pop3_store->engine, 0, NULL, NULL, "DELE %u\r\n", info->uid);
+ while (camel_pop3_engine_iterate(pop3_store->engine, cmd) > 0);
+ if (pop3_store->cache && info->uid)
+ camel_data_cache_remove(pop3_store->cache, "cache", info->uid, NULL);
+ camel_pop3_engine_command_free(pop3_store->engine, cmd);
+ camel_message_info_free((CamelMessageInfo *)info);
+ }
+
+ }
+
camel_operation_end(NULL);
- camel_pop3_store_expunge (pop3_store, ex);
+ g_static_rec_mutex_unlock (pop3_store->eng_lock);
}
+
int
-camel_pop3_delete_old(CamelFolder *folder, int days_to_delete, CamelException *ex)
+camel_pop3_delete_old(CamelFolder *folder, int days_to_delete, CamelException *ex)
{
CamelPOP3Folder *pop3_folder;
CamelPOP3FolderInfo *fi;
int i;
CamelPOP3Store *pop3_store;
time_t temp;
- CamelMimeMessage *message;
pop3_folder = CAMEL_POP3_FOLDER (folder);
- pop3_store = CAMEL_POP3_STORE (CAMEL_FOLDER(pop3_folder)->parent_store);
+ pop3_store = CAMEL_POP3_STORE (CAMEL_FOLDER(pop3_folder)->parent_store);
temp = time(&temp);
- for (i = 0; i < pop3_folder->uids->len; i++) {
+ g_static_rec_mutex_lock (pop3_store->eng_lock);
+
+ for (i = 0; i < pop3_folder->uids->len; i++)
+ {
+ CamelMimeMessage *message = NULL;
+
fi = pop3_folder->uids->pdata[i];
-
- message = pop3_get_message (folder, fi->uid, ex);
- if(message) {
- time_t message_time = message->date + message->date_offset;
- double time_diff = difftime(temp,message_time);
- int day_lag = time_diff/(60*60*24);
- if( day_lag > days_to_delete)
+
+ if (pop3_store->cache && fi->uid && !camel_data_cache_is_partial(pop3_store->cache, "cache", fi->uid))
+ message = pop3_get_message (folder, fi->uid, CAMEL_FOLDER_RECEIVE_FULL, -1, ex);
+ else if (fi->uid)
+ message = pop3_get_message (folder, fi->uid, CAMEL_FOLDER_RECEIVE_PARTIAL, -1, ex);
+
+ time_t message_time = message->date + message->date_offset;
+
+ if (message)
+ {
+ double time_diff = difftime(temp,message_time);
+ int day_lag = time_diff/(60*60*24);
+ if (day_lag > days_to_delete)
+ {
+ if (fi->cmd)
{
- if (fi->cmd) {
- while (camel_pop3_engine_iterate(pop3_store->engine, fi->cmd) > 0) {
- ; /* do nothing - iterating until end */
- }
-
- camel_pop3_engine_command_free(pop3_store->engine, fi->cmd);
- fi->cmd = NULL;
- }
-
- fi->cmd = camel_pop3_engine_command_new(pop3_store->engine,
- 0,
- NULL,
- NULL,
- "DELE %u\r\n",
- fi->id);
- /* also remove from cache */
- if (pop3_store->cache && fi->uid) {
- camel_data_cache_remove(pop3_store->cache, "cache", fi->uid, NULL);
- }
- }
- /* free message - not used anymore */
- camel_object_unref((CamelObject *)message);
+ while (camel_pop3_engine_iterate(pop3_store->engine, fi->cmd) > 0)
+ ;
+ camel_pop3_engine_command_free(pop3_store->engine, fi->cmd);
+ fi->cmd = NULL;
+ }
+
+ fi->cmd = camel_pop3_engine_command_new(pop3_store->engine, 0, NULL, NULL, "DELE %u\r\n", fi->id);
+ /* also remove from cache */
+ if (pop3_store->cache && fi->uid)
+ camel_data_cache_remove(pop3_store->cache, "cache", fi->uid, NULL);
+ }
+
+ camel_object_unref (CAMEL_OBJECT (message));
}
+
}
- for (i = 0; i < pop3_folder->uids->len; i++) {
+ for (i = 0; i < pop3_folder->uids->len; i++)
+ {
fi = pop3_folder->uids->pdata[i];
/* wait for delete commands to finish */
if (fi->cmd) {
@@ -414,32 +549,36 @@
camel_pop3_engine_command_free(pop3_store->engine, fi->cmd);
fi->cmd = NULL;
}
- camel_operation_progress(NULL, (i+1) * 100 / pop3_folder->uids->len);
+ camel_operation_progress(NULL, (i+1) , pop3_folder->uids->len);
}
camel_operation_end(NULL);
- camel_pop3_store_expunge (pop3_store, ex);
+ /* camel_pop3_store_expunge (pop3_store, ex); */
+ g_static_rec_mutex_unlock (pop3_store->eng_lock);
+
return 0;
-
+
}
static void
cmd_tocache(CamelPOP3Engine *pe, CamelPOP3Stream *stream, void *data)
{
+ CamelPOP3Store *tstore = (CamelPOP3Store *) pe->store;
CamelPOP3FolderInfo *fi = data;
char buffer[2048];
int w = 0, n;
/* What if it fails? */
-
/* We write an '*' to the start of the stream to say its not complete yet */
/* This should probably be part of the cache code */
+
if ((n = camel_stream_write(fi->stream, "*", 1)) == -1)
goto done;
- while ((n = camel_stream_read((CamelStream *)stream, buffer, sizeof(buffer))) > 0) {
+ while ((n = camel_stream_read((CamelStream *)stream, buffer, sizeof(buffer))) > 0)
+ {
n = camel_stream_write(fi->stream, buffer, n);
if (n == -1)
break;
@@ -448,13 +587,15 @@
if (w > fi->size)
w = fi->size;
if (fi->size != 0)
- camel_operation_progress(NULL, (w * 100) / fi->size);
+ camel_operation_progress(NULL, w , fi->size);
}
/* it all worked, output a '#' to say we're a-ok */
if (n != -1) {
camel_stream_reset(fi->stream);
n = camel_stream_write(fi->stream, "#", 1);
+
+ camel_data_cache_set_partial (tstore->cache, "cache", fi->uid, FALSE);
}
done:
if (n == -1) {
@@ -468,29 +609,161 @@
fi->stream = NULL;
}
+
+static void
+cmd_tocache_partial (CamelPOP3Engine *pe, CamelPOP3Stream *stream, void *data)
+{
+ CamelPOP3Store *tstore = (CamelPOP3Store *) pe->store;
+ CamelPOP3FolderInfo *fi = data;
+ unsigned char *buffer;
+ int w = 0, n;
+ gchar *boundary = NULL;
+ gboolean occurred = FALSE, theend = FALSE;
+ unsigned int len;
+
+ /* We write an '*' to the start of the stream to say its not complete yet */
+ if ((n = camel_stream_write(fi->stream, "*", 1)) == -1)
+ goto done;
+
+
+ while (!theend && camel_pop3_stream_line (stream, &buffer, &len) > 0)
+ {
+ if (!buffer)
+ continue;
+
+ if (boundary == NULL)
+ {
+ CamelContentType *ct = NULL;
+ const char *bound=NULL;
+ char *pstr = (char*)strcasestr ((const char *) buffer, "Content-Type:");
+
+ if (pstr)
+ {
+ pstr = strchr (pstr, ':');
+ if (pstr) { pstr++;
+ ct = camel_content_type_decode(pstr); }
+ }
+
+ if (ct)
+ {
+ bound = camel_content_type_param(ct, "boundary");
+ if (bound && strlen (bound) > 0)
+ boundary = g_strdup (bound);
+ }
+ } else if (strstr ((const char*) buffer, (const char*) boundary))
+ {
+ if (occurred)
+ {
+ CamelException myex = CAMEL_EXCEPTION_INITIALISER;
+ camel_service_disconnect (CAMEL_SERVICE (tstore), FALSE, &myex);
+ camel_service_connect (CAMEL_SERVICE (tstore), &myex);
+ pe->partial_happening = TRUE;
+ theend = TRUE;
+ }
+
+ occurred = TRUE;
+ }
+
+ if (!theend)
+ {
+ n = camel_stream_write(fi->stream, (const char*) buffer, len);
+ if (n == -1 || camel_stream_write(fi->stream, "\n", 1) == -1)
+ break;
+ w += n+1;
+ } else if (boundary != NULL)
+ {
+ gchar *nb = g_strdup_printf ("\n--%s\n", boundary);
+ n = camel_stream_write(fi->stream, nb, strlen (nb));
+ g_free (nb);
+ }
+
+ if (w > fi->size)
+ w = fi->size;
+ if (fi->size != 0)
+ camel_operation_progress(NULL, w , fi->size);
+ }
+
+ /* it all worked, output a '#' to say we're a-ok */
+ if (n != -1 || theend) {
+ camel_stream_reset(fi->stream);
+ n = camel_stream_write(fi->stream, "#", 1);
+ if (theend)
+ camel_data_cache_set_partial (tstore->cache, "cache", fi->uid, TRUE);
+ else
+ camel_data_cache_set_partial (tstore->cache, "cache", fi->uid, FALSE);
+
+ }
+done:
+ if (n == -1 && !theend) {
+ fi->err = errno;
+ g_warning("POP3 retrieval failed: %s", strerror(errno));
+ } else {
+ fi->err = 0;
+ }
+
+ camel_object_unref((CamelObject *)fi->stream);
+ fi->stream = NULL;
+
+ if (boundary)
+ g_free (boundary);
+}
+
+
static CamelMimeMessage *
-pop3_get_message (CamelFolder *folder, const char *uid, CamelException *ex)
+pop3_get_message (CamelFolder *folder, const char *uid, CamelFolderReceiveType type, gint param, CamelException *ex)
{
CamelMimeMessage *message = NULL;
CamelPOP3Store *pop3_store = CAMEL_POP3_STORE (folder->parent_store);
CamelPOP3Folder *pop3_folder = (CamelPOP3Folder *)folder;
- CamelPOP3Command *pcr;
+ CamelPOP3Command *pcr=NULL;
CamelPOP3FolderInfo *fi;
- char buffer[1];
- int i, last;
+ char buffer[1]; int i;
CamelStream *stream = NULL;
+ CamelFolderSummary *summary = folder->summary;
+ CamelMessageInfoBase *mi; gboolean im_certain=FALSE;
- fi = g_hash_table_lookup(pop3_folder->uids_uid, uid);
+ g_static_rec_mutex_lock (pop3_store->eng_lock);
+
+ stream = camel_data_cache_get(pop3_store->cache, "cache", uid, NULL);
+ if (stream)
+ {
+ message = camel_mime_message_new ();
+ if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)message, stream) == -1) {
+ if (errno == EINTR)
+ camel_exception_setv(ex, CAMEL_EXCEPTION_USER_CANCEL, _("User canceled"));
+ else
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot get message %s: %s"),
+ uid, g_strerror (errno));
+ camel_object_unref((CamelObject *)message);
+ message = NULL;
+ }
+
+ camel_object_unref (CAMEL_OBJECT (stream));
+
+ g_static_rec_mutex_unlock (pop3_store->eng_lock);
+
+ return message;
+ }
+
+ if (pop3_folder->uids_uid)
+ fi = g_hash_table_lookup(pop3_folder->uids_uid, uid);
+ else
+ fi = NULL;
+
if (fi == NULL) {
camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID,
_("No message with UID %s"), uid);
+
+ g_static_rec_mutex_unlock (pop3_store->eng_lock);
+
return NULL;
}
/* Sigh, most of the crap in this function is so that the cancel button
returns the proper exception code. Sigh. */
- camel_operation_start_transient(NULL, _("Retrieving POP message %d"), fi->id);
+ camel_operation_start (NULL, _("Retrieving message"));
/* If we have an oustanding retrieve message running, wait for that to complete
& then retrieve from cache, otherwise, start a new one, and similar */
@@ -518,8 +791,24 @@
}
}
+ if (pop3_store->cache != NULL)
+ {
+ CamelException tex = CAMEL_EXCEPTION_INITIALISER;
+
+ if ((type & CAMEL_FOLDER_RECEIVE_FULL) && camel_data_cache_is_partial (pop3_store->cache, "cache", fi->uid))
+ {
+ camel_data_cache_remove (pop3_store->cache, "cache", fi->uid, &tex);
+ im_certain = TRUE;
+ } else if ((type & CAMEL_FOLDER_RECEIVE_PARTIAL || type & CAMEL_FOLDER_RECEIVE_SIZE_LIMITED)
+ && !camel_data_cache_is_partial (pop3_store->cache, "cache", fi->uid))
+ {
+ camel_data_cache_remove (pop3_store->cache, "cache", fi->uid, &tex);
+ im_certain = TRUE;
+ }
+ }
+
/* check to see if we have safely written flag set */
- if (pop3_store->cache == NULL
+ if (im_certain || pop3_store->cache == NULL
|| (stream = camel_data_cache_get(pop3_store->cache, "cache", fi->uid, NULL)) == NULL
|| camel_stream_read(stream, buffer, 1) != 1
|| buffer[0] != '#') {
@@ -533,32 +822,20 @@
camel_object_ref((CamelObject *)stream);
fi->stream = stream;
fi->err = EIO;
- pcr = camel_pop3_engine_command_new(pop3_store->engine, CAMEL_POP3_COMMAND_MULTI, cmd_tocache, fi, "RETR %u\r\n", fi->id);
- /* Also initiate retrieval of some of the following messages, assume we'll be receiving them */
- if (pop3_store->cache != NULL) {
- /* This should keep track of the last one retrieved, also how many are still
- oustanding incase of random access on large folders */
- i = fi->index+1;
- last = MIN(i+10, pop3_folder->uids->len);
- for (;i<last;i++) {
- CamelPOP3FolderInfo *pfi = pop3_folder->uids->pdata[i];
-
- if (pfi->uid && pfi->cmd == NULL) {
- pfi->stream = camel_data_cache_add(pop3_store->cache, "cache", pfi->uid, NULL);
- if (pfi->stream) {
- pfi->err = EIO;
- pfi->cmd = camel_pop3_engine_command_new(pop3_store->engine, CAMEL_POP3_COMMAND_MULTI,
- cmd_tocache, pfi, "RETR %u\r\n", pfi->id);
- }
- }
- }
- }
- /* now wait for the first one to finish */
+ pop3_store->engine->type = type;
+ pop3_store->engine->param = param;
+
+ if (type & CAMEL_FOLDER_RECEIVE_FULL)
+ pcr = camel_pop3_engine_command_new(pop3_store->engine, CAMEL_POP3_COMMAND_MULTI,
+ cmd_tocache, fi, "RETR %u\r\n", fi->id);
+ else if (type & CAMEL_FOLDER_RECEIVE_PARTIAL || type & CAMEL_FOLDER_RECEIVE_SIZE_LIMITED)
+ pcr = camel_pop3_engine_command_new(pop3_store->engine, CAMEL_POP3_COMMAND_MULTI,
+ cmd_tocache_partial, fi, "RETR %u\r\n", fi->id);
+
while ((i = camel_pop3_engine_iterate(pop3_store->engine, pcr)) > 0)
;
-
if (i == -1)
fi->err = errno;
@@ -595,15 +872,184 @@
uid, g_strerror (errno));
camel_object_unref((CamelObject *)message);
message = NULL;
+ } else {
+ if (type & CAMEL_FOLDER_RECEIVE_FULL && pop3_store->immediate_delete_after)
+ {
+ struct _CamelPOP3Command *cmd = NULL;
+ cmd = camel_pop3_engine_command_new(pop3_store->engine, 0, NULL, NULL, "DELE %u\r\n", uid);
+ while (camel_pop3_engine_iterate(pop3_store->engine, cmd) > 0);
+ camel_pop3_engine_command_free(pop3_store->engine, cmd);
+ }
}
+
+ mi = (CamelMessageInfoBase *) camel_folder_summary_uid (summary, uid);
+ if (mi)
+ camel_folder_summary_remove (summary, (CamelMessageInfo *) mi);
+
+ mi = (CamelMessageInfoBase *) camel_folder_summary_info_new_from_message (summary, message);
+ if (mi->uid)
+ g_free (mi->uid);
+ mi->uid = g_strdup (uid);
+
+ camel_folder_summary_add (summary, (CamelMessageInfo *)mi);
+
done:
camel_object_unref((CamelObject *)stream);
fail:
camel_operation_end(NULL);
+ g_static_rec_mutex_unlock (pop3_store->eng_lock);
+
return message;
}
+
+
+static CamelMimeMessage *
+pop3_get_top (CamelFolder *folder, const char *uid, CamelException *ex)
+{
+ CamelMimeMessage *message = NULL;
+ CamelPOP3Store *pop3_store = CAMEL_POP3_STORE (folder->parent_store);
+ CamelPOP3Folder *pop3_folder = (CamelPOP3Folder *)folder;
+ CamelPOP3Command *pcr;
+ CamelPOP3FolderInfo *fi;
+ char buffer[1]; int i;
+ CamelStream *stream = NULL, *old;
+ CamelFolderSummary *summary = folder->summary;
+ CamelMessageInfoBase *mi;
+
+ g_static_rec_mutex_lock (pop3_store->eng_lock);
+
+ fi = g_hash_table_lookup(pop3_folder->uids_uid, uid);
+
+ if (fi == NULL) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID,
+ _("No message with UID %s"), uid);
+
+ g_static_rec_mutex_unlock (pop3_store->eng_lock);
+
+ return NULL;
+ }
+
+ old = fi->stream;
+
+ /* Sigh, most of the crap in this function is so that the cancel button
+ returns the proper exception code. Sigh. */
+
+ camel_operation_start_transient(NULL, _("Retrieving POP message %d"), fi->id);
+
+ /* If we have an oustanding retrieve message running, wait for that to complete
+ & then retrieve from cache, otherwise, start a new one, and similar */
+
+ if (fi->cmd != NULL) {
+ while ((i = camel_pop3_engine_iterate(pop3_store->engine, fi->cmd)) > 0)
+ ;
+
+ if (i == -1)
+ fi->err = errno;
+
+ /* getting error code? */
+ /*g_assert (fi->cmd->state == CAMEL_POP3_COMMAND_DATA);*/
+ camel_pop3_engine_command_free(pop3_store->engine, fi->cmd);
+ fi->cmd = NULL;
+
+ if (fi->err != 0) {
+ if (fi->err == EINTR)
+ camel_exception_setv(ex, CAMEL_EXCEPTION_USER_CANCEL, _("User canceled"));
+ else
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot get message %s: %s"),
+ uid, g_strerror (fi->err));
+ goto fail;
+ }
+ }
+
+ /* check to see if we have safely written flag set */
+ if (pop3_store->cache == NULL
+ || (stream = camel_data_cache_get(pop3_store->cache, "cache", fi->uid, NULL)) == NULL
+ || camel_stream_read(stream, buffer, 1) != 1
+ || buffer[0] != '#') {
+
+
+ stream = camel_stream_mem_new();
+
+ /* the cmd_tocache thing unrefs it, therefore this is to keep it
+ compatible with existing code */
+ camel_object_ref (CAMEL_OBJECT (stream));
+
+ fi->stream = stream;
+ fi->err = EIO;
+
+ /* TOP %s 1 only returns the headers of a message and the first
+ line. Which is fine and to make sure broken POP servers also
+ return something (in case TOP %s 0 would otherwise be
+ misinterpreted by the POP server) */
+
+ pcr = camel_pop3_engine_command_new(pop3_store->engine, CAMEL_POP3_COMMAND_MULTI,
+ cmd_tocache, fi, "TOP %u 0\r\n", fi->id);
+
+ while ((i = camel_pop3_engine_iterate(pop3_store->engine, pcr)) > 0)
+ ;
+ if (i == -1)
+ fi->err = errno;
+
+ camel_pop3_engine_command_free(pop3_store->engine, pcr);
+ camel_stream_reset(stream);
+
+ fi->stream = old;
+
+ /* Check to see we have safely written flag set */
+ if (fi->err != 0) {
+ if (fi->err == EINTR)
+ camel_exception_setv(ex, CAMEL_EXCEPTION_USER_CANCEL, _("User canceled"));
+ else
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot get message %s: %s"),
+ uid, g_strerror (fi->err));
+ goto done;
+ }
+
+ if (camel_stream_read(stream, buffer, 1) != 1 || buffer[0] != '#') {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot get message %s: %s"), uid, _("Unknown reason"));
+ goto done;
+ }
+ }
+
+ message = camel_mime_message_new ();
+ if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)message, stream) == -1) {
+ if (errno == EINTR)
+ camel_exception_setv(ex, CAMEL_EXCEPTION_USER_CANCEL, _("User canceled"));
+ else
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot get message %s: %s"),
+ uid, g_strerror (errno));
+ camel_object_unref((CamelObject *)message);
+ message = NULL;
+ }
+
+ mi = (CamelMessageInfoBase *) camel_folder_summary_uid (summary, uid);
+ if (mi)
+ camel_folder_summary_remove (summary, (CamelMessageInfo *) mi);
+
+ mi = (CamelMessageInfoBase *) camel_folder_summary_info_new_from_message (summary, message);
+
+ if (mi->uid)
+ g_free (mi->uid);
+ mi->uid = g_strdup(uid);
+
+ camel_folder_summary_add (summary, (CamelMessageInfo *)mi);
+
+done:
+ camel_object_unref((CamelObject *)stream);
+fail:
+ camel_operation_end(NULL);
+
+ g_static_rec_mutex_unlock (pop3_store->eng_lock);
+
+ return message;
+}
+
static gboolean
pop3_set_message_flags (CamelFolder *folder, const char *uid, guint32 flags, guint32 set)
{
@@ -621,6 +1067,8 @@
}
}
+ /* TNY TODO: Sync to POP server and in the summary.mmap file */
+
return res;
}
@@ -628,7 +1076,10 @@
pop3_get_message_count (CamelFolder *folder)
{
CamelPOP3Folder *pop3_folder = CAMEL_POP3_FOLDER (folder);
-
+
+ if (!pop3_folder->uids)
+ return 0;
+
return pop3_folder->uids->len;
}
@@ -647,3 +1098,172 @@
return uids;
}
+
+
+static void
+pop3_sync_offline (CamelFolder *folder, CamelException *ex)
+{
+ camel_folder_summary_save (folder->summary);
+}
+
+static void
+pop3_sync_online (CamelFolder *folder, CamelException *ex)
+{
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Not supported"));
+
+ pop3_sync_offline (folder, ex);
+
+ return;
+}
+
+static void
+pop3_expunge_uids_online (CamelFolder *folder, GPtrArray *uids, CamelException *ex)
+{
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Not supported"));
+
+ return;
+}
+
+
+static int
+uid_compar (const void *va, const void *vb)
+{
+ const char **sa = (const char **)va, **sb = (const char **)vb;
+ unsigned long a, b;
+
+ a = strtoul (*sa, NULL, 10);
+ b = strtoul (*sb, NULL, 10);
+ if (a < b)
+ return -1;
+ else if (a == b)
+ return 0;
+ else
+ return 1;
+}
+
+static void
+pop3_expunge_uids_offline (CamelFolder *folder, GPtrArray *uids, CamelException *ex)
+{
+ CamelFolderChangeInfo *changes;
+ int i;
+
+ qsort (uids->pdata, uids->len, sizeof (void *), uid_compar);
+
+ changes = camel_folder_change_info_new ();
+
+ for (i = 0; i < uids->len; i++) {
+ camel_folder_summary_remove_uid (folder->summary, uids->pdata[i]);
+ camel_folder_change_info_remove_uid (changes, uids->pdata[i]);
+ /* We intentionally don't remove it from the cache because
+ * the cached data may be useful in replaying a COPY later.
+ */
+ }
+ camel_folder_summary_save (folder->summary);
+
+ camel_disco_diary_log (CAMEL_DISCO_STORE (folder->parent_store)->diary,
+ CAMEL_DISCO_DIARY_FOLDER_EXPUNGE, folder, uids);
+
+ camel_object_trigger_event (CAMEL_OBJECT (folder), "folder_changed", changes);
+ camel_folder_change_info_free (changes);
+
+ return;
+}
+
+static void
+pop3_expunge_uids_resyncing (CamelFolder *folder, GPtrArray *uids, CamelException *ex)
+{
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Not supported"));
+
+ return;
+}
+
+
+static void
+pop3_append_offline (CamelFolder *folder, CamelMimeMessage *message,
+ const CamelMessageInfo *info, char **appended_uid,
+ CamelException *ex)
+{
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Not supported"));
+
+ return;
+}
+
+static void
+pop3_transfer_offline (CamelFolder *source, GPtrArray *uids,
+ CamelFolder *dest, GPtrArray **transferred_uids,
+ gboolean delete_originals, CamelException *ex)
+{
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Not supported"));
+ return;
+}
+
+static void
+pop3_cache_message (CamelDiscoFolder *disco_folder, const char *uid,
+ CamelException *ex)
+{
+ CamelMimeMessage *msg = pop3_get_message (CAMEL_FOLDER (disco_folder), uid,
+ CAMEL_FOLDER_RECEIVE_FULL, -1, ex);
+
+ if (msg)
+ camel_object_unref (CAMEL_OBJECT (msg));
+
+}
+
+static void
+camel_pop3_folder_class_init (CamelPOP3FolderClass *camel_pop3_folder_class)
+{
+ CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS(camel_pop3_folder_class);
+ CamelDiscoFolderClass *camel_disco_folder_class = CAMEL_DISCO_FOLDER_CLASS (camel_pop3_folder_class);
+
+ disco_folder_class = CAMEL_DISCO_FOLDER_CLASS (camel_type_get_global_classfuncs (camel_disco_folder_get_type ()));
+
+ parent_class = CAMEL_FOLDER_CLASS(camel_folder_get_type());
+
+ /* virtual method overload */
+ camel_folder_class->refresh_info = pop3_refresh_info;
+ camel_folder_class->sync = pop3_sync;
+
+ camel_folder_class->get_message_count = pop3_get_message_count;
+ camel_folder_class->get_uids = pop3_get_uids;
+ camel_folder_class->free_uids = camel_folder_free_shallow;
+ camel_folder_class->get_message = pop3_get_message;
+ camel_folder_class->set_message_flags = pop3_set_message_flags;
+
+ camel_disco_folder_class->refresh_info_online = pop3_refresh_info;
+ camel_disco_folder_class->sync_online = pop3_sync_online;
+ camel_disco_folder_class->sync_offline = pop3_sync_offline;
+
+ camel_disco_folder_class->sync_resyncing = pop3_sync_offline;
+
+ camel_disco_folder_class->expunge_uids_online = pop3_expunge_uids_online;
+ camel_disco_folder_class->expunge_uids_offline = pop3_expunge_uids_offline;
+ camel_disco_folder_class->expunge_uids_resyncing = pop3_expunge_uids_resyncing;
+
+ camel_disco_folder_class->append_online = pop3_append_offline;
+ camel_disco_folder_class->append_offline = pop3_append_offline;
+ camel_disco_folder_class->append_resyncing = pop3_append_offline;
+
+ camel_disco_folder_class->transfer_online = pop3_transfer_offline;
+ camel_disco_folder_class->transfer_offline = pop3_transfer_offline;
+ camel_disco_folder_class->transfer_resyncing = pop3_transfer_offline;
+
+ camel_disco_folder_class->cache_message = pop3_cache_message;
+}
+
+CamelType
+camel_pop3_folder_get_type (void)
+{
+ static CamelType camel_pop3_folder_type = CAMEL_INVALID_TYPE;
+
+ if (!camel_pop3_folder_type) {
+ camel_pop3_folder_type = camel_type_register (CAMEL_DISCO_FOLDER_TYPE, "CamelPOP3Folder",
+ sizeof (CamelPOP3Folder),
+ sizeof (CamelPOP3FolderClass),
+ (CamelObjectClassInitFunc) camel_pop3_folder_class_init,
+ NULL,
+ NULL,
+ (CamelObjectFinalizeFunc) pop3_finalize);
+ }
+
+ return camel_pop3_folder_type;
+}
Index: camel-pop3-stream.c
===================================================================
--- camel-pop3-stream.c (revision 7816)
+++ camel-pop3-stream.c (working copy)
@@ -57,13 +57,13 @@
memcpy(is->buf, is->ptr, left);
is->end = is->buf + left;
is->ptr = is->buf;
- left = camel_stream_read(is->source, is->end, CAMEL_POP3_STREAM_SIZE - (is->end - is->buf));
+ left = camel_stream_read(is->source, (char*) is->end, CAMEL_POP3_STREAM_SIZE - (is->end - is->buf));
if (left > 0) {
is->end += left;
is->end[0] = '\n';
return is->end - is->ptr;
} else {
- dd(printf("POP3_STREAM_FILL(ERROR): '%s'\n", strerror (errno)));
+ pop3_debug ("POP3_STREAM_FILL(ERROR): '%s'\n", strerror (errno));
return -1;
}
}
@@ -105,7 +105,7 @@
is->ptr = p+3;
is->mode = CAMEL_POP3_STREAM_EOD;
is->state = 0;
- dd(printf("POP3_STREAM_READ(%d):\n%.*s\n", (int)(o-buffer), (int)(o-buffer), buffer));
+ pop3_debug ("POP3_STREAM_READ(%d):\n%.*s\n", (int)(o-buffer), (int)(o-buffer), buffer);
return o-buffer;
}
p++;
@@ -138,7 +138,7 @@
is->ptr = p;
is->state = state;
- dd(printf("POP3_STREAM_READ(%d):\n%.*s\n", (int)(o-buffer), (int)(o-buffer), buffer));
+ pop3_debug ("POP3_STREAM_READ(%d):\n%.*s\n", (int)(o-buffer), (int)(o-buffer), buffer);
return o-buffer;
}
@@ -147,12 +147,13 @@
stream_write(CamelStream *stream, const char *buffer, size_t n)
{
CamelPOP3Stream *is = (CamelPOP3Stream *)stream;
-
- if (strncmp (buffer, "PASS ", 5) != 0)
- dd(printf("POP3_STREAM_WRITE(%d):\n%.*s\n", (int)n, (int)n, buffer));
- else
- dd(printf("POP3_STREAM_WRITE(%d):\nPASS xxxxxxxx\n", (int)n));
-
+
+ if (strncmp (buffer, "PASS ", 5) != 0) {
+ pop3_debug("POP3_STREAM_WRITE(%d):\n%.*s\n", (int)n, (int)n, buffer);
+ } else {
+ pop3_debug("POP3_STREAM_WRITE(%d):\nPASS xxxxxxxx\n", (int)n);
+ }
+
return camel_stream_write(is->source, buffer, n);
}
Index: camel-pop3-store.c
===================================================================
--- camel-pop3-store.c (revision 7816)
+++ camel-pop3-store.c (working copy)
@@ -5,7 +5,12 @@
* Authors:
* Dan Winship <danw ximian com>
* Michael Zucchi <notzed ximian com>
+ * Philip Van Hoof <pvanhoof gnome org>
*
+ * This is CamelPop3Store for camel-lite that implements CamelDiscoStore. Its
+ * implementation is significantly different from Camel's upstream version
+ * (being used by Evolution): this version supports offline and online modes.
+ *
* Copyright (C) 2000-2002 Ximian, Inc. (www.ximian.com)
*
* This program is free software; you can redistribute it and/or
@@ -27,18 +32,28 @@
#include <config.h>
#endif
+#include <sys/types.h>
+#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <dirent.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <stdio.h>
#include <sys/types.h>
-#include <ctype.h>
-#include <glib/gi18n-lib.h>
+#include "camel-file-utils.h"
-#include <libedataserver/md5-utils.h>
-
#include "camel-data-cache.h"
#include "camel-exception.h"
#include "camel-net-utils.h"
@@ -52,15 +67,21 @@
#include "camel-tcp-stream-raw.h"
#include "camel-tcp-stream.h"
#include "camel-url.h"
+#include "camel/camel-string-utils.h"
#ifdef HAVE_SSL
#include "camel-tcp-stream-ssl.h"
#endif
+#include "camel-disco-diary.h"
+#include <libedataserver/md5-utils.h>
+
/* Specified in RFC 1939 */
#define POP3_PORT "110"
#define POP3S_PORT "995"
+#define _(o) o
+
static CamelStoreClass *parent_class = NULL;
static void finalize (CamelObject *object);
@@ -74,68 +95,156 @@
static CamelFolder *get_trash (CamelStore *store, CamelException *ex);
-static void
-camel_pop3_store_class_init (CamelPOP3StoreClass *camel_pop3_store_class)
+
+
+static void
+pop3_delete_cache (CamelStore *store)
{
- CamelServiceClass *camel_service_class =
- CAMEL_SERVICE_CLASS (camel_pop3_store_class);
- CamelStoreClass *camel_store_class =
- CAMEL_STORE_CLASS (camel_pop3_store_class);
+ CamelPOP3Store *pop3_store = (CamelPOP3Store *) store;
+ gchar *folder_dir = pop3_store->storage_path;
+ camel_rm (folder_dir);
+}
- parent_class = CAMEL_STORE_CLASS (camel_type_get_global_classfuncs (camel_store_get_type ()));
-
- /* virtual method overload */
- camel_service_class->query_auth_types = query_auth_types;
- camel_service_class->connect = pop3_connect;
- camel_service_class->disconnect = pop3_disconnect;
- camel_store_class->get_folder = get_folder;
- camel_store_class->get_trash = get_trash;
+static gboolean
+pop3_can_work_offline (CamelDiscoStore *disco_store)
+{
+ return TRUE;
}
+static gboolean
+pop3_connect_offline (CamelService *service, CamelException *ex)
+{
+ CamelPOP3Store *store = CAMEL_POP3_STORE (service);
+ store->connected = !camel_exception_is_set (ex);
+ return store->connected;
+}
-static void
-camel_pop3_store_init (gpointer object, gpointer klass)
+static gboolean
+pop3_connect_online (CamelService *service, CamelException *ex)
{
- ;
+ return pop3_connect (service, ex);
}
-CamelType
-camel_pop3_store_get_type (void)
+
+static gboolean
+pop3_disconnect_offline (CamelService *service, gboolean clean, CamelException *ex)
{
- static CamelType camel_pop3_store_type = CAMEL_INVALID_TYPE;
+ return TRUE;
+}
- if (!camel_pop3_store_type) {
- camel_pop3_store_type = camel_type_register (CAMEL_STORE_TYPE,
- "CamelPOP3Store",
- sizeof (CamelPOP3Store),
- sizeof (CamelPOP3StoreClass),
- (CamelObjectClassInitFunc) camel_pop3_store_class_init,
- NULL,
- (CamelObjectInitFunc) camel_pop3_store_init,
- finalize);
+static gboolean
+pop3_disconnect_online (CamelService *service, gboolean clean, CamelException *ex)
+{
+
+ CamelPOP3Store *store = CAMEL_POP3_STORE (service);
+
+ if (clean) {
+ CamelPOP3Command *pc;
+
+ pc = camel_pop3_engine_command_new(store->engine, 0, NULL, NULL, "QUIT\r\n");
+ while (camel_pop3_engine_iterate(store->engine, NULL) > 0)
+ ;
+ camel_pop3_engine_command_free(store->engine, pc);
}
- return camel_pop3_store_type;
+ g_static_rec_mutex_lock (store->eng_lock);
+ camel_object_unref((CamelObject *)store->engine);
+ store->engine = NULL;
+ g_static_rec_mutex_unlock (store->eng_lock);
+
+ return TRUE;
}
-static void
-finalize (CamelObject *object)
+static CamelFolder *
+pop3_get_folder_online (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex)
{
- CamelPOP3Store *pop3_store = CAMEL_POP3_STORE (object);
+ return get_folder (store, folder_name, flags, ex);
+}
- /* force disconnect so we dont have it run later, after we've cleaned up some stuff */
- /* SIGH */
- camel_service_disconnect((CamelService *)pop3_store, TRUE, NULL);
+static CamelFolderInfo *
+pop3_build_folder_info(CamelPOP3Store *store, const char *folder_name)
+{
+ const char *name;
+ CamelFolderInfo *fi;
+ gint msize;
+ gchar *folder_dir = store->storage_path;
+ gchar *spath;
+ FILE *f;
- if (pop3_store->engine)
- camel_object_unref((CamelObject *)pop3_store->engine);
- if (pop3_store->cache)
- camel_object_unref((CamelObject *)pop3_store->cache);
+ fi = camel_folder_info_new ();
+
+ fi->full_name = g_strdup(folder_name);
+ fi->unread = 0;
+ fi->total = 0;
+
+ camel_du (folder_dir, &msize);
+
+ spath = g_strdup_printf ("%s/summary.mmap", folder_dir);
+ f = fopen (spath, "r");
+ g_free (spath);
+ if (f) {
+ gint tsize = ((sizeof (guint32) * 5) + sizeof (time_t));
+ char *buffer = malloc (tsize), *ptr;
+ guint32 version, a;
+ a = fread (buffer, 1, tsize, f);
+ if (a == tsize)
+ {
+ ptr = buffer;
+ version = g_ntohl(get_unaligned_u32(ptr));
+ ptr += 16;
+ fi->total = g_ntohl(get_unaligned_u32(ptr));
+ ptr += 4;
+ if (version < 0x100 && version >= 13)
+ fi->unread = g_ntohl(get_unaligned_u32(ptr));
+ }
+ g_free (buffer);
+ fclose (f);
+ }
+
+ fi->local_size = (guint) msize;
+
+ fi->uri = g_strdup ("");
+ name = strrchr (fi->full_name, '/');
+ if (name == NULL)
+ name = fi->full_name;
+ else
+ name++;
+ if (!g_ascii_strcasecmp (fi->full_name, "INBOX"))
+ fi->name = g_strdup ((const gchar *) _("Inbox"));
+ else
+ fi->name = g_strdup (name);
+
+ return fi;
}
+static CamelFolder *
+pop3_get_folder_offline (CamelStore *store, const char *folder_name,
+ guint32 flags, CamelException *ex)
+{
+ return get_folder (store, folder_name, flags, ex);
+}
+
+
+static CamelFolderInfo *
+pop3_get_folder_info_offline (CamelStore *store, const char *top, guint32 flags, CamelException *ex)
+{
+ return pop3_build_folder_info (CAMEL_POP3_STORE (store), "INBOX");
+}
+
+static CamelFolderInfo *
+pop3_get_folder_info_online (CamelStore *store, const char *top, guint32 flags, CamelException *ex)
+{
+ CamelFolderInfo *info = pop3_get_folder_info_offline (store, top, flags, ex);
+
+ /* TODO: get read and unread count into info->unread & info->total */
+
+ return info;
+}
+
+
enum {
MODE_CLEAR,
MODE_SSL,
@@ -148,7 +257,7 @@
#endif
static gboolean
-connect_to_server (CamelService *service, struct addrinfo *ai, int ssl_mode, CamelException *ex)
+connect_to_server (CamelService *service, struct addrinfo *ai, int ssl_mode, int must_tls, CamelException *ex)
{
CamelPOP3Store *store = CAMEL_POP3_STORE (service);
CamelStream *tcp_stream;
@@ -156,128 +265,151 @@
guint32 flags = 0;
int clean_quit = TRUE;
int ret;
- const gchar *delete_days;
-
- if (ssl_mode != MODE_CLEAR) {
+ gchar *delete_days;
+
+ store->connected = FALSE;
+
+ if (ssl_mode != MODE_CLEAR)
+ {
+
#ifdef HAVE_SSL
- if (ssl_mode == MODE_TLS) {
+ if (ssl_mode == MODE_TLS)
tcp_stream = camel_tcp_stream_ssl_new_raw (service->session, service->url->host, STARTTLS_FLAGS);
- } else {
+ else
tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, SSL_PORT_FLAGS);
- }
#else
+
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
- _("Could not connect to %s: %s"),
- service->url->host, _("SSL unavailable"));
-
+ _("Could not connect to %s: %s"),
+ service->url->host, _("SSL unavailable"));
+
return FALSE;
+
#endif /* HAVE_SSL */
- } else {
+ } else
tcp_stream = camel_tcp_stream_raw_new ();
- }
-
- if ((ret = camel_tcp_stream_connect ((CamelTcpStream *) tcp_stream, ai)) == -1) {
+
+ if ((ret = camel_tcp_stream_connect ((CamelTcpStream *) tcp_stream, ai)) == -1)
+ {
if (errno == EINTR)
camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
- _("Connection canceled"));
+ _("Connection canceled"));
else
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
- _("Could not connect to %s: %s"),
- service->url->host,
- g_strerror (errno));
+ _("Could not connect to %s: %s"),
+ service->url->host,
+ g_strerror (errno));
camel_object_unref (tcp_stream);
return FALSE;
}
-
+
/* parent class connect initialization */
- if (CAMEL_SERVICE_CLASS (parent_class)->connect (service, ex) == FALSE) {
+ /*if (CAMEL_SERVICE_CLASS (parent_class)->connect (service, ex) == FALSE) {
camel_object_unref (tcp_stream);
return FALSE;
- }
-
+ }*/
+
if (camel_url_get_param (service->url, "disable_extensions"))
flags |= CAMEL_POP3_ENGINE_DISABLE_EXTENSIONS;
-
- if ((delete_days = camel_url_get_param(service->url,"delete_after")))
+
+ if ((delete_days = (gchar *) camel_url_get_param(service->url,"delete_after")))
store->delete_after = atoi(delete_days);
-
+
+ g_static_rec_mutex_lock (store->eng_lock);
if (!(store->engine = camel_pop3_engine_new (tcp_stream, flags))) {
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Failed to read a valid greeting from POP server %s"),
- service->url->host);
+ _("Failed to read a valid greeting from POP server %s"),
+ service->url->host);
camel_object_unref (tcp_stream);
+ g_static_rec_mutex_unlock (store->eng_lock);
return FALSE;
}
-
- if (ssl_mode != MODE_TLS) {
+ store->engine->store = store;
+ store->engine->partial_happening = FALSE;
+ g_static_rec_mutex_unlock (store->eng_lock);
+
+ if (!must_tls && (ssl_mode != MODE_TLS))
+ {
camel_object_unref (tcp_stream);
+ store->connected = TRUE;
return TRUE;
}
-
+
#ifdef HAVE_SSL
- if (!(store->engine->capa & CAMEL_POP3_CAP_STLS)) {
+
+ if (!(store->engine->capa & CAMEL_POP3_CAP_STLS))
+ {
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Failed to connect to POP server %s in secure mode: %s"),
- service->url->host, _("STLS not supported by server"));
+ _("Failed to connect to POP server %s in secure mode: %s"),
+ service->url->host, _("STLS not supported by server"));
goto stls_exception;
}
-
+
/* as soon as we send a STLS command, all hope is lost of a clean QUIT if problems arise */
clean_quit = FALSE;
-
+
pc = camel_pop3_engine_command_new (store->engine, 0, NULL, NULL, "STLS\r\n");
while (camel_pop3_engine_iterate (store->engine, NULL) > 0)
;
-
+
ret = pc->state == CAMEL_POP3_COMMAND_OK;
camel_pop3_engine_command_free (store->engine, pc);
-
- if (ret == FALSE) {
+
+ if (ret == FALSE)
+ {
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Failed to connect to POP server %s in secure mode: %s"),
- service->url->host, store->engine->line);
+ _("Failed to connect to POP server %s in secure mode: %s"),
+ service->url->host, store->engine->line);
goto stls_exception;
}
-
+
/* Okay, now toggle SSL/TLS mode */
ret = camel_tcp_stream_ssl_enable_ssl (CAMEL_TCP_STREAM_SSL (tcp_stream));
-
+
if (ret == -1) {
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
_("Failed to connect to POP server %s in secure mode: %s"),
service->url->host, _("TLS negotiations failed"));
goto stls_exception;
}
+
#else
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Failed to connect to POP server %s in secure mode: %s"),
- service->url->host, _("TLS is not available in this build"));
+ _("Failed to connect to POP server %s in secure mode: %s"),
+ service->url->host, _("TLS is not available in this build"));
+
goto stls_exception;
#endif /* HAVE_SSL */
-
+
camel_object_unref (tcp_stream);
-
+
/* rfc2595, section 4 states that after a successful STLS
- command, the client MUST discard prior CAPA responses */
+ command, the client MUST discard prior CAPA responses */
+
camel_pop3_engine_reget_capabilities (store->engine);
-
+ store->connected = TRUE;
+
return TRUE;
-
+
stls_exception:
- if (clean_quit) {
+ if (clean_quit)
+ {
/* try to disconnect cleanly */
pc = camel_pop3_engine_command_new (store->engine, 0, NULL, NULL, "QUIT\r\n");
while (camel_pop3_engine_iterate (store->engine, NULL) > 0)
;
camel_pop3_engine_command_free (store->engine, pc);
}
-
+
+ g_static_rec_mutex_lock (store->eng_lock);
camel_object_unref (CAMEL_OBJECT (store->engine));
camel_object_unref (CAMEL_OBJECT (tcp_stream));
store->engine = NULL;
-
+ store->connected = FALSE;
+ g_static_rec_mutex_unlock (store->eng_lock);
+
return FALSE;
}
@@ -286,12 +418,14 @@
char *serv;
char *port;
int mode;
+ int must_tls;
} ssl_options[] = {
- { "", "pop3s", POP3S_PORT, MODE_SSL }, /* really old (1.x) */
- { "always", "pop3s", POP3S_PORT, MODE_SSL },
- { "when-possible", "pop3", POP3_PORT, MODE_TLS },
- { "never", "pop3", POP3_PORT, MODE_CLEAR },
- { NULL, "pop3", POP3_PORT, MODE_CLEAR },
+ { "", "pop3s", POP3S_PORT, MODE_SSL, 0 }, /* really old (1.x) */
+ { "wrapped", "pop3s", POP3S_PORT, MODE_SSL, 0 },
+ { "tls", "pop3", POP3_PORT, MODE_TLS, 1 },
+ { "when-possible", "pop3", POP3_PORT, MODE_TLS, 0 },
+ { "never", "pop3", POP3_PORT, MODE_CLEAR, 0 },
+ { NULL, "pop3", POP3_PORT, MODE_CLEAR, 0 },
};
static gboolean
@@ -299,7 +433,7 @@
{
struct addrinfo hints, *ai;
const char *ssl_mode;
- int mode, ret, i;
+ int mode, ret, i, must_tls=0;
char *serv;
const char *port;
@@ -310,10 +444,12 @@
mode = ssl_options[i].mode;
serv = ssl_options[i].serv;
port = ssl_options[i].port;
+ must_tls = ssl_options[i].must_tls;
} else {
mode = MODE_CLEAR;
serv = "pop3";
port = POP3S_PORT;
+ must_tls = 0;
}
if (service->url->port) {
@@ -334,7 +470,7 @@
if (ai == NULL)
return FALSE;
- ret = connect_to_server (service, ai, mode, ex);
+ ret = connect_to_server (service, ai, mode, must_tls, ex);
camel_freeaddrinfo (ai);
@@ -366,28 +502,7 @@
return types;
}
-/**
- * camel_pop3_store_expunge:
- * @store: the store
- * @ex: a CamelException
- *
- * Expunge messages from the store. This will result in the connection
- * being closed, which may cause later commands to fail if they can't
- * reconnect.
- **/
-void
-camel_pop3_store_expunge (CamelPOP3Store *store, CamelException *ex)
-{
- CamelPOP3Command *pc;
- pc = camel_pop3_engine_command_new(store->engine, 0, NULL, NULL, "QUIT\r\n");
- while (camel_pop3_engine_iterate(store->engine, NULL) > 0)
- ;
- camel_pop3_engine_command_free(store->engine, pc);
-
- camel_service_disconnect (CAMEL_SERVICE (store), FALSE, ex);
-}
-
static int
try_sasl(CamelPOP3Store *store, const char *mech, CamelException *ex)
{
@@ -412,9 +527,9 @@
while (1) {
if (camel_pop3_stream_line(stream, &line, &len) == -1)
goto ioerror;
- if (strncmp(line, "+OK", 3) == 0)
+ if (strncmp((char *) line, "+OK", 3) == 0)
break;
- if (strncmp(line, "-ERR", 4) == 0) {
+ if (strncmp((char *) line, "-ERR", 4) == 0) {
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
_("SASL `%s' Login failed for POP server %s: %s"),
mech, CAMEL_SERVICE (store)->url->host, line);
@@ -422,9 +537,9 @@
}
/* If we dont get continuation, or the sasl object's run out of work, or we dont get a challenge,
its a protocol error, so fail, and try reset the server */
- if (strncmp(line, "+ ", 2) != 0
+ if (strncmp((char *) line, "+ ", 2) != 0
|| camel_sasl_authenticated(sasl)
- || (resp = camel_sasl_challenge_base64(sasl, line+2, ex)) == NULL) {
+ || (resp = (unsigned char *) camel_sasl_challenge_base64(sasl, (const char *) line+2, ex)) == NULL) {
camel_stream_printf((CamelStream *)stream, "*\r\n");
camel_pop3_stream_line(stream, &line, &len);
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
@@ -444,7 +559,7 @@
ioerror:
if (errno == EINTR) {
- camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, _("Canceled"));
+ camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, "Canceled");
} else {
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
_("Failed to authenticate on POP server %s: %s"),
@@ -540,7 +655,7 @@
if (status == -1) {
if (errno == EINTR) {
- camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, _("Canceled"));
+ camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, "Canceled");
} else {
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
_("Unable to connect to POP server %s.\n"
@@ -579,22 +694,7 @@
int status;
session = camel_service_get_session (service);
-
- if (store->cache == NULL) {
- char *root;
- root = camel_session_get_storage_path (session, service, ex);
- if (root) {
- store->cache = camel_data_cache_new(root, 0, ex);
- g_free(root);
- if (store->cache) {
- /* Default cache expiry - 1 week or not visited in a day */
- camel_data_cache_set_expire_age(store->cache, 60*60*24*7);
- camel_data_cache_set_expire_access(store->cache, 60*60*24);
- }
- }
- }
-
if (!connect_to_server_wrapper (service, ex))
return FALSE;
@@ -610,6 +710,7 @@
service->url->passwd = NULL;
reprompt = TRUE;
camel_exception_clear (ex);
+ sleep (5); /* For example Cyrus-POPd dislikes hammering */
} else
break;
}
@@ -641,13 +742,12 @@
;
camel_pop3_engine_command_free(store->engine, pc);
}
-
- if (!CAMEL_SERVICE_CLASS (parent_class)->disconnect (service, clean, ex))
- return FALSE;
-
+
+ g_static_rec_mutex_lock (store->eng_lock);
camel_object_unref((CamelObject *)store->engine);
store->engine = NULL;
-
+ g_static_rec_mutex_unlock (store->eng_lock);
+
return TRUE;
}
@@ -668,3 +768,134 @@
/* no-op */
return NULL;
}
+
+
+static void
+finalize (CamelObject *object)
+{
+ CamelPOP3Store *pop3_store = CAMEL_POP3_STORE (object);
+
+ g_static_rec_mutex_lock (pop3_store->eng_lock);
+ if (pop3_store->engine)
+ camel_object_unref((CamelObject *)pop3_store->engine);
+ pop3_store->engine = NULL;
+ g_static_rec_mutex_unlock (pop3_store->eng_lock);
+
+ if (pop3_store->cache)
+ camel_object_unref((CamelObject *)pop3_store->cache);
+ pop3_store->cache = NULL;
+ if (pop3_store->storage_path)
+ g_free (pop3_store->storage_path);
+ pop3_store->storage_path = NULL;
+
+ g_static_rec_mutex_free (pop3_store->eng_lock);
+ pop3_store->eng_lock = NULL;
+
+}
+
+
+
+static void
+pop3_construct (CamelService *service, CamelSession *session,
+ CamelProvider *provider, CamelURL *url,
+ CamelException *ex)
+{
+ CamelPOP3Store *pop3_store = CAMEL_POP3_STORE (service);
+ CamelDiscoStore *disco_store = CAMEL_DISCO_STORE (service);
+ char *path;
+
+ CAMEL_SERVICE_CLASS (parent_class)->construct (service, session, provider, url, ex);
+ if (camel_exception_is_set (ex))
+ return;
+
+ pop3_store->storage_path = camel_session_get_storage_path (session, service, ex);
+ if (!pop3_store->storage_path)
+ return;
+
+ pop3_store->cache = camel_data_cache_new(pop3_store->storage_path, 0, ex);
+ if (pop3_store->cache) {
+ /* Default cache expiry - 1 week or not visited in a day */
+ camel_data_cache_set_expire_age (pop3_store->cache, 60*60*24*7);
+ camel_data_cache_set_expire_access (pop3_store->cache, 60*60*24);
+ }
+
+ pop3_store->base_url = camel_url_to_string (service->url, (CAMEL_URL_HIDE_PASSWORD |
+ CAMEL_URL_HIDE_PARAMS |
+ CAMEL_URL_HIDE_AUTH));
+
+ /* setup journal*/
+ path = g_strdup_printf ("%s/journal", pop3_store->storage_path);
+ disco_store->diary = camel_disco_diary_new (disco_store, path, ex);
+ g_free (path);
+
+}
+
+static void
+camel_pop3_store_class_init (CamelPOP3StoreClass *camel_pop3_store_class)
+{
+ CamelServiceClass *camel_service_class =
+ CAMEL_SERVICE_CLASS (camel_pop3_store_class);
+ CamelStoreClass *camel_store_class =
+ CAMEL_STORE_CLASS (camel_pop3_store_class);
+ CamelDiscoStoreClass *camel_disco_store_class =
+ CAMEL_DISCO_STORE_CLASS (camel_pop3_store_class);
+
+ parent_class = CAMEL_STORE_CLASS (camel_type_get_global_classfuncs (camel_disco_store_get_type ()));
+
+ /* virtual method overload */
+ camel_service_class->construct = pop3_construct;
+ camel_service_class->query_auth_types = query_auth_types;
+
+ /* camel_service_class->connect = pop3_connect; */
+ /* camel_service_class->disconnect = pop3_disconnect; */
+
+ camel_store_class->get_folder = get_folder;
+ camel_store_class->get_trash = get_trash;
+
+ camel_store_class->delete_cache = pop3_delete_cache;
+
+ camel_disco_store_class->can_work_offline = pop3_can_work_offline;
+ camel_disco_store_class->connect_online = pop3_connect_online;
+ camel_disco_store_class->connect_offline = pop3_connect_offline;
+ camel_disco_store_class->disconnect_online = pop3_disconnect_online;
+ camel_disco_store_class->disconnect_offline = pop3_disconnect_offline;
+ camel_disco_store_class->get_folder_online = pop3_get_folder_online;
+ camel_disco_store_class->get_folder_offline = pop3_get_folder_offline;
+ camel_disco_store_class->get_folder_resyncing = pop3_get_folder_online;
+ camel_disco_store_class->get_folder_info_online = pop3_get_folder_info_online;
+ camel_disco_store_class->get_folder_info_offline = pop3_get_folder_info_offline;
+ camel_disco_store_class->get_folder_info_resyncing = pop3_get_folder_info_online;
+}
+
+
+
+static void
+camel_pop3_store_init (gpointer object, gpointer klass)
+{
+ CamelPOP3Store *store = (CamelPOP3Store *) object;
+
+ store->immediate_delete_after = FALSE;
+ store->eng_lock = g_new0 (GStaticRecMutex, 1);
+ g_static_rec_mutex_init (store->eng_lock);
+
+ return;
+}
+
+CamelType
+camel_pop3_store_get_type (void)
+{
+ static CamelType camel_pop3_store_type = CAMEL_INVALID_TYPE;
+
+ if (!camel_pop3_store_type) {
+ camel_pop3_store_type = camel_type_register (CAMEL_DISCO_STORE_TYPE,
+ "CamelPOP3Store",
+ sizeof (CamelPOP3Store),
+ sizeof (CamelPOP3StoreClass),
+ (CamelObjectClassInitFunc) camel_pop3_store_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_pop3_store_init,
+ finalize);
+ }
+
+ return camel_pop3_store_type;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]