[Commits] [SCM] claws branch, master, updated. 3.16.0-195-gd28d627

ticho at claws-mail.org ticho at claws-mail.org
Sun Jun 10 12:39:50 CEST 2018


The branch, master has been updated
       via  d28d62772b7b621b8dfea91c743404e3deef7daa (commit)
      from  6767709b0d603e9013ab10c749b77b9d69cd1500 (commit)

Summary of changes:
 po/POTFILES.in                            |    1 +
 src/Makefile.am                           |    2 +
 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/etpan/imap-thread.c                   |   90 ++++++++-
 src/etpan/imap-thread.h                   |    4 +-
 src/etpan/nntp-thread.c                   |   88 ++++++++-
 src/etpan/nntp-thread.h                   |    5 +-
 src/imap.c                                |   27 ++-
 src/inc.c                                 |   37 +++-
 src/main.c                                |    3 +
 src/news.c                                |   58 +++---
 src/passwordstore.h                       |    4 +
 src/plugins/managesieve/managesieve.c     |   20 ++
 src/prefs_account.c                       |  273 +++++++++++++++++++++++++-
 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/send_message.c                        |   20 +-
 25 files changed, 1201 insertions(+), 79 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 d28d62772b7b621b8dfea91c743404e3deef7daa
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 6701400..dc176ca 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,
@@ -2369,8 +2431,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)		\
 {									\
@@ -2383,6 +2443,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,		\
@@ -2712,9 +2774,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)
@@ -3129,6 +3332,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);
@@ -3172,6 +3388,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; */
@@ -3249,6 +3470,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;
@@ -3350,6 +3581,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;
@@ -3563,6 +3805,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];
@@ -3594,6 +3854,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();
 }
 
@@ -3610,6 +3871,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();
@@ -3652,6 +3914,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);
 
@@ -3781,6 +4044,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);
@@ -3824,6 +4088,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 5b646a4..c7dc37c 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;

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


hooks/post-receive
-- 
Claws Mail


More information about the Commits mailing list