[Commits] [SCM] claws branch, gtk3, updated. 3.16.0-223-gafb888f

ticho at claws-mail.org ticho at claws-mail.org
Mon Jun 11 13:17:26 CEST 2018


The branch, gtk3 has been updated
       via  afb888f0752b0a72c540686bcc87a6f09e3d6ac8 (commit)
       via  aedbcf598e6158e8dad3e83a0b36b862a805b071 (commit)
       via  51ae22db181118e8f4c6450ec6e7c8344651c75b (commit)
       via  dbb3153c5c90a23777415ad4a72aab54ce564e80 (commit)
       via  ff566d10643c2b4ed05b230f036bd454fce73771 (commit)
       via  67ced10190629b23529d3098c9b686592338aef3 (commit)
       via  8f139f2a1c4ca17123e68899fd6634317be20f8f (commit)
       via  ad39cec75255dc1cb6dcc8673a080ab8b435a18e (commit)
       via  51fd2be1343e1ec7722c892d23188045c67f404e (commit)
       via  845a1ee156c662e8f9245beb27f405d1ac49882c (commit)
       via  29ce3575e56789547ee612df02e331f2f2476f28 (commit)
       via  6e6295e1023b8a09169bd22695b3360939bd931e (commit)
       via  7dbdb3ebae0d47f19edc5b490e49bd317b775d8e (commit)
       via  997324a908aa1e6533ed2e604ea55cf96a99a631 (commit)
       via  534d04d477a97a61c0a015ffcaa784b4b8e78f16 (commit)
      from  ea396ce934502170a544cc12c0289ae4599ea57e (commit)

Summary of changes:
 doc/src/password_encryption.txt           |   15 +-
 po/POTFILES.in                            |    2 +
 src/Makefile.am                           |    2 +
 src/account.c                             |   72 +++++++
 src/account.h                             |    5 +
 src/common/Makefile.am                    |    2 +
 src/common/proxy.c                        |  300 +++++++++++++++++++++++++++++
 src/{etpan/etpan-ssl.h => common/proxy.h} |   42 ++--
 src/common/session.c                      |   19 ++
 src/common/session.h                      |    9 +
 src/common/socket.c                       |    8 +-
 src/common/utils.c                        |   18 --
 src/common/utils.h                        |   13 --
 src/etpan/imap-thread.c                   |   90 ++++++++-
 src/etpan/imap-thread.h                   |    4 +-
 src/etpan/nntp-thread.c                   |   88 ++++++++-
 src/etpan/nntp-thread.h                   |    5 +-
 src/filtering.c                           |    4 +-
 src/gtk/gtkutils.c                        |    2 +-
 src/gtk/gtkutils.h                        |    2 +-
 src/html.c                                |   11 +-
 src/imap.c                                |   27 ++-
 src/inc.c                                 |   37 +++-
 src/main.c                                |    3 +
 src/mainwindow.c                          |   11 +-
 src/news.c                                |   58 +++---
 src/password.c                            |   26 ++-
 src/passwordstore.h                       |    4 +
 src/plugins/libravatar/libravatar.c       |    2 +-
 src/plugins/libravatar/libravatar_prefs.c |   10 +-
 src/plugins/libravatar/libravatar_prefs.h |    2 +-
 src/plugins/managesieve/managesieve.c     |   20 ++
 src/plugins/vcalendar/vcal_dbus.c         |   34 ++--
 src/prefs_account.c                       |  279 ++++++++++++++++++++++++++-
 src/prefs_account.h                       |    6 +
 src/prefs_common.c                        |    9 +
 src/prefs_common.h                        |    4 +
 src/prefs_proxy.c                         |  237 +++++++++++++++++++++++
 src/{gtk/about.h => prefs_proxy.h}        |   12 +-
 src/procmime.c                            |    9 +-
 src/quote_fmt_parse.y                     |    6 +-
 src/send_message.c                        |   20 +-
 src/summaryview.c                         |    2 +-
 src/textview.c                            |   23 ++-
 src/wizard.c                              |   16 +-
 45 files changed, 1388 insertions(+), 182 deletions(-)
 create mode 100644 src/common/proxy.c
 copy src/{etpan/etpan-ssl.h => common/proxy.h} (54%)
 create mode 100644 src/prefs_proxy.c
 copy src/{gtk/about.h => prefs_proxy.h} (80%)


- Log -----------------------------------------------------------------
commit afb888f0752b0a72c540686bcc87a6f09e3d6ac8
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Mon Jun 11 10:46:11 2018 +0200

    Corrected copyright header in proxy.[ch]

diff --git a/src/common/proxy.c b/src/common/proxy.c
index db21429..9902b0d 100644
--- a/src/common/proxy.c
+++ b/src/common/proxy.c
@@ -1,6 +1,6 @@
 /*
  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2014 Hiroyuki Yamamoto
+ * Copyright (C) 2018 the Claws Mail team
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/common/proxy.h b/src/common/proxy.h
index c009cc4..8f527ac 100644
--- a/src/common/proxy.h
+++ b/src/common/proxy.h
@@ -1,6 +1,6 @@
 /*
  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2010 Hiroyuki Yamamoto
+ * Copyright (C) 2018 the Claws Mail team
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by

commit aedbcf598e6158e8dad3e83a0b36b862a805b071
Author: wwp <wwp at free.fr>
Date:   Mon Jun 11 09:32:50 2018 +0200

    Fix use of uninitialized pointer, CID#1436911.

diff --git a/src/filtering.c b/src/filtering.c
index d0f0e83..9a3cd95 100644
--- a/src/filtering.c
+++ b/src/filtering.c
@@ -473,8 +473,8 @@ static gboolean filteringaction_apply(FilteringAction * action, MsgInfo * info)
 			AddressBookFile *abf = NULL;
 			ItemFolder *folder = NULL;
 #endif
-			gchar *buf;
-			Header *header;
+			gchar *buf = NULL;
+			Header *header = NULL;
 			gint errors = 0;
 
 #ifndef USE_ALT_ADDRBOOK

commit 51ae22db181118e8f4c6450ec6e7c8344651c75b
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Sun Jun 10 23:09:18 2018 +0200

    Fixed an off-by-one buffer overflow in proxy.c.

diff --git a/src/common/proxy.c b/src/common/proxy.c
index 7bde533..db21429 100644
--- a/src/common/proxy.c
+++ b/src/common/proxy.c
@@ -257,7 +257,7 @@ gint socks5_connect(SockInfo *sock, const gchar *hostname, gushort port,
 		} else if (socks_req[3] == 3) { /* Domain name */
 			gint hnlen = socks_req[4];
 			gchar *hn = malloc(hnlen + 1);
-			hn[hnlen + 1] = '\0';
+			hn[hnlen] = '\0';
 			memcpy(hn, &socks_req[5], hnlen);
 			g_warning("socks5_connect: SOCKS5 connection to %s:%u failed. (%u)",
 					hn, ntohs(*(gushort *)(socks_req + 5 + hnlen)), socks_req[1]);
@@ -265,7 +265,7 @@ gint socks5_connect(SockInfo *sock, const gchar *hostname, gushort port,
 		} else if (socks_req[3] == 4) { /* IPv6 address */
 			gint hnlen = 16;
 			gchar *hn = malloc(hnlen + 1);
-			hn[hnlen + 1] = '\0';
+			hn[hnlen] = '\0';
 			memcpy(hn, &socks_req[4], hnlen);
 			g_warning("socks5_connect: SOCKS5 connection to IPv6 %s:%u failed. (%u)",
 					hn, ntohs(*(gushort *)(socks_req + 5 + hnlen)), socks_req[1]);

commit dbb3153c5c90a23777415ad4a72aab54ce564e80
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Sun Jun 10 15:15:49 2018 +0200

    Fix up POTFILES.in to match previous commit (d28d62772).

diff --git a/po/POTFILES.in b/po/POTFILES.in
index cee9aa9..0af1ab4 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -17,7 +17,7 @@ src/common/plugin.c
 src/common/session.c
 src/common/smtp.c
 src/common/socket.c
-src/common/socks.c
+src/common/proxy.c
 src/common/ssl.c
 src/common/ssl_certificate.c
 src/common/string_match.c
@@ -200,6 +200,7 @@ src/prefs_message.c
 src/prefs_migration.c
 src/prefs_msg_colors.c
 src/prefs_other.c
+src/prefs_proxy.c
 src/prefs_quote.c
 src/prefs_receive.c
 src/prefs_send.c

commit ff566d10643c2b4ed05b230f036bd454fce73771
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Fri May 18 20:27:52 2018 +0200

    Added SOCKS proxy support.
    
    Based on UI and network code from LibSylph/Sylpheed, rewritten
    to use getaddrinfo(), fixed some small bugs in handling errors.
    
    Added connect wrappers for etpan IMAP and NNTP, as well as for
    anything Session-based (POP3, SMTP, Managesieve).
    
    Adds support for global, as well as per-account proxy servers.
    
    Original patch by Charles Lehner <cel at celehner com>, from
    bug #2244.

diff --git a/po/POTFILES.in b/po/POTFILES.in
index c0a7d39..cee9aa9 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -17,6 +17,7 @@ src/common/plugin.c
 src/common/session.c
 src/common/smtp.c
 src/common/socket.c
+src/common/socks.c
 src/common/ssl.c
 src/common/ssl_certificate.c
 src/common/string_match.c
diff --git a/src/Makefile.am b/src/Makefile.am
index d2d1548..1fb6dcd 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -202,6 +202,7 @@ claws_mail_SOURCES = \
 	prefs_migration.c \
 	prefs_msg_colors.c \
 	prefs_other.c \
+	prefs_proxy.c \
 	prefs_quote.c \
 	prefs_receive.c \
 	prefs_send.c \
@@ -322,6 +323,7 @@ claws_mailinclude_HEADERS = \
 	prefs_migration.h \
 	prefs_msg_colors.h \
 	prefs_other.h \
+	prefs_proxy.h \
 	prefs_quote.h \
 	prefs_receive.h \
 	prefs_send.h \
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index 1dd8e91..f9ad434 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -27,6 +27,7 @@ libclawscommon_la_SOURCES = $(arch_sources) \
 	plugin.c \
 	prefs.c \
 	progressindicator.c \
+	proxy.c \
 	quoted-printable.c \
 	session.c \
 	smtp.c \
@@ -55,6 +56,7 @@ clawscommoninclude_HEADERS = $(arch_headers) \
 	plugin.h \
 	prefs.h \
 	progressindicator.h \
+	proxy.h \
 	quoted-printable.h \
 	session.h \
 	smtp.h \
diff --git a/src/common/proxy.c b/src/common/proxy.c
new file mode 100644
index 0000000..7bde533
--- /dev/null
+++ b/src/common/proxy.c
@@ -0,0 +1,300 @@
+/*
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2014 Hiroyuki Yamamoto
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <glib.h>
+
+#ifdef G_OS_WIN32
+#  include <winsock2.h>
+#  include <ws2tcpip.h>
+#endif
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include "proxy.h"
+#include "socket.h"
+#include "utils.h"
+
+gint socks4_connect(SockInfo *sock, const gchar *hostname, gushort port);
+gint socks5_connect(SockInfo *sock, const gchar *hostname, gushort port,
+		const gchar *proxy_name, const gchar *proxy_pass);
+
+gint proxy_connect(SockInfo *sock, const gchar *hostname, gushort port,
+		   ProxyInfo *proxy_info)
+{
+	gint ret;
+
+	g_return_val_if_fail(sock != NULL, -1);
+	g_return_val_if_fail(hostname != NULL, -1);
+	g_return_val_if_fail(proxy_info != NULL, -1);
+
+	debug_print("proxy_connect: connect to %s:%u via %s:%u\n",
+		    hostname, port,
+		    proxy_info->proxy_host, proxy_info->proxy_port);
+
+	if (proxy_info->proxy_type == PROXY_SOCKS5) {
+		ret = socks5_connect(sock, hostname, port,
+				      proxy_info->use_proxy_auth ? proxy_info->proxy_name : NULL,
+				      proxy_info->use_proxy_auth ? proxy_info->proxy_pass : NULL);
+		/* Scrub the password before returning */
+		if (proxy_info->proxy_pass != NULL) {
+			memset(proxy_info->proxy_pass, 0, strlen(proxy_info->proxy_pass));
+			g_free(proxy_info->proxy_pass);
+		}
+		return ret;
+	} else if (proxy_info->proxy_type == PROXY_SOCKS4) {
+		return socks4_connect(sock, hostname, port);
+	} else {
+		g_warning("proxy_connect: unknown SOCKS type: %d\n",
+			  proxy_info->proxy_type);
+	}
+
+	return -1;
+}
+
+gint socks4_connect(SockInfo *sock, const gchar *hostname, gushort port)
+{
+	guchar socks_req[1024];
+	struct addrinfo hints, *res, *ai;
+	gboolean got_address = FALSE;
+	int s;
+
+	g_return_val_if_fail(sock != NULL, -1);
+	g_return_val_if_fail(hostname != NULL, -1);
+
+	debug_print("socks4_connect: connect to %s:%u\n", hostname, port);
+
+	socks_req[0] = 4;
+	socks_req[1] = 1;
+	*((gushort *)(socks_req + 2)) = htons(port);
+
+	/* lookup */
+	memset(&hints, 0, sizeof(struct addrinfo));
+	hints.ai_family = AF_INET; /* SOCKS4 only supports IPv4 addresses */
+
+	s = getaddrinfo(hostname, NULL, &hints, &res);
+	if (s != 0) {
+		fprintf(stderr, "getaddrinfo for '%s' failed: %s\n",
+				hostname, gai_strerror(s));
+		return -1;
+	}
+
+	for (ai = res; ai != NULL; ai = ai->ai_next) {
+		uint32_t addr;
+
+		if (ai->ai_family != AF_INET)
+			continue;
+
+		addr = ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr;
+		memcpy(socks_req + 4, &addr, 4);
+		got_address = TRUE;
+		break;
+	}
+
+	if (res != NULL)
+		freeaddrinfo(res);
+
+	if (!got_address) {
+		g_warning("socks4_connect: could not get valid IPv4 address for '%s'", hostname);
+		return -1;
+	}
+
+	debug_print("got a valid IPv4 address, continuing\n");
+
+	/* userid (empty) */
+	socks_req[8] = 0;
+
+	if (sock_write_all(sock, (gchar *)socks_req, 9) != 9) {
+		g_warning("socks4_connect: SOCKS4 initial request write failed");
+		return -1;
+	}
+
+	if (sock_read(sock, (gchar *)socks_req, 8) != 8) {
+		g_warning("socks4_connect: SOCKS4 response read failed");
+		return -1;
+	}
+	if (socks_req[0] != 0) {
+		g_warning("socks4_connect: SOCKS4 response has invalid version");
+		return -1;
+	}
+	if (socks_req[1] != 90) {
+		g_warning("socks4_connect: SOCKS4 connection to %u.%u.%u.%u:%u failed. (%u)", socks_req[4], socks_req[5], socks_req[6], socks_req[7], ntohs(*(gushort *)(socks_req + 2)), socks_req[1]);
+		return -1;
+	}
+
+	/* replace sock->hostname with endpoint */
+	if (sock->hostname != hostname) {
+		g_free(sock->hostname);
+		sock->hostname = g_strdup(hostname);
+		sock->port = port;
+	}
+
+	debug_print("socks4_connect: SOCKS4 connection to %s:%u successful.\n", hostname, port);
+
+	return 0;
+}
+
+gint socks5_connect(SockInfo *sock, const gchar *hostname, gushort port,
+		    const gchar *proxy_name, const gchar *proxy_pass)
+{
+	guchar socks_req[1024];
+	size_t len;
+	size_t size;
+
+	g_return_val_if_fail(sock != NULL, -1);
+	g_return_val_if_fail(hostname != NULL, -1);
+
+	debug_print("socks5_connect: connect to %s:%u\n", hostname, port);
+
+	len = strlen(hostname);
+	if (len > 255) {
+		g_warning("socks5_connect: hostname too long");
+		return -1;
+	}
+
+	socks_req[0] = 5;
+	socks_req[1] = proxy_name ? 2 : 1;
+	socks_req[2] = 0;
+	socks_req[3] = 2;
+
+	if (sock_write_all(sock, (gchar *)socks_req, 2 + socks_req[1]) != 2 + socks_req[1]) {
+		g_warning("socks5_connect: SOCKS5 initial request write failed");
+		return -1;
+	}
+
+	if (sock_read(sock, (gchar *)socks_req, 2) != 2) {
+		g_warning("socks5_connect: SOCKS5 response read failed");
+		return -1;
+	}
+	if (socks_req[0] != 5) {
+		g_warning("socks5_connect: SOCKS5 response has invalid version");
+		return -1;
+	}
+	if (socks_req[1] == 2) {
+		/* auth */
+		size_t userlen, passlen;
+		gint reqlen;
+
+		if (proxy_name && proxy_pass) {
+			debug_print("socks5_connect: auth using username '%s'\n", proxy_name);
+			userlen = strlen(proxy_name);
+			passlen = strlen(proxy_pass);
+		} else
+			userlen = passlen = 0;
+
+		socks_req[0] = 1;
+		socks_req[1] = (guchar)userlen;
+		if (proxy_name && userlen > 0)
+			memcpy(socks_req + 2, proxy_name, userlen);
+		socks_req[2 + userlen] = (guchar)passlen;
+		if (proxy_pass && passlen > 0)
+			memcpy(socks_req + 2 + userlen + 1, proxy_pass, passlen);
+
+		reqlen = 2 + userlen + 1 + passlen;
+		if (sock_write_all(sock, (gchar *)socks_req, reqlen) != reqlen) {
+			memset(socks_req, 0, reqlen);
+			g_warning("socks5_connect: SOCKS5 auth write failed");
+			return -1;
+		}
+		memset(socks_req, 0, reqlen);
+		if (sock_read(sock, (gchar *)socks_req, 2) != 2) {
+			g_warning("socks5_connect: SOCKS5 auth response read failed");
+			return -1;
+		}
+		if (socks_req[1] != 0) {
+			g_warning("socks5_connect: SOCKS5 authentication failed: user: %s (%u %u)", proxy_name ? proxy_name : "(none)", socks_req[0], socks_req[1]);
+			return -1;
+		}
+	} else if (socks_req[1] != 0) {
+		g_warning("socks5_connect: SOCKS5 reply (%u) error", socks_req[1]);
+		return -1;
+	}
+
+	socks_req[0] = 5;
+	socks_req[1] = 1;
+	socks_req[2] = 0;
+
+	socks_req[3] = 3;
+	socks_req[4] = (guchar)len;
+	memcpy(socks_req + 5, hostname, len);
+	*((gushort *)(socks_req + 5 + len)) = htons(port);
+
+	if (sock_write_all(sock, (gchar *)socks_req, 5 + len + 2) != 5 + len + 2) {
+		g_warning("socks5_connect: SOCKS5 connect request write failed");
+		return -1;
+	}
+
+	if (sock_read(sock, (gchar *)socks_req, 10) != 10) {
+		g_warning("socks5_connect: SOCKS5 connect request response read failed");
+		return -1;
+	}
+	if (socks_req[0] != 5) {
+		g_warning("socks5_connect: SOCKS5 response has invalid version");
+		return -1;
+	}
+	if (socks_req[1] != 0) {
+		if (socks_req[3] == 1) { /* IPv4 address */
+			g_warning("socks5_connect: SOCKS5 connection to %u.%u.%u.%u:%u failed. (%u)", socks_req[4], socks_req[5], socks_req[6], socks_req[7], ntohs(*(gushort *)(socks_req + 8)), socks_req[1]);
+		} else if (socks_req[3] == 3) { /* Domain name */
+			gint hnlen = socks_req[4];
+			gchar *hn = malloc(hnlen + 1);
+			hn[hnlen + 1] = '\0';
+			memcpy(hn, &socks_req[5], hnlen);
+			g_warning("socks5_connect: SOCKS5 connection to %s:%u failed. (%u)",
+					hn, ntohs(*(gushort *)(socks_req + 5 + hnlen)), socks_req[1]);
+			g_free(hn);
+		} else if (socks_req[3] == 4) { /* IPv6 address */
+			gint hnlen = 16;
+			gchar *hn = malloc(hnlen + 1);
+			hn[hnlen + 1] = '\0';
+			memcpy(hn, &socks_req[4], hnlen);
+			g_warning("socks5_connect: SOCKS5 connection to IPv6 %s:%u failed. (%u)",
+					hn, ntohs(*(gushort *)(socks_req + 5 + hnlen)), socks_req[1]);
+			g_free(hn);
+		}
+		return -1;
+	}
+
+	size = 10;
+	if (socks_req[3] == 3)
+		size = 5 + socks_req[4] + 2;
+	else if (socks_req[3] == 4)
+		size = 4 + 16 + 2;
+	if (size > 10) {
+		size -= 10;
+		if (sock_read(sock, (gchar *)socks_req + 10, size) != size) {
+			g_warning("socks5_connect: SOCKS5 connect request response read failed");
+			return -1;
+		}
+	}
+
+	/* replace sock->hostname with endpoint */
+	if (sock->hostname != hostname) {
+		g_free(sock->hostname);
+		sock->hostname = g_strdup(hostname);
+		sock->port = port;
+	}
+
+	debug_print("socks5_connect: SOCKS5 connection to %s:%u successful.\n", hostname, port);
+
+	return 0;
+}
diff --git a/src/common/proxy.h b/src/common/proxy.h
new file mode 100644
index 0000000..c009cc4
--- /dev/null
+++ b/src/common/proxy.h
@@ -0,0 +1,54 @@
+/*
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2010 Hiroyuki Yamamoto
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __PROXY_H__
+#define __PROXY_H__
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <glib.h>
+
+#include "socket.h"
+
+typedef struct _ProxyInfo ProxyInfo;
+
+typedef enum {
+	PROXY_SOCKS4,
+	PROXY_SOCKS5
+} ProxyType;
+
+struct _ProxyInfo
+{
+	ProxyType proxy_type;
+	gchar *proxy_host;
+	gushort proxy_port;
+
+	gboolean use_proxy_auth;
+	gchar *proxy_name;
+	gchar *proxy_pass;
+};
+
+/* As a side effect, this function will zero out and free
+ * string pointed to by proxy_info->proxy_pass after the password
+ * is no longer needed. */
+gint proxy_connect(SockInfo *sock, const gchar *hostname, gushort port,
+		   ProxyInfo *proxy_info);
+
+#endif /* __PROXY_H__ */
diff --git a/src/common/session.c b/src/common/session.c
index 0e4a62d..1342ef9 100644
--- a/src/common/session.c
+++ b/src/common/session.c
@@ -102,6 +102,8 @@ void session_init(Session *session, const void *prefs_account, gboolean is_smtp)
 	session->is_smtp = is_smtp;
 
 	session->ping_tag = -1;
