[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