From 49b37933f943d47bfa6518d30ca12026c83802d9 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Thu, 15 Jun 2000 19:38:00 +0000 Subject: Check server for various interesting extensions. * 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 svn path=/trunk/; revision=3578 --- camel/ChangeLog | 7 ++ camel/providers/pop3/camel-pop3-folder.c | 170 +++++++++++++++++++++++++------ camel/providers/pop3/camel-pop3-folder.h | 3 +- camel/providers/pop3/camel-pop3-store.c | 51 +++++++++- camel/providers/pop3/camel-pop3-store.h | 4 +- 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 + * 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; -- cgit