+
+	session->proxy_info = NULL;
 }
 
 /*!
@@ -123,6 +125,11 @@ gint session_connect(Session *session, const gchar *server, gushort port)
 	session->server = g_strdup(server);
 	session->port = port;
 
+	if (session->proxy_info) {
+		server = session->proxy_info->proxy_host;
+		port = session->proxy_info->proxy_port;
+	}
+
 	session->conn_id = sock_connect_async(server, port, session_connect_cb,
 					      session);
 	if (session->conn_id < 0) {
@@ -173,6 +180,18 @@ static gint session_connect_cb(SockInfo *sock, gpointer data)
 	sock->is_smtp = session->is_smtp;
 	sock->ssl_cert_auto_accept = session->ssl_cert_auto_accept;
 
+	if (session->proxy_info) {
+		debug_print("connecting through socks\n");
+		sock_set_nonblocking_mode(sock, FALSE);
+		if (proxy_connect(sock, session->server, session->port,
+					session->proxy_info) < 0) {
+			g_warning("can't establish SOCKS connection.");
+			session->state = SESSION_ERROR;
+			return -1;
+		}
+	}
+
+
 #ifdef USE_GNUTLS
 	sock->gnutls_priority = session->gnutls_priority;
 
diff --git a/src/common/session.h b/src/common/session.h
index 72b4512..5cd518b 100644
--- a/src/common/session.h
+++ b/src/common/session.h
@@ -30,6 +30,7 @@
 #include <unistd.h>
 
 #include "socket.h"
+#include "proxy.h"
 
 #define SESSION_BUFFSIZE	4096
 
@@ -148,6 +149,14 @@ struct _Session
 	gboolean ssl_cert_auto_accept;
 	gint ping_tag;
 
+	/* Pointer to ProxyInfo struct holding the info about proxy
+	 * to be used. Set to NULL if no proxy is used.
+	 * If non-NULL, the memory this pointer is pointing at does
+	 * not belong to this Session, and shouldn't be modified
+	 * or freed by Session. It is usually a pointer to the
+	 * SockInfo in common prefs, or in account prefs. */
+	ProxyInfo *proxy_info;
+
 #ifdef USE_GNUTLS
 	SSLType ssl_type;
 	gchar *gnutls_priority;
