Added SOCKS proxy support.
authorAndrej Kacian <ticho@claws-mail.org>
Fri, 18 May 2018 18:27:52 +0000 (20:27 +0200)
committerAndrej Kacian <ticho@claws-mail.org>
Sun, 10 Jun 2018 10:39:31 +0000 (12:39 +0200)
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.

25 files changed:
po/POTFILES.in
src/Makefile.am
src/common/Makefile.am
src/common/proxy.c [new file with mode: 0644]
src/common/proxy.h [new file with mode: 0644]
src/common/session.c
src/common/session.h
src/common/socket.c
src/etpan/imap-thread.c
src/etpan/imap-thread.h
src/etpan/nntp-thread.c
src/etpan/nntp-thread.h
src/imap.c
src/inc.c
src/main.c
src/news.c
src/passwordstore.h
src/plugins/managesieve/managesieve.c
src/prefs_account.c
src/prefs_account.h
src/prefs_common.c
src/prefs_common.h
src/prefs_proxy.c [new file with mode: 0644]
src/prefs_proxy.h [new file with mode: 0644]
src/send_message.c

index c0a7d39..cee9aa9 100644 (file)
@@ -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
index d2d1548..1fb6dcd 100644 (file)
@@ -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 \
index 1dd8e91..f9ad434 100644 (file)
@@ -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 (file)
index 0000000..7bde533
--- /dev/null
@@ -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 (file)
index 0000000..c009cc4
--- /dev/null
@@ -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__ */
index 0e4a62d..1342ef9 100644 (file)
@@ -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;
 
index 72b4512..5cd518b 100644 (file)
@@ -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;
index f401f28..7751f62 100644 (file)
@@ -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);
index 093f78a..80279d2 100644 (file)
@@ -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;
index 30bce70..e9826a0 100644 (file)
@@ -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
index 3c147d2..ccaede9 100644 (file)
@@ -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;
index d030efa..ddfb8ff 100644 (file)
@@ -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);
 
index fce5ed9..23232f8 100644 (file)
@@ -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;
index d4a6e0f..f0455e3 100644 (file)
--- 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);
 
index 22baeb4..28640c9 100644 (file)
@@ -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();
index c062ac3..7d5fbfa 100644 (file)
@@ -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]) {
index d9d3fed..aeaa40d 100644 (file)
@@ -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 */
index e7b53f5..d1cbcc4 100644 (file)
@@ -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);
 }
index 6701400..dc176ca 100644 (file)
@@ -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);
 }
 
index 39aed6f..e0844af 100644 (file)
@@ -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;
index 5b646a4..c7dc37c 100644 (file)
@@ -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}
 };
 
index cc9451c..95e3c64 100644 (file)
@@ -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 (file)
index 0000000..c3cf43d
--- /dev/null
@@ -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 (file)
index 0000000..e73a010
--- /dev/null
@@ -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 */
index 45fd5cf..497fe4d 100644 (file)
@@ -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;