aboutsummaryrefslogtreecommitdiffstats
path: root/camel
diff options
context:
space:
mode:
Diffstat (limited to 'camel')
-rw-r--r--camel/ChangeLog7
-rw-r--r--camel/providers/pop3/camel-pop3-folder.c170
-rw-r--r--camel/providers/pop3/camel-pop3-folder.h3
-rw-r--r--camel/providers/pop3/camel-pop3-store.c51
-rw-r--r--camel/providers/pop3/camel-pop3-store.h4
5 files changed, 197 insertions, 38 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog
index 4daf3f466c..e6d3fa4f86 100644
--- a/camel/ChangeLog
+++ b/camel/ChangeLog
@@ -1,5 +1,12 @@
2000-06-15 Dan Winship <danw@helixcode.com>
+ * providers/pop3/camel-pop3-store.c (connect_to_server): Check
+ server for various interesting extensions.
+
+ * providers/pop3/camel-pop3-folder.c (get_uids): If the server
+ supports UIDL, use real UIDs rather than fake ones.
+ (etc): Map uids back to numbers appropriately
+
* providers/mbox/camel-mbox-folder.c (mbox_append_message): Fix to
previous change: make sure the "seek" variable ends up with the
value it should.
diff --git a/camel/providers/pop3/camel-pop3-folder.c b/camel/providers/pop3/camel-pop3-folder.c
index c24157d168..807a810d06 100644
--- a/camel/providers/pop3/camel-pop3-folder.c
+++ b/camel/providers/pop3/camel-pop3-folder.c
@@ -36,6 +36,8 @@
#define CF_CLASS(o) (CAMEL_FOLDER_CLASS (GTK_OBJECT (o)->klass))
static CamelFolderClass *parent_class;
+static void finalize (GtkObject *object);
+
static void pop3_open (CamelFolder *folder, CamelFolderOpenMode mode,
CamelException *ex);
static void pop3_close (CamelFolder *folder, gboolean expunge,
@@ -43,6 +45,7 @@ static void pop3_close (CamelFolder *folder, gboolean expunge,
static gint get_message_count (CamelFolder *folder, CamelException *ex);
static GPtrArray *get_uids (CamelFolder *folder, CamelException *ex);
+static void free_uids (CamelFolder *folder, GPtrArray *uids);
static CamelMimeMessage *get_message_by_uid (CamelFolder *folder,
const char *uid,
CamelException *ex);
@@ -55,6 +58,8 @@ camel_pop3_folder_class_init (CamelPop3FolderClass *camel_pop3_folder_class)
{
CamelFolderClass *camel_folder_class =
CAMEL_FOLDER_CLASS (camel_pop3_folder_class);
+ GtkObjectClass *object_class =
+ GTK_OBJECT_CLASS (camel_pop3_folder_class);
parent_class = gtk_type_class (camel_folder_get_type ());
@@ -64,9 +69,12 @@ camel_pop3_folder_class_init (CamelPop3FolderClass *camel_pop3_folder_class)
camel_folder_class->get_message_count = get_message_count;
camel_folder_class->get_uids = get_uids;
+ camel_folder_class->free_uids = free_uids;
camel_folder_class->get_message_by_uid = get_message_by_uid;
camel_folder_class->delete_message_by_uid = delete_message_by_uid;
+
+ object_class->finalize = finalize;
}
@@ -81,7 +89,7 @@ camel_pop3_folder_init (gpointer object, gpointer klass)
folder->has_summary_capability = FALSE;
folder->has_search_capability = FALSE;
- pop3_folder->count = -1;
+ pop3_folder->uids = NULL;
}
@@ -110,7 +118,16 @@ camel_pop3_folder_get_type (void)
}
-CamelFolder *camel_pop3_folder_new (CamelStore *parent, CamelException *ex)
+void
+finalize (GtkObject *object)
+{
+ CamelPop3Folder *pop3_folder = CAMEL_POP3_FOLDER (object);
+
+ g_ptr_array_free (pop3_folder->uids, TRUE);
+}
+
+CamelFolder *
+camel_pop3_folder_new (CamelStore *parent, CamelException *ex)
{
CamelFolder *folder =
CAMEL_FOLDER (gtk_object_new (camel_pop3_folder_get_type (),
@@ -138,16 +155,69 @@ pop3_close (CamelFolder *folder, gboolean expunge, CamelException *ex)
}
+static GPtrArray *
+parse_listing (int count, char *data)
+{
+ GPtrArray *ans;
+ char *p;
+ int index, len;
+
+ ans = g_ptr_array_new ();
+ g_ptr_array_set_size (ans, count);
+
+ p = data;
+ while (*p) {
+ index = strtoul (p, &p, 10);
+ len = strcspn (p, "\n");
+ if (index <= count && *p == ' ')
+ ans->pdata[index - 1] = g_strndup (p + 1, len - 1);
+ p += len;
+ if (*p == '\n')
+ p++;
+ }
+
+ for (index = 0; index < count; index++) {
+ if (ans->pdata[index] == NULL) {
+ g_ptr_array_free (ans, TRUE);
+ return NULL;
+ }
+ }
+
+ return ans;
+}
+
+static int
+uid_to_number (CamelFolder *folder, const char *uid, CamelException *ex)
+{
+ CamelPop3Folder *pop3_folder = CAMEL_POP3_FOLDER (folder);
+ int i;
+
+ if (!get_uids (folder, ex))
+ return -1;
+
+ for (i = 0; i < pop3_folder->uids->len; i++) {
+ if (!strcmp (uid, pop3_folder->uids->pdata[i]))
+ return i + 1;
+ }
+
+ return -1;
+}
+
+
static CamelMimeMessage *
get_message_by_uid (CamelFolder *folder, const char *uid, CamelException *ex)
{
- int status;
+ int status, num;
char *result, *body;
CamelStream *msgstream;
CamelMimeMessage *msg;
+ num = uid_to_number (folder, uid, ex);
+ if (num == -1)
+ return NULL;
+
status = camel_pop3_command (CAMEL_POP3_STORE (folder->parent_store),
- &result, "RETR %d", atoi (uid));
+ &result, "RETR %d", num);
if (status != CAMEL_POP3_OK) {
CamelService *service = CAMEL_SERVICE (folder->parent_store);
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
@@ -185,11 +255,15 @@ static void
delete_message_by_uid (CamelFolder *folder, const char *uid,
CamelException *ex)
{
- int status;
+ int status, num;
char *resp;
+ num = uid_to_number (folder, uid, ex);
+ if (num == -1)
+ return;
+
status = camel_pop3_command (CAMEL_POP3_STORE (folder->parent_store),
- &resp, "DELE %d", atoi (uid));
+ &resp, "DELE %d", num);
if (status != CAMEL_POP3_OK) {
camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID,
"Unable to delete message %s%s%s",
@@ -203,44 +277,76 @@ static gint
get_message_count (CamelFolder *folder, CamelException *ex)
{
CamelPop3Folder *pop3_folder = CAMEL_POP3_FOLDER (folder);
- int status;
- char *result;
- if (pop3_folder->count != -1)
- return pop3_folder->count;
+ if (!get_uids (folder, ex))
+ return -1;
- status = camel_pop3_command (CAMEL_POP3_STORE (folder->parent_store),
- &result, "STAT");
+ return pop3_folder->uids->len;
+}
+
+static GPtrArray *
+get_uids (CamelFolder *folder, CamelException *ex)
+{
+ CamelPop3Store *pop3_store = CAMEL_POP3_STORE (folder->parent_store);
+ CamelPop3Folder *pop3_folder = CAMEL_POP3_FOLDER (folder);
+ int count, status;
+ char *data;
+
+ if (pop3_folder->uids)
+ return pop3_folder->uids;
+
+ status = camel_pop3_command (pop3_store, &data, "STAT");
if (status != CAMEL_POP3_OK) {
CamelService *service = CAMEL_SERVICE (folder->parent_store);
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
"Could not get message count from POP "
"server %s: %s.", service->url->host,
- status == CAMEL_POP3_ERR ? result :
- "Unknown error");
- g_free (result);
- return -1;
+ data ? data : "Unknown error");
+ g_free (data);
+ return NULL;
}
- pop3_folder->count = atoi (result);
- g_free (result);
- return pop3_folder->count;
-}
+ count = atoi (data);
+ g_free (data);
-static GPtrArray *
-get_uids (CamelFolder *folder, CamelException *ex)
-{
- int count, i;
- GPtrArray *array;
+ if (pop3_store->supports_uidl != FALSE) {
+ status = camel_pop3_command (pop3_store, NULL, "UIDL");
+ if (status != CAMEL_POP3_OK)
+ pop3_store->supports_uidl = FALSE;
+ }
- count = get_message_count (folder, ex);
- if (count == -1)
+ if (pop3_store->supports_uidl == FALSE) {
+ int i;
+
+ pop3_folder->uids = g_ptr_array_new ();
+ g_ptr_array_set_size (pop3_folder->uids, count);
+
+ for (i = 0; i < count; i++) {
+ pop3_folder->uids->pdata[i] =
+ g_strdup_printf ("%d", i + 1);
+ }
+
+ return pop3_folder->uids;
+ }
+
+ data = camel_pop3_command_get_additional_data (pop3_store, ex);
+ if (camel_exception_is_set (ex))
return NULL;
- array = g_ptr_array_new ();
- g_ptr_array_set_size (array, count);
- for (i = 0; i < count; i++)
- array->pdata[i] = g_strdup_printf ("%d", i + 1);
+ pop3_folder->uids = parse_listing (count, data);
+ g_free (data);
+
+ if (!pop3_folder->uids) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ "UID listing from server was "
+ "incomplete.");
+ }
- return array;
+ return pop3_folder->uids;
+}
+
+static void
+free_uids (CamelFolder *folder, GPtrArray *uids)
+{
+ ;
}
diff --git a/camel/providers/pop3/camel-pop3-folder.h b/camel/providers/pop3/camel-pop3-folder.h
index 2a478dc283..874c7a3a04 100644
--- a/camel/providers/pop3/camel-pop3-folder.h
+++ b/camel/providers/pop3/camel-pop3-folder.h
@@ -45,8 +45,7 @@ extern "C" {
typedef struct {
CamelFolder parent_object;
- CamelMessageInfo *msg_info;
- int count;
+ GPtrArray *uids;
} CamelPop3Folder;
diff --git a/camel/providers/pop3/camel-pop3-store.c b/camel/providers/pop3/camel-pop3-store.c
index d82ef7b0b4..c915b0916f 100644
--- a/camel/providers/pop3/camel-pop3-store.c
+++ b/camel/providers/pop3/camel-pop3-store.c
@@ -136,11 +136,15 @@ camel_pop3_store_get_type (void)
static void
finalize (GtkObject *object)
{
+ CamelPop3Store *pop3_store = CAMEL_POP3_STORE (object);
CamelException ex;
camel_exception_init (&ex);
pop3_disconnect (CAMEL_SERVICE (object), &ex);
camel_exception_clear (&ex);
+
+ if (pop3_store->apop_timestamp)
+ g_free (pop3_store->apop_timestamp);
}
@@ -183,7 +187,7 @@ connect_to_server (CamelService *service, gboolean real, CamelException *ex)
CamelPop3Store *store = CAMEL_POP3_STORE (service);
struct hostent *h;
struct sockaddr_in sin;
- int fd;
+ int fd, status;
char *buf, *apoptime, *apopend;
#ifdef HAVE_KRB4
gboolean kpop = (service->url->port == KPOP_PORT);
@@ -263,11 +267,52 @@ connect_to_server (CamelService *service, gboolean real, CamelException *ex)
}
apoptime = strchr (buf, '<');
apopend = apoptime ? strchr (apoptime, '>') : NULL;
- if (apoptime && apopend) {
+ if (apopend) {
store->apop_timestamp = g_strndup (apoptime,
apopend - apoptime + 1);
+ memmove (apoptime, apopend + 1, strlen (apopend + 1));
+ }
+ store->implementation = buf;
+
+ /* Check extensions */
+ store->login_delay = -1;
+ store->supports_top = -1;
+ store->supports_uidl = -1;
+ store->expires = -1;
+
+ status = camel_pop3_command (store, NULL, "CAPA");
+ if (status == CAMEL_POP3_OK) {
+ char *p;
+ int len;
+
+ buf = camel_pop3_command_get_additional_data (store, ex);
+ if (camel_exception_is_set (ex)) {
+ pop3_disconnect (service, ex);
+ return FALSE;
+ }
+
+ p = buf;
+ while (*p) {
+ len = strcspn (p, "\n");
+ if (!strncmp (p, "IMPLEMENTATION ", 15)) {
+ store->implementation =
+ g_strndup (p + 15, len - 15);
+ } else if (!strncmp (p, "TOP", len))
+ store->supports_top = TRUE;
+ else if (!strncmp (p, "UIDL", len))
+ store->supports_uidl = TRUE;
+ else if (!strncmp (p, "LOGIN-DELAY ", 12))
+ store->login_delay = atoi (p + 12);
+ else if (!strncmp (p, "EXPIRE NEVER", 12))
+ store->expires = FALSE;
+ else if (!strncmp (p, "EXPIRE ", 7))
+ store->expires = TRUE;
+
+ p += len;
+ }
+
+ g_free (buf);
}
- g_free (buf);
return TRUE;
}
diff --git a/camel/providers/pop3/camel-pop3-store.h b/camel/providers/pop3/camel-pop3-store.h
index 41bc069ff9..97d65741f9 100644
--- a/camel/providers/pop3/camel-pop3-store.h
+++ b/camel/providers/pop3/camel-pop3-store.h
@@ -47,7 +47,9 @@ typedef struct {
CamelStore parent_object;
CamelStream *istream, *ostream;
- char *apop_timestamp;
+ char *apop_timestamp, *implementation;
+ gboolean supports_top, supports_uidl, expires;
+ int login_delay;
} CamelPop3Store;