[Commits] [SCM] claws branch, master, updated. 3.12.0-15-g8be3195
charles at claws-mail.org
charles at claws-mail.org
Wed Jul 22 03:34:56 CEST 2015
The branch, master has been updated
via 8be31955028980da209a38dea361c57d43fba96b (commit)
via 510d72d37de71c76e5ab11fd673e8f5685505c0a (commit)
via a5fcd7b5d797115135e308e9a25f8436c0462714 (commit)
from bd4e7f852004067a820a9f4fd9036ebfc235b1bb (commit)
Summary of changes:
src/plugins/managesieve/managesieve.c | 277 +++++++++++++++++++++++++-------
src/plugins/managesieve/managesieve.h | 2 -
src/plugins/managesieve/sieve_editor.c | 12 +-
3 files changed, 224 insertions(+), 67 deletions(-)
- Log -----------------------------------------------------------------
commit 8be31955028980da209a38dea361c57d43fba96b
Author: Charles Lehner <charles at claws-mail.org>
Date: Tue Jul 21 21:18:33 2015 -0400
managesieve: read literals in chunks, not line-by-line
This adds a way to read data chunks with a known length from a Session, rather
than until a newline or terminator string is reached. It is used to let Sieve
scripts be loaded faster.
diff --git a/src/plugins/managesieve/managesieve.c b/src/plugins/managesieve/managesieve.c
index 4e7508a..1a09620 100644
--- a/src/plugins/managesieve/managesieve.c
+++ b/src/plugins/managesieve/managesieve.c
@@ -21,6 +21,7 @@
#include <glib.h>
#include <glib/gi18n.h>
#include <ctype.h>
+#include <errno.h>
#include "claws.h"
#include "account.h"
@@ -42,6 +43,9 @@ 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);
+static gint sieve_session_recv_chunk(SieveSession *, guint len);
+static void sieve_read_chunk(SieveSession *, gchar *data, guint len);
+static gint sieve_read_chunk_done(SieveSession *session);
void sieve_sessions_close()
{
@@ -127,6 +131,125 @@ static void sieve_connected(SieveSession *session, gboolean connected)
session->on_connected(session, connected, session->cb_data);
}
+static gboolean sieve_read_chunk_cb(SockInfo *source,
+ GIOCondition condition, gpointer data)
+{
+ SieveSession *sieve_session = SIEVE_SESSION(data);
+ Session *session = &sieve_session->session;
+ gint data_len;
+ gint ret;
+
+ cm_return_val_if_fail(condition == G_IO_IN, FALSE);
+
+ session_set_timeout(session, session->timeout_interval);
+
+ if (session->read_buf_len == 0) {
+ gint read_len = -1;
+
+ if (session->sock)
+ read_len = sock_read(session->sock,
+ session->read_buf,
+ SESSION_BUFFSIZE - 1);
+
+ if (read_len == -1 &&
+ session->state == SESSION_DISCONNECTED) {
+ g_warning ("sock_read: session disconnected\n");
+ if (session->io_tag > 0) {
+ g_source_remove(session->io_tag);
+ session->io_tag = 0;
+ }
+ return FALSE;
+ }
+
+ if (read_len == 0) {
+ g_warning("sock_read: received EOF\n");
+ session->state = SESSION_EOF;
+ return FALSE;
+ }
+
+ if (read_len < 0) {
+ switch (errno) {
+ case EAGAIN:
+ return TRUE;
+ default:
+ g_warning("sock_read: %s\n",
+ g_strerror(errno));
+ session->state = SESSION_ERROR;
+ return FALSE;
+ }
+ }
+
+ session->read_buf_len = read_len;
+ }
+
+ data_len = MIN(session->read_buf_len,
+ sieve_session->octets_remaining);
+ sieve_session->octets_remaining -= data_len;
+ session->read_buf_len -= data_len;
+ session->read_buf_p[data_len] = '\0';
+
+ /* progress callback */
+ sieve_read_chunk(sieve_session, session->read_buf_p, data_len);
+
+ if (session->read_buf_len == 0) {
+ session->read_buf_p = session->read_buf;
+ } else {
+ session->read_buf_p += data_len;
+ }
+
+ /* incomplete read */
+ if (sieve_session->octets_remaining > 0)
+ return TRUE;
+
+ /* complete */
+ if (session->io_tag > 0) {
+ g_source_remove(session->io_tag);
+ session->io_tag = 0;
+ }
+
+ /* completion callback */
+ ret = sieve_read_chunk_done(sieve_session);
+
+ if (ret < 0)
+ session->state = SESSION_ERROR;
+
+ return FALSE;
+}
+
+static gboolean sieve_read_chunk_idle_cb(gpointer data)
+{
+ Session *session = SESSION(data);
+ gboolean ret;
+
+ ret = sieve_read_chunk_cb(session->sock, G_IO_IN, session);
+
+ if (ret == TRUE)
+ session->io_tag = sock_add_watch(session->sock, G_IO_IN,
+ sieve_read_chunk_cb, session);
+
+ return G_SOURCE_REMOVE;
+}
+
+/* Get data of specified length.
+ * If needed elsewhere, this should be put in session.c */
+static gint sieve_session_recv_chunk(SieveSession *sieve_session,
+ guint bytes)
+{
+ Session *session = &sieve_session->session;
+ cm_return_val_if_fail(session->read_msg_buf->len == 0, -1);
+
+ session->state = SESSION_RECV;
+ sieve_session->octets_remaining = bytes;
+
+ if (session->read_buf_len > 0)
+ g_idle_add(sieve_read_chunk_idle_cb, session);
+ else
+ session->io_tag = sock_add_watch(session->sock, G_IO_IN,
+ sieve_read_chunk_cb, session);
+ return 0;
+}
+
+
static gint sieve_auth_recv(SieveSession *session, const gchar *msg)
{
gchar buf[MESSAGEBUFSIZE], *tmp;
@@ -328,9 +451,18 @@ static gint sieve_auth(SieveSession *session)
static void sieve_session_putscript_cb(SieveSession *session, SieveResult *result)
{
/* Remove script name from the beginning the response,
- * which are added by Dovecot/Pigeonhole */
+ * which is added by Dovecot/Pigeonhole */
gchar *start, *desc = result->description;
- if (desc) {
+ gchar *end = NULL;
+ if (!desc) {
+ /* callback just for the status */
+ command_cb(session->current_cmd, result);
+ }
+ while (desc && desc[0]) {
+ if ((end = strchr(desc, '\r')) ||
+ (end = strchr(desc, '\n')))
+ while (*end == '\n' || *end == '\r')
+ *end++ = '\0';
if (g_str_has_prefix(desc, "NULL_") && (start = strchr(desc+5, ':'))) {
desc = start+1;
while (*desc == ' ')
@@ -342,9 +474,9 @@ static void sieve_session_putscript_cb(SieveSession *session, SieveResult *resul
desc = start+2;
}
result->description = desc;
+ command_cb(session->current_cmd, result);
+ desc = end;
}
- /* pass along the callback */
- command_cb(session->current_cmd, result);
}
static inline gboolean response_is_ok(const char *msg)
@@ -536,27 +668,21 @@ static gint sieve_session_recv_msg(Session *session, const gchar *msg)
SieveResult result;
gint ret = SE_OK;
- switch (sieve_session->state) {
- case SIEVE_GETSCRIPT_DATA:
- log_print(LOG_PROTOCOL, "Sieve< [GETSCRIPT data]\n");
- break;
- default:
- log_print(LOG_PROTOCOL, "Sieve< %s\n", msg);
- if (response_is_bye(msg)) {
- gchar *status;
- parse_response((gchar *)msg, &result);
- if (!result.description)
- status = g_strdup(_("Disconnected"));
- else if (g_str_has_prefix(result.description, "Disconnected"))
- status = g_strdup(result.description);
- else
- status = g_strdup_printf(_("Disconnected: %s"), result.description);
- sieve_session->error = SE_ERROR;
- sieve_error(sieve_session, status);
- sieve_session->state = SIEVE_DISCONNECTED;
- g_free(status);
- return -1;
- }
+ log_print(LOG_PROTOCOL, "Sieve< %s\n", msg);
+ if (response_is_bye(msg)) {
+ gchar *status;
+ parse_response((gchar *)msg, &result);
+ if (!result.description)
+ status = g_strdup(_("Disconnected"));
+ else if (g_str_has_prefix(result.description, "Disconnected"))
+ status = g_strdup(result.description);
+ else
+ status = g_strdup_printf(_("Disconnected: %s"), result.description);
+ sieve_session->error = SE_ERROR;
+ sieve_error(sieve_session, status);
+ sieve_session->state = SIEVE_DISCONNECTED;
+ g_free(status);
+ return -1;
}
switch (sieve_session->state) {
@@ -596,6 +722,8 @@ static gint sieve_session_recv_msg(Session *session, const gchar *msg)
}
break;
case SIEVE_READY:
+ if (!msg[0])
+ break;
log_warning(LOG_PROTOCOL,
_("unhandled message on Sieve session: %s\n"), msg);
break;
@@ -688,18 +816,8 @@ static gint sieve_session_recv_msg(Session *session, const gchar *msg)
log_warning(LOG_PROTOCOL, _("error occurred on SIEVE session\n"));
}
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);
+ return sieve_session_recv_chunk(sieve_session,
+ result.octets);
} else {
sieve_session->state = SIEVE_READY;
}
@@ -711,41 +829,31 @@ static gint sieve_session_recv_msg(Session *session, const gchar *msg)
} else {
parse_response((gchar *)msg, &result);
sieve_session->state = SIEVE_GETSCRIPT_DATA;
- /* account for newline */
- sieve_session->octets_remaining = result.octets + 1;
+ return sieve_session_recv_chunk(sieve_session,
+ result.octets);
}
break;
case SIEVE_GETSCRIPT_DATA:
- if (sieve_session->octets_remaining > 0) {
- 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;
+ if (!msg[0])
+ break;
+ sieve_session->state = SIEVE_READY;
+ if (response_is_ok(msg)) {
command_cb(sieve_session->current_cmd, NULL);
- } else {
+ } else if (msg[0]) {
log_warning(LOG_PROTOCOL, _("error occurred on SIEVE session\n"));
}
break;
case SIEVE_PUTSCRIPT:
+ if (!msg[0])
+ break;
parse_response((gchar *)msg, &result);
+ sieve_session_putscript_cb(sieve_session, &result);
if (result.has_octets) {
- sieve_session->state = SIEVE_PUTSCRIPT_DATA;
+ return sieve_session_recv_chunk(sieve_session,
+ result.octets);
} else {
sieve_session->state = SIEVE_READY;
}
- sieve_session_putscript_cb(sieve_session, &result);
- break;
- case SIEVE_PUTSCRIPT_DATA:
- if (!msg[0]) {
- sieve_session->state = SIEVE_READY;
- } else {
- result.has_status = FALSE;
- result.has_octets = FALSE;
- result.success = -1;
- result.code = SIEVE_CODE_NONE;
- result.description = (gchar *)msg;
- sieve_session_putscript_cb(sieve_session, &result);
- }
break;
case SIEVE_DELETESCRIPT:
parse_response((gchar *)msg, &result);
@@ -793,6 +901,57 @@ static gint sieve_recv_message(Session *session, const gchar *msg,
return 0;
}
+static void sieve_read_chunk(SieveSession *session, gchar *data, guint len)
+{
+ log_print(LOG_PROTOCOL, "Sieve< [%u bytes]\n", len);
+
+ switch (session->state) {
+ case SIEVE_GETSCRIPT_DATA:
+ command_cb(session->current_cmd, (gchar *)data);
+ break;
+ case SIEVE_SETACTIVE:
+ /* Dovecot shows a script's warnings when making it active */
+ /* TODO: append message in case it is very long*/
+ strretchomp(data);
+ sieve_error(session, data);
+ break;
+ case SIEVE_PUTSCRIPT: {
+ SieveResult result = {.description = (gchar *)data};
+ sieve_session_putscript_cb(session, &result);
+ break;
+ }
+ default:
+ log_warning(LOG_PROTOCOL,
+ _("error occurred on SIEVE session\n"));
+ }
+}
+
+static gint sieve_read_chunk_done(SieveSession *session)
+{
+ gint ret = SE_OK;
+
+ switch (session->state) {
+ case SIEVE_GETSCRIPT_DATA:
+ /* wait for ending "OK" response */
+ break;
+ case SIEVE_SETACTIVE:
+ case SIEVE_PUTSCRIPT:
+ session->state = SIEVE_READY;
+ break;
+ default:
+ log_warning(LOG_PROTOCOL,
+ _("error occurred on SIEVE session\n"));
+ }
+
+ if (ret == SE_OK && session->state == SIEVE_READY)
+ ret = sieve_pop_send_queue(session);
+
+ if (ret == SE_OK)
+ return session_recv_msg(SESSION(session));
+
+ return 0;
+}
+
static gint sieve_cmd_noop(SieveSession *session)
{
log_print(LOG_PROTOCOL, "Sieve> NOOP\n");
diff --git a/src/plugins/managesieve/managesieve.h b/src/plugins/managesieve/managesieve.h
index f5c5fbb..cf26ed0 100644
--- a/src/plugins/managesieve/managesieve.h
+++ b/src/plugins/managesieve/managesieve.h
@@ -71,11 +71,9 @@ typedef enum
SIEVE_AUTH_CRAM_MD5,
SIEVE_RENAMESCRIPT,
SIEVE_SETACTIVE,
- SIEVE_SETACTIVE_DATA,
SIEVE_GETSCRIPT,
SIEVE_GETSCRIPT_DATA,
SIEVE_PUTSCRIPT,
- SIEVE_PUTSCRIPT_DATA,
SIEVE_DELETESCRIPT,
SIEVE_ERROR,
SIEVE_DISCONNECTED,
diff --git a/src/plugins/managesieve/sieve_editor.c b/src/plugins/managesieve/sieve_editor.c
index 5dc56a1..8c41f68 100644
--- a/src/plugins/managesieve/sieve_editor.c
+++ b/src/plugins/managesieve/sieve_editor.c
@@ -313,7 +313,6 @@ static void got_data_reverting(SieveSession *session, gboolean abort,
/* append data */
gtk_text_buffer_insert(buffer, &end, contents, strlen(contents));
} else {
- sieve_editor_append_text(page, "\n", 1);
sieve_editor_append_text(page, contents, strlen(contents));
}
}
@@ -729,8 +728,6 @@ static void got_data_loading(SieveSession *session, gboolean aborted,
if (page->first_line) {
page->first_line = FALSE;
sieve_editor_show(page);
- } else {
- sieve_editor_append_text(page, "\n", 1);
}
sieve_editor_append_text(page, contents, strlen(contents));
}
commit 510d72d37de71c76e5ab11fd673e8f5685505c0a
Author: Charles Lehner <charles at claws-mail.org>
Date: Tue Jul 21 21:11:15 2015 -0400
managesieve: count script length in bytes, not characters
diff --git a/src/plugins/managesieve/sieve_editor.c b/src/plugins/managesieve/sieve_editor.c
index 2931c86..5dc56a1 100644
--- a/src/plugins/managesieve/sieve_editor.c
+++ b/src/plugins/managesieve/sieve_editor.c
@@ -140,7 +140,8 @@ static gint sieve_editor_get_text(SieveEditorPage *page, gchar **text)
gtk_text_buffer_get_start_iter(buffer, &start);
gtk_text_buffer_get_end_iter(buffer, &end);
*text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
- return gtk_text_iter_get_offset(&end) - gtk_text_iter_get_offset(&start);
+ /* return length in bytes */
+ return strlen(*text);
}
static void sieve_editor_set_status(SieveEditorPage *page, const gchar *status)
commit a5fcd7b5d797115135e308e9a25f8436c0462714
Author: Charles Lehner <charles at claws-mail.org>
Date: Tue Jul 21 20:43:44 2015 -0400
managesieve: fix memory leak
diff --git a/src/plugins/managesieve/sieve_editor.c b/src/plugins/managesieve/sieve_editor.c
index f8b43ee..2931c86 100644
--- a/src/plugins/managesieve/sieve_editor.c
+++ b/src/plugins/managesieve/sieve_editor.c
@@ -158,12 +158,14 @@ static void sieve_editor_set_status_icon(SieveEditorPage *page, const gchar *img
}
static void sieve_editor_append_status(SieveEditorPage *page,
- const gchar *status)
+ const gchar *new_status)
{
GtkLabel *label = GTK_LABEL(page->status_text);
const gchar *prev_status = gtk_label_get_text(label);
const gchar *sep = prev_status && prev_status[0] ? "\n" : "";
- gtk_label_set_text(label, g_strconcat(prev_status, sep, status, NULL));
+ gchar *status = g_strconcat(prev_status, sep, new_status, NULL);
+ gtk_label_set_text(label, status);
+ g_free(status);
}
/* Update the status icon and text from a response. */
-----------------------------------------------------------------------
hooks/post-receive
--
Claws Mail
More information about the Commits
mailing list