aboutsummaryrefslogtreecommitdiffstats
path: root/camel
diff options
context:
space:
mode:
Diffstat (limited to 'camel')
-rw-r--r--camel/ChangeLog14
-rw-r--r--camel/camel-folder.c65
-rw-r--r--camel/camel-folder.h14
-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
6 files changed, 297 insertions, 7 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog
index 4bfe15c373..3d6877ee11 100644
--- a/camel/ChangeLog
+++ b/camel/ChangeLog
@@ -1,3 +1,17 @@
+2000-03-27 Dan Winship <danw@helixcode.com>
+
+ * camel-folder.[ch]: add delete_message_by_{number,uid}.
+
+ * providers/pop3/camel-pop3-folder.[ch]: implement
+ delete_message_by_uid. Add a close method to do expunging
+ of deleted messages if requested.
+
+ * providers/pop3/camel-pop3-store.[ch]: support for
+ CamelPop3Folder::close. (You have to close the connection
+ in order to expunge the folder, thus the store may be
+ connected in the CamelService::is_connected sense when it
+ is not actually connected to the server.) Also some bugfixes.
+
2000-03-27 NotZed <NotZed@HelixCode.com>
* providers/mbox/camel-mbox-folder.c (_append_message): Unref the
diff --git a/camel/camel-folder.c b/camel/camel-folder.c
index f26921526f..8abc5d177b 100644
--- a/camel/camel-folder.c
+++ b/camel/camel-folder.c
@@ -104,6 +104,9 @@ 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);
@@ -129,6 +132,9 @@ static const gchar *_get_message_uid (CamelFolder *folder,
static CamelMimeMessage *_get_message_by_uid (CamelFolder *folder,
const gchar *uid,
CamelException *ex);
+static void _delete_message_by_uid (CamelFolder *folder,
+ const gchar *uid,
+ CamelException *ex);
@@ -168,12 +174,14 @@ camel_folder_class_init (CamelFolderClass *camel_folder_class)
camel_folder_class->expunge = _expunge;
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;
camel_folder_class->append_message = _append_message;
camel_folder_class->list_permanent_flags = _list_permanent_flags;
camel_folder_class->copy_message_to = _copy_message_to;
camel_folder_class->get_message_uid = _get_message_uid;
camel_folder_class->get_message_by_uid = _get_message_by_uid;
+ camel_folder_class->delete_message_by_uid = _delete_message_by_uid;
camel_folder_class->get_uid_list = _get_uid_list;
/* virtual method overload */
@@ -1098,6 +1106,35 @@ camel_folder_get_message_by_number (CamelFolder *folder, gint number, CamelExcep
}
+static void
+_delete_message_by_number (CamelFolder *folder, gint number,
+ CamelException *ex)
+{
+ CAMEL_LOG_WARNING ("Calling CamelFolder::delete_message_by_number "
+ "directly. Should be overloaded\n");
+}
+
+/**
+ * camel_folder_delete_message_by_number: delete the message
+ * corresponding to that number in the folder
+ * @folder: a CamelFolder object
+ * @number: the number of the message within the folder.
+ *
+ * Delete the message corresponding to that number within the folder.
+ *
+ **/
+void
+camel_folder_delete_message_by_number (CamelFolder *folder, gint number,
+ CamelException *ex)
+{
+ g_assert (folder != NULL);
+ g_assert (camel_folder_is_open (folder));
+
+ return CF_CLASS (folder)->delete_message_by_number (folder, number,
+ ex);
+}
+
+
static gint
_get_message_count (CamelFolder *folder, CamelException *ex)
{
@@ -1354,6 +1391,34 @@ camel_folder_get_message_by_uid (CamelFolder *folder, const gchar *uid, CamelEx
return CF_CLASS (folder)->get_message_by_uid (folder, uid, ex);
}
+static void
+_delete_message_by_uid (CamelFolder *folder, const gchar *uid,
+ CamelException *ex)
+{
+ CAMEL_LOG_WARNING ("Calling CamelFolder::delete_message_by_uid "
+ "directly. Should be overloaded\n");
+}
+
+
+/**
+ * camel_folder_delete_message_by_uid: Delete a message by its UID in a folder
+ * @folder: the folder object
+ * @uid: the UID
+ *
+ * Delete a message from a folder given its UID.
+ *
+ **/
+void
+camel_folder_delete_message_by_uid (CamelFolder *folder, const gchar *uid,
+ CamelException *ex)
+{
+ g_assert (folder != NULL);
+ g_assert (folder->has_uid_capability);
+ g_assert (camel_folder_is_open (folder));
+
+ return CF_CLASS (folder)->delete_message_by_uid (folder, uid, ex);
+}
+
static GList *
_get_uid_list (CamelFolder *folder, CamelException *ex)
{
diff --git a/camel/camel-folder.h b/camel/camel-folder.h
index 68a6c8f214..c6a36cd3a7 100644
--- a/camel/camel-folder.h
+++ b/camel/camel-folder.h
@@ -165,6 +165,10 @@ typedef struct {
gint number,
CamelException *ex);
+ void (*delete_message_by_number) (CamelFolder *folder,
+ gint number,
+ CamelException *ex);
+
gint (*get_message_count) (CamelFolder *folder,
CamelException *ex);
@@ -190,6 +194,10 @@ typedef struct {
const gchar *uid,
CamelException *ex);
+ void (*delete_message_by_uid) (CamelFolder *folder,
+ const gchar *uid,
+ CamelException *ex);
+
GList * (*get_uid_list) (CamelFolder *folder,
CamelException *ex);
@@ -287,6 +295,9 @@ gboolean camel_folder_has_message_number_capability (CamelFolder *fold
CamelMimeMessage * camel_folder_get_message_by_number (CamelFolder *folder,
gint number,
CamelException *ex);
+void camel_folder_delete_message_by_number (CamelFolder *folder,
+ gint number,
+ CamelException *ex);
gint camel_folder_get_message_count (CamelFolder *folder,
CamelException *ex);
@@ -299,6 +310,9 @@ const gchar * camel_folder_get_message_uid (CamelFolder *folder,
CamelMimeMessage * camel_folder_get_message_by_uid (CamelFolder *folder,
const gchar *uid,
CamelException *ex);
+void camel_folder_delete_message_by_uid (CamelFolder *folder,
+ const gchar *uid,
+ CamelException *ex);
GList * camel_folder_get_uid_list (CamelFolder *folder,
CamelException *ex);
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 };