diff --git a/src/common/socket.c b/src/common/socket.c
index f401f28..7751f62 100644
--- a/src/common/socket.c
+++ b/src/common/socket.c
@@ -589,7 +589,7 @@ static gint sock_connect_with_timeout(gint sock,
 				      gint addrlen,
 				      guint timeout_secs)
 {
-	gint ret;
+	gint ret, saved_errno;
 #ifdef G_OS_UNIX
 	void (*prev_handler)(gint);
 	
@@ -606,6 +606,12 @@ static gint sock_connect_with_timeout(gint sock,
 #endif
 
 	ret = connect(sock, serv_addr, addrlen);
+	saved_errno = errno;
+
+	if (ret == -1) {
+		debug_print("connect() failed: %d (%s)\n",
+				saved_errno, g_strerror(saved_errno));
+	}
 
 #ifdef G_OS_UNIX
 	alarm(0);
diff --git a/src/etpan/imap-thread.c b/src/etpan/imap-thread.c
index 093f78a..80279d2 100644
--- a/src/etpan/imap-thread.c
+++ b/src/etpan/imap-thread.c
@@ -43,6 +43,7 @@
 #include "etpan-ssl.h"
 #include "utils.h"
 #include "mainwindow.h"
+#include "proxy.h"
 #include "ssl.h"
 #include "ssl_certificate.h"
 #include "socket.h"
@@ -58,6 +59,79 @@ static chash * session_hash = NULL;
 static guint thread_manager_signal = 0;
 static GIOChannel * io_channel = NULL;
 
+static int do_mailimap_socket_connect(mailimap * imap, const char * server,
+			       gushort port, ProxyInfo * proxy_info)
+{
+	SockInfo * sock;
+	mailstream * stream;
+
+	if (!proxy_info)
+		return mailimap_socket_connect(imap, server, port);
+
+	if (port == 0)
+		port = 143;
+
+	sock = sock_connect(proxy_info->proxy_host, proxy_info->proxy_port);
+
+	if (sock == NULL)
+		return MAILIMAP_ERROR_CONNECTION_REFUSED;
+
+	if (proxy_connect(sock, server, port, proxy_info) < 0) {
+		sock_close(sock);
+		return MAILIMAP_ERROR_CONNECTION_REFUSED;
+	}
+
+	stream = mailstream_socket_open_timeout(sock->sock,
+			imap->imap_timeout);
+	if (stream == NULL) {
+		sock_close(sock);
+		return MAILIMAP_ERROR_MEMORY;
+	}
+
+	return mailimap_connect(imap, stream);
+}
+
+static int do_mailimap_ssl_connect_with_callback(mailimap * imap, const char * server,
+	gushort port,
+	void (* callback)(struct mailstream_ssl_context * ssl_context, void * data),
+	void * data,
+	ProxyInfo *proxy_info)
+{
+	SockInfo * sock;
+	mailstream * stream;
+
+	if (!proxy_info)
+		return mailimap_ssl_connect_with_callback(imap, server,
+				port, callback, data);
+
+	if (port == 0)
+		port = 993;
+
+	sock = sock_connect(proxy_info->proxy_host, proxy_info->proxy_port);
+
+	if (sock == NULL) {
+		debug_print("Can not connect to proxy %s:%d\n",
+				proxy_info->proxy_host, proxy_info->proxy_port);
+		return MAILIMAP_ERROR_CONNECTION_REFUSED;
+	}
+
+	if (proxy_connect(sock, server, port, proxy_info) < 0) {
+		debug_print("Can not make proxy connection via %s:%d\n",
+				proxy_info->proxy_host, proxy_info->proxy_port);
+		sock_close(sock);
+		return MAILIMAP_ERROR_CONNECTION_REFUSED;
+	}
+
+	stream = mailstream_ssl_open_with_callback_timeout(sock->sock,
+			imap->imap_timeout, callback, data);
+	if (stream == NULL) {
+		sock_close(sock);
+		return MAILIMAP_ERROR_SSL;
+	}
+
+	return mailimap_connect(imap, stream);
+}
+
 static gboolean thread_manager_event(GIOChannel * source,
     GIOCondition condition,
     gpointer data)
@@ -446,6 +520,7 @@ struct connect_param {
 	PrefsAccount *account;
 	const char * server;
 	int port;
+	ProxyInfo * proxy_info;
 };
 
 struct connect_result {
@@ -519,14 +594,14 @@ static void connect_run(struct etpan_thread_op * op)
 	
 	CHECK_IMAP();
 
-	r = mailimap_socket_connect(param->imap,
-				    param->server, param->port);
+	r = do_mailimap_socket_connect(param->imap,
+				    param->server, param->port, param->proxy_info);
 	
 	result->error = r;
 }
 
 
-int imap_threaded_connect(Folder * folder, const char * server, int port)
+int imap_threaded_connect(Folder * folder, const char * server, int port, ProxyInfo *proxy_info)
 {
 	struct connect_param param;
 	struct connect_result result;
@@ -552,6 +627,7 @@ int imap_threaded_connect(Folder * folder, const char * server, int port)
 	param.imap = imap;
 	param.server = server;
 	param.port = port;
+	param.proxy_info = proxy_info;
 
 	refresh_resolvers();
 	threaded_run(folder, &param, &result, connect_run);
@@ -572,13 +648,14 @@ static void connect_ssl_run(struct etpan_thread_op * op)
 	
 	CHECK_IMAP();
 
-	r = mailimap_ssl_connect_with_callback(param->imap,
+	r = do_mailimap_ssl_connect_with_callback(param->imap,
 				 		param->server, param->port,
-						etpan_connect_ssl_context_cb, param->account);
+						etpan_connect_ssl_context_cb, param->account,
+						param->proxy_info);
 	result->error = r;
 }
 
-int imap_threaded_connect_ssl(Folder * folder, const char * server, int port)
+int imap_threaded_connect_ssl(Folder * folder, const char * server, int port, ProxyInfo *proxy_info)
 {
 	struct connect_param param;
 	struct connect_result result;
@@ -606,6 +683,7 @@ int imap_threaded_connect_ssl(Folder * folder, const char * server, int port)
 	param.server = server;
 	param.port = port;
 	param.account = folder->account;
+	param.proxy_info = proxy_info;
 
 	if (folder->account)
 		accept_if_valid = folder->account->ssl_certs_auto_accept;
diff --git a/src/etpan/imap-thread.h b/src/etpan/imap-thread.h
index 30bce70..e9826a0 100644
--- a/src/etpan/imap-thread.h
+++ b/src/etpan/imap-thread.h
@@ -45,8 +45,8 @@ void imap_main_done(gboolean have_connectivity);
 void imap_init(Folder * folder);
 void imap_done(Folder * folder);
 
-int imap_threaded_connect(Folder * folder, const char * server, int port);
-int imap_threaded_connect_ssl(Folder * folder, const char * server, int port);
+int imap_threaded_connect(Folder * folder, const char * server, int port, ProxyInfo *proxy_info);
+int imap_threaded_connect_ssl(Folder * folder, const char * server, int port, ProxyInfo *proxy_info);
 int imap_threaded_capability(Folder *folder, struct mailimap_capability_data ** caps);
 
 #ifndef G_OS_WIN32
diff --git a/src/etpan/nntp-thread.c b/src/etpan/nntp-thread.c
index 3c147d2..ccaede9 100644
--- a/src/etpan/nntp-thread.c
+++ b/src/etpan/nntp-thread.c
@@ -60,6 +60,75 @@ static chash * session_hash = NULL;
 static guint thread_manager_signal = 0;
 static GIOChannel * io_channel = NULL;
 
+static int do_newsnntp_socket_connect(newsnntp * imap, const char * server,
+			       gushort port, ProxyInfo * proxy_info)
+{
+	SockInfo * sock;
+	mailstream * stream;
+
+	if (!proxy_info)
+		return newsnntp_socket_connect(imap, server, port);
+
+	if (port == 0)
+		port = 119;
+
+	sock = sock_connect(proxy_info->proxy_host, proxy_info->proxy_port);
+
+	if (sock == NULL)
+		return NEWSNNTP_ERROR_CONNECTION_REFUSED;
+
+	if (proxy_connect(sock, server, port, proxy_info) < 0) {
+		sock_close(sock);
+		return NEWSNNTP_ERROR_CONNECTION_REFUSED;
+	}
+
+	stream = mailstream_socket_open_timeout(sock->sock,
+			imap->nntp_timeout);
+	if (stream == NULL) {
+		sock_close(sock);
+		return NEWSNNTP_ERROR_MEMORY;
+	}
+
+	return newsnntp_connect(imap, stream);
+}
+
+static int do_newsnntp_ssl_connect_with_callback(newsnntp * imap, const char * server,
+	gushort port,
+	void (* callback)(struct mailstream_ssl_context * ssl_context, void * data),
+	void * data,
+	ProxyInfo *proxy_info)
+{
+	SockInfo * sock;
+	mailstream * stream;
+
+	if (!proxy_info)
+		return newsnntp_ssl_connect_with_callback(imap, server,
+				port, callback, data);
+
+	if (port == 0)
+		port = 563;
+
+	sock = sock_connect(proxy_info->proxy_host, proxy_info->proxy_port);
+
+	if (sock == NULL)
+		return NEWSNNTP_ERROR_CONNECTION_REFUSED;
+
+	if (proxy_connect(sock, server, port, proxy_info) < 0) {
+		sock_close(sock);
+		return NEWSNNTP_ERROR_CONNECTION_REFUSED;
+	}
+
+	stream = mailstream_ssl_open_with_callback_timeout(sock->sock,
+			imap->nntp_timeout, callback, data);
+	if (stream == NULL) {
+		sock_close(sock);
+		return NEWSNNTP_ERROR_SSL;
+	}
+
+	return newsnntp_connect(imap, stream);
+}
+
+
 static void nntp_logger(int direction, const char * str, size_t size) 
 {
 	gchar *buf;
@@ -309,6 +378,7 @@ struct connect_param {
 	PrefsAccount *account;
 	const char * server;
 	int port;
+	ProxyInfo * proxy_info;
 };
 
 struct connect_result {
@@ -333,14 +403,15 @@ static void connect_run(struct etpan_thread_op * op)
 	
 	CHECK_NNTP();
 
-	r = newsnntp_socket_connect(param->nntp,
-				    param->server, param->port);
+	r = do_newsnntp_socket_connect(param->nntp,
+				    param->server, param->port,
+				    param->proxy_info);
 	
 	result->error = r;
 }
 
 
-int nntp_threaded_connect(Folder * folder, const char * server, int port)
+int nntp_threaded_connect(Folder * folder, const char * server, int port, ProxyInfo *proxy_info)
 {
 	struct connect_param param;
 	struct connect_result result;
@@ -366,7 +437,8 @@ int nntp_threaded_connect(Folder * folder, const char * server, int port)
 	param.nntp = nntp;
 	param.server = server;
 	param.port = port;
-	
+	param.proxy_info = proxy_info;
+
 	refresh_resolvers();
 	threaded_run(folder, &param, &result, connect_run);
 	
@@ -386,13 +458,14 @@ static void connect_ssl_run(struct etpan_thread_op * op)
 	
 	CHECK_NNTP();
 
-	r = newsnntp_ssl_connect_with_callback(param->nntp,
+	r = do_newsnntp_ssl_connect_with_callback(param->nntp,
 				 param->server, param->port,
-				 etpan_connect_ssl_context_cb, param->account);
+				 etpan_connect_ssl_context_cb, param->account,
+				 param->proxy_info);
 	result->error = r;
 }
 
-int nntp_threaded_connect_ssl(Folder * folder, const char * server, int port)
+int nntp_threaded_connect_ssl(Folder * folder, const char * server, int port, ProxyInfo *proxy_info)
 {
 	struct connect_param param;
 	struct connect_result result;
@@ -420,6 +493,7 @@ int nntp_threaded_connect_ssl(Folder * folder, const char * server, int port)
 	param.server = server;
 	param.port = port;
 	param.account = folder->account;
+	param.proxy_info = proxy_info;
 
 	if (folder->account)
 		accept_if_valid = folder->account->ssl_certs_auto_accept;
diff --git a/src/etpan/nntp-thread.h b/src/etpan/nntp-thread.h
index d030efa..ddfb8ff 100644
--- a/src/etpan/nntp-thread.h
+++ b/src/etpan/nntp-thread.h
@@ -23,6 +23,7 @@
 
 #include <libetpan/libetpan.h>
 #include "folder.h"
+#include "proxy.h"
 
 void nntp_main_set_timeout(int sec);
 void nntp_main_init(gboolean skip_ssl_cert_check);
@@ -31,8 +32,8 @@ void nntp_main_done(gboolean have_connectivity);
 void nntp_init(Folder * folder);
 void nntp_done(Folder * folder);
 
-int nntp_threaded_connect(Folder * folder, const char * server, int port);
-int nntp_threaded_connect_ssl(Folder * folder, const char * server, int port);
+int nntp_threaded_connect(Folder * folder, const char * server, int port, ProxyInfo *proxy_info);
+int nntp_threaded_connect_ssl(Folder * folder, const char * server, int port, ProxyInfo *proxy_info);
 
 void nntp_threaded_disconnect(Folder * folder);
 
diff --git a/src/imap.c b/src/imap.c
index fce5ed9..23232f8 100644
--- a/src/imap.c
+++ b/src/imap.c
@@ -1131,6 +1131,7 @@ static IMAPSession *imap_session_new(Folder * folder,
 				     const PrefsAccount *account)
 {
 	IMAPSession *session;
+	ProxyInfo *proxy_info = NULL;
 	gushort port;
 	int r;
 	int authenticated = FALSE;
@@ -1169,6 +1170,20 @@ static IMAPSession *imap_session_new(Folder * folder,
 	log_message(LOG_PROTOCOL, "%s\n", buf);
 	g_free(buf);
 
+	if (account->use_proxy) {
+		if (account->use_default_proxy) {
+			proxy_info = (ProxyInfo *)&(prefs_common.proxy_info);
+			if (proxy_info->use_proxy_auth)
+				proxy_info->proxy_pass = passwd_store_get(PWS_CORE, PWS_CORE_PROXY,
+					PWS_CORE_PROXY_PASS);
+		} else {
+			proxy_info = (ProxyInfo *)&(account->proxy_info);
+			if (proxy_info->use_proxy_auth)
+				proxy_info->proxy_pass = passwd_store_get_account(account->account_id,
+					PWS_ACCOUNT_PROXY_PASS);
+		}
+	}
+
 #ifndef G_OS_WIN32
 	if (account->set_tunnelcmd) {
 		r = imap_threaded_connect_cmd(folder,
@@ -1180,17 +1195,20 @@ static IMAPSession *imap_session_new(Folder * folder,
 #endif
 	{
 #ifdef USE_GNUTLS
+
 		if (ssl_type == SSL_TUNNEL) {
 			r = imap_threaded_connect_ssl(folder,
 						      account->recv_server,
-						      port);
+						      port,
+						      proxy_info);
 		}
 		else 
 #endif
 		{
 			r = imap_threaded_connect(folder,
 						  account->recv_server,
-						  port);
+						  port,
+						  proxy_info);
 		}
 	}
 	
@@ -1224,13 +1242,12 @@ static IMAPSession *imap_session_new(Folder * folder,
 	session_init(SESSION(session), account, FALSE);
 	SESSION(session)->type             = SESSION_IMAP;
 	SESSION(session)->server           = g_strdup(account->recv_server);
-	SESSION(session)->port		   = port;
+	SESSION(session)->port             = port;
  	SESSION(session)->sock             = NULL;
-	
+	SESSION(session)->proxy_info       = proxy_info;
 	SESSION(session)->destroy          = imap_session_destroy;
 
 	session->capability = NULL;
-	
 	session->authenticated = authenticated;
 	session->mbox = NULL;
 	session->exists = 0;
diff --git a/src/inc.c b/src/inc.c
index d4a6e0f..f0455e3 100644
--- a/src/inc.c
+++ b/src/inc.c
@@ -39,6 +39,7 @@
 #include "prefs_account.h"
 #include "account.h"
 #include "procmsg.h"
+#include "proxy.h"
 #include "socket.h"
 #include "ssl.h"
 #include "pop.h"
@@ -783,32 +784,34 @@ static IncState inc_pop3_session_do(IncSession *session)
 {
 	Pop3Session *pop3_session = POP3_SESSION(session->session);
 	IncProgressDialog *inc_dialog = (IncProgressDialog *)session->data;
+	PrefsAccount *ac = pop3_session->ac_prefs;
 	gchar *server;
 	gchar *account_name;
 	gushort port;
 	gchar *buf;
+	ProxyInfo *proxy_info = NULL;
 
 	debug_print("getting new messages of account %s...\n",
-		    pop3_session->ac_prefs->account_name);
+		    ac->account_name);
 		    
-	pop3_session->ac_prefs->last_pop_login_time = time(NULL);
+	ac->last_pop_login_time = time(NULL);
 
 	buf = g_strdup_printf(_("%s: Retrieving new messages"),
-			      pop3_session->ac_prefs->recv_server);
+			      ac->recv_server);
 	gtk_window_set_title(GTK_WINDOW(inc_dialog->dialog->window), buf);
 	g_free(buf);
 
-	server = pop3_session->ac_prefs->recv_server;
-	account_name = pop3_session->ac_prefs->account_name;
+	server = ac->recv_server;
+	account_name = ac->account_name;
 	port = pop3_get_port(pop3_session);
 
 #ifdef USE_GNUTLS
-	SESSION(pop3_session)->ssl_type = pop3_session->ac_prefs->ssl_pop;
-	if (pop3_session->ac_prefs->ssl_pop != SSL_NONE)
+	SESSION(pop3_session)->ssl_type = ac->ssl_pop;
+	if (ac->ssl_pop != SSL_NONE)
 		SESSION(pop3_session)->nonblocking =
-			pop3_session->ac_prefs->use_nonblocking_ssl;
+			ac->use_nonblocking_ssl;
 #else
-	if (pop3_session->ac_prefs->ssl_pop != SSL_NONE) {
+	if (ac->ssl_pop != SSL_NONE) {
 		if (alertpanel_full(_("Insecure connection"),
 			_("This connection is configured to be secured "
 			  "using SSL/TLS, but SSL/TLS is not available "
@@ -829,6 +832,22 @@ static IncState inc_pop3_session_do(IncSession *session)
 	log_message(LOG_PROTOCOL, "%s\n", buf);
 
 	progress_dialog_set_label(inc_dialog->dialog, buf);
+
+	if (ac->use_proxy) {
+		if (ac->use_default_proxy) {
+			proxy_info = (ProxyInfo *)&(prefs_common.proxy_info);
+			if (proxy_info->use_proxy_auth)
+				proxy_info->proxy_pass = passwd_store_get(PWS_CORE, PWS_CORE_PROXY,
+					PWS_CORE_PROXY_PASS);
+		} else {
+			proxy_info = (ProxyInfo *)&(ac->proxy_info);
+			if (proxy_info->use_proxy_auth)
+				proxy_info->proxy_pass = passwd_store_get_account(ac->account_id,
+					PWS_ACCOUNT_PROXY_PASS);
+		}
+	}
+	SESSION(session)->proxy_info = proxy_info;
+
 	GTK_EVENTS_FLUSH();
 	g_free(buf);
 
diff --git a/src/main.c b/src/main.c
index 22baeb4..28640c9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -90,6 +90,7 @@
 #include "prefs_summaries.h"
 #include "prefs_themes.h"
 #include "prefs_other.h"
+#include "prefs_proxy.h"
 #include "prefs_logging.h"
 #include "prefs_send.h"
 #include "prefs_wrapping.h"
@@ -1261,6 +1262,7 @@ int main(int argc, char *argv[])
 	prefs_summaries_init();
 	prefs_message_init();
 	prefs_other_init();
+	prefs_proxy_init();
 	prefs_logging_init();
 	prefs_receive_init();
 	prefs_send_init();
@@ -1744,6 +1746,7 @@ static void exit_claws(MainWindow *mainwin)
 	prefs_summaries_done();
 	prefs_message_done();
 	prefs_other_done();
+	prefs_proxy_done();
 	prefs_receive_done();
 	prefs_logging_done();
 	prefs_send_done();
diff --git a/src/news.c b/src/news.c
index c062ac3..7d5fbfa 100644
--- a/src/news.c
+++ b/src/news.c
@@ -104,18 +104,14 @@ static void news_remove_cached_msg	(Folder 	*folder,
 					 FolderItem 	*item, 
 					 MsgInfo 	*msginfo);
 #ifdef USE_GNUTLS
-static Session *news_session_new	 (Folder 	*folder,
-					  const gchar	*server,
-					  gushort	 port,
-					  const gchar	*userid,
-					  const gchar	*passwd,
-					  SSLType	 ssl_type);
+static Session *news_session_new	 (Folder		*folder,
+					  const PrefsAccount 	*account,
+					  gushort		 port,
+					  SSLType		 ssl_type);
 #else
-static Session *news_session_new	 (Folder 	*folder,
-					  const gchar	*server,
-					  gushort	 port,
-					  const gchar	*userid,
-					  const gchar	*passwd);
+static Session *news_session_new	 (Folder		*folder,
+					  const PrefsAccount 	*account,
+					  gushort		 port);
 #endif
 
 static gint news_get_article		 (Folder	*folder,
@@ -321,20 +317,22 @@ static gboolean nntp_ping(gpointer data)
 
 
 #ifdef USE_GNUTLS
-static Session *news_session_new(Folder *folder, const gchar *server, gushort port,
-				 const gchar *userid, const gchar *passwd,
+static Session *news_session_new(Folder *folder, const PrefsAccount *account, gushort port,
 				 SSLType ssl_type)
 #else
-static Session *news_session_new(Folder *folder, const gchar *server, gushort port,
-				 const gchar *userid, const gchar *passwd)
+static Session *news_session_new(Folder *folder, const PrefsAccount *account, gushort port)
 #endif
 {
 	NewsSession *session;
+	const char *server = account->nntp_server;
 	int r = 0;
+	ProxyInfo *proxy_info = NULL;
+
 	cm_return_val_if_fail(server != NULL, NULL);
 
-	log_message(LOG_PROTOCOL, _("Account '%s': Connecting to NNTP server: %s:%d...\n"),
-				    folder->account->account_name, server, port);
+	log_message(LOG_PROTOCOL,
+			_("Account '%s': Connecting to NNTP server: %s:%d...\n"),
+			folder->account->account_name, server, port);
 
 	session = g_new0(NewsSession, 1);
 	session_init(SESSION(session), folder->account, FALSE);
@@ -343,15 +341,30 @@ static Session *news_session_new(Folder *folder, const gchar *server, gushort po
 	SESSION(session)->port             = port;
  	SESSION(session)->sock             = NULL;
 	SESSION(session)->destroy          = news_session_destroy;
-	
+
+	if (account->use_proxy) {
+		if (account->use_default_proxy) {
+			proxy_info = (ProxyInfo *)&(prefs_common.proxy_info);
+			if (proxy_info->use_proxy_auth)
+				proxy_info->proxy_pass = passwd_store_get(PWS_CORE, PWS_CORE_PROXY,
+					PWS_CORE_PROXY_PASS);
+		} else {
+			proxy_info = (ProxyInfo *)&(account->proxy_info);
+			if (proxy_info->use_proxy_auth)
+				proxy_info->proxy_pass = passwd_store_get_account(account->account_id,
+					PWS_ACCOUNT_PROXY_PASS);
+		}
+	}
+	SESSION(session)->proxy_info = proxy_info;
+
 	nntp_init(folder);
 
 #ifdef USE_GNUTLS
 	if (ssl_type != SSL_NONE)
-		r = nntp_threaded_connect_ssl(folder, server, port);
+		r = nntp_threaded_connect_ssl(folder, server, port, proxy_info);
 	else
 #endif
-		r = nntp_threaded_connect(folder, server, port);
+		r = nntp_threaded_connect(folder, server, port, proxy_info);
 	
 	if (r != NEWSNNTP_NO_ERROR) {
 		log_error(LOG_PROTOCOL, _("Error logging in to %s:%d...\n"), server, port);
@@ -381,8 +394,7 @@ static Session *news_session_new_for_folder(Folder *folder)
 #ifdef USE_GNUTLS
 	port = ac->set_nntpport ? ac->nntpport
 		: ac->ssl_nntp ? NNTPS_PORT : NNTP_PORT;
-	session = news_session_new(folder, ac->nntp_server, port, userid, passwd,
-				   ac->ssl_nntp);
+	session = news_session_new(folder, ac, port, ac->ssl_nntp);
 #else
 	if (ac->ssl_nntp != SSL_NONE) {
 		if (alertpanel_full(_("Insecure connection"),
@@ -398,7 +410,7 @@ static Session *news_session_new_for_folder(Folder *folder)
 			return NULL;
 	}
 	port = ac->set_nntpport ? ac->nntpport : NNTP_PORT;
-	session = news_session_new(folder, ac->nntp_server, port, userid, passwd);
+	session = news_session_new(folder, ac, port);
 #endif
 
 	if (ac->use_nntp_auth && ac->userid && ac->userid[0]) {
diff --git a/src/passwordstore.h b/src/passwordstore.h
index d9d3fed..aeaa40d 100644
--- a/src/passwordstore.h
+++ b/src/passwordstore.h
@@ -83,5 +83,9 @@ gchar *passwd_store_get_account(gint account_id, const gchar *block_name);
 #define PWS_ACCOUNT_SEND      "send"
 #define PWS_ACCOUNT_RECV_CERT "recv_cert"
 #define PWS_ACCOUNT_SEND_CERT "send_cert"
+#define PWS_ACCOUNT_PROXY_PASS "proxy_pass"
+
+#define PWS_CORE_PROXY "proxy"
+#define PWS_CORE_PROXY_PASS "proxy_pass"
 
 #endif /* __PASSWORDSTORE_H */
diff --git a/src/plugins/managesieve/managesieve.c b/src/plugins/managesieve/managesieve.c
index e7b53f5..d1cbcc4 100644
--- a/src/plugins/managesieve/managesieve.c
+++ b/src/plugins/managesieve/managesieve.c
@@ -31,6 +31,7 @@
 #include "utils.h"
 #include "log.h"
 #include "session.h"
+#include "prefs_common.h"
 
 #include "managesieve.h"
 #include "sieve_editor.h"
@@ -994,11 +995,30 @@ static void sieve_connect_finished(Session *session, gboolean success)
 
 static gint sieve_session_connect(SieveSession *session)
 {
+	PrefsAccount *ac = session->account;
+	ProxyInfo *proxy_info = NULL;
+
 	session->state = SIEVE_CAPABILITIES;
 	session->authenticated = FALSE;
 #ifdef USE_GNUTLS
 	session->tls_init_done = FALSE;
 #endif
+
+	if (ac->use_proxy) {
+		if (ac->use_default_proxy) {
+			proxy_info = (ProxyInfo *)&(prefs_common.proxy_info);
+			if (proxy_info->use_proxy_auth)
+				proxy_info->proxy_pass = passwd_store_get(PWS_CORE, PWS_CORE_PROXY,
+					PWS_CORE_PROXY_PASS);
+		} else {
+			proxy_info = (ProxyInfo *)&(ac->proxy_info);
+			if (proxy_info->use_proxy_auth)
+				proxy_info->proxy_pass = passwd_store_get_account(ac->account_id,
+					PWS_ACCOUNT_PROXY_PASS);
+		}
+	}
+	SESSION(session)->proxy_info = proxy_info;
+
 	return session_connect(SESSION(session), session->host,
 			session->port);
 }
diff --git a/src/prefs_account.c b/src/prefs_account.c
index 62a039e..74740d2 100644
--- a/src/prefs_account.c
+++ b/src/prefs_account.c
@@ -273,6 +273,24 @@ typedef struct SSLPage
 	GtkWidget *use_nonblocking_ssl_checkbtn;
 } SSLPage;
 
+typedef struct ProxyPage
+{
+	PrefsPage page;
+
+	GtkWidget *vbox;
+
+	GtkWidget *proxy_checkbtn;
+	GtkWidget *default_proxy_checkbtn;
+	GtkWidget *socks4_radiobtn;
+	GtkWidget *socks5_radiobtn;
+	GtkWidget *proxy_host_entry;
+	GtkWidget *proxy_port_spinbtn;
+	GtkWidget *proxy_auth_checkbtn;
+	GtkWidget *proxy_name_entry;
+	GtkWidget *proxy_pass_entry;
+	GtkWidget *proxy_send_checkbtn;
+} ProxyPage;
+
 typedef struct AdvancedPage
 {
     PrefsPage page;
@@ -321,6 +339,7 @@ static PrivacyPage privacy_page;
 #ifdef USE_GNUTLS
 static SSLPage ssl_page;
 #endif
+static ProxyPage proxy_page;
 static AdvancedPage advanced_page;
 
 struct BasicProtocol {
@@ -788,6 +807,49 @@ static PrefParam ssl_param[] = {
 	{NULL, NULL, NULL, P_OTHER, NULL, NULL, NULL}
 };
 
+static PrefParam proxy_param[] = {
+	/* SOCKS proxy */
+	{"use_proxy", "FALSE", &tmp_ac_prefs.use_proxy, P_BOOL,
+	&proxy_page.proxy_checkbtn,
+	prefs_set_data_from_toggle, prefs_set_toggle},
+
+	{"use_default_proxy", "TRUE", &tmp_ac_prefs.use_default_proxy, P_BOOL,
+	&proxy_page.default_proxy_checkbtn,
+	prefs_set_data_from_toggle, prefs_set_toggle},
+
+	{"use_proxy_for_send", "TRUE", &tmp_ac_prefs.use_proxy_for_send, P_BOOL,
+	&proxy_page.proxy_send_checkbtn,
+	prefs_set_data_from_toggle, prefs_set_toggle},
+
+	{"proxy_type", "1", &tmp_ac_prefs.proxy_info.proxy_type, P_ENUM,
+	&proxy_page.socks4_radiobtn,
+	prefs_account_enum_set_data_from_radiobtn,
+	prefs_account_enum_set_radiobtn},
+
+	{"proxy_host", "localhost", &tmp_ac_prefs.proxy_info.proxy_host, P_STRING,
+	&proxy_page.proxy_host_entry,
+	prefs_set_data_from_entry, prefs_set_entry},
+
+	{"proxy_port", "1080", &tmp_ac_prefs.proxy_info.proxy_port, P_USHORT,
+	&proxy_page.proxy_port_spinbtn,
+	prefs_set_data_from_spinbtn, prefs_set_spinbtn},
+
+	{"use_proxy_auth", "FALSE", &tmp_ac_prefs.proxy_info.use_proxy_auth, P_BOOL,
+	&proxy_page.proxy_auth_checkbtn,
+	prefs_set_data_from_toggle, prefs_set_toggle},
+
+	{"proxy_name", "", &tmp_ac_prefs.proxy_info.proxy_name, P_STRING,
+	&proxy_page.proxy_name_entry,
+	prefs_set_data_from_entry, prefs_set_entry},
+
+	{"proxy_pass", "", &tmp_ac_prefs.proxy_info.proxy_pass, P_PASSWORD,
+	&proxy_page.proxy_pass_entry,
+	prefs_set_data_from_entry, prefs_set_entry},
+
+
+	{NULL, NULL, NULL, P_OTHER, NULL, NULL, NULL}
+};
+
 static PrefParam advanced_param[] = {
 	{"set_smtpport", "FALSE", &tmp_ac_prefs.set_smtpport, P_BOOL,
 	 &advanced_page.smtpport_checkbtn,
@@ -2366,8 +2428,6 @@ static void privacy_create_widget_func(PrefsPage * _page,
 
 	page->page.widget = vbox1;
 }
-	
-#ifdef USE_GNUTLS
 
 #define CREATE_RADIO_BUTTON(box, btn, btn_p, label, data)		\
 {									\
@@ -2380,6 +2440,8 @@ static void privacy_create_widget_func(PrefsPage * _page,
 			   GINT_TO_POINTER (data));			\
 }
 
+#ifdef USE_GNUTLS
+
 #define CREATE_RADIO_BUTTONS(box,					\
 			     btn1, btn1_label, btn1_data,		\
 			     btn2, btn2_label, btn2_data,		\
@@ -2709,9 +2771,150 @@ static void ssl_create_widget_func(PrefsPage * _page,
 }
 
 #undef CREATE_RADIO_BUTTONS
-#undef CREATE_RADIO_BUTTON
 #endif /* USE_GNUTLS */
-	
+
+static void proxy_create_widget_func(PrefsPage * _page,
+                                           GtkWindow * window,
+                                           gpointer data)
+{
+	ProxyPage *page = (ProxyPage *) _page;
+	PrefsAccount *ac_prefs = (PrefsAccount *) data;
+	GtkWidget *vbox1, *vbox2, *vbox3, *vbox4;
+	GtkWidget *proxy_frame;
+	GtkWidget *proxy_checkbtn;
+	GtkWidget *default_proxy_checkbtn;
+	GtkWidget *hbox2;
+	GtkWidget *label;
+	GtkWidget *socks4_radiobtn;
+	GtkWidget *socks5_radiobtn;
+	GtkWidget *proxy_host_entry;
+	GtkWidget *proxy_port_spinbtn;
+	GtkWidget *proxy_auth_checkbtn;
+	GtkWidget *proxy_name_entry;
+	GtkWidget *proxy_pass_entry;
+	GtkWidget *proxy_send_checkbtn;
+	gchar *buf;
+
+	vbox1 = gtk_vbox_new (FALSE, VSPACING);
+	gtk_container_set_border_width (GTK_CONTAINER (vbox1), VBOX_BORDER);
+
+	proxy_checkbtn = gtk_check_button_new_with_label (_("Use proxy server for this account"));
+	PACK_FRAME (vbox1, proxy_frame, NULL);
+	gtk_frame_set_label_widget (GTK_FRAME(proxy_frame), proxy_checkbtn);
+
+	vbox2 = gtk_vbox_new (FALSE, VSPACING_NARROW);
+	gtk_container_add (GTK_CONTAINER (proxy_frame), vbox2);
+	gtk_container_set_border_width (GTK_CONTAINER (vbox2), 8);
+
+	default_proxy_checkbtn =
+		gtk_check_button_new_with_label (C_("In account preferences, referring to whether or not use proxy settings from common preferences", "Use default settings"));
+	CLAWS_SET_TIP(default_proxy_checkbtn,
+			_("Use proxy server settings from common preferences."));
+	gtk_box_pack_start (GTK_BOX (vbox2), default_proxy_checkbtn, FALSE, FALSE, 0);
+
+	vbox3 = gtk_vbox_new (FALSE, VSPACING_NARROW);
+	gtk_box_pack_start (GTK_BOX (vbox2), vbox3, FALSE, FALSE, 0);
+
+	hbox2 = gtk_hbox_new (FALSE, 8);
+	gtk_box_pack_start (GTK_BOX (vbox3), hbox2, FALSE, FALSE, 0);
+
+	socks4_radiobtn = gtk_radio_button_new_with_label(NULL, "SOCKS4");
+	gtk_box_pack_start (GTK_BOX (hbox2), socks4_radiobtn, FALSE, FALSE, 0);
+	g_object_set_data(G_OBJECT(socks4_radiobtn), MENU_VAL_ID,
+			  GINT_TO_POINTER(PROXY_SOCKS4));
+
+	CREATE_RADIO_BUTTON(hbox2, socks5_radiobtn, socks4_radiobtn, "SOCKS5",
+			    PROXY_SOCKS5);
+
+	hbox2 = gtk_hbox_new (FALSE, 8);
+	gtk_box_pack_start (GTK_BOX (vbox3), hbox2, FALSE, FALSE, 0);
+
+	label = gtk_label_new(_("Hostname"));
+	gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
+
+	proxy_host_entry = gtk_entry_new();
+	gtk_widget_set_size_request(proxy_host_entry, DEFAULT_ENTRY_WIDTH, -1);
+	gtk_box_pack_start(GTK_BOX(hbox2), proxy_host_entry, TRUE, TRUE, 0);
+
+	label = gtk_label_new(_("Port"));
+	gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
+
+	proxy_port_spinbtn = gtk_spin_button_new_with_range(0, 65535, 1080);
+	gtk_widget_set_size_request(proxy_port_spinbtn, 64, -1);
+	gtk_box_pack_start(GTK_BOX(hbox2), proxy_port_spinbtn, FALSE, FALSE, 0);
+
+	vbox4 = gtk_vbox_new (FALSE, VSPACING_NARROW);
+	gtk_box_pack_start(GTK_BOX(vbox3), vbox4, FALSE, FALSE, 0);
+
+	PACK_CHECK_BUTTON (vbox4, proxy_auth_checkbtn, _("Use authentication"));
+
+	hbox2 = gtk_hbox_new (FALSE, 8);
+	gtk_box_pack_start (GTK_BOX (vbox4), hbox2, FALSE, FALSE, 0);
+
+	label = gtk_label_new(_("Username"));
+	gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
+
+	proxy_name_entry = gtk_entry_new();
+	gtk_widget_set_size_request(proxy_name_entry, DEFAULT_ENTRY_WIDTH, -1);
+	gtk_box_pack_start(GTK_BOX(hbox2), proxy_name_entry, TRUE, TRUE, 0);
+
+	label = gtk_label_new(_("Password"));
+	gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
+
+	proxy_pass_entry = gtk_entry_new();
+	gtk_widget_set_size_request(proxy_pass_entry, DEFAULT_ENTRY_WIDTH, -1);
+	gtk_entry_set_visibility(GTK_ENTRY(proxy_pass_entry), FALSE);
+	gtk_box_pack_start(GTK_BOX(hbox2), proxy_pass_entry, TRUE, TRUE, 0);
+
+	gtk_box_pack_start(GTK_BOX(vbox2), gtk_hseparator_new(), FALSE, FALSE, 0);
+
+	PACK_CHECK_BUTTON(vbox2, proxy_send_checkbtn,
+			  _("Use proxy server for sending"));
+	CLAWS_SET_TIP(proxy_send_checkbtn,
+			_("If disabled, messages will be sent using direct connection to configured outgoing server, bypassing any configured proxy server."));
+
+	SET_TOGGLE_SENSITIVITY(proxy_auth_checkbtn, hbox2);
+	SET_TOGGLE_SENSITIVITY(socks5_radiobtn, vbox4);
+	SET_TOGGLE_SENSITIVITY(proxy_checkbtn, vbox2);
+	SET_TOGGLE_SENSITIVITY_REVERSE(default_proxy_checkbtn, vbox3);
+
+	gtk_widget_show_all(vbox1);
+
+	page->proxy_checkbtn = proxy_checkbtn;
+	page->default_proxy_checkbtn = default_proxy_checkbtn;
+	page->socks4_radiobtn = socks4_radiobtn;
+	page->socks5_radiobtn = socks5_radiobtn;
+	page->proxy_host_entry = proxy_host_entry;
+	page->proxy_port_spinbtn = proxy_port_spinbtn;
+	page->proxy_auth_checkbtn = proxy_auth_checkbtn;
+	page->proxy_name_entry = proxy_name_entry;
+	page->proxy_pass_entry = proxy_pass_entry;
+	page->proxy_send_checkbtn = proxy_send_checkbtn;
+	page->vbox = vbox1;
+	page->page.widget = vbox1;
+
+	tmp_ac_prefs = *ac_prefs;
+
+	if (new_account) {
+		prefs_set_dialog_to_default(proxy_param);
+	} else
+		prefs_set_dialog(proxy_param);
+
+		/* Passwords are handled outside of PrefParams. */
+		buf = passwd_store_get_account(ac_prefs->account_id,
+				PWS_ACCOUNT_PROXY_PASS);
+		gtk_entry_set_text(GTK_ENTRY(page->proxy_pass_entry),
+				buf != NULL ? buf : "");
+		if (buf != NULL) {
+			memset(buf, 0, strlen(buf));
+			g_free(buf);
+		}
+
+	page->vbox = vbox1;
+
+	page->page.widget = vbox1;
+}
+
 static void advanced_create_widget_func(PrefsPage * _page,
                                            GtkWindow * window,
                                            gpointer data)
@@ -3126,6 +3329,19 @@ static gint prefs_ssl_apply(void)
 }
 #endif
 
+static gint prefs_proxy_apply(void)
+{
+	prefs_set_data_from_dialog(proxy_param);
+
+	/* Passwords are stored outside of PrefParams. */
+	passwd_store_set_account(tmp_ac_prefs.account_id,
+			PWS_ACCOUNT_PROXY_PASS,
+			gtk_entry_get_text(GTK_ENTRY(proxy_page.proxy_pass_entry)),
+			FALSE);
+
+	return 0;
+}
+
 static gint prefs_advanced_apply(void)
 {
 	prefs_set_data_from_dialog(advanced_param);
@@ -3169,6 +3385,11 @@ static void ssl_destroy_widget_func(PrefsPage *_page)
 }
 #endif
 
+static void proxy_destroy_widget_func(PrefsPage *_page)
+{
+	/* ProxyPage *page = (ProxyPage *) _page; */
+}
+
 static void advanced_destroy_widget_func(PrefsPage *_page)
 {
 	/* AdvancedPage *page = (AdvancedPage *) _page; */
@@ -3246,6 +3467,16 @@ static gboolean ssl_can_close_func(PrefsPage *_page)
 }
 #endif
 
+static gboolean proxy_can_close_func(PrefsPage *_page)
+{
+	ProxyPage *page = (ProxyPage *) _page;
+
+	if (!page->page.page_open)
+		return TRUE;
+
+	return prefs_proxy_apply() >= 0;
+}
+
 static gboolean advanced_can_close_func(PrefsPage *_page)
 {
 	AdvancedPage *page = (AdvancedPage *) _page;
@@ -3347,6 +3578,17 @@ static void ssl_save_func(PrefsPage *_page)
 }
 #endif
 
+static void proxy_save_func(PrefsPage *_page)
+{
+	ProxyPage *page = (ProxyPage *) _page;
+
+	if (!page->page.page_open)
+		return;
+
+	if (prefs_proxy_apply() >= 0)
+		cancelled = FALSE;
+}
+
 static void advanced_save_func(PrefsPage *_page)
 {
 	AdvancedPage *page = (AdvancedPage *) _page;
@@ -3560,6 +3802,24 @@ static gboolean sslcert_get_password(gpointer source, gpointer data)
 }
 #endif
 
+static void register_proxy_page(void)
+{
+	static gchar *path[3];
+
+	path[0] = _("Account");
+	path[1] = _("Proxy");
+	path[2] = NULL;
+
+	proxy_page.page.path = path;
+	proxy_page.page.weight = 1000.0;
+	proxy_page.page.create_widget = proxy_create_widget_func;
+	proxy_page.page.destroy_widget = proxy_destroy_widget_func;
+	proxy_page.page.save_page = proxy_save_func;
+	proxy_page.page.can_close = proxy_can_close_func;
+
+	prefs_account_register_page((PrefsPage *) &proxy_page);
+}
+
 static void register_advanced_page(void)
 {
 	static gchar *path[3];
@@ -3591,6 +3851,7 @@ void prefs_account_init()
 	hooks_register_hook(SSLCERT_GET_CLIENT_CERT_HOOKLIST, sslcert_get_client_cert_hook, NULL);
 	hooks_register_hook(SSL_CERT_GET_PASSWORD, sslcert_get_password, NULL);
 #endif
+	register_proxy_page();
 	register_advanced_page();
 }
 
@@ -3607,6 +3868,7 @@ PrefsAccount *prefs_account_new(void)
 	prefs_set_default(templates_param);
 	prefs_set_default(privacy_param);
 	prefs_set_default(ssl_param);
+	prefs_set_default(proxy_param);
 	prefs_set_default(advanced_param);
 	*ac_prefs = tmp_ac_prefs;
 	ac_prefs->account_id = prefs_account_get_new_id();
@@ -3649,6 +3911,7 @@ PrefsAccount *prefs_account_new_from_config(const gchar *label)
 	prefs_read_config(templates_param, label, rcpath, NULL);
 	prefs_read_config(privacy_param, label, rcpath, NULL);
 	prefs_read_config(ssl_param, label, rcpath, NULL);
+	prefs_read_config(proxy_param, label, rcpath, NULL);
 	prefs_read_config(advanced_param, label, rcpath, NULL);
 	g_free(rcpath);
 
@@ -3778,6 +4041,7 @@ void prefs_account_write_config_all(GList *account_list)
 		WRITE_PARAM(templates_param)
 		WRITE_PARAM(privacy_param)
 		WRITE_PARAM(ssl_param)
+		WRITE_PARAM(proxy_param)
 		WRITE_PARAM(advanced_param)
 
 		g_free(privacy_prefs);
@@ -3821,6 +4085,7 @@ void prefs_account_free(PrefsAccount *ac_prefs)
 	prefs_free(templates_param);
 	prefs_free(privacy_param);
 	prefs_free(ssl_param);
+	prefs_free(proxy_param);
 	prefs_free(advanced_param);
 }
 
diff --git a/src/prefs_account.h b/src/prefs_account.h
index 39aed6f..e0844af 100644
--- a/src/prefs_account.h
+++ b/src/prefs_account.h
@@ -204,6 +204,12 @@ struct _PrefsAccount
 	/* Unique account ID */
 	gint account_id;
 
+	/* SOCKS proxy */
+	gboolean use_proxy;
+	gboolean use_default_proxy;
+	gboolean use_proxy_for_send;
+	ProxyInfo proxy_info;
+
 	struct _Folder *folder;
 	GHashTable *privacy_prefs;
 	SMTPSession *session;
diff --git a/src/prefs_common.c b/src/prefs_common.c
index 750ab47..ed55ff4 100644
--- a/src/prefs_common.c
+++ b/src/prefs_common.c
@@ -60,6 +60,7 @@
 #include "stock_pixmap.h"
 #include "prefswindow.h"
 #include "colorlabel.h"
+#include "passwordstore.h"
 #ifndef USE_ALT_ADDRBOOK
 	#include "addrcustomattr.h"
 #endif
@@ -1255,6 +1256,14 @@ static PrefParam param[] = {
 	{"master_passphrase_pbkdf2_rounds", "50000", &prefs_common.master_passphrase_pbkdf2_rounds, P_INT, NULL, NULL, NULL},
 #endif
 
+	{"use_proxy", "FALSE", &prefs_common.use_proxy, P_BOOL, NULL, NULL, NULL},
+	{"proxy_type", "1", &prefs_common.proxy_info.proxy_type, P_ENUM, NULL, NULL, NULL},
+	{"proxy_host", "localhost", &prefs_common.proxy_info.proxy_host, P_STRING, NULL, NULL, NULL},
+	{"proxy_port", "1080", &prefs_common.proxy_info.proxy_port, P_USHORT, NULL, NULL, NULL},
+	{"use_proxy_auth", "FALSE", &prefs_common.proxy_info.use_proxy_auth, P_BOOL, NULL, NULL, NULL},
+	{"proxy_name", "", &prefs_common.proxy_info.proxy_name, P_STRING, NULL, NULL, NULL},
+	{"proxy_pass", "", &prefs_common.proxy_info.proxy_pass, P_STRING, NULL, NULL, NULL},
+
 	{NULL, NULL, NULL, P_OTHER, NULL, NULL, NULL}
 };
 
diff --git a/src/prefs_common.h b/src/prefs_common.h
index cc9451c..95e3c64 100644
--- a/src/prefs_common.h
+++ b/src/prefs_common.h
@@ -568,6 +568,10 @@ struct _PrefsCommon
 	gchar *master_passphrase_salt;
 	guint master_passphrase_pbkdf2_rounds;
 #endif
+
+	/* Proxy */
+	gboolean use_proxy;
+	ProxyInfo proxy_info;
 };
 
 extern PrefsCommon prefs_common;
diff --git a/src/prefs_proxy.c b/src/prefs_proxy.c
new file mode 100644
index 0000000..c3cf43d
--- /dev/null
+++ b/src/prefs_proxy.c
@@ -0,0 +1,237 @@
+/*
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2018 the Claws Mail team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "common/defs.h"
+#include "common/proxy.h"
+
+#include "gtk/menu.h"
+
+#include "prefs_common.h"
+#include "prefs_gtk.h"
+#include "passwordstore.h"
+
+typedef struct _ProxyPage
+{
+	PrefsPage page;
+
+	GtkWidget *proxy_checkbtn;
+	GtkWidget *socks4_radiobtn;
+	GtkWidget *socks5_radiobtn;
+	GtkWidget *proxy_host_entry;
+	GtkWidget *proxy_port_spinbtn;
+	GtkWidget *proxy_auth_checkbtn;
+	GtkWidget *proxy_name_entry;
+	GtkWidget *proxy_pass_entry;
+} ProxyPage;
+
+
+static void prefs_proxy_create_widget(PrefsPage *_page, GtkWindow *window,
+		gpointer data)
+{
+	ProxyPage *page = (ProxyPage *)_page;
+
+	GtkWidget *vbox0, *vbox1, *vbox2;
+	GtkWidget *hbox;
+	GtkWidget *label;
+	GtkWidget *proxy_checkbtn;
+	GtkWidget *socks4_radiobtn, *socks5_radiobtn;
+	GtkWidget *proxy_auth_checkbtn;
+	GtkWidget *proxy_frame;
+	GtkWidget *proxy_host_entry;
+	GtkWidget *proxy_port_spinbtn;
+	GtkWidget *proxy_name_entry;
+	GtkWidget *proxy_pass_entry;
+	GtkWidget *button;
+	gchar *buf;
+
+	vbox0 = gtk_vbox_new(FALSE, VSPACING);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox0), VBOX_BORDER);
+
+	proxy_checkbtn = gtk_check_button_new_with_label(_("Use proxy server"));
+	PACK_FRAME(vbox0, proxy_frame, NULL);
+	gtk_frame_set_label_widget(GTK_FRAME(proxy_frame), proxy_checkbtn);
+
+	vbox1 = gtk_vbox_new(FALSE, VSPACING_NARROW);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox1), 8);
+	gtk_container_add(GTK_CONTAINER(proxy_frame), vbox1);
+
+	hbox = gtk_hbox_new(FALSE, 8);
+	gtk_box_pack_start(GTK_BOX(vbox1), hbox, FALSE, FALSE, 0);
+
+	socks4_radiobtn = gtk_radio_button_new_with_label(NULL, "SOCKS4");
+	gtk_box_pack_start(GTK_BOX(hbox), socks4_radiobtn, FALSE, FALSE, 0);
+	g_object_set_data(G_OBJECT(socks4_radiobtn), MENU_VAL_ID,
+			GINT_TO_POINTER(PROXY_SOCKS4));
+
+	socks5_radiobtn = gtk_radio_button_new_with_label_from_widget(
+			GTK_RADIO_BUTTON(socks4_radiobtn), "SOCKS5");
+	gtk_box_pack_start(GTK_BOX(hbox), socks5_radiobtn, FALSE, FALSE, 0);
+	g_object_set_data(G_OBJECT(socks5_radiobtn), MENU_VAL_ID,
+			GINT_TO_POINTER(PROXY_SOCKS5));
+
+	hbox = gtk_hbox_new(FALSE, 8);
+	gtk_box_pack_start(GTK_BOX(vbox1), hbox, FALSE, FALSE, 0);
+
+	label = gtk_label_new(_("Hostname"));
+	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+
+	proxy_host_entry = gtk_entry_new();
+	gtk_widget_set_size_request(proxy_host_entry, DEFAULT_ENTRY_WIDTH, -1);
+	gtk_box_pack_start(GTK_BOX(hbox), proxy_host_entry, TRUE, TRUE, 0);
+
+	label = gtk_label_new(_("Port"));
+	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+
+	proxy_port_spinbtn = gtk_spin_button_new_with_range(0, 65535, 1080);
+	gtk_widget_set_size_request(proxy_port_spinbtn, 64, -1);
+	gtk_box_pack_start(GTK_BOX(hbox), proxy_port_spinbtn, FALSE, FALSE, 0);
+
+	vbox2 = gtk_vbox_new(FALSE, VSPACING_NARROW);
+	gtk_box_pack_start(GTK_BOX(vbox1), vbox2, FALSE, FALSE, 0);
+
+	PACK_CHECK_BUTTON(vbox2, proxy_auth_checkbtn, _("Use authentication"));
+
+	hbox = gtk_hbox_new(FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
+
+	label = gtk_label_new(_("Username"));
+	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+
+	proxy_name_entry = gtk_entry_new();
+	gtk_widget_set_size_request(proxy_name_entry, DEFAULT_ENTRY_WIDTH, -1);
+	gtk_box_pack_start(GTK_BOX(hbox), proxy_name_entry, TRUE, TRUE, 0);
+
+	label = gtk_label_new(_("Password"));
+	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+
+	proxy_pass_entry = gtk_entry_new();
+	gtk_widget_set_size_request(proxy_pass_entry, DEFAULT_ENTRY_WIDTH, -1);
+	gtk_entry_set_visibility(GTK_ENTRY(proxy_pass_entry), FALSE);
+	gtk_box_pack_start(GTK_BOX(hbox), proxy_pass_entry, TRUE, TRUE, 0);
+
+	gtk_widget_show_all(vbox0);
+
+	SET_TOGGLE_SENSITIVITY(proxy_checkbtn, vbox1);
+	SET_TOGGLE_SENSITIVITY(proxy_auth_checkbtn, hbox);
+	SET_TOGGLE_SENSITIVITY(socks5_radiobtn, vbox2);
+
+	/* Set widgets to their correct states, based on prefs. */
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(proxy_checkbtn),
+			prefs_common.use_proxy);
+	if (prefs_common.proxy_info.proxy_type == PROXY_SOCKS4)
+		button = socks4_radiobtn;
+	else
+		button = socks5_radiobtn;
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
+	gtk_entry_set_text(GTK_ENTRY(proxy_host_entry),
+			prefs_common.proxy_info.proxy_host);
+	gtk_spin_button_set_value(GTK_SPIN_BUTTON(proxy_port_spinbtn),
+			(gdouble)prefs_common.proxy_info.proxy_port);
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(proxy_auth_checkbtn),
+			prefs_common.proxy_info.use_proxy_auth);
+	gtk_entry_set_text(GTK_ENTRY(proxy_name_entry),
+			prefs_common.proxy_info.proxy_name);
+
+	buf =
+		passwd_store_get(PWS_CORE, PWS_CORE_PROXY, PWS_CORE_PROXY_PASS);
+	gtk_entry_set_text(GTK_ENTRY(proxy_pass_entry), buf != NULL ? buf : "");
+	if (buf != NULL) {
+		memset(buf, 0, strlen(buf));
+		g_free(buf);
+	}
+
+	page->proxy_checkbtn = proxy_checkbtn;
+	page->socks4_radiobtn = socks4_radiobtn;
+	page->socks5_radiobtn = socks5_radiobtn;
+	page->proxy_host_entry = proxy_host_entry;
+	page->proxy_port_spinbtn = proxy_port_spinbtn;
+	page->proxy_auth_checkbtn = proxy_auth_checkbtn;
+	page->proxy_name_entry = proxy_name_entry;
+	page->proxy_pass_entry = proxy_pass_entry;
+	page->page.widget = vbox0;
+}
+
+
+static void prefs_proxy_destroy_widget(PrefsPage *_page)
+{
+}
+
+
+static void prefs_proxy_save(PrefsPage *_page)
+{
+	ProxyPage *page = (ProxyPage *)_page;
+
+	prefs_common.use_proxy = gtk_toggle_button_get_active(
+			GTK_TOGGLE_BUTTON(page->proxy_checkbtn));
+
+	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->socks4_radiobtn)))
+		prefs_common.proxy_info.proxy_type = PROXY_SOCKS4;
+	else
+		prefs_common.proxy_info.proxy_type = PROXY_SOCKS5;
+
+	g_free(prefs_common.proxy_info.proxy_host);
+	prefs_common.proxy_info.proxy_host = g_strdup(gtk_entry_get_text(
+				GTK_ENTRY(page->proxy_host_entry)));
+
+	prefs_common.proxy_info.proxy_port = gtk_spin_button_get_value_as_int(
+			GTK_SPIN_BUTTON(page->proxy_port_spinbtn));
+
+	prefs_common.proxy_info.use_proxy_auth = gtk_toggle_button_get_active(
+			GTK_TOGGLE_BUTTON(page->proxy_auth_checkbtn));
+
+	g_free(prefs_common.proxy_info.proxy_name);
+	prefs_common.proxy_info.proxy_name = g_strdup(gtk_entry_get_text(
+				GTK_ENTRY(page->proxy_name_entry)));
+
+	passwd_store_set(PWS_CORE, PWS_CORE_PROXY, PWS_CORE_PROXY_PASS,
+			gtk_entry_get_text(GTK_ENTRY(page->proxy_pass_entry)), FALSE);
+}
+
+
+ProxyPage *prefs_proxy;
+
+void prefs_proxy_init(void)
+{
+	ProxyPage *page;
+	static gchar *path[3];
+
+	path[0] = _("Other");
+	path[1] = _("Proxy");
+	path[2] = NULL;
+
+	page = g_new0(ProxyPage, 1);
+	page->page.path = path;
+	page->page.create_widget = prefs_proxy_create_widget;
+	page->page.destroy_widget = prefs_proxy_destroy_widget;
+	page->page.save_page = prefs_proxy_save;
+	page->page.weight = 5.0;
+
+	prefs_gtk_register_page((PrefsPage *)page);
+	prefs_proxy = page;
+}
+
+void prefs_proxy_done(void)
+{
+	prefs_gtk_unregister_page((PrefsPage *)prefs_proxy);
+	g_free(prefs_proxy);
+}
diff --git a/src/prefs_proxy.h b/src/prefs_proxy.h
new file mode 100644
index 0000000..e73a010
--- /dev/null
+++ b/src/prefs_proxy.h
@@ -0,0 +1,26 @@
+/*
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2018 the Claws Mail team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef PREFS_PROXY_H
+#define PREFS_PROXY_H
+
+void prefs_proxy_init	(void);
+void prefs_proxy_done	(void);
+
+#endif /* PREFS_PROXY_H */
diff --git a/src/send_message.c b/src/send_message.c
index 45fd5cf..497fe4d 100644
--- a/src/send_message.c
+++ b/src/send_message.c
@@ -49,6 +49,7 @@
 #include "alertpanel.h"
 #include "manage_window.h"
 #include "logwindow.h"
+#include "proxy.h"
 #include "socket.h"
 #include "utils.h"
 #include "gtkutils.h"
@@ -221,6 +222,7 @@ gint send_message_smtp_full(PrefsAccount *ac_prefs, GSList *to_list, FILE *fp, g
 	MsgFlags flags = {0, 0};
 	long fp_pos = 0;
 	gchar spec_from[BUFFSIZE];
+	ProxyInfo *proxy_info = NULL;
 
 	cm_return_val_if_fail(ac_prefs != NULL, -1);
 	cm_return_val_if_fail(ac_prefs->address != NULL, -1);
@@ -389,10 +391,26 @@ gint send_message_smtp_full(PrefsAccount *ac_prefs, GSList *to_list, FILE *fp, g
 	smtp_session->send_data = (guchar *)get_outgoing_rfc2822_str(fp);
 	smtp_session->send_data_len = strlen((gchar *)smtp_session->send_data);
 
+	if (ac_prefs->use_proxy && ac_prefs->use_proxy_for_send) {
+		if (ac_prefs->use_default_proxy) {
+			proxy_info = (ProxyInfo *)&(prefs_common.proxy_info);
+			if (proxy_info->use_proxy_auth)
+				proxy_info->proxy_pass = passwd_store_get(PWS_CORE, PWS_CORE_PROXY,
+						PWS_CORE_PROXY_PASS);
+		} else {
+			proxy_info = (ProxyInfo *)&(ac_prefs->proxy_info);
+			if (proxy_info->use_proxy_auth)
+				proxy_info->proxy_pass = passwd_store_get_account(ac_prefs->account_id,
+						PWS_ACCOUNT_PROXY_PASS);
+		}
+	}
+	SESSION(smtp_session)->proxy_info = proxy_info;
+
 	session_set_timeout(session,
 			    prefs_common.io_timeout_secs * 1000);
 	/* connect if necessary */
-	if (!was_inited && session_connect(session, ac_prefs->smtp_server, port) < 0) {
+	if (!was_inited && session_connect(session, ac_prefs->smtp_server,
+				port) < 0) {
 		session_destroy(session);
 		send_progress_dialog_destroy(send_dialog);
 		ac_prefs->session = NULL;

commit 67ced10190629b23529d3098c9b686592338aef3
Author: Paul <paul at claws-mail.org>
Date:   Sun Jun 10 11:23:51 2018 +0100

    when changing sort_key by clicking column header, preserve sort_type

diff --git a/src/summaryview.c b/src/summaryview.c
index f4298a9..9bf4420 100644
--- a/src/summaryview.c
+++ b/src/summaryview.c
@@ -7291,7 +7291,7 @@ static void summary_sort_by_column_click(SummaryView *summaryview,
 			     summaryview->sort_type == SORT_ASCENDING
 			     ? SORT_DESCENDING : SORT_ASCENDING);
 	else
-		summary_sort(summaryview, sort_key, SORT_ASCENDING);
+		summary_sort(summaryview, sort_key, summaryview->sort_type);
 
 	node = GTK_CMCTREE_NODE(GTK_CMCLIST(summaryview->ctree)->row_list);
 

commit 8f139f2a1c4ca17123e68899fd6634317be20f8f
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Sun Jun 10 00:38:42 2018 +0200

    Fix a buffer overflow in password encryption, and allow arbitrary password length.
    
    Fixes bug #4033 - Claws Mail crashes [malloc(): memory
    corruption] while trying to save account password greater
    than 136 chars

diff --git a/doc/src/password_encryption.txt b/doc/src/password_encryption.txt
index 7746499..f618378 100644
--- a/doc/src/password_encryption.txt
+++ b/doc/src/password_encryption.txt
@@ -12,9 +12,18 @@ IV (initialization vector) for the cipher is filled with random bytes.
 
 Encryption
 ----------
-We prepare a buffer 128+blocksize bytes long, with one block of random
-data at the beginning, followed by the password we want to encrypt (in
-UTF-8), rest is padded with zero bytes.
+We prepare a buffer long enough to fit the NULL-terminated password string
+plus one cipher block in it, with one block of random data at the beginning,
+followed by the password we want to encrypt (in UTF-8), rest is padded
+with zero bytes.
+
+The minimal buffer size is 128+blocksize, and if the password (including
+the trailing NULL byte) is longer than 128 bytes, the size is increased by
+another 128 bytes until it is long enough to fit the password plus one
+cipher block. This is to make it harder to guess the password length from
+length of the encrypted string. So for example, if the password (again,
+including the trailing NULL byte) is 129 characters long, our buffer will
+be 256+blocksize bytes long.
 
 We encrypt the buffer using the encryption key and IV mentioned above,
 resulting in ciphertext of the same length as the buffer.
diff --git a/src/password.c b/src/password.c
index 9e66a92..8f764e3 100644
--- a/src/password.c
+++ b/src/password.c
@@ -319,7 +319,7 @@ gchar *password_encrypt_gnutls(const gchar *password,
 	gnutls_cipher_algorithm_t algo = GNUTLS_CIPHER_AES_256_CBC;
 	gnutls_cipher_hd_t handle;
 	gnutls_datum_t key, iv;
-	int keylen, blocklen, ret;
+	int keylen, blocklen, ret, len, i;
 	unsigned char *buf, *encbuf, *base, *output;
 	guint rounds = prefs_common_get_prefs()->master_passphrase_pbkdf2_rounds;
 
@@ -353,10 +353,18 @@ gchar *password_encrypt_gnutls(const gchar *password,
 		return NULL;
 	}
 
+	/* Find out how big buffer (in multiples of BUFSIZE)
+	 * we need to store the password. */
+	i = 1;
+	len = strlen(password);
+	while(len >= i * BUFSIZE)
+		i++;
+	len = i * BUFSIZE;
+
 	/* Fill buf with one block of random data, our password, pad the
 	 * rest with zero bytes. */
-	buf = malloc(BUFSIZE + blocklen);
-	memset(buf, 0, BUFSIZE + blocklen);
+	buf = malloc(len + blocklen);
+	memset(buf, 0, len + blocklen);
 	if (!get_random_bytes(buf, blocklen)) {
 		g_free(buf);
 		g_free(key.data);
@@ -368,10 +376,10 @@ gchar *password_encrypt_gnutls(const gchar *password,
 	memcpy(buf + blocklen, password, strlen(password));
 
 	/* Encrypt into encbuf */
-	encbuf = malloc(BUFSIZE + blocklen);
-	memset(encbuf, 0, BUFSIZE + blocklen);
-	ret = gnutls_cipher_encrypt2(handle, buf, BUFSIZE + blocklen,
-			encbuf, BUFSIZE + blocklen);
+	encbuf = malloc(len + blocklen);
+	memset(encbuf, 0, len + blocklen);
+	ret = gnutls_cipher_encrypt2(handle, buf, len + blocklen,
+			encbuf, len + blocklen);
 	if (ret < 0) {
 		g_free(key.data);
 		g_free(iv.data);
@@ -389,7 +397,7 @@ gchar *password_encrypt_gnutls(const gchar *password,
 
 	/* And finally prepare the resulting string:
 	 * "{algorithm,rounds}base64encodedciphertext" */
-	base = g_base64_encode(encbuf, BUFSIZE + blocklen);
+	base = g_base64_encode(encbuf, len + blocklen);
 	g_free(encbuf);
 	output = g_strdup_printf("{%s,%d}%s",
 			gnutls_cipher_get_name(algo), rounds, base);
@@ -515,7 +523,7 @@ gchar *password_decrypt_gnutls(const gchar *password,
 
 	/* 'buf+blocklen' should now be pointing to the plaintext
 	 * password string. The first block contains random data from the IV. */
-	tmp = g_strndup(buf + blocklen, MIN(strlen(buf + blocklen), BUFSIZE));
+	tmp = g_strndup(buf + blocklen, strlen(buf + blocklen));
 	memset(buf, 0, len);
 	g_free(buf);
 

commit ad39cec75255dc1cb6dcc8673a080ab8b435a18e
Author: Paul <paul at claws-mail.org>
Date:   Sat Jun 9 12:12:32 2018 +0100

    fix bug where 'sort_type' is lost when changing 'sort_key' from /View/sort
    
    the bug was apparent with a descending sort. changing the sort_key
    always set it to ascending

diff --git a/src/mainwindow.c b/src/mainwindow.c
index ce5c006..077cbc8 100644
--- a/src/mainwindow.c
+++ b/src/mainwindow.c
@@ -4653,29 +4653,26 @@ static void set_folder_display_item_cb(GtkAction *action, gpointer data)
 static void sort_summary_cb(GtkAction *action, GtkRadioAction *current, gpointer data)
 {
 	MainWindow *mainwin = (MainWindow *)data;
-	FolderItem *item = mainwin->summaryview->folder_item;
 	gint value = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (current));
 
 	if (mainwin->menu_lock_count) return;
 
-	if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (current)) && item) {
+	if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (current))) {
 		summary_sort(mainwin->summaryview, (FolderSortKey)value,
-			     item->sort_type);
-		item->sort_key = value;
+			     mainwin->summaryview->sort_type);
 	}
 }
 
 static void sort_summary_type_cb(GtkAction *gaction, GtkRadioAction *current, gpointer data)
 {
 	MainWindow *mainwin = (MainWindow *)data;
-	FolderItem *item = mainwin->summaryview->folder_item;
 	gint value = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (current));
 
 	if (mainwin->menu_lock_count) return;
 
-	if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (current)) && item)
+	if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (current)))
 		summary_sort(mainwin->summaryview,
-			     item->sort_key, (FolderSortType)value);
+			     mainwin->summaryview->sort_key, (FolderSortType)value);
 }
 
 static void attract_by_subject_cb(GtkAction *action, gpointer data)

commit 51fd2be1343e1ec7722c892d23188045c67f404e
Author: wwp <wwp at free.fr>
Date:   Thu Jun 7 13:06:58 2018 +0200

    Make use of all signature separators defined in accounts instead
    of just the hardcoded standard one we use.

diff --git a/src/account.c b/src/account.c
index 527b16d..b3a92da 100644
--- a/src/account.c
+++ b/src/account.c
@@ -1925,3 +1925,75 @@ gboolean password_get(const gchar *user,
 	}
 	return FALSE;
 }
+
+static GSList *account_signatures_list = NULL;
+
+/* create a list of unique signatures from accounts list */
+void account_signatures_matchlist_create(void)
+{
+	GList *cur_ac = NULL;
+	PrefsAccount *ac_prefs = NULL;
+
+	if (account_signatures_list)
+		return;
+
+	account_signatures_list = g_slist_prepend(account_signatures_list, g_strdup("-- "));
+	for (cur_ac = account_get_list();
+		 cur_ac != NULL;
+		 cur_ac = g_list_next(cur_ac)) {
+		ac_prefs = (PrefsAccount *)cur_ac->data;
+
+		if (ac_prefs->sig_sep && *ac_prefs->sig_sep != '\0') {
+			if (!g_slist_find_custom(account_signatures_list, ac_prefs->sig_sep,
+					(GCompareFunc)strcmp2)) {
+				account_signatures_list = g_slist_prepend(account_signatures_list,
+						g_strdup(ac_prefs->sig_sep));
+			}
+		}
+	}
+}
+
+/* delete the list of signatures created by account_signatures_matchlist_create() */
+void account_signatures_matchlist_delete(void)
+{
+	if (account_signatures_list) {
+		slist_free_strings_full(account_signatures_list);
+		account_signatures_list = NULL;
+	}
+}
+
+/* match a string against all signatures in list, using the specified format */
+gboolean account_signatures_matchlist_str_found(const gchar *str, const gchar *format)
+{
+	gchar *tmp = NULL;
+	gboolean found = FALSE;
+	GSList *item;
+
+	for (item = account_signatures_list;
+		 item != NULL && !found;
+		 item = g_slist_next(item)) {
+		tmp = g_strdup_printf(format, (gchar *)item->data);
+		found = (strcmp(tmp, str) == 0);
+		g_free(tmp);
+	}
+	return found;
+}
+
+/* match M first char of a string against all signatures in list, using the specified format */
+gboolean account_signatures_matchlist_nchar_found(const gchar *str, const gchar *format)
+{
+	gchar *tmp = NULL;
+	gboolean found = FALSE;
+	GSList *item;
+	gint len;
+
+	for (item = account_signatures_list;
+		 item != NULL && !found;
+		 item = g_slist_next(item)) {
+		tmp = g_strdup_printf(format, (gchar *)item->data);
+		len = strlen(tmp);
+		found = (strncmp(tmp, str, len) == 0);
+		g_free(tmp);
+	}
+	return found;
+}
diff --git a/src/account.h b/src/account.h
index 4462f66..649366b 100644
--- a/src/account.h
+++ b/src/account.h
@@ -80,4 +80,9 @@ gboolean      password_get(const gchar *user,
 			   guint16 port,
 			   gchar **password);
 
+void		  account_signatures_matchlist_create		(void);
+void		  account_signatures_matchlist_delete		(void);
+gboolean	  account_signatures_matchlist_str_found	(const gchar *str, const gchar *format);
+gboolean	  account_signatures_matchlist_nchar_found	(const gchar *str, const gchar *format);
+
 #endif /* __ACCOUNT_H__ */
diff --git a/src/procmime.c b/src/procmime.c
index 080f27c..f53e530 100644
--- a/src/procmime.c
+++ b/src/procmime.c
@@ -52,6 +52,7 @@
 #include "alertpanel.h"
 #include "timing.h"
 #include "privacy.h"
+#include "account.h"
 
 static GHashTable *procmime_get_mime_type_table	(void);
 static MimeInfo *procmime_scan_file_short(const gchar *filename);
@@ -293,7 +294,7 @@ static int procmime_fclose(FILE *fp)
 		gint llen = 0;							\
 		strretchomp(lastline);						\
 		llen = strlen(lastline);					\
-		if (lastline[llen-1] == ' ' && strcmp(lastline,"-- ") &&	\
+		if (lastline[llen-1] == ' ' && !account_signatures_matchlist_str_found(lastline, "%s") &&	\
 		    !(llen == 2 && lastline[1] == ' ' && strchr(prefs_common.quote_chars, lastline[0]))) {					\
 			/* this is flowed */					\
 			if (delsp)						\
@@ -381,6 +382,8 @@ gboolean procmime_decode_content(MimeInfo *mimeinfo)
 	tmp_file = TRUE;
 	readend = mimeinfo->offset + mimeinfo->length;
 
+	account_signatures_matchlist_create(); /* FLUSH_LASTLINE will use it */
+
 	*buf = '\0';
 	if (encoding == ENC_QUOTED_PRINTABLE) {
 		while ((ftell(infp) < readend) && (SC_FGETS(buf, sizeof(buf), infp) != NULL)) {
@@ -502,6 +505,8 @@ gboolean procmime_decode_content(MimeInfo *mimeinfo)
 	procmime_fclose(outfp);
 	procmime_fclose(infp);
 
+	account_signatures_matchlist_delete();
+
 	if (err == TRUE) {
 		return FALSE;
 	}
diff --git a/src/quote_fmt_parse.y b/src/quote_fmt_parse.y
index dc330c1..03c872a 100644
--- a/src/quote_fmt_parse.y
+++ b/src/quote_fmt_parse.y
@@ -487,10 +487,11 @@ static void quote_fmt_show_msg(MsgInfo *msginfo, const gchar *body,
 	if (fp == NULL)
 		g_warning("Can't get text part");
 	else {
+		account_signatures_matchlist_create();
 		while (fgets(buf, sizeof(buf), fp) != NULL) {
 			strcrchomp(buf);
-			
-			if (!signature && strncmp(buf, "-- \n", 4) == 0)
+
+			if (!signature && account_signatures_matchlist_nchar_found(buf, "%\n"))
 				break;
 		
 			if (quoted && quote_str)
@@ -498,6 +499,7 @@ static void quote_fmt_show_msg(MsgInfo *msginfo, const gchar *body,
 			
 			INSERT(buf);
 		}
+		account_signatures_matchlist_delete();
 		fclose(fp);
 	}
 }
diff --git a/src/textview.c b/src/textview.c
index 0751e01..55276d8 100644
--- a/src/textview.c
+++ b/src/textview.c
@@ -1084,6 +1084,8 @@ static void textview_write_body(TextView *textview, MimeInfo *mimeinfo)
 
 	procmime_decode_content(mimeinfo);
 
+	account_signatures_matchlist_create();
+
 	if (!g_ascii_strcasecmp(mimeinfo->subtype, "html") &&
 	    prefs_common.render_html) {
 		gchar *filename;
@@ -1165,6 +1167,7 @@ static void textview_write_body(TextView *textview, MimeInfo *mimeinfo)
 				fclose(tmpfp);
 				waitpid(pid, pfd, 0);
 				g_unlink(fname);
+				account_signatures_matchlist_delete();
 				return;
 			}
 		}
@@ -1194,11 +1197,13 @@ textview_default:
 			tmpfp = g_fopen(mimeinfo->data.filename, "rb");
 		if (!tmpfp) {
 			FILE_OP_ERROR(mimeinfo->data.filename, "fopen");
+			account_signatures_matchlist_delete();
 			return;
 		}
 		if (fseek(tmpfp, mimeinfo->offset, SEEK_SET) < 0) {
 			FILE_OP_ERROR(mimeinfo->data.filename, "fseek");
 			fclose(tmpfp);
+			account_signatures_matchlist_delete();
 			return;
 		}
 		debug_print("Viewing text content of type: %s (length: %d)\n", mimeinfo->subtype, mimeinfo->length);
@@ -1208,6 +1213,7 @@ textview_default:
 			textview_write_line(textview, buf, conv, TRUE);
 			if (textview->stop_loading) {
 				fclose(tmpfp);
+				account_signatures_matchlist_delete();
 				return;
 			}
 			wrote += ftell(tmpfp)-i;
@@ -1220,6 +1226,8 @@ textview_default:
 		fclose(tmpfp);
 	}
 
+	account_signatures_matchlist_delete();
+
 	conv_code_converter_destroy(conv);
 	procmime_force_encoding(0);
 
@@ -1256,6 +1264,8 @@ static void textview_show_html(TextView *textview, FILE *fp,
 	parser = sc_html_parser_new(fp, conv);
 	cm_return_if_fail(parser != NULL);
 
+	account_signatures_matchlist_create();
+
 	while ((str = sc_html_parse(parser)) != NULL) {
 	        if (parser->state == SC_HTML_HREF) {
 		        /* first time : get and copy the URL */
@@ -1280,10 +1290,14 @@ static void textview_show_html(TextView *textview, FILE *fp,
 		if (lines % 500 == 0)
 			GTK_EVENTS_FLUSH();
 		if (textview->stop_loading) {
+			account_signatures_matchlist_delete();
 			return;
 		}
 	}
 	textview_write_line(textview, "\n", NULL, FALSE);
+
+	account_signatures_matchlist_delete();
+
 	sc_html_parser_destroy(parser);
 }
 
@@ -1297,16 +1311,21 @@ static void textview_show_ertf(TextView *textview, FILE *fp,
 	parser = ertf_parser_new(fp, conv);
 	cm_return_if_fail(parser != NULL);
 
+	account_signatures_matchlist_create();
+
 	while ((str = ertf_parse(parser)) != NULL) {
 		textview_write_line(textview, str, NULL, FALSE);
 		lines++;
 		if (lines % 500 == 0)
 			GTK_EVENTS_FLUSH();
 		if (textview->stop_loading) {
+			account_signatures_matchlist_delete();
 			return;
 		}
 	}
 	
+	account_signatures_matchlist_delete();
+
 	ertf_parser_destroy(parser);
 }
 
@@ -1647,8 +1666,8 @@ static void textview_write_line(TextView *textview, const gchar *str,
 			else if (strncmp(buf, "@@ ", 3) == 0 &&
 					strcmp(buf+strlen(buf)-4, " @@\n") == 0)
 				fg_color = "diff-hunk";
-		} else if (strcmp(buf,"-- \n") == 0
-				|| strcmp(buf, "- -- \n") == 0
+		} else if (account_signatures_matchlist_str_found(buf,"%s\n")
+				|| account_signatures_matchlist_str_found(buf, "- %s\n")
 				|| textview->is_in_signature) {
 			fg_color = "signature";
 			textview->is_in_signature = TRUE;

commit 845a1ee156c662e8f9245beb27f405d1ac49882c
Author: wwp <wwp at free.fr>
Date:   Wed Jun 6 21:16:21 2018 +0200

    Honor quote_chars from prefs instead of hard-coding "> ".

diff --git a/src/procmime.c b/src/procmime.c
index 76ee317..080f27c 100644
--- a/src/procmime.c
+++ b/src/procmime.c
@@ -294,7 +294,7 @@ static int procmime_fclose(FILE *fp)
 		strretchomp(lastline);						\
 		llen = strlen(lastline);					\
 		if (lastline[llen-1] == ' ' && strcmp(lastline,"-- ") &&	\
-		    strcmp(lastline,"> ")) {					\
+		    !(llen == 2 && lastline[1] == ' ' && strchr(prefs_common.quote_chars, lastline[0]))) {					\
 			/* this is flowed */					\
 			if (delsp)						\
 				lastline[llen-1] = '\0';			\

commit 29ce3575e56789547ee612df02e331f2f2476f28
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Fri Jun 1 08:01:05 2018 +0200

    Fix HTML <hX> header handling.
    
    Fix one-by-off error in detection of the end tag,
    and add an extra newline at the beginning to make
    the heading stand out visually.

diff --git a/src/html.c b/src/html.c
index e982794..ca8fd4c 100644
--- a/src/html.c
+++ b/src/html.c
@@ -395,8 +395,7 @@ static SC_HTMLState sc_html_parse_tag(SC_HTMLParser *parser)
 		   !strcmp(tag->name, "li")     ||
 		   !strcmp(tag->name, "table")  ||
 		   !strcmp(tag->name, "dd")     ||
-		   !strcmp(tag->name, "tr")     ||
-		   (tag->name[0] == 'h' && g_ascii_isdigit(tag->name[1]))) {
+		   !strcmp(tag->name, "tr")) {
 		if (!parser->newline) {
 			parser->space = FALSE;
 			sc_html_append_char(parser, '\n');
@@ -405,6 +404,12 @@ static SC_HTMLState sc_html_parse_tag(SC_HTMLParser *parser)
 			sc_html_append_str(parser, LI_STR, -1);
 		}
 		parser->state = SC_HTML_NORMAL;
+	} else if (tag->name[0] == 'h' && g_ascii_isdigit(tag->name[1])) {
+		if (!parser->newline) {
+			parser->space = FALSE;
+			sc_html_append_char(parser, '\n');
+		}
+		sc_html_append_char(parser, '\n');
 	} else if (!strcmp(tag->name, "blockquote")) {
 		parser->state = SC_HTML_NORMAL;
 		parser->indent++;
@@ -414,7 +419,7 @@ static SC_HTMLState sc_html_parse_tag(SC_HTMLParser *parser)
 	} else if (!strcmp(tag->name, "/table") ||
 		   (tag->name[0] == '/' &&
 		    tag->name[1] == 'h' &&
-		    g_ascii_isdigit(tag->name[1]))) {
+		    g_ascii_isdigit(tag->name[2]))) {
 		if (!parser->empty_line) {
 			parser->space = FALSE;
 			if (!parser->newline) sc_html_append_char(parser, '\n');

commit 6e6295e1023b8a09169bd22695b3360939bd931e
Author: wwp <wwp at free.fr>
Date:   Mon May 28 17:44:59 2018 +0200

    Code cleanup around glib version check (2.28 minimum).

diff --git a/src/common/utils.c b/src/common/utils.c
index 5172982..0a7f421 100644
--- a/src/common/utils.c
+++ b/src/common/utils.c
@@ -90,24 +90,6 @@
 
 static gboolean debug_mode = FALSE;
 
-#if !GLIB_CHECK_VERSION(2, 26, 0)
-guchar *g_base64_decode_wa(const gchar *text, gsize *out_len)
-{
-	guchar *ret;
-	gsize input_length;
-	gint state = 0;
-	guint save = 0;
-
-	input_length = strlen(text);
-
-	ret = g_malloc0((input_length / 4) * 3 + 1);
-
-	*out_len = g_base64_decode_step(text, input_length, ret, &state, &save);
-
-	return ret;
-}
-#endif
-
 /* Return true if we are running as root.  This function should beused
    instead of getuid () == 0.  */
 gboolean superuser_p (void)
diff --git a/src/common/utils.h b/src/common/utils.h
index b37495e..a1f356e 100644
--- a/src/common/utils.h
+++ b/src/common/utils.h
@@ -74,19 +74,6 @@ typedef gint64 goffset;
   #define HAVE_U32_TYPEDEF
 #endif
 
-#if !GLIB_CHECK_VERSION(2, 26, 0)
-#define g_base64_decode(t,l)	g_base64_decode_wa((t),(l))
-guchar *g_base64_decode_wa(const gchar *text, gsize *out_len);
-#endif
-
-#if !GLIB_CHECK_VERSION(2, 25, 0)
-# ifdef G_OS_WIN32
-	typedef _g_stat_struct GStatBuf;
-# else
-	typedef struct stat GStatBuf;
-# endif
-#endif
-
 #ifndef BIG_ENDIAN_HOST
   #if (G_BYTE_ORDER == G_BIG_ENDIAN)
     #define BIG_ENDIAN_HOST 1
diff --git a/src/gtk/gtkutils.c b/src/gtk/gtkutils.c
index b077b62..1f5938b 100644
--- a/src/gtk/gtkutils.c
+++ b/src/gtk/gtkutils.c
@@ -1807,7 +1807,7 @@ GdkPixbuf *claws_load_pixbuf_fitting(GdkPixbuf *src_pixbuf, int box_width,
 	return pixbuf;
 }
 
-#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+#if defined USE_GNUTLS
 static void auto_configure_done(const gchar *hostname, gint port, gboolean ssl, AutoConfigureData *data)
 {
 	gboolean smtp = strcmp(data->tls_service, "submission") == 0 ? TRUE : FALSE;
diff --git a/src/gtk/gtkutils.h b/src/gtk/gtkutils.h
index 15b95f4..b35cf34 100644
--- a/src/gtk/gtkutils.h
+++ b/src/gtk/gtkutils.h
@@ -205,7 +205,7 @@ claws_input_add    (gint	      source,
 	}									\
 }
 
-#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+#if defined USE_GNUTLS
 typedef struct _AutoConfigureData {
 	const gchar *ssl_service;
 	const gchar *tls_service;
diff --git a/src/plugins/libravatar/libravatar.c b/src/plugins/libravatar/libravatar.c
index f07c6a2..de5100a 100644
--- a/src/plugins/libravatar/libravatar.c
+++ b/src/plugins/libravatar/libravatar.c
@@ -79,7 +79,7 @@ static gboolean libravatar_header_update_hook(gpointer source, gpointer data)
 
 static gchar *federated_base_url_from_address(const gchar *address)
 {
-#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+#if defined USE_GNUTLS
 	gchar *base_url = NULL;
 
 	if (!libravatarprefs.allow_federated) {
diff --git a/src/plugins/libravatar/libravatar_prefs.c b/src/plugins/libravatar/libravatar_prefs.c
index 7f46d02..89fd2e7 100644
--- a/src/plugins/libravatar/libravatar_prefs.c
+++ b/src/plugins/libravatar/libravatar_prefs.c
@@ -58,7 +58,7 @@ struct LibravatarPrefsPage
 	GtkWidget *defm_radio[NUM_DEF_BUTTONS];
 	GtkWidget *defm_url_text;
 	GtkWidget *allow_redirects_check;
-#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+#if defined USE_GNUTLS
 	GtkWidget *allow_federated_check;
 #endif
 	GtkWidget *timeout;
@@ -85,7 +85,7 @@ static PrefParam param[] = {
 	{ "allow_redirects", "TRUE",
 	  &libravatarprefs.allow_redirects,
           P_BOOL, NULL, NULL, NULL },
-#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+#if defined USE_GNUTLS
 	{ "allow_federated", "TRUE",
 	  &libravatarprefs.allow_federated,
           P_BOOL, NULL, NULL, NULL },
@@ -374,7 +374,7 @@ static GtkWidget *p_create_frame_network(struct LibravatarPrefsPage *page)
 {
 	GtkWidget *vbox, *chk_redirects, *spinner, *hbox;
 	GtkAdjustment *adj;
-#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+#if defined USE_GNUTLS
 	GtkWidget *chk_federated;
 #endif
 
@@ -389,7 +389,7 @@ static GtkWidget *p_create_frame_network(struct LibravatarPrefsPage *page)
 	page->allow_redirects_check = chk_redirects;
 	gtk_box_pack_start(GTK_BOX(vbox), chk_redirects, FALSE, FALSE, 0);
 
-#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+#if defined USE_GNUTLS
 	chk_federated = create_checkbox(_("_Enable federated servers"),
 				_("Try to get avatar from sender's domain "
 				  "libravatar server"));
@@ -527,7 +527,7 @@ static void libravatar_prefs_save_func(PrefsPage * _page)
 	libravatarprefs.allow_redirects = gtk_toggle_button_get_active(
 		GTK_TOGGLE_BUTTON(page->allow_redirects_check));
 	/* federation */
-#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+#if defined USE_GNUTLS
 	libravatarprefs.allow_federated = gtk_toggle_button_get_active(
 		GTK_TOGGLE_BUTTON(page->allow_federated_check));
 #endif
diff --git a/src/plugins/libravatar/libravatar_prefs.h b/src/plugins/libravatar/libravatar_prefs.h
index 2e81aff..49be964 100644
--- a/src/plugins/libravatar/libravatar_prefs.h
+++ b/src/plugins/libravatar/libravatar_prefs.h
@@ -44,7 +44,7 @@ struct _LibravatarPrefs
 	guint		default_mode;
 	gchar		*default_mode_url;
 	gboolean	allow_redirects;
-#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+#if defined USE_GNUTLS
 	gboolean	allow_federated;
 #endif
 	guint		timeout;
diff --git a/src/plugins/vcalendar/vcal_dbus.c b/src/plugins/vcalendar/vcal_dbus.c
index c716031..f609872 100644
--- a/src/plugins/vcalendar/vcal_dbus.c
+++ b/src/plugins/vcalendar/vcal_dbus.c
@@ -34,8 +34,6 @@
 #include "vcal_manager.h"
 #include "vcal_folder.h"
 
-#if(GLIB_CHECK_VERSION(2,26,0))
-
 static guint dbus_own_id;
 
 static void add_event_to_builder_if_match(VCalEvent *event, GVariantBuilder *array,
@@ -208,14 +206,3 @@ void disconnect_dbus(void)
 	g_free(interface_vtable);
 	interface_vtable = NULL;
 }
-
-#else
-void connect_dbus(void)
-{
-	debug_print("DBUS calendar export is not supported with Glib < 2.26\n");
-}
-void disconnect_dbus(void)
-{
-	debug_print("DBUS calendar export is not supported with Glib < 2.26\n");
-}
-#endif
diff --git a/src/prefs_account.c b/src/prefs_account.c
index 7fc738b..62a039e 100644
--- a/src/prefs_account.c
+++ b/src/prefs_account.c
@@ -915,7 +915,7 @@ static void prefs_account_signature_edit_cb	(GtkWidget	*widget,
 static void pop_bfr_smtp_tm_set_sens		(GtkWidget	*widget,
 						 gpointer	 data);
 
-#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+#if (defined USE_GNUTLS)
 static void auto_configure_cb			(GtkWidget	*widget,
 						 gpointer	 data);
 
@@ -1139,7 +1139,7 @@ static void basic_create_widget_func(PrefsPage * _page,
 	auto_configure_lbl = gtk_label_new("");
 	gtk_label_set_justify(GTK_LABEL(auto_configure_lbl), GTK_JUSTIFY_LEFT);
 	gtk_box_pack_start(GTK_BOX (optmenubox), auto_configure_lbl, FALSE, FALSE, 0);
-#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+#if (defined USE_GNUTLS)
 	gtk_widget_show(auto_configure_btn);
 	gtk_widget_show(auto_configure_lbl);
 	g_signal_connect (G_OBJECT (auto_configure_btn), "clicked",
@@ -3989,7 +3989,7 @@ static void prefs_account_select_folder_cb(GtkWidget *widget, gpointer data)
 	}
 }
 
-#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+#if (defined USE_GNUTLS)
 static void auto_configure_cb (GtkWidget *widget, gpointer data)
 {
 	gchar *address = NULL;
diff --git a/src/wizard.c b/src/wizard.c
index f46c287..db4a108 100644
--- a/src/wizard.c
+++ b/src/wizard.c
@@ -112,7 +112,7 @@ typedef struct
 	GtkWidget *smtp_cert_table;
 	GtkWidget *recv_cert_table;
 #endif
-#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+#if defined USE_GNUTLS
 	GtkWidget *auto_configure_lbl;
 	GtkWidget *auto_configure_btn;
 	GtkWidget *auto_configure_cancel_btn;
@@ -1246,7 +1246,7 @@ static void wizard_protocol_change(WizardWindow *wizard, RecvProtocol protocol)
 		gtk_widget_show(wizard->recv_use_tls);
 		gtk_widget_show(wizard->recv_cert_table);
 #endif
-#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+#if defined USE_GNUTLS
 		gtk_widget_show(wizard->auto_configure_btn);
 		gtk_widget_hide(wizard->auto_configure_cancel_btn);
 		gtk_widget_show(wizard->auto_configure_lbl);
@@ -1278,7 +1278,7 @@ static void wizard_protocol_change(WizardWindow *wizard, RecvProtocol protocol)
 		gtk_widget_show(wizard->recv_use_tls);
 		gtk_widget_show(wizard->recv_cert_table);
 #endif
-#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+#if defined USE_GNUTLS
 		gtk_widget_show(wizard->auto_configure_btn);
 		gtk_widget_hide(wizard->auto_configure_cancel_btn);
 		gtk_widget_show(wizard->auto_configure_lbl);
@@ -1327,7 +1327,7 @@ static void wizard_protocol_change(WizardWindow *wizard, RecvProtocol protocol)
 		gtk_widget_hide(wizard->recv_password);
 		gtk_widget_hide(wizard->recv_username_label);
 		gtk_widget_hide(wizard->recv_password_label);
-#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+#if defined USE_GNUTLS
 		gtk_widget_hide(wizard->auto_configure_btn);
 		gtk_widget_hide(wizard->auto_configure_cancel_btn);
 		gtk_widget_hide(wizard->auto_configure_lbl);
@@ -1353,7 +1353,7 @@ static void wizard_protocol_changed(GtkComboBox *combo, gpointer data)
 	wizard_protocol_change(wizard, protocol);	
 }
 
-#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+#if defined USE_GNUTLS
 static void auto_configure_cb (GtkWidget *widget, gpointer data)
 {
 	gchar *address = NULL;
@@ -1462,7 +1462,7 @@ static GtkWidget* recv_page (WizardWindow * wizard)
 	GtkWidget *button;
 	GtkWidget *recv_cert_table;
 #endif
-#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+#if defined USE_GNUTLS
 	GtkWidget *auto_configure_btn;
 	GtkWidget *auto_configure_cancel_btn;
 	GtkWidget *auto_configure_lbl;
@@ -1518,7 +1518,7 @@ static GtkWidget* recv_page (WizardWindow * wizard)
 	gtk_table_attach(GTK_TABLE(recv_table), wizard->recv_type, 1,2,0,1, 
 			 GTK_EXPAND|GTK_FILL, 0, 0, 0);
 
-#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+#if defined USE_GNUTLS
 	auto_configure_btn = gtk_button_new_with_label(_("Auto-configure"));
 	auto_configure_cancel_btn = gtk_button_new_with_label(_("Cancel"));
 	gtk_table_attach(GTK_TABLE(recv_table), auto_configure_btn, 0,1,1,2,
@@ -1925,7 +1925,7 @@ gboolean run_wizard(MainWindow *mainwin, gboolean create_mailbox) {
 	gtk_widget_hide(wizard->recv_imap_label);
 	gtk_widget_hide(wizard->recv_imap_subdir);
 	gtk_widget_hide(wizard->subsonly_checkbtn);
-#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+#if defined USE_GNUTLS
 	gtk_widget_hide(wizard->auto_configure_cancel_btn);
 #endif
 	wizard_protocol_change(wizard, tmpl.recvtype);

commit 7dbdb3ebae0d47f19edc5b490e49bd317b775d8e
Author: wwp <wwp at free.fr>
Date:   Mon May 28 17:17:05 2018 +0200

    Dynamically allocate interface_vtable.

diff --git a/src/plugins/vcalendar/vcal_dbus.c b/src/plugins/vcalendar/vcal_dbus.c
index 05add6d..c716031 100644
--- a/src/plugins/vcalendar/vcal_dbus.c
+++ b/src/plugins/vcalendar/vcal_dbus.c
@@ -125,13 +125,7 @@ static void handle_method_call (GDBusConnection       *connection,
 }
 
 
-static const GDBusInterfaceVTable interface_vtable =
-{
-	handle_method_call,
-	NULL,
-	NULL,
-	{0,0,0,0,0,0,0,0}
-};
+static GDBusInterfaceVTable* interface_vtable = NULL;
 
 static GDBusNodeInfo *introspection_data = NULL;
 static GDBusInterfaceInfo *interface_info = NULL;
@@ -167,10 +161,13 @@ static void bus_acquired(GDBusConnection *connection,
 			 gpointer         user_data)
 {
 	GError *err = NULL;
+
+	cm_return_if_fail(interface_vtable);
+
 	g_dbus_connection_register_object(connection,
 		"/org/gnome/Shell/CalendarServer",
 		introspection_data->interfaces[0],
-		&interface_vtable, NULL, NULL, &err);
+		(const GDBusInterfaceVTable *)interface_vtable, NULL, NULL, &err);
 	if (err != NULL)
 		debug_print("Error: %s\n", err->message);
 }
@@ -178,13 +175,18 @@ static void bus_acquired(GDBusConnection *connection,
 void connect_dbus(void)
 {
 	debug_print("connect_dbus() invoked\n");
+
+	interface_vtable = g_malloc0(sizeof(GDBusInterfaceVTable));
+	cm_return_if_fail(interface_vtable);
+	interface_vtable->method_call = (GDBusInterfaceMethodCallFunc)handle_method_call;
+
 	introspection_data = g_dbus_node_info_new_for_xml(
 				introspection_xml, NULL);
 	if (introspection_data == NULL) {
 		debug_print("Couldn't figure out XML.\n");
 		return;
 	}
-	
+
 	interface_info = g_dbus_node_info_lookup_interface(
 				introspection_data,
 				"org.gnome.Shell.CalendarServer");
@@ -202,6 +204,9 @@ void disconnect_dbus(void)
 {
 	debug_print("disconnect_dbus() invoked\n");
 	g_bus_unown_name(dbus_own_id);
+
+	g_free(interface_vtable);
+	interface_vtable = NULL;
 }
 
 #else

commit 997324a908aa1e6533ed2e604ea55cf96a99a631
Author: wwp <wwp at free.fr>
Date:   Mon May 28 16:45:47 2018 +0200

    Properly initialize GDBusInterfaceVTable's private member 'padding' (void*[8]).

diff --git a/src/plugins/vcalendar/vcal_dbus.c b/src/plugins/vcalendar/vcal_dbus.c
index f6269ed..05add6d 100644
--- a/src/plugins/vcalendar/vcal_dbus.c
+++ b/src/plugins/vcalendar/vcal_dbus.c
@@ -129,7 +129,8 @@ static const GDBusInterfaceVTable interface_vtable =
 {
 	handle_method_call,
 	NULL,
-	NULL
+	NULL,
+	{0,0,0,0,0,0,0,0}
 };
 
 static GDBusNodeInfo *introspection_data = NULL;

commit 534d04d477a97a61c0a015ffcaa784b4b8e78f16
Author: Ricardo Mones <ricardo at mones.org>
Date:   Mon May 28 14:04:32 2018 +0200

    Fix warning: missing braces around initializer

diff --git a/src/plugins/vcalendar/vcal_dbus.c b/src/plugins/vcalendar/vcal_dbus.c
index cc9c725..f6269ed 100644
--- a/src/plugins/vcalendar/vcal_dbus.c
+++ b/src/plugins/vcalendar/vcal_dbus.c
@@ -129,7 +129,6 @@ static const GDBusInterfaceVTable interface_vtable =
 {
 	handle_method_call,
 	NULL,
-	NULL,
 	NULL
 };
 

-----------------------------------------------------------------------


hooks/post-receive
-- 
Claws Mail


More information about the Commits mailing list