commit 32924ce7e82afbe83ffa9087fa56694825c6d0ef
parent 99738a91f6c2ca14fb8feeef9be42904556cf97f
Author: Charles Lehner <cel@celehner.com>
Date: Thu, 16 Jul 2015 20:06:47 -0400
managesieve: fix command aborting and discarding
- Add "aborted" callback argument to indicate command is cancelled
- Add helper function for issuing command callbacks
Diffstat:
4 files changed, 93 insertions(+), 61 deletions(-)
diff --git a/src/plugins/managesieve/managesieve.c b/src/plugins/managesieve/managesieve.c
@@ -39,6 +39,9 @@ GSList *sessions = NULL;
static void sieve_session_destroy(Session *session);
static gint sieve_pop_send_queue(SieveSession *session);
static void sieve_session_reset(SieveSession *session);
+static void command_free(SieveCommand *cmd);
+static void command_abort(SieveCommand *cmd);
+static void command_cb(SieveCommand *cmd, gpointer result);
void sieve_sessions_close()
{
@@ -48,34 +51,55 @@ void sieve_sessions_close()
}
}
-void noop_data_cb_fn(SieveSession *session, gpointer cb_data,
- gpointer user_data)
-{
- /* noop */
-}
-
/* remove all command callbacks with a given data pointer */
void sieve_sessions_discard_callbacks(gpointer user_data)
{
GSList *item;
GSList *queue;
+ GSList *prev = NULL;
SieveSession *session;
SieveCommand *cmd;
for (item = sessions; item; item = item->next) {
session = (SieveSession *)item->data;
cmd = session->current_cmd;
- if (cmd && cmd->data == user_data)
- cmd->cb = noop_data_cb_fn;
+ /* abort current command handler */
+ if (cmd && cmd->data == user_data) {
+ command_abort(cmd);
+ session->current_cmd = NULL;
+ }
+ /* abort queued command handlers */
for (queue = session->send_queue; queue; queue = queue->next) {
- cmd = (SieveCommand *)item->data;
- if (cmd && cmd->data == user_data)
- cmd->cb = noop_data_cb_fn;
+ cmd = (SieveCommand *)queue->data;
+ if (cmd && cmd->data == user_data) {
+ if (prev)
+ prev->next = queue->next;
+ else
+ session->send_queue = NULL;
+ command_abort(cmd);
+ g_slist_free_1(queue);
+ } else {
+ prev = queue;
+ }
}
}
}
-void command_free(SieveCommand *cmd) {
+static void command_cb(SieveCommand *cmd, gpointer result)
+{
+ if (cmd)
+ cmd->cb(cmd->session, FALSE, result, cmd->data);
+}
+
+static void command_abort(SieveCommand *cmd)
+{
+ cmd->cb(cmd->session, TRUE, NULL, cmd->data);
+ g_free(cmd->msg);
+ g_free(cmd);
+}
+
+static void command_free(SieveCommand *cmd)
+{
g_free(cmd->msg);
g_free(cmd);
}
@@ -319,7 +343,7 @@ static void sieve_session_putscript_cb(SieveSession *session, SieveResult *resul
result->description = desc;
}
/* pass along the callback */
- session->current_cmd->cb(session, result, session->current_cmd->data);
+ command_cb(session->current_cmd, result);
}
static inline gboolean response_is_ok(const char *msg)
@@ -614,17 +638,15 @@ static gint sieve_session_recv_msg(Session *session, const gchar *msg)
case SIEVE_LISTSCRIPTS:
if (response_is_no(msg)) {
/* got an error. probably not authenticated. */
- sieve_session->current_cmd->cb(sieve_session, NULL,
- sieve_session->current_cmd->data);
+ command_cb(sieve_session->current_cmd, NULL);
sieve_session->state = SIEVE_READY;
ret = sieve_pop_send_queue(sieve_session);
} else if (response_is_ok(msg)) {
/* end of list */
sieve_session->state = SIEVE_READY;
sieve_session->error = SE_OK;
- sieve_session->current_cmd->cb(sieve_session,
- (gpointer)&(SieveScript){0},
- sieve_session->current_cmd->data);
+ command_cb(sieve_session->current_cmd,
+ (gpointer)&(SieveScript){0});
ret = sieve_pop_send_queue(sieve_session);
} else {
/* got a script name */
@@ -635,19 +657,17 @@ static gint sieve_session_recv_msg(Session *session, const gchar *msg)
script.active = (script_status &&
strcasecmp(script_status, "active") == 0);
- sieve_session->current_cmd->cb(sieve_session, (gpointer)&script,
- sieve_session->current_cmd->data);
+ command_cb(sieve_session->current_cmd,
+ (gpointer)&script);
ret = SE_OK;
}
break;
case SIEVE_RENAMESCRIPT:
if (response_is_no(msg)) {
/* error */
- sieve_session->current_cmd->cb(sieve_session, NULL,
- sieve_session->current_cmd->data);
+ command_cb(sieve_session->current_cmd, NULL);
} else if (response_is_ok(msg)) {
- sieve_session->current_cmd->cb(sieve_session, (void*)TRUE,
- sieve_session->current_cmd->data);
+ command_cb(sieve_session->current_cmd, (void*)TRUE);
} else {
log_warning(LOG_PROTOCOL, _("error occurred on SIEVE session\n"));
}
@@ -656,11 +676,9 @@ static gint sieve_session_recv_msg(Session *session, const gchar *msg)
case SIEVE_SETACTIVE:
if (response_is_no(msg)) {
/* error */
- sieve_session->current_cmd->cb(sieve_session, NULL,
- sieve_session->current_cmd->data);
+ command_cb(sieve_session->current_cmd, NULL);
} else if (response_is_ok(msg)) {
- sieve_session->current_cmd->cb(sieve_session, (void*)TRUE,
- sieve_session->current_cmd->data);
+ command_cb(sieve_session->current_cmd, (void*)TRUE);
} else {
log_warning(LOG_PROTOCOL, _("error occurred on SIEVE session\n"));
}
@@ -668,8 +686,7 @@ static gint sieve_session_recv_msg(Session *session, const gchar *msg)
break;
case SIEVE_GETSCRIPT:
if (response_is_no(msg)) {
- sieve_session->current_cmd->cb(sieve_session, (void *)-1,
- sieve_session->current_cmd->data);
+ command_cb(sieve_session->current_cmd, (void *)-1);
sieve_session->state = SIEVE_READY;
} else {
parse_response((gchar *)msg, &result);
@@ -681,14 +698,11 @@ static gint sieve_session_recv_msg(Session *session, const gchar *msg)
break;
case SIEVE_GETSCRIPT_DATA:
if (sieve_session->octets_remaining > 0) {
- sieve_session->current_cmd->cb(sieve_session,
- (gchar *)msg,
- sieve_session->current_cmd->data);
+ command_cb(sieve_session->current_cmd, (gchar *)msg);
sieve_session->octets_remaining -= strlen(msg) + 1;
} else if (response_is_ok(msg)) {
sieve_session->state = SIEVE_READY;
- sieve_session->current_cmd->cb(sieve_session, NULL,
- sieve_session->current_cmd->data);
+ command_cb(sieve_session->current_cmd, NULL);
} else {
log_warning(LOG_PROTOCOL, _("error occurred on SIEVE session\n"));
}
@@ -720,11 +734,10 @@ static gint sieve_session_recv_msg(Session *session, const gchar *msg)
case SIEVE_DELETESCRIPT:
parse_response((gchar *)msg, &result);
if (!result.success) {
- sieve_session->current_cmd->cb(sieve_session, result.description,
- sieve_session->current_cmd->data);
+ command_cb(sieve_session->current_cmd,
+ result.description);
} else {
- sieve_session->current_cmd->cb(sieve_session, NULL,
- sieve_session->current_cmd->data);
+ command_cb(sieve_session->current_cmd, NULL);
}
sieve_session->state = SIEVE_READY;
break;
@@ -791,8 +804,10 @@ static void sieve_session_destroy(Session *session)
SieveSession *sieve_session = SIEVE_SESSION(session);
g_free(sieve_session->pass);
if (sieve_session->current_cmd)
- command_free(sieve_session->current_cmd);
+ command_abort(sieve_session->current_cmd);
sessions = g_slist_remove(sessions, (gconstpointer)session);
+ g_slist_free_full(sieve_session->send_queue,
+ (GDestroyNotify)command_abort);
}
static void sieve_connect_finished(Session *session, gboolean success)
@@ -834,7 +849,7 @@ static void sieve_session_reset(SieveSession *session)
SieveAccountConfig *config = sieve_prefs_account_get_config(account);
gboolean reuse_auth = (config->auth == SIEVEAUTH_REUSE);
- g_slist_free_full(session->send_queue, (GDestroyNotify)command_free);
+ g_slist_free_full(session->send_queue, (GDestroyNotify)command_abort);
session_disconnect(SESSION(session));
@@ -921,6 +936,7 @@ static void sieve_queue_send(SieveSession *session, SieveState next_state,
{
gboolean queue = FALSE;
SieveCommand *cmd = g_new0(SieveCommand, 1);
+ cmd->session = session;
cmd->next_state = next_state;
cmd->msg = msg;
cmd->data = data;
@@ -980,7 +996,7 @@ void sieve_session_set_active_script(SieveSession *session,
gchar *msg = g_strdup_printf("SETACTIVE \"%s\"",
filter_name ? filter_name : "");
if (!msg) {
- cb(session, (void*)FALSE, data);
+ cb(session, FALSE, (void*)FALSE, data);
return;
}
diff --git a/src/plugins/managesieve/managesieve.h b/src/plugins/managesieve/managesieve.h
@@ -98,7 +98,7 @@ typedef enum {
typedef void (*sieve_session_cb_fn) (SieveSession *session, gpointer data);
typedef void (*sieve_session_data_cb_fn) (SieveSession *session,
- gpointer cb_data, gpointer user_data);
+ gboolean aborted, gpointer cb_data, gpointer user_data);
typedef void (*sieve_session_error_cb_fn) (SieveSession *session,
const gchar *msg, gpointer user_data);
typedef void (*sieve_session_connected_cb_fn) (SieveSession *session,
@@ -140,6 +140,7 @@ struct SieveSession
};
struct SieveCommand {
+ SieveSession *session;
SieveState next_state;
gchar *msg;
sieve_session_data_cb_fn cb;
diff --git a/src/plugins/managesieve/sieve_editor.c b/src/plugins/managesieve/sieve_editor.c
@@ -266,9 +266,12 @@ static void sieve_editor_search(SieveEditorPage *page)
/* Actions */
-static void got_data_reverting(SieveSession *session, gchar *contents,
+static void got_data_reverting(SieveSession *session, gboolean abort,
+ gchar *contents,
SieveEditorPage *page)
{
+ if (abort)
+ return;
if (contents == NULL) {
/* end of data */
undo_unblock(page->undostruct);
@@ -324,9 +327,11 @@ static void sieve_editor_revert_cb(GtkAction *action, SieveEditorPage *page)
sieve_editor_revert(page);
}
-static void got_data_saved(SieveSession *session, SieveResult *result,
- SieveEditorPage *page)
+static void got_data_saved(SieveSession *session, gboolean abort,
+ SieveResult *result, SieveEditorPage *page)
{
+ if (abort)
+ return;
if (result->has_status && result->success) {
sieve_editor_set_modified(page, FALSE);
if (page->closing) {
@@ -362,9 +367,11 @@ static void sieve_editor_find_cb(GtkAction *action, SieveEditorPage *page)
sieve_editor_search(page);
}
-static void got_data_checked(SieveSession *session, SieveResult *result,
- SieveEditorPage *page)
+static void got_data_checked(SieveSession *session, gboolean abort,
+ SieveResult *result, SieveEditorPage *page)
{
+ if (abort)
+ return;
sieve_editor_update_status(page, result);
}
diff --git a/src/plugins/managesieve/sieve_manager.c b/src/plugins/managesieve/sieve_manager.c
@@ -164,13 +164,13 @@ static void filter_add(GtkWidget *widget, SieveManagerPage *page)
*/
}
-static void filter_got_data(SieveSession *session, gchar *contents,
- CommandDataGetScript *cmd_data)
+static void filter_got_data(SieveSession *session, gboolean abort,
+ gchar *contents, CommandDataGetScript *cmd_data)
{
SieveManagerPage *page = cmd_data->page;
SieveEditorPage *editor;
- if (!contents) {
+ if (abort || !contents) {
g_free(cmd_data->filter_name);
g_free(cmd_data);
return;
@@ -215,13 +215,14 @@ static void filter_edit(GtkWidget *widget, SieveManagerPage *page)
}
}
-static void filter_renamed(SieveSession *session, gboolean success,
- CommandDataRename *data)
+static void filter_renamed(SieveSession *session, gboolean abort,
+ gboolean success, CommandDataRename *data)
{
SieveManagerPage *page = data->page;
GSList *cur;
- if (!success) {
+ if (abort) {
+ } else if (!success) {
got_session_error(session, "Unable to rename script", page);
} else {
manager_sessions_foreach(cur, session, page) {
@@ -261,13 +262,14 @@ static void filter_rename(GtkWidget *widget, SieveManagerPage *page)
(sieve_session_data_cb_fn)filter_renamed, (gpointer)cmd_data);
}
-static void filter_activated(SieveSession *session, gboolean success,
- CommandDataName *cmd_data)
+static void filter_activated(SieveSession *session, gboolean abort,
+ gboolean success, CommandDataName *cmd_data)
{
SieveManagerPage *page = cmd_data->page;
GSList *cur;
- if (!success) {
+ if (abort) {
+ } else if (!success) {
got_session_error(session, "Unable to set active script", page);
} else {
manager_sessions_foreach(cur, session, page) {
@@ -292,13 +294,15 @@ static void sieve_set_active_filter(SieveManagerPage *page, gchar *filter_name)
(sieve_session_data_cb_fn)filter_activated, cmd_data);
}
-static void filter_deleted(SieveSession *session, const gchar *err_msg,
+static void filter_deleted(SieveSession *session, gboolean abort,
+ const gchar *err_msg,
CommandDataName *cmd_data)
{
SieveManagerPage *page = cmd_data->page;
GSList *cur;
- if (err_msg) {
+ if (abort) {
+ } else if (err_msg) {
got_session_error(session, err_msg, page);
} else {
manager_sessions_foreach(cur, session, page) {
@@ -550,6 +554,8 @@ static void size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation)
static void got_session_error(SieveSession *session, const gchar *msg,
SieveManagerPage *page)
{
+ if (!g_slist_find(manager_pages, page))
+ return;
if (page->active_session != session)
return;
gtk_label_set_text(GTK_LABEL(page->status_text), msg);
@@ -575,9 +581,11 @@ static void sieve_manager_on_connected(SieveSession *session,
}
}
-static void got_filter_listed(SieveSession *session, SieveScript *script,
- SieveManagerPage *page)
+static void got_filter_listed(SieveSession *session, gboolean abort,
+ SieveScript *script, SieveManagerPage *page)
{
+ if (abort)
+ return;
if (!script) {
got_session_error(session, "Unable to list scripts", page);
return;