[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, ¶m, &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, ¶m, &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