managesieve: fix command aborting and discarding

- Add "aborted" callback argument to indicate command is cancelled
- Add helper function for issuing command callbacks
This commit is contained in:
Charles Lehner 2015-07-16 20:06:47 -04:00
parent 99738a91f6
commit 32924ce7e8
4 changed files with 93 additions and 61 deletions

View 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;
}

View 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;

View 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);
}

View 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;