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()
{
if (sessions) {
- g_slist_free_full(sessions, (GDestroyNotify)session_destroy);
+ GSList *list = sessions;
sessions = NULL;
+ g_slist_free_full(list, (GDestroyNotify)session_destroy);
}
}
-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);
}
if (!session->use_auth) {
session->state = SIEVE_READY;
sieve_connected(session, TRUE);
- return sieve_pop_send_queue(session);
+ return SE_OK;
}
session->state = SIEVE_AUTH;
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)
SieveCommand *cmd;
GSList *send_queue = session->send_queue;
+ if (session->current_cmd) {
+ command_free(session->current_cmd);
+ session->current_cmd = NULL;
+ }
+
if (!send_queue)
return SE_OK;
log_send(session, cmd);
session->state = cmd->next_state;
- if (session->current_cmd)
- command_free(session->current_cmd);
session->current_cmd = cmd;
if (session_send_msg(SESSION(session), SESSION_SEND, cmd->msg) < 0)
return SE_ERROR;
{
gchar *end;
+ cm_return_if_fail(msg != NULL);
+
/* response status */
if (isalpha(msg[0])) {
end = strchr(msg, ' ');
{
SieveSession *sieve_session = SIEVE_SESSION(session);
SieveResult result;
- gint ret = 0;
+ gint ret = SE_OK;
switch (sieve_session->state) {
case SIEVE_GETSCRIPT_DATA:
sieve_session->state = SIEVE_ERROR;
} else {
log_warning(LOG_PROTOCOL, "Sieve: continuing without TLS\n");
- sieve_session->state = SIEVE_CAPABILITIES;
+ sieve_session->state = SIEVE_READY;
}
break;
}
} else {
sieve_session->state = SIEVE_READY;
sieve_connected(sieve_session, TRUE);
- ret = sieve_pop_send_queue(sieve_session);
}
} else {
/* got a capability */
}
sieve_session->tls_init_done = TRUE;
sieve_session->state = SIEVE_CAPABILITIES;
- ret = SE_OK;
#endif
break;
case SIEVE_AUTH:
sieve_session->authenticated = TRUE;
sieve_session->state = SIEVE_READY;
sieve_connected(sieve_session, TRUE);
- ret = sieve_pop_send_queue(sieve_session);
}
break;
case SIEVE_NOOP:
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);
- ret = sieve_pop_send_queue(sieve_session);
+ command_cb(sieve_session->current_cmd,
+ (gpointer)&(SieveScript){0});
} else {
/* got a script name */
SieveScript script;
script.active = (script_status &&
strcasecmp(script_status, "active") == 0);
- sieve_session->current_cmd->cb(sieve_session, (gpointer)&script,
- sieve_session->current_cmd->data);
- ret = SE_OK;
+ command_cb(sieve_session->current_cmd,
+ (gpointer)&script);
}
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"));
}
sieve_session->state = SIEVE_READY;
break;
case SIEVE_SETACTIVE:
- if (response_is_no(msg)) {
- /* error */
- sieve_session->current_cmd->cb(sieve_session, NULL,
- sieve_session->current_cmd->data);
- } else if (response_is_ok(msg)) {
- sieve_session->current_cmd->cb(sieve_session, (void*)TRUE,
- sieve_session->current_cmd->data);
+ parse_response((gchar *)msg, &result);
+ if (result.success) {
+ /* clear status possibly set when setting another
+ * script active. TODO: give textual feedback */
+ sieve_error(sieve_session, "");
+
+ command_cb(sieve_session->current_cmd, NULL);
+ } else if (result.description) {
+ command_cb(sieve_session->current_cmd,
+ result.description);
} else {
log_warning(LOG_PROTOCOL, _("error occurred on SIEVE session\n"));
}
- sieve_session->state = SIEVE_READY;
+ if (result.has_octets) {
+ sieve_session->octets_remaining = result.octets;
+ sieve_session->state = SIEVE_SETACTIVE_DATA;
+ } else {
+ sieve_session->state = SIEVE_READY;
+ }
+ break;
+ case SIEVE_SETACTIVE_DATA:
+ /* Dovecot shows a script's warnings when making it active */
+ sieve_session->octets_remaining -= strlen(msg) + 1;
+ if (sieve_session->octets_remaining > 0) {
+ /* TODO: buffer multi-line message */
+ sieve_error(sieve_session, msg);
+ } else {
+ sieve_session->state = SIEVE_READY;
+ }
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);
/* account for newline */
sieve_session->octets_remaining = result.octets + 1;
}
- ret = SE_OK;
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"));
}
- ret = SE_OK;
break;
case SIEVE_PUTSCRIPT:
parse_response((gchar *)msg, &result);
sieve_session->state = SIEVE_READY;
}
sieve_session_putscript_cb(sieve_session, &result);
- ret = SE_OK;
break;
case SIEVE_PUTSCRIPT_DATA:
if (!msg[0]) {
result.description = (gchar *)msg;
sieve_session_putscript_cb(sieve_session, &result);
}
- ret = SE_OK;
break;
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;
return -1;
}
- if (ret == SE_OK)
+ if (ret == SE_OK && sieve_session->state == SIEVE_READY)
+ ret = sieve_pop_send_queue(sieve_session);
+
+ if (ret == SE_OK) {
return session_recv_msg(session);
- else if (ret == SE_AUTHFAIL) {
+ } else if (ret == SE_AUTHFAIL) {
sieve_error(sieve_session, _("Auth failed"));
sieve_session->state = SIEVE_ERROR;
sieve_session->error = SE_ERROR;
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)
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));
{
gboolean queue = FALSE;
SieveCommand *cmd = g_new0(SieveCommand, 1);
+ cmd->session = session;
cmd->next_state = next_state;
cmd->msg = msg;
cmd->data = data;
sieve_queue_send(session, SIEVE_LISTSCRIPTS, msg, cb, data);
}
-void sieve_session_add_script(SieveSession *session, const gchar *filter_name,
- sieve_session_data_cb_fn cb, gpointer data)
-{
-/*
- gchar *msg = g_strdup("LISTSCRIPTS");
- sieve_queue_send(session, SIEVE_LISTSCRIPTS, msg, cb, data);
-*/
-}
-
void sieve_session_set_active_script(SieveSession *session,
const gchar *filter_name,
sieve_session_data_cb_fn cb, gpointer data)
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;
}
sieve_session_data_cb_fn cb, gpointer data)
{
/* TODO: refactor so don't have to copy the whole script here */
- gchar *msg = g_strdup_printf("PUTSCRIPT \"%s\" {%u+}\r\n%s",
- filter_name, len, script_contents);
+ gchar *msg = g_strdup_printf("PUTSCRIPT \"%s\" {%u+}%s%s",
+ filter_name, len, len > 0 ? "\r\n" : "",
+ script_contents);
sieve_queue_send(session, SIEVE_PUTSCRIPT, msg, cb, data);
}
gint len, const gchar *script_contents,
sieve_session_data_cb_fn cb, gpointer data)
{
- gchar *msg = g_strdup_printf("CHECKSCRIPT {%u+}\r\n%s",
- len, script_contents);
+ gchar *msg = g_strdup_printf("CHECKSCRIPT {%u+}%s%s",
+ len, len > 0 ? "\r\n" : "", script_contents);
sieve_queue_send(session, SIEVE_PUTSCRIPT, msg, cb, data);
}