managesieve: fix command aborting and discarding
authorCharles Lehner <cel@celehner.com>
Fri, 17 Jul 2015 00:06:47 +0000 (20:06 -0400)
committerCharles Lehner <cel@celehner.com>
Fri, 17 Jul 2015 03:24:32 +0000 (23:24 -0400)
- Add "aborted" callback argument to indicate command is cancelled
- Add helper function for issuing command callbacks

src/plugins/managesieve/managesieve.c
src/plugins/managesieve/managesieve.h
src/plugins/managesieve/sieve_editor.c
src/plugins/managesieve/sieve_manager.c

index a6d7bbb..323c52d 100644 (file)
@@ -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;
        }
 
index c150d4a..068f8bb 100644 (file)
@@ -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;
index a6be14f..eedd3e7 100644 (file)
@@ -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);
 }
 
index 9e89bad..400a671 100644 (file)
@@ -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;