aboutsummaryrefslogtreecommitdiffstats
path: root/camel/providers/pop3
diff options
context:
space:
mode:
Diffstat (limited to 'camel/providers/pop3')
-rw-r--r--camel/providers/pop3/camel-pop3-folder.c80
-rw-r--r--camel/providers/pop3/camel-pop3-store.c128
-rw-r--r--camel/providers/pop3/camel-pop3-store.h3
3 files changed, 204 insertions, 7 deletions
diff --git a/camel/providers/pop3/camel-pop3-folder.c b/camel/providers/pop3/camel-pop3-folder.c
index ad856cc2be..0b2ccb030b 100644
--- a/camel/providers/pop3/camel-pop3-folder.c
+++ b/camel/providers/pop3/camel-pop3-folder.c
@@ -32,11 +32,19 @@
#include <stdlib.h>
#define CF_CLASS(o) (CAMEL_FOLDER_CLASS (GTK_OBJECT (o)->klass))
+static CamelFolderClass *parent_class;
+static void pop3_open (CamelFolder *folder, CamelFolderOpenMode mode,
+ CamelException *ex);
+static void pop3_close (CamelFolder *folder, gboolean expunge,
+ CamelException *ex);
+static gboolean delete_messages (CamelFolder *folder, CamelException *ex);
static gboolean has_message_number_capability (CamelFolder *folder);
static CamelMimeMessage *get_message_by_number (CamelFolder *folder,
gint number,
CamelException *ex);
+static void delete_message_by_number (CamelFolder *folder, gint number,
+ CamelException *ex);
static gint get_message_count (CamelFolder *folder, CamelException *ex);
@@ -45,12 +53,19 @@ camel_pop3_folder_class_init (CamelPop3FolderClass *camel_pop3_folder_class)
{
CamelFolderClass *camel_folder_class =
CAMEL_FOLDER_CLASS (camel_pop3_folder_class);
-
+
+ parent_class = gtk_type_class (camel_folder_get_type ());
+
/* virtual method overload */
+ camel_folder_class->open = pop3_open;
+ camel_folder_class->close = pop3_close;
+ camel_folder_class->delete_messages = delete_messages;
camel_folder_class->has_message_number_capability =
has_message_number_capability;
camel_folder_class->get_message_by_number =
get_message_by_number;
+ camel_folder_class->delete_message_by_number =
+ delete_message_by_number;
camel_folder_class->get_message_count =
get_message_count;
}
@@ -109,6 +124,50 @@ CamelFolder *camel_pop3_folder_new (CamelStore *parent, CamelException *ex)
return folder;
}
+static void
+pop3_open (CamelFolder *folder, CamelFolderOpenMode mode, CamelException *ex)
+{
+ camel_pop3_store_open (CAMEL_POP3_STORE (folder->parent_store), ex);
+ if (camel_exception_get_id (ex) == CAMEL_EXCEPTION_NONE)
+ parent_class->open (folder, mode, ex);
+}
+
+static void
+pop3_close (CamelFolder *folder, gboolean expunge, CamelException *ex)
+{
+ camel_pop3_store_close (CAMEL_POP3_STORE (folder->parent_store),
+ expunge, ex);
+ if (camel_exception_get_id (ex) == CAMEL_EXCEPTION_NONE)
+ parent_class->close (folder, expunge, ex);
+}
+
+static gboolean
+delete_messages (CamelFolder *folder, CamelException *ex)
+{
+ int msgs;
+ gboolean status;
+
+ msgs = get_message_count (folder, ex);
+ if (camel_exception_get_id (ex) != CAMEL_EXCEPTION_NONE)
+ return FALSE;
+
+ status = TRUE;
+ for (; msgs > 0; msgs--) {
+ status = status &&
+ (camel_pop3_command (CAMEL_POP3_STORE (folder->parent_store),
+ NULL, "DELE %d", msgs) ==
+ CAMEL_POP3_OK);
+ }
+
+ if (!status) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ "Unable to delete all messages.");
+ }
+
+ return status;
+}
+
+
static gboolean
has_message_number_capability (CamelFolder *folder)
{
@@ -155,8 +214,25 @@ get_message_by_number (CamelFolder *folder, gint number, CamelException *ex)
return msg;
}
+static void
+delete_message_by_number (CamelFolder *folder, gint number, CamelException *ex)
+{
+ int status;
+ char *resp;
+
+ status = camel_pop3_command (CAMEL_POP3_STORE (folder->parent_store),
+ &resp, "DELE %d", number);
+ if (status != CAMEL_POP3_OK) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID,
+ "Unable to delete message %d%s%s",
+ number, resp ? ": " : "",
+ resp ? resp : "");
+ }
+ g_free (resp);
+}
-static gint get_message_count (CamelFolder *folder, CamelException *ex)
+static gint
+get_message_count (CamelFolder *folder, CamelException *ex)
{
int status, count;
char *result;
diff --git a/camel/providers/pop3/camel-pop3-store.c b/camel/providers/pop3/camel-pop3-store.c
index 61ff4aaddb..8b9ff03fac 100644
--- a/camel/providers/pop3/camel-pop3-store.c
+++ b/camel/providers/pop3/camel-pop3-store.c
@@ -46,7 +46,10 @@
static CamelServiceClass *service_class = NULL;
+static void finalize (GtkObject *object);
+
static gboolean pop3_connect (CamelService *service, CamelException *ex);
+static gboolean pop3_disconnect (CamelService *service, CamelException *ex);
static GList *query_auth_types (CamelService *service);
static void free_auth_types (CamelService *service, GList *authtypes);
@@ -57,6 +60,8 @@ static CamelFolder *get_folder (CamelStore *store, const gchar *folder_name,
static void
camel_pop3_store_class_init (CamelPop3StoreClass *camel_pop3_store_class)
{
+ GtkObjectClass *object_class =
+ GTK_OBJECT_CLASS (camel_pop3_store_class);
CamelServiceClass *camel_service_class =
CAMEL_SERVICE_CLASS (camel_pop3_store_class);
CamelStoreClass *camel_store_class =
@@ -65,7 +70,10 @@ camel_pop3_store_class_init (CamelPop3StoreClass *camel_pop3_store_class)
service_class = gtk_type_class (camel_service_get_type ());
/* virtual method overload */
+ object_class->finalize = finalize;
+
camel_service_class->connect = pop3_connect;
+ camel_service_class->disconnect = pop3_disconnect;
camel_service_class->query_auth_types = query_auth_types;
camel_service_class->free_auth_types = free_auth_types;
@@ -112,6 +120,16 @@ camel_pop3_store_get_type (void)
return camel_pop3_store_type;
}
+static void
+finalize (GtkObject *object)
+{
+ CamelException ex;
+
+ camel_exception_init (&ex);
+ pop3_disconnect (CAMEL_SERVICE (object), &ex);
+ camel_exception_free (&ex);
+}
+
static CamelServiceAuthType password_authtype = {
"Password/APOP",
@@ -123,7 +141,8 @@ static CamelServiceAuthType password_authtype = {
TRUE
};
-static GList *query_auth_types (CamelService *service)
+static GList
+*query_auth_types (CamelService *service)
{
GList *ret;
@@ -131,11 +150,54 @@ static GList *query_auth_types (CamelService *service)
return ret;
}
-static void free_auth_types (CamelService *service, GList *authtypes)
+static void
+free_auth_types (CamelService *service, GList *authtypes)
{
g_list_free (authtypes);
}
+/**
+ * camel_pop3_store_open: Connect to the server if we are currently
+ * disconnected.
+ * @store: the store
+ * @ex: a CamelException
+ *
+ * The POP protocol does not allow deleted messages to be expunged
+ * except by closing the connection. Thus, camel_pop3_folder_{open,close}
+ * sometimes need to connect to or disconnect from the server. This
+ * routine reconnects to the server if we have disconnected.
+ *
+ **/
+void
+camel_pop3_store_open (CamelPop3Store *store, CamelException *ex)
+{
+ CamelService *service = CAMEL_SERVICE (store);
+
+ if (!camel_service_is_connected (service))
+ pop3_connect (service, ex);
+}
+
+/**
+ * camel_pop3_store_close: Close the connection to the server and
+ * possibly expunge deleted messages.
+ * @store: the store
+ * @expunge: whether or not to expunge deleted messages
+ * @ex: a CamelException
+ *
+ * See camel_pop3_store_open for an explanation of why this is needed.
+ *
+ **/
+void
+camel_pop3_store_close (CamelPop3Store *store, gboolean expunge,
+ CamelException *ex)
+{
+ if (expunge)
+ camel_pop3_command (store, NULL, "QUIT");
+ else
+ camel_pop3_command (store, NULL, "RSET");
+ pop3_disconnect (CAMEL_SERVICE (store), ex);
+}
+
static gboolean
pop3_connect (CamelService *service, CamelException *ex)
{
@@ -255,6 +317,27 @@ pop3_connect (CamelService *service, CamelException *ex)
return TRUE;
}
+static gboolean
+pop3_disconnect (CamelService *service, CamelException *ex)
+{
+ CamelPop3Store *store = CAMEL_POP3_STORE (service);
+
+ if (!service->connected)
+ return TRUE;
+
+ if (!service_class->disconnect (service, ex))
+ return FALSE;
+
+ /* Closing the buffered write stream will close the
+ * unbuffered read stream wrapped inside it as well.
+ */
+ camel_stream_close (store->ostream);
+ gtk_object_unref (GTK_OBJECT (store->ostream));
+ store->ostream = NULL;
+ store->istream = NULL;
+ return TRUE;
+}
+
static CamelFolder *get_folder (CamelStore *store, const gchar *folder_name,
CamelException *ex)
{
@@ -267,6 +350,26 @@ static CamelFolder *get_folder (CamelStore *store, const gchar *folder_name,
}
}
+/**
+ * camel_pop3_command: Send a command to a POP3 server.
+ * @store: the POP3 store
+ * @ret: a pointer to return the full server response in
+ * @fmt: a printf-style format string, followed by arguments
+ *
+ * This command sends the command specified by @fmt and the following
+ * arguments to the connected POP3 store specified by @store. It then
+ * reads the server's response and parses out the status code. If
+ * the caller passed a non-NULL pointer for @ret, camel_pop3_command
+ * will set it to point to an buffer containing the rest of the
+ * response from the POP3 server. (If @ret was passed but there was
+ * no extended response, @ret will be set to NULL.) The caller must
+ * free this buffer when it is done with it.
+ *
+ * Return value: one of CAMEL_POP3_OK (command executed successfully),
+ * CAMEL_POP3_ERR (command encounted an error), or CAMEL_POP3_FAIL
+ * (a protocol-level error occurred, and Camel is uncertain of the
+ * result of the command.)
+ **/
int
camel_pop3_command (CamelPop3Store *store, char **ret, char *fmt, ...)
{
@@ -305,6 +408,20 @@ camel_pop3_command (CamelPop3Store *store, char **ret, char *fmt, ...)
return status;
}
+/**
+ * camel_pop3_command_get_additional_data: get "additional data" from
+ * a POP3 command.
+ * @store: the POP3 store
+ *
+ * This command gets the additional data returned by "multi-line" POP
+ * commands, such as LIST, RETR, TOP, and UIDL. This command _must_
+ * be called after a successful (CAMEL_POP3_OK) call to
+ * camel_pop3_command for a command that has a multi-line response.
+ * The returned data is un-byte-stuffed, and has lines termined by
+ * newlines rather than CR/LF pairs.
+ *
+ * Return value: the data, which the caller must free.
+ **/
char *
camel_pop3_command_get_additional_data (CamelPop3Store *store)
{
@@ -329,8 +446,9 @@ camel_pop3_command_get_additional_data (CamelPop3Store *store)
}
if (status == CAMEL_POP3_OK) {
- /* The empty string is so that we end up with a "\n"
- * at the end of the string.
+ /* Append an empty string to the end of the array
+ * so when we g_strjoinv it, we get a "\n" after
+ * the last real line.
*/
g_ptr_array_add (data, "");
g_ptr_array_add (data, NULL);
@@ -338,7 +456,7 @@ camel_pop3_command_get_additional_data (CamelPop3Store *store)
} else
buf = NULL;
- for (i = 0; i < data->len - 1; i++)
+ for (i = 0; i < data->len - 2; i++)
g_free (data->pdata[i]);
g_ptr_array_free (data, TRUE);
diff --git a/camel/providers/pop3/camel-pop3-store.h b/camel/providers/pop3/camel-pop3-store.h
index 23aac3a522..a4373a884a 100644
--- a/camel/providers/pop3/camel-pop3-store.h
+++ b/camel/providers/pop3/camel-pop3-store.h
@@ -59,6 +59,9 @@ typedef struct {
/* public methods */
+void camel_pop3_store_open (CamelPop3Store *store, CamelException *ex);
+void camel_pop3_store_close (CamelPop3Store *store, gboolean expunge,
+ CamelException *ex);
/* support functions */
enum { CAMEL_POP3_OK, CAMEL_POP3_ERR, CAMEL_POP3_FAIL };