From 81fd89ef633cec2d54b3cff170127cd8d88f544d Mon Sep 17 00:00:00 2001 From: Colin Leroy Date: Thu, 18 Oct 2007 07:13:06 +0000 Subject: [PATCH] 2007-10-18 [colin] 3.0.2cvs82 * src/common/Makefile.am * src/common/nntp.c * src/common/nntp.h * src/etpan/Makefile.am * src/etpan/etpan-thread-manager-types.h * src/etpan/etpan-thread-manager.c * src/etpan/imap-thread.c * src/etpan/nntp-thread.c * src/etpan/nntp-thread.h * src/news.c * src/news.h Rewrite the nntp implementation to use libetpan. Non-blocking NNTP! * src/account.c * src/crash.c * src/imap.c * src/inc.c * src/main.c * src/mainwindow.c * src/pop.c * src/pop.h * src/prefs_account.c * src/recv.c * src/recv.h * src/send_message.c * src/send_message.h * src/ssl_manager.c * src/ssl_manager.h * src/wizard.c * src/common/claws.c * src/common/session.c * src/common/session.h * src/common/smtp.c * src/common/smtp.h * src/common/socket.c * src/common/socket.h * src/common/ssl.c * src/common/ssl.h * src/common/ssl_certificate.c * src/common/ssl_certificate.h * src/gtk/about.c * src/gtk/sslcertwindow.c * src/gtk/sslcertwindow.h Implement GnuTLS support. GnuTLS support will be used if OpenSSL isn't available, or specified explicitely. (the reason is that GnuTLS cerficate checking is a bit less practical than OpenSSL's) --- ChangeLog | 51 ++ PATCHSETS | 1 + configure.ac | 37 +- src/account.c | 2 +- src/common/Makefile.am | 2 - src/common/claws.c | 4 +- src/common/nntp.c | 402 ----------- src/common/nntp.h | 99 --- src/common/session.c | 6 +- src/common/session.h | 4 +- src/common/smtp.c | 14 +- src/common/smtp.h | 2 +- src/common/socket.c | 149 ++-- src/common/socket.h | 6 +- src/common/ssl.c | 137 +++- src/common/ssl.h | 10 +- src/common/ssl_certificate.c | 312 +++++--- src/common/ssl_certificate.h | 23 +- src/crash.c | 3 + src/etpan/Makefile.am | 6 +- src/etpan/etpan-thread-manager-types.h | 1 + src/etpan/etpan-thread-manager.c | 1 + src/etpan/imap-thread.c | 32 +- src/etpan/nntp-thread.c | 946 +++++++++++++++++++++++++ src/etpan/nntp-thread.h | 51 ++ src/gtk/about.c | 10 + src/gtk/sslcertwindow.c | 110 ++- src/gtk/sslcertwindow.h | 7 +- src/imap.c | 20 +- src/inc.c | 2 +- src/main.c | 5 +- src/mainwindow.c | 8 +- src/news.c | 699 +++++++++--------- src/news.h | 4 + src/pop.c | 10 +- src/pop.h | 2 +- src/prefs_account.c | 37 +- src/recv.c | 97 --- src/recv.h | 3 - src/send_message.c | 6 +- src/send_message.h | 2 +- src/ssl_manager.c | 2 +- src/ssl_manager.h | 2 +- src/wizard.c | 20 +- 44 files changed, 2133 insertions(+), 1214 deletions(-) delete mode 100644 src/common/nntp.c delete mode 100644 src/common/nntp.h create mode 100644 src/etpan/nntp-thread.c create mode 100644 src/etpan/nntp-thread.h diff --git a/ChangeLog b/ChangeLog index 87f865ec2..5c115a535 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,54 @@ +2007-10-18 [colin] 3.0.2cvs82 + + * src/common/Makefile.am + * src/common/nntp.c + * src/common/nntp.h + * src/etpan/Makefile.am + * src/etpan/etpan-thread-manager-types.h + * src/etpan/etpan-thread-manager.c + * src/etpan/imap-thread.c + * src/etpan/nntp-thread.c + * src/etpan/nntp-thread.h + * src/news.c + * src/news.h + Rewrite the nntp implementation + to use libetpan. Non-blocking NNTP! + * src/account.c + * src/crash.c + * src/imap.c + * src/inc.c + * src/main.c + * src/mainwindow.c + * src/pop.c + * src/pop.h + * src/prefs_account.c + * src/recv.c + * src/recv.h + * src/send_message.c + * src/send_message.h + * src/ssl_manager.c + * src/ssl_manager.h + * src/wizard.c + * src/common/claws.c + * src/common/session.c + * src/common/session.h + * src/common/smtp.c + * src/common/smtp.h + * src/common/socket.c + * src/common/socket.h + * src/common/ssl.c + * src/common/ssl.h + * src/common/ssl_certificate.c + * src/common/ssl_certificate.h + * src/gtk/about.c + * src/gtk/sslcertwindow.c + * src/gtk/sslcertwindow.h + Implement GnuTLS support. GnuTLS support + will be used if OpenSSL isn't available, or + specified explicitely. (the reason is that + GnuTLS cerficate checking is a bit less + practical than OpenSSL's) + 2007-10-18 [paul] 3.0.2cvs81 * src/gtk/inputdialog.c diff --git a/PATCHSETS b/PATCHSETS index bb4504dd3..12ad59f3b 100644 --- a/PATCHSETS +++ b/PATCHSETS @@ -2994,3 +2994,4 @@ ( cvs diff -u -r 1.382.2.417 -r 1.382.2.418 src/compose.c; cvs diff -u -r 1.8.2.25 -r 1.8.2.26 src/quote_fmt.c; cvs diff -u -r 1.5.12.12 -r 1.5.12.13 src/quote_fmt.h; cvs diff -u -r 1.8.2.15 -r 1.8.2.16 src/quote_fmt_lex.l; cvs diff -u -r 1.22.2.36 -r 1.22.2.37 src/quote_fmt_parse.y; ) > 3.0.2cvs79.patchset ( cvs diff -u -r 1.1.2.18 -r 1.1.2.19 src/plugins/pgpcore/select-keys.c; ) > 3.0.2cvs80.patchset ( cvs diff -u -r 1.2.2.24 -r 1.2.2.25 src/gtk/inputdialog.c; cvs diff -u -r 1.1.2.6 -r 1.1.2.7 src/gtk/inputdialog.h; ) > 3.0.2cvs81.patchset +( cvs diff -u -r 1.61.2.74 -r 1.61.2.75 src/account.c; cvs diff -u -r 1.23.2.26 -r 1.23.2.27 src/crash.c; cvs diff -u -r 1.179.2.194 -r 1.179.2.195 src/imap.c; cvs diff -u -r 1.149.2.83 -r 1.149.2.84 src/inc.c; cvs diff -u -r 1.115.2.173 -r 1.115.2.174 src/main.c; cvs diff -u -r 1.274.2.217 -r 1.274.2.218 src/mainwindow.c; cvs diff -u -r 1.101.2.41 -r 1.101.2.42 src/news.c; cvs diff -u -r 1.21.2.7 -r 1.21.2.8 src/news.h; cvs diff -u -r 1.56.2.59 -r 1.56.2.60 src/pop.c; cvs diff -u -r 1.17.2.20 -r 1.17.2.21 src/pop.h; cvs diff -u -r 1.105.2.112 -r 1.105.2.113 src/prefs_account.c; cvs diff -u -r 1.17.2.13 -r 1.17.2.14 src/recv.c; cvs diff -u -r 1.6.12.7 -r 1.6.12.8 src/recv.h; cvs diff -u -r 1.17.2.44 -r 1.17.2.45 src/send_message.c; cvs diff -u -r 1.1.4.7 -r 1.1.4.8 src/send_message.h; cvs diff -u -r 1.3.2.29 -r 1.3.2.30 src/ssl_manager.c; cvs diff -u -r 1.2.2.7 -r 1.2.2.8 src/ssl_manager.h; cvs diff -u -r 1.1.2.62 -r 1.1.2.63 src/wizard.c; cvs diff -u -r 1.24.2.15 -r 1.24.2.16 src/common/Makefile.am; cvs diff -u -r 1.1.2.2 -r 1.1.2.3 src/common/claws.c; cvs diff -u -r -1.6.2.15 -r -1.6.2.16 src/common/nntp.c; cvs diff -u -r -1.4.2.6 -r -1.4.2.7 src/common/nntp.h; cvs diff -u -r 1.23.2.15 -r 1.23.2.16 src/common/session.c; cvs diff -u -r 1.8.2.10 -r 1.8.2.11 src/common/session.h; cvs diff -u -r 1.11.2.22 -r 1.11.2.23 src/common/smtp.c; cvs diff -u -r 1.6.2.12 -r 1.6.2.13 src/common/smtp.h; cvs diff -u -r 1.13.2.36 -r 1.13.2.37 src/common/socket.c; cvs diff -u -r 1.13.2.16 -r 1.13.2.17 src/common/socket.h; cvs diff -u -r 1.9.2.21 -r 1.9.2.22 src/common/ssl.c; cvs diff -u -r 1.2.2.6 -r 1.2.2.7 src/common/ssl.h; cvs diff -u -r 1.4.2.20 -r 1.4.2.21 src/common/ssl_certificate.c; cvs diff -u -r 1.1.4.9 -r 1.1.4.10 src/common/ssl_certificate.h; cvs diff -u -r 1.1.4.7 -r 1.1.4.8 src/etpan/Makefile.am; cvs diff -u -r 1.1.4.6 -r 1.1.4.7 src/etpan/etpan-thread-manager-types.h; cvs diff -u -r 1.1.4.8 -r 1.1.4.9 src/etpan/etpan-thread-manager.c; cvs diff -u -r 1.1.4.87 -r 1.1.4.88 src/etpan/imap-thread.c; diff -u /dev/null src/etpan/nntp-thread.c; diff -u /dev/null src/etpan/nntp-thread.h; cvs diff -u -r 1.4.2.53 -r 1.4.2.54 src/gtk/about.c; cvs diff -u -r 1.9.2.18 -r 1.9.2.19 src/gtk/sslcertwindow.c; cvs diff -u -r 1.6.2.8 -r 1.6.2.9 src/gtk/sslcertwindow.h; ) > 3.0.2cvs82.patchset diff --git a/configure.ac b/configure.ac index 280b99c07..b04ba3efd 100644 --- a/configure.ac +++ b/configure.ac @@ -11,7 +11,7 @@ MINOR_VERSION=0 MICRO_VERSION=2 INTERFACE_AGE=0 BINARY_AGE=0 -EXTRA_VERSION=81 +EXTRA_VERSION=82 EXTRA_RELEASE= EXTRA_GTK2_VERSION= @@ -363,7 +363,7 @@ fi dnl Check for OpenSSL AC_ARG_ENABLE(openssl, - [ --disable-openssl disable SSL (OpenSSL) support.], + [ --disable-openssl disable OpenSSL support.], [ac_cv_enable_openssl=$enableval], [ac_cv_enable_openssl=yes]) AC_MSG_CHECKING([whether to use OpenSSL]) if test x"$ac_cv_enable_openssl" = xyes; then @@ -371,6 +371,7 @@ if test x"$ac_cv_enable_openssl" = xyes; then PKG_CHECK_MODULES(OPENSSL, openssl >= 0.9.7, :, ac_cv_enable_openssl=no) if test x$ac_cv_enable_openssl = xyes; then AC_DEFINE(USE_OPENSSL, 1, Define if you want OpenSSL support) + disable_gnutls="yes" else AC_MSG_RESULT(not found) AC_MSG_WARN([*** OpenSSL will not be supported ***]) @@ -381,6 +382,37 @@ fi AC_SUBST(OPENSSL_CFLAGS) AC_SUBST(OPENSSL_LIBS) +dnl GNUTLS +AC_ARG_ENABLE(gnutls, [ --disable-gnutls disable GnuTLS support], + [ac_cv_enable_gnutls=$enableval], [ac_cv_enable_gnutls=yes]) +if test "x$disable_gnutls" != "xyes"; then + AC_MSG_CHECKING([whether to use GnuTLS]) + if test "x$ac_cv_enable_gnutls" != "xno"; then + OCPPFLAGS="$CPPFLAGS" + OLDFLAGS="$LDFLAGS" + GNUTLS_LIBS="" + AC_CHECK_HEADER(gnutls/gnutls.h, [ + AC_CHECK_LIB(gnutls, gnutls_global_deinit, + [AC_DEFINE(USE_GNUTLS, 1, Define to use GnuTLS.)], + [ac_cv_enable_gnutls=no]) + ],[ac_cv_enable_gnutls=no]) + if test "x$ac_cv_enable_gnutls" != "xyes"; then + CPPFLAGS="$OCPPFLAGS" + LDFLAGS="$OLDFLAGS" + fi + fi + if test "x$ac_cv_enable_gnutls" = "xyes"; then + AC_DEFINE([USE_GNUTLS],1, [Define to use GnuTLS]) + GNUTLS_LIBS="-lgnutls" + disable_openssl="yes" + else + GNUTLS_LIBS="" + fi +else + ac_cv_enable_gnutls="no" +fi +AC_SUBST(GNUTLS_LIBS) + dnl password encryption OLDLIBS=$LIBS LIBS= @@ -954,6 +986,7 @@ echo "" echo "JPilot : $ac_cv_enable_jpilot" echo "LDAP : $ac_cv_enable_ldap" echo "OpenSSL : $ac_cv_enable_openssl" +echo "gnuTLS : $ac_cv_enable_gnutls" echo "iconv : $am_cv_func_iconv" echo "compface : $ac_cv_enable_compface" echo "IPv6 : $ac_cv_enable_ipv6" diff --git a/src/account.c b/src/account.c index 6ec5a3614..fc1e8891e 100644 --- a/src/account.c +++ b/src/account.c @@ -1238,7 +1238,7 @@ static void account_list_view_add(PrefsAccount *ac_prefs) gboolean getall; name = ac_prefs->account_name; -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) protocol = ac_prefs->protocol == A_POP3 ? (ac_prefs->ssl_pop == SSL_TUNNEL ? "POP3 (SSL)" : diff --git a/src/common/Makefile.am b/src/common/Makefile.am index edd5b1b7f..508ba9d44 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -18,7 +18,6 @@ libclawscommon_la_SOURCES = $(arch_sources) \ log.c \ md5.c \ mgutils.c \ - nntp.c \ passcrypt.c \ plugin.c \ prefs.c \ @@ -47,7 +46,6 @@ clawscommoninclude_HEADERS = $(arch_headers) \ log.h \ md5.h \ mgutils.h \ - nntp.h \ passcrypt.h \ plugin.h \ prefs.h \ diff --git a/src/common/claws.c b/src/common/claws.c index 44d6dd0f0..38fd532e9 100644 --- a/src/common/claws.c +++ b/src/common/claws.c @@ -115,7 +115,7 @@ gboolean claws_init(int *argc, char ***argv) srand((gint) time(NULL)); -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) ssl_init(); #endif @@ -127,7 +127,7 @@ gboolean claws_init(int *argc, char ***argv) void claws_done(void) { -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) ssl_done(); #endif } diff --git a/src/common/nntp.c b/src/common/nntp.c deleted file mode 100644 index 1733efd8a..000000000 --- a/src/common/nntp.c +++ /dev/null @@ -1,402 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2007 Hiroyuki Yamamoto and 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 . - * - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#ifdef ENABLE_NLS -#include -#else -#define _(a) (a) -#define N_(a) (a) -#endif -#include -#include - -#include "nntp.h" -#include "socket.h" -#include "utils.h" -#include "log.h" -#if USE_OPENSSL -# include "ssl.h" -#endif - -static gint verbose = 1; - -static void nntp_session_destroy(Session *session); - -static gint nntp_ok (SockInfo *sock, - gchar *argbuf); - -static gint nntp_gen_send (SockInfo *sock, - const gchar *format, - ...); -static gint nntp_gen_recv (SockInfo *sock, - gchar *buf, - gint size); -static gint nntp_gen_command (NNTPSession *session, - gchar *argbuf, - const gchar *format, - ...); - -#if USE_OPENSSL -Session *nntp_session_new(const gchar *server, gushort port, gchar *buf, - const gchar *userid, const gchar *passwd, - SSLType ssl_type) -#else -Session *nntp_session_new(const gchar *server, gushort port, gchar *buf, - const gchar *userid, const gchar *passwd) -#endif -{ - NNTPSession *session; - SockInfo *sock; - - if ((sock = sock_connect(server, port)) == NULL) { - log_warning(LOG_PROTOCOL, _("Can't connect to NNTP server: %s:%d\n"), - server, port); - return NULL; - } - -#if USE_OPENSSL - if (ssl_type == SSL_TUNNEL && !ssl_init_socket(sock)) { - log_error(LOG_PROTOCOL, _("SSL handshake failed\n")); - sock_close(sock); - return NULL; - } -#endif - - if (nntp_ok(sock, buf) != NN_SUCCESS) { - sock_close(sock); - return NULL; - } - - session = g_new0(NNTPSession, 1); - - session_init(SESSION(session)); - - SESSION(session)->type = SESSION_NEWS; - SESSION(session)->server = g_strdup(server); - SESSION(session)->sock = sock; - SESSION(session)->last_access_time = time(NULL); - SESSION(session)->data = NULL; - - SESSION(session)->destroy = nntp_session_destroy; - - session->group = NULL; - - nntp_mode(session, FALSE); - - if (userid && passwd) { - gint ok; - - session->userid = g_strdup(userid); - session->passwd = g_strdup(passwd); - - ok = nntp_gen_send(sock, "AUTHINFO USER %s", session->userid); - if (ok != NN_SUCCESS) { - session_destroy(SESSION(session)); - return NULL; - } - ok = nntp_ok(sock, NULL); - if (ok == NN_AUTHCONT) { - ok = nntp_gen_send(sock, "AUTHINFO PASS %s", - session->passwd); - if (ok != NN_SUCCESS) { - session_destroy(SESSION(session)); - return NULL; - } - ok = nntp_ok(sock, NULL); - if (ok != NN_SUCCESS) - session->auth_failed = TRUE; - } - if (ok == NN_SOCKET) { - session_destroy(SESSION(session)); - return NULL; - } - } - - session_set_access_time(SESSION(session)); - - return SESSION(session); -} - -void nntp_forceauth(NNTPSession *session, gchar *buf, const gchar *userid, const gchar *passwd) - -{ - if (!session) return; - - nntp_gen_command(session, buf , "AUTHINFO USER %s", userid); - - -} - -static void nntp_session_destroy(Session *session) -{ - NNTPSession *nntp_session = NNTP_SESSION(session); - - g_return_if_fail(session != NULL); - - g_free(nntp_session->group); - g_free(nntp_session->userid); - g_free(nntp_session->passwd); -} - -gint nntp_group(NNTPSession *session, const gchar *group, - gint *num, gint *first, gint *last) -{ - gint ok; - gint resp; - gchar buf[NNTPBUFSIZE]; - - ok = nntp_gen_command(session, buf, "GROUP %s", group); - - if (ok != NN_SUCCESS && ok != NN_SOCKET && ok != NN_AUTHREQ) { - ok = nntp_mode(session, FALSE); - if (ok == NN_SUCCESS) - ok = nntp_gen_command(session, buf, "GROUP %s", group); - } - - if (ok != NN_SUCCESS) - return ok; - - if (sscanf(buf, "%d %d %d %d", &resp, num, first, last) - != 4) { - log_warning(LOG_PROTOCOL, _("protocol error: %s\n"), buf); - return NN_PROTOCOL; - } - - return NN_SUCCESS; -} - -gint nntp_get_article(NNTPSession *session, const gchar *cmd, gint num, - gchar **msgid) -{ - gint ok; - gchar buf[NNTPBUFSIZE]; - - if (num > 0) - ok = nntp_gen_command(session, buf, "%s %d", cmd, num); - else - ok = nntp_gen_command(session, buf, cmd); - - if (ok != NN_SUCCESS) - return ok; - - extract_parenthesis(buf, '<', '>'); - if (buf[0] == '\0') { - log_warning(LOG_PROTOCOL, _("protocol error\n")); - *msgid = g_strdup("0"); - } else - *msgid = g_strdup(buf); - - return NN_SUCCESS; -} - -gint nntp_xover(NNTPSession *session, gint first, gint last) -{ - gint ok; - gchar buf[NNTPBUFSIZE]; - - ok = nntp_gen_command(session, buf, "XOVER %d-%d", first, last); - if (ok != NN_SUCCESS) - return ok; - - return NN_SUCCESS; -} - -gint nntp_xhdr(NNTPSession *session, const gchar *header, gint first, gint last) -{ - gint ok; - gchar buf[NNTPBUFSIZE]; - - ok = nntp_gen_command(session, buf, "XHDR %s %d-%d", - header, first, last); - if (ok != NN_SUCCESS) - return ok; - - return NN_SUCCESS; -} - -gint nntp_list(NNTPSession *session) -{ - return nntp_gen_command(session, NULL, "LIST"); -} - -gint nntp_post(NNTPSession *session, FILE *fp) -{ - gint ok; - gchar buf[NNTPBUFSIZE]; - gchar *msg; - - ok = nntp_gen_command(session, buf, "POST"); - if (ok != NN_SUCCESS) - return ok; - - msg = get_outgoing_rfc2822_str(fp); - if (sock_write_all(SESSION(session)->sock, msg, strlen(msg)) < 0) { - log_warning(LOG_PROTOCOL, _("Error occurred while posting\n")); - g_free(msg); - return NN_SOCKET; - } - g_free(msg); - - sock_write_all(SESSION(session)->sock, ".\r\n", 3); - if ((ok = nntp_ok(SESSION(session)->sock, buf)) != NN_SUCCESS) - return ok; - - session_set_access_time(SESSION(session)); - - return NN_SUCCESS; -} - -gint nntp_mode(NNTPSession *session, gboolean stream) -{ - gint ok; - - ok = nntp_gen_command(session, NULL, "MODE %s", - stream ? "STREAM" : "READER"); - - return ok; -} - -static gint nntp_ok(SockInfo *sock, gchar *argbuf) -{ - gint ok; - gchar buf[NNTPBUFSIZE]; - - if ((ok = nntp_gen_recv(sock, buf, sizeof(buf))) == NN_SUCCESS) { - if (strlen(buf) < 3) - return NN_ERROR; - - if ((buf[0] == '1' || buf[0] == '2' || buf[0] == '3') && - (buf[3] == ' ' || buf[3] == '\0')) { - if (argbuf) - strcpy(argbuf, buf); - - if (!strncmp(buf, "381", 3)) - return NN_AUTHCONT; - - return NN_SUCCESS; - } else if (!strncmp(buf, "480", 3)) - return NN_AUTHREQ; - else - return NN_ERROR; - } - - return ok; -} - -static gint nntp_gen_send(SockInfo *sock, const gchar *format, ...) -{ - gchar buf[NNTPBUFSIZE]; - va_list args; - - va_start(args, format); - g_vsnprintf(buf, sizeof(buf), format, args); - va_end(args); - - if (verbose) { - if (!g_ascii_strncasecmp(buf, "AUTHINFO PASS", 13)) - log_print(LOG_PROTOCOL, "NNTP> AUTHINFO PASS ********\n"); - else - log_print(LOG_PROTOCOL, "NNTP> %s\n", buf); - } - - strcat(buf, "\r\n"); - if (sock_write_all(sock, buf, strlen(buf)) < 0) { - log_warning(LOG_PROTOCOL, _("Error occurred while sending command\n")); - return NN_SOCKET; - } - - return NN_SUCCESS; -} - -static gint nntp_gen_recv(SockInfo *sock, gchar *buf, gint size) -{ - if (sock_gets(sock, buf, size) == -1) - return NN_SOCKET; - - strretchomp(buf); - - if (verbose) - log_print(LOG_PROTOCOL, "NNTP< %s\n", buf); - - return NN_SUCCESS; -} - -static gint nntp_gen_command(NNTPSession *session, gchar *argbuf, - const gchar *format, ...) -{ - gchar buf[NNTPBUFSIZE]; - va_list args; - gint ok; - SockInfo *sock; - - va_start(args, format); - g_vsnprintf(buf, sizeof(buf), format, args); - va_end(args); - - sock = SESSION(session)->sock; - ok = nntp_gen_send(sock, "%s", buf); - if (ok != NN_SUCCESS) - return ok; - ok = nntp_ok(sock, argbuf); - if (ok == NN_AUTHREQ) { - if (!session->userid || !session->passwd) { - session->auth_failed = TRUE; - return ok; - } - - ok = nntp_gen_send(sock, "AUTHINFO USER %s", session->userid); - if (ok != NN_SUCCESS) - return ok; - ok = nntp_ok(sock, NULL); - if (ok == NN_AUTHCONT) { - ok = nntp_gen_send(sock, "AUTHINFO PASS %s", - session->passwd); - if (ok != NN_SUCCESS) - return ok; - ok = nntp_ok(sock, NULL); - } - if (ok != NN_SUCCESS) { - session->auth_failed = TRUE; - return ok; - } - - ok = nntp_gen_send(sock, "%s", buf); - if (ok != NN_SUCCESS) - return ok; - ok = nntp_ok(sock, argbuf); - - } else if (ok == NN_AUTHCONT) { - ok = nntp_gen_send(sock, "AUTHINFO PASS %s", - session->passwd); - if (ok != NN_SUCCESS) { - session->auth_failed = TRUE; - return ok; - } - ok = nntp_ok(sock, NULL); - } - - session_set_access_time(SESSION(session)); - - return ok; -} diff --git a/src/common/nntp.h b/src/common/nntp.h deleted file mode 100644 index fde9e239e..000000000 --- a/src/common/nntp.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2007 Hiroyuki Yamamoto and 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 . - * - */ - -#ifndef __NNTP_H__ -#define __NNTP_H__ - -#include "session.h" -#if USE_OPENSSL -# include "ssl.h" -#endif - -typedef struct _NNTPSession NNTPSession; - -#define NNTP_SESSION(obj) ((NNTPSession *)obj) - -struct _NNTPSession -{ - Session session; - - gchar *group; - gfloat fetch_base_percentage; - gfloat fetch_total_percentage; - - gchar *userid; - gchar *passwd; - gboolean auth_failed; -}; - -#define NN_SUCCESS 0 -#define NN_SOCKET 2 -#define NN_AUTHFAIL 3 -#define NN_PROTOCOL 4 -#define NN_SYNTAX 5 -#define NN_IOERR 6 -#define NN_ERROR 7 -#define NN_AUTHREQ 8 -#define NN_AUTHCONT 9 - -#define NNTPBUFSIZE 8192 - -#if USE_OPENSSL -Session *nntp_session_new (const gchar *server, - gushort port, - gchar *buf, - const gchar *userid, - const gchar *passwd, - SSLType ssl_type); -#else -Session *nntp_session_new (const gchar *server, - gushort port, - gchar *buf, - const gchar *userid, - const gchar *passwd); -#endif - -void nntp_forceauth (NNTPSession *session, - gchar *buf, - const gchar *userid, - const gchar *passwd); - -gint nntp_group (NNTPSession *session, - const gchar *group, - gint *num, - gint *first, - gint *last); -gint nntp_get_article (NNTPSession *session, - const gchar *cmd, - gint num, - gchar **msgid); -gint nntp_xover (NNTPSession *session, - gint first, - gint last); -gint nntp_xhdr (NNTPSession *session, - const gchar *header, - gint first, - gint last); -gint nntp_list (NNTPSession *session); -gint nntp_post (NNTPSession *session, - FILE *fp); -gint nntp_mode (NNTPSession *sessio, - gboolean stream); - -#endif /* __NNTP_H__ */ diff --git a/src/common/session.c b/src/common/session.c index 997372e03..5bc00982c 100644 --- a/src/common/session.c +++ b/src/common/session.c @@ -66,7 +66,7 @@ void session_init(Session *session) session->sock = NULL; session->server = NULL; session->port = 0; -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) session->ssl_type = SSL_NONE; #endif session->nonblocking = TRUE; @@ -158,7 +158,7 @@ static gint session_connect_cb(SockInfo *sock, gpointer data) session->sock = sock; -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) if (session->ssl_type == SSL_TUNNEL) { sock_set_nonblocking_mode(sock, FALSE); if (!ssl_init_socket(sock)) { @@ -335,7 +335,7 @@ static gint session_close(Session *session) return 0; } -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) gint session_start_tls(Session *session) { gboolean nb_mode; diff --git a/src/common/session.h b/src/common/session.h index c94d45e02..f192721d3 100644 --- a/src/common/session.h +++ b/src/common/session.h @@ -92,7 +92,7 @@ struct _Session gchar *server; gushort port; -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) SSLType ssl_type; #endif @@ -187,7 +187,7 @@ void session_set_send_data_notify (Session *session, SendDataNotify notify_func, gpointer data); -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) gint session_start_tls (Session *session); #endif diff --git a/src/common/smtp.c b/src/common/smtp.c index 80b579771..f7e5c39d4 100644 --- a/src/common/smtp.c +++ b/src/common/smtp.c @@ -40,7 +40,7 @@ static void smtp_session_destroy(Session *session); static gint smtp_auth(SMTPSession *session); -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) static gint smtp_starttls(SMTPSession *session); #endif static gint smtp_auth_cram_md5(SMTPSession *session); @@ -80,7 +80,7 @@ Session *smtp_session_new(void) session->state = SMTP_READY; -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) session->tls_init_done = FALSE; #endif @@ -330,7 +330,7 @@ static gint smtp_ehlo_recv(SMTPSession *session, const gchar *msg) return SM_ERROR; } -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) static gint smtp_starttls(SMTPSession *session) { session->state = SMTP_STARTTLS; @@ -580,7 +580,7 @@ static gint smtp_session_recv_msg(Session *session, const gchar *msg) if (strstr(msg, "ESMTP")) smtp_session->is_esmtp = TRUE; case SMTP_CONNECTED: -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) if (smtp_session->user || session->ssl_type != SSL_NONE || smtp_session->is_esmtp) #else @@ -608,7 +608,7 @@ static gint smtp_session_recv_msg(Session *session, const gchar *msg) smtp_session->error_val = SM_ERROR; return -1; } -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) if (session->ssl_type == SSL_STARTTLS && smtp_session->tls_init_done == FALSE) { ret = smtp_starttls(smtp_session); @@ -617,7 +617,7 @@ static gint smtp_session_recv_msg(Session *session, const gchar *msg) #endif if (smtp_session->user) { if (smtp_auth(smtp_session) != SM_OK) { -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) if (session->ssl_type == SSL_NONE && smtp_session->tls_init_done == FALSE && (smtp_session->avail_auth_type & SMTPAUTH_TLS_AVAILABLE)) @@ -630,7 +630,7 @@ static gint smtp_session_recv_msg(Session *session, const gchar *msg) ret = smtp_from(smtp_session); break; case SMTP_STARTTLS: -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) if (session_start_tls(session) < 0) { log_warning(LOG_PROTOCOL, _("couldn't start TLS session\n")); smtp_session->state = SMTP_ERROR; diff --git a/src/common/smtp.h b/src/common/smtp.h index def5f2324..216fb61b2 100644 --- a/src/common/smtp.h +++ b/src/common/smtp.h @@ -90,7 +90,7 @@ struct _SMTPSession SMTPState state; -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) gboolean tls_init_done; #endif diff --git a/src/common/socket.c b/src/common/socket.c index 83529d5a0..adefb2fda 100644 --- a/src/common/socket.c +++ b/src/common/socket.c @@ -62,7 +62,7 @@ #include "socket.h" #include "utils.h" #include "log.h" -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) # include "ssl.h" #endif @@ -409,6 +409,8 @@ static gboolean sock_check(GSource *source) condition |= G_IO_IN; } } +#elif USE_GNUTLS +/* ?? */ #endif FD_ZERO(&fds); @@ -454,7 +456,7 @@ guint sock_add_watch(SockInfo *sock, GIOCondition condition, SockFunc func, sock->condition = condition; sock->data = data; -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) if (sock->ssl) { GSource *source = g_source_new(&sock_watch_funcs, @@ -1284,6 +1286,37 @@ static gint ssl_read(SSL *ssl, gchar *buf, gint len) return -1; } } +#elif USE_GNUTLS +static gint ssl_read(gnutls_session ssl, gchar *buf, gint len) +{ + gint r; + + if (gnutls_record_check_pending(ssl) == 0) { + if (fd_check_io(GPOINTER_TO_INT(gnutls_transport_get_ptr(ssl)), G_IO_IN) < 0) + return -1; + } + + while (1) { + r = gnutls_record_recv(ssl, buf, len); + if (r > 0) + return r; + + switch (r) { + case 0: /* closed connection */ + return -1; + + case GNUTLS_E_AGAIN: + case GNUTLS_E_INTERRUPTED: + errno = EAGAIN; + return -1; + break; + + default: + return -1; + } + } + +} #endif gint sock_read(SockInfo *sock, gchar *buf, gint len) @@ -1292,7 +1325,7 @@ gint sock_read(SockInfo *sock, gchar *buf, gint len) g_return_val_if_fail(sock != NULL, -1); -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) if (sock->ssl) ret = ssl_read(sock->ssl, buf, len); else @@ -1332,6 +1365,28 @@ static gint ssl_write(SSL *ssl, const gchar *buf, gint len) return -1; } } +#elif USE_GNUTLS +static gint ssl_write(gnutls_session ssl, const gchar *buf, gint len) +{ + gint ret; + + if (fd_check_io(GPOINTER_TO_INT(gnutls_transport_get_ptr(ssl)), G_IO_OUT) < 0) + return -1; + + ret = gnutls_record_send(ssl, buf, len); + + switch (ret) { + case 0: + return -1; + case GNUTLS_E_AGAIN: + case GNUTLS_E_INTERRUPTED: + return 0; + + default: + return ret; + } +} + #endif gint sock_write(SockInfo *sock, const gchar *buf, gint len) @@ -1340,7 +1395,7 @@ gint sock_write(SockInfo *sock, const gchar *buf, gint len) g_return_val_if_fail(sock != NULL, -1); -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) if (sock->ssl) ret = ssl_write(sock->ssl, buf, len); else @@ -1379,8 +1434,12 @@ gint fd_write_all(gint fd, const gchar *buf, gint len) return wrlen; } +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) #if USE_OPENSSL static gint ssl_write_all(SSL *ssl, const gchar *buf, gint len) +#else +static gint ssl_write_all(gnutls_session ssl, const gchar *buf, gint len) +#endif { gint n, wrlen = 0; @@ -1403,7 +1462,7 @@ gint sock_write_all(SockInfo *sock, const gchar *buf, gint len) g_return_val_if_fail(sock != NULL, -1); -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) if (sock->ssl) ret = ssl_write_all(sock->ssl, buf, len); else @@ -1470,84 +1529,6 @@ Single-byte send() and recv(). return bp - buf; } -#if USE_OPENSSL -static gint ssl_peek (SSL *ssl, gchar *buf, gint len); - -static gint ssl_gets(SSL *ssl, gchar *buf, gint len) -{ - gchar *newline, *bp = buf; - gint n; - - if (--len < 1) - return -1; - do { - if ((n = ssl_peek(ssl, bp, len)) <= 0) - return -1; - if ((newline = memchr(bp, '\n', n)) != NULL) - n = newline - bp + 1; - if ((n = ssl_read(ssl, bp, n)) < 0) - return -1; - bp += n; - len -= n; - } while (!newline && len); - - *bp = '\0'; - return bp - buf; -} -#endif - -gint sock_gets(SockInfo *sock, gchar *buf, gint len) -{ - gint ret; - - g_return_val_if_fail(sock != NULL, -1); - -#if USE_OPENSSL - if (sock->ssl) - return ssl_gets(sock->ssl, buf, len); - else -#endif - return fd_gets(sock->sock, buf, len); - - if (ret < 0) - sock->state = CONN_DISCONNECTED; - return ret; -} - -/* peek at the socket data without actually reading it */ -#if USE_OPENSSL -static gint ssl_peek(SSL *ssl, gchar *buf, gint len) -{ - gint err, ret; - - if (SSL_pending(ssl) == 0) { - if (fd_check_io(SSL_get_rfd(ssl), G_IO_IN) < 0) - return -1; - } - - ret = SSL_peek(ssl, buf, len); - - switch ((err = SSL_get_error(ssl, ret))) { - case SSL_ERROR_NONE: - return ret; - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: - errno = EAGAIN; - return -1; - case SSL_ERROR_ZERO_RETURN: - return 0; - case SSL_ERROR_SYSCALL: - g_warning("SSL_peek() returned syscall error. errno=%d\n", errno); - return -1; - default: - g_warning("SSL_peek() returned error %d, ret = %d\n", err, ret); - if (ret == 0) - return 0; - return -1; - } -} -#endif - gint sock_close(SockInfo *sock) { gint ret; @@ -1558,7 +1539,7 @@ gint sock_close(SockInfo *sock) if (sock->sock_ch) g_io_channel_unref(sock->sock_ch); -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) if (sock->ssl) ssl_done_socket(sock); if (sock->g_source != 0) diff --git a/src/common/socket.h b/src/common/socket.h index 916ba39c3..d017ee995 100644 --- a/src/common/socket.h +++ b/src/common/socket.h @@ -35,7 +35,7 @@ typedef struct _SockInfo SockInfo; -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) # include "ssl.h" #endif @@ -61,6 +61,9 @@ struct _SockInfo #if USE_OPENSSL SSL *ssl; guint g_source; +#elif USE_GNUTLS + gnutls_session ssl; + guint g_source; #endif GIOChannel *sock_ch; @@ -97,7 +100,6 @@ gint sock_connect_async_cancel (gint id); gint sock_read (SockInfo *sock, gchar *buf, gint len); gint sock_write (SockInfo *sock, const gchar *buf, gint len); gint sock_write_all (SockInfo *sock, const gchar *buf, gint len); -gint sock_gets (SockInfo *sock, gchar *buf, gint len); gint sock_close (SockInfo *sock); /* Functions to directly work on FD. They are needed for pipes */ diff --git a/src/common/ssl.c b/src/common/ssl.c index 0055117d4..8228543aa 100644 --- a/src/common/ssl.c +++ b/src/common/ssl.c @@ -21,8 +21,7 @@ # include "config.h" #endif -#if USE_OPENSSL - +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) #include "defs.h" #include @@ -43,16 +42,23 @@ #ifdef USE_PTHREAD typedef struct _thread_data { +#ifdef USE_OPENSSL SSL *ssl; +#else + gnutls_session ssl; +#endif gboolean done; } thread_data; #endif +#ifdef USE_OPENSSL static SSL_CTX *ssl_ctx; +#endif void ssl_init(void) { +#ifdef USE_OPENSSL SSL_METHOD *meth; /* Global system initialization*/ @@ -73,14 +79,21 @@ void ssl_init(void) #if (OPENSSL_VERSION_NUMBER < 0x0090600fL) SSL_CTX_set_verify_depth(ssl_ctx,1); #endif +#else + gnutls_global_init(); +#endif } void ssl_done(void) { +#if USE_OPENSSL if (!ssl_ctx) return; SSL_CTX_free(ssl_ctx); +#else + gnutls_global_deinit(); +#endif } #ifdef USE_PTHREAD @@ -92,18 +105,31 @@ static void *SSL_connect_thread(void *data) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); +#ifdef USE_OPENSSL result = SSL_connect(td->ssl); +#else + do { + result = gnutls_handshake(td->ssl); + } while (result == GNUTLS_E_AGAIN || result == GNUTLS_E_INTERRUPTED); +#endif td->done = TRUE; /* let the caller thread join() */ return GINT_TO_POINTER(result); } #endif +#ifdef USE_OPENSSL static gint SSL_connect_nb(SSL *ssl) +#else +static gint SSL_connect_nb(gnutls_session ssl) +#endif { #if (defined USE_PTHREAD && ((defined __GLIBC__ && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3))) || !defined __GLIBC__)) thread_data *td = g_new0(thread_data, 1); pthread_t pt; void *res = NULL; +#ifdef USE_GNUTLS + int result; +#endif time_t start_time = time(NULL); gboolean killed = FALSE; @@ -114,9 +140,15 @@ static gint SSL_connect_nb(SSL *ssl) * fallback to blocking method in case of problem */ if (pthread_create(&pt, PTHREAD_CREATE_JOINABLE, - SSL_connect_thread, td) != 0) + SSL_connect_thread, td) != 0) { +#ifdef USE_OPENSSL return SSL_connect(ssl); - +#else + do { + result = gnutls_handshake(td->ssl); + } while (result == GNUTLS_E_AGAIN || result == GNUTLS_E_INTERRUPTED); +#endif + } debug_print("waiting for SSL_connect thread...\n"); while(!td->done) { /* don't let the interface freeze while waiting */ @@ -140,7 +172,13 @@ static gint SSL_connect_nb(SSL *ssl) return GPOINTER_TO_INT(res); #else +#ifdef USE_OPENSSL return SSL_connect(ssl); +#else + do { + result = gnutls_handshake(td->ssl); + } while (result == GNUTLS_E_AGAIN || result == GNUTLS_E_INTERRUPTED); +#endif #endif } @@ -149,8 +187,20 @@ gboolean ssl_init_socket(SockInfo *sockinfo) return ssl_init_socket_with_method(sockinfo, SSL_METHOD_SSLv23); } +static const gchar *ssl_get_cert_file(void) +{ + if (g_getenv("SSL_CERT_FILE")) + return g_getenv("SSL_CERT_FILE"); +#ifndef G_OS_WIN32 + return "/etc/ssl/certs/ca-certificates.crt"; +#else + return "put_what_s_needed_here"; +#endif +} + gboolean ssl_init_socket_with_method(SockInfo *sockinfo, SSLMethod method) { +#ifdef USE_OPENSSL X509 *server_cert; SSL *ssl; @@ -202,14 +252,93 @@ gboolean ssl_init_socket_with_method(SockInfo *sockinfo, SSLMethod method) X509_free(server_cert); sockinfo->ssl = ssl; +#else + gnutls_session session; + int r; + const int cipher_prio[] = { GNUTLS_CIPHER_AES_128_CBC, + GNUTLS_CIPHER_3DES_CBC, + GNUTLS_CIPHER_AES_256_CBC, + GNUTLS_CIPHER_ARCFOUR_128, 0 }; + const int kx_prio[] = { GNUTLS_KX_DHE_RSA, + GNUTLS_KX_RSA, + GNUTLS_KX_DHE_DSS, 0 }; + const int mac_prio[] = { GNUTLS_MAC_SHA1, + GNUTLS_MAC_MD5, 0 }; + const int proto_prio[] = { GNUTLS_TLS1, + GNUTLS_SSL3, 0 }; + const gnutls_datum *raw_cert_list; + unsigned int raw_cert_list_length; + gnutls_x509_crt cert = NULL; + guint status; + gnutls_certificate_credentials_t xcred; + + if (gnutls_certificate_allocate_credentials (&xcred) != 0) + return FALSE; + + r = gnutls_init(&session, GNUTLS_CLIENT); + if (session == NULL || r != 0) + return FALSE; + + gnutls_set_default_priority(session); + gnutls_protocol_set_priority (session, proto_prio); + gnutls_cipher_set_priority (session, cipher_prio); + gnutls_kx_set_priority (session, kx_prio); + gnutls_mac_set_priority (session, mac_prio); + + gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred); + + r = gnutls_certificate_set_x509_trust_file(xcred, ssl_get_cert_file(), GNUTLS_X509_FMT_PEM); + if (r < 0) + g_warning("Can't read SSL_CERT_FILE %s: %s\n", + ssl_get_cert_file(), + gnutls_strerror(r)); + + gnutls_certificate_set_verify_flags (xcred, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); + + gnutls_transport_set_ptr(session, (gnutls_transport_ptr) + sockinfo->sock); + + if (SSL_connect_nb(session) == -1) { + g_warning("SSL connection failed"); + gnutls_deinit(session); + return FALSE; + } + /* Get server's certificate (note: beware of dynamic allocation) */ + raw_cert_list = gnutls_certificate_get_peers(session, &raw_cert_list_length); + + if (!raw_cert_list + || gnutls_certificate_type_get(session) != GNUTLS_CRT_X509 + || (r = gnutls_x509_crt_init(&cert)) < 0 + || (r = gnutls_x509_crt_import(cert, &raw_cert_list[0], GNUTLS_X509_FMT_DER)) < 0) { + g_warning("cert get failure: %d %s\n", r, gnutls_strerror(r)); + gnutls_deinit(session); + return FALSE; + } + + r = gnutls_certificate_verify_peers2(session, &status); + + if (!ssl_certificate_check(cert, status, sockinfo->canonical_name, sockinfo->hostname, sockinfo->port)) { + gnutls_x509_crt_deinit(cert); + gnutls_deinit(session); + return FALSE; + } + + gnutls_x509_crt_deinit(cert); + + sockinfo->ssl = session; +#endif return TRUE; } void ssl_done_socket(SockInfo *sockinfo) { if (sockinfo && sockinfo->ssl) { +#ifdef USE_OPENSSL SSL_free(sockinfo->ssl); +#else + gnutls_deinit(sockinfo->ssl); +#endif sockinfo->ssl = NULL; } } diff --git a/src/common/ssl.h b/src/common/ssl.h index 3e576ec7a..e016b6dce 100644 --- a/src/common/ssl.h +++ b/src/common/ssl.h @@ -30,16 +30,20 @@ typedef enum { SSL_STARTTLS } SSLType; -#if USE_OPENSSL - +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) #include + +#if USE_OPENSSL #include #include #include #include #include #include - +#else +#include +#include +#endif #include "socket.h" typedef enum { diff --git a/src/common/ssl_certificate.c b/src/common/ssl_certificate.c index 73e16389a..7bdfc5fd8 100644 --- a/src/common/ssl_certificate.c +++ b/src/common/ssl_certificate.c @@ -22,9 +22,18 @@ # include "config.h" #endif +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) #if USE_OPENSSL - #include +#else +#include +#include +#include +#include +#include +#include +#include +#endif #include #include @@ -33,6 +42,7 @@ #include "log.h" #include "socket.h" #include "hooks.h" +#include "defs.h" static GHashTable *warned_expired = NULL; @@ -50,8 +60,12 @@ static gchar *get_certificate_path(const gchar *host, const gchar *port, const g host, ".", port, ".cert", NULL); } +#if USE_OPENSSL static SSLCertificate *ssl_certificate_new_lookup(X509 *x509_cert, gchar *host, gushort port, gboolean lookup); - +#else +static SSLCertificate *ssl_certificate_new_lookup(gnutls_x509_crt x509_cert, gchar *host, gushort port, gboolean lookup); +#endif +#if USE_OPENSSL /* from Courier */ time_t asn1toTime(ASN1_TIME *asn1Time) { @@ -97,6 +111,7 @@ time_t asn1toTime(ASN1_TIME *asn1Time) return mktime(&tm)-offset; } +#endif static char * get_fqdn(char *host) { @@ -134,17 +149,68 @@ char * readable_fingerprint(unsigned char *src, int len) return ret; } +#if USE_GNUTLS +static gnutls_x509_crt x509_crt_copy(gnutls_x509_crt src) +{ + int ret; + size_t size; + gnutls_datum tmp; + gnutls_x509_crt dest; + + if (gnutls_x509_crt_init(&dest) != 0) { + g_warning("couldn't gnutls_x509_crt_init\n"); + return NULL; + } + + if (gnutls_x509_crt_export(src, GNUTLS_X509_FMT_DER, NULL, &size) + != GNUTLS_E_SHORT_MEMORY_BUFFER) { + g_warning("couldn't gnutls_x509_crt_export to get size\n"); + gnutls_x509_crt_deinit(dest); + return NULL; + } + + tmp.data = malloc(size); + memset(tmp.data, 0, size); + ret = gnutls_x509_crt_export(src, GNUTLS_X509_FMT_DER, tmp.data, &size); + if (ret == 0) { + tmp.size = size; + ret = gnutls_x509_crt_import(dest, &tmp, GNUTLS_X509_FMT_DER); + if (ret) { + g_warning("couldn't gnutls_x509_crt_import for real (%d %s)\n", ret, gnutls_strerror(ret)); + gnutls_x509_crt_deinit(dest); + dest = NULL; + } + } else { + g_warning("couldn't gnutls_x509_crt_export for real (%d %s)\n", ret, gnutls_strerror(ret)); + gnutls_x509_crt_deinit(dest); + dest = NULL; + } + + free(tmp.data); + return dest; +} +#endif + +#if USE_OPENSSL static SSLCertificate *ssl_certificate_new_lookup(X509 *x509_cert, gchar *host, gushort port, gboolean lookup) +#else +static SSLCertificate *ssl_certificate_new_lookup(gnutls_x509_crt x509_cert, gchar *host, gushort port, gboolean lookup) +#endif { SSLCertificate *cert = g_new0(SSLCertificate, 1); unsigned int n; - unsigned char md[EVP_MAX_MD_SIZE]; - + unsigned char md[128]; + if (host == NULL || x509_cert == NULL) { ssl_certificate_destroy(cert); return NULL; } +#if USE_OPENSSL cert->x509_cert = X509_dup(x509_cert); +#else + cert->x509_cert = x509_crt_copy(x509_cert); + cert->status = (guint)-1; +#endif if (lookup) cert->host = get_fqdn(host); else @@ -152,11 +218,60 @@ static SSLCertificate *ssl_certificate_new_lookup(X509 *x509_cert, gchar *host, cert->port = port; /* fingerprint */ +#if USE_OPENSSL X509_digest(cert->x509_cert, EVP_md5(), md, &n); cert->fingerprint = readable_fingerprint(md, (int)n); +#else + gnutls_x509_crt_get_fingerprint(cert->x509_cert, GNUTLS_DIG_MD5, md, &n); + cert->fingerprint = readable_fingerprint(md, (int)n); +#endif + return cert; +} + +#ifdef USE_GNUTLS +static void i2d_X509_fp(FILE *fp, gnutls_x509_crt x509_cert) +{ + char output[10*1024]; + size_t cert_size; + int r; + + if ((r = gnutls_x509_crt_export(x509_cert, GNUTLS_X509_FMT_DER, output, &cert_size)) < 0) { + g_warning("couldn't export cert %s\n", gnutls_strerror(r)); + return; + } + debug_print("writing %zd bytes\n",cert_size); + if (fwrite(&output, 1, cert_size, fp) < cert_size) { + g_warning("failed to write cert\n"); + } +} +static gnutls_x509_crt d2i_X509_fp(FILE *fp, int unused) +{ + gnutls_x509_crt cert = NULL; + gnutls_datum tmp; + struct stat s; + int r; + if (fstat(fileno(fp), &s) < 0) { + perror("fstat"); + return NULL; + } + tmp.data = malloc(s.st_size); + memset(tmp.data, 0, s.st_size); + tmp.size = s.st_size; + if (fread (tmp.data, 1, s.st_size, fp) < s.st_size) { + perror("fread"); + return NULL; + } + gnutls_x509_crt_init(&cert); + if ((r = gnutls_x509_crt_import(cert, &tmp, GNUTLS_X509_FMT_DER)) < 0) { + g_warning("import failed: %s\n", gnutls_strerror(r)); + gnutls_x509_crt_deinit(cert); + cert = NULL; + } + debug_print("got cert! %p\n", cert); return cert; } +#endif static void ssl_certificate_save (SSLCertificate *cert) { @@ -186,94 +301,17 @@ static void ssl_certificate_save (SSLCertificate *cert) } -char* ssl_certificate_to_string(SSLCertificate *cert) -{ - char *ret, buf[100]; - char *issuer_commonname, *issuer_location, *issuer_organization; - char *subject_commonname, *subject_location, *subject_organization; - char *fingerprint, *sig_status; - unsigned int n; - unsigned char md[EVP_MAX_MD_SIZE]; - - /* issuer */ - if (X509_NAME_get_text_by_NID(X509_get_issuer_name(cert->x509_cert), - NID_commonName, buf, 100) >= 0) - issuer_commonname = g_strdup(buf); - else - issuer_commonname = g_strdup(_("")); - if (X509_NAME_get_text_by_NID(X509_get_issuer_name(cert->x509_cert), - NID_localityName, buf, 100) >= 0) { - issuer_location = g_strdup(buf); - if (X509_NAME_get_text_by_NID(X509_get_issuer_name(cert->x509_cert), - NID_countryName, buf, 100) >= 0) - issuer_location = g_strconcat(issuer_location,", ",buf, NULL); - } else if (X509_NAME_get_text_by_NID(X509_get_issuer_name(cert->x509_cert), - NID_countryName, buf, 100) >= 0) - issuer_location = g_strdup(buf); - else - issuer_location = g_strdup(_("")); - - if (X509_NAME_get_text_by_NID(X509_get_issuer_name(cert->x509_cert), - NID_organizationName, buf, 100) >= 0) - issuer_organization = g_strdup(buf); - else - issuer_organization = g_strdup(_("")); - - /* subject */ - if (X509_NAME_get_text_by_NID(X509_get_subject_name(cert->x509_cert), - NID_commonName, buf, 100) >= 0) - subject_commonname = g_strdup(buf); - else - subject_commonname = g_strdup(_("")); - if (X509_NAME_get_text_by_NID(X509_get_subject_name(cert->x509_cert), - NID_localityName, buf, 100) >= 0) { - subject_location = g_strdup(buf); - if (X509_NAME_get_text_by_NID(X509_get_subject_name(cert->x509_cert), - NID_countryName, buf, 100) >= 0) - subject_location = g_strconcat(subject_location,", ",buf, NULL); - } else if (X509_NAME_get_text_by_NID(X509_get_subject_name(cert->x509_cert), - NID_countryName, buf, 100) >= 0) - subject_location = g_strdup(buf); - else - subject_location = g_strdup(_("")); - - if (X509_NAME_get_text_by_NID(X509_get_subject_name(cert->x509_cert), - NID_organizationName, buf, 100) >= 0) - subject_organization = g_strdup(buf); - else - subject_organization = g_strdup(_("")); - - /* fingerprint */ - X509_digest(cert->x509_cert, EVP_md5(), md, &n); - fingerprint = readable_fingerprint(md, (int)n); - - /* signature */ - sig_status = ssl_certificate_check_signer(cert->x509_cert); - - ret = g_strdup_printf(_(" Owner: %s (%s) in %s\n Signed by: %s (%s) in %s\n Fingerprint: %s\n Signature status: %s"), - subject_commonname, subject_organization, subject_location, - issuer_commonname, issuer_organization, issuer_location, - fingerprint, - (sig_status==NULL ? "correct":sig_status)); - - g_free(issuer_commonname); - g_free(issuer_location); - g_free(issuer_organization); - g_free(subject_commonname); - g_free(subject_location); - g_free(subject_organization); - g_free(fingerprint); - g_free(sig_status); - return ret; -} - void ssl_certificate_destroy(SSLCertificate *cert) { if (cert == NULL) return; if (cert->x509_cert) +#if USE_OPENSSL X509_free(cert->x509_cert); +#else + gnutls_x509_crt_deinit(cert->x509_cert); +#endif g_free(cert->host); g_free(cert->fingerprint); g_free(cert); @@ -302,7 +340,11 @@ SSLCertificate *ssl_certificate_find_lookup (gchar *host, gushort port, const gc gchar *buf; gchar *fqdn_host; SSLCertificate *cert = NULL; +#if USE_OPENSSL X509 *tmp_x509; +#else + gnutls_x509_crt tmp_x509; +#endif FILE *fp = NULL; gboolean must_rename = FALSE; @@ -319,12 +361,17 @@ SSLCertificate *ssl_certificate_find_lookup (gchar *host, gushort port, const gc } if (fp == NULL) { /* see if we have the old one */ + debug_print("didn't get %s\n", file); g_free(file); file = get_certificate_path(fqdn_host, buf, NULL); fp = g_fopen(file, "rb"); - if (fp) + if (fp) { + debug_print("got %s\n", file); must_rename = (fingerprint != NULL); + } + } else { + debug_print("got %s first try\n", file); } if (fp == NULL) { g_free(file); @@ -335,7 +382,12 @@ SSLCertificate *ssl_certificate_find_lookup (gchar *host, gushort port, const gc if ((tmp_x509 = d2i_X509_fp(fp, 0)) != NULL) { cert = ssl_certificate_new_lookup(tmp_x509, fqdn_host, port, lookup); + debug_print("got cert %p\n", cert); +#if USE_OPENSSL X509_free(tmp_x509); +#else + gnutls_x509_crt_deinit(tmp_x509); +#endif } fclose(fp); g_free(file); @@ -356,14 +408,58 @@ SSLCertificate *ssl_certificate_find_lookup (gchar *host, gushort port, const gc static gboolean ssl_certificate_compare (SSLCertificate *cert_a, SSLCertificate *cert_b) { - if (cert_a == NULL || cert_b == NULL) - return FALSE; +#ifdef USE_OPENSSL + if (cert_a == NULL || cert_b == NULL) + return FALSE; else if (!X509_cmp(cert_a->x509_cert, cert_b->x509_cert)) return TRUE; else return FALSE; +#else + char *output_a; + char *output_b; + size_t cert_size_a, cert_size_b; + int r; + + if (cert_a == NULL || cert_b == NULL) + return FALSE; + + if ((r = gnutls_x509_crt_export(cert_a->x509_cert, GNUTLS_X509_FMT_DER, NULL, &cert_size_a)) + != GNUTLS_E_SHORT_MEMORY_BUFFER) { + g_warning("couldn't gnutls_x509_crt_export to get size a %s\n", gnutls_strerror(r)); + return FALSE; + } + + if ((r = gnutls_x509_crt_export(cert_b->x509_cert, GNUTLS_X509_FMT_DER, NULL, &cert_size_b)) + != GNUTLS_E_SHORT_MEMORY_BUFFER) { + g_warning("couldn't gnutls_x509_crt_export to get size b %s\n", gnutls_strerror(r)); + return FALSE; + } + + output_a = malloc(cert_size_a); + output_b = malloc(cert_size_b); + if ((r = gnutls_x509_crt_export(cert_a->x509_cert, GNUTLS_X509_FMT_DER, output_a, &cert_size_a)) < 0) { + g_warning("couldn't gnutls_x509_crt_export a %s\n", gnutls_strerror(r)); + return FALSE; + } + if ((r = gnutls_x509_crt_export(cert_b->x509_cert, GNUTLS_X509_FMT_DER, output_b, &cert_size_b)) < 0) { + g_warning("couldn't gnutls_x509_crt_export b %s\n", gnutls_strerror(r)); + return FALSE; + } + if (cert_size_a != cert_size_b) { + g_warning("size differ %d %d\n", cert_size_a, cert_size_b); + return FALSE; + } + if (memcmp(output_a, output_b, cert_size_a)) { + g_warning("contents differ\n"); + return FALSE; + } + + return TRUE; +#endif } +#if USE_OPENSSL char *ssl_certificate_check_signer (X509 *cert) { X509_STORE_CTX store_ctx; @@ -395,8 +491,33 @@ char *ssl_certificate_check_signer (X509 *cert) X509_STORE_free (store); return NULL; } +#else +char *ssl_certificate_check_signer (gnutls_x509_crt cert, guint status) +{ + if (status == (guint)-1) + return g_strdup(_("Uncheckable")); + + if (status & GNUTLS_CERT_INVALID) { + if (gnutls_x509_crt_check_issuer(cert, cert)) + return g_strdup(_("Self-signed certificate")); + } + if (status & GNUTLS_CERT_REVOKED) + return g_strdup(_("Revoked certificate")); + if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) + return g_strdup(_("No certificate issuer found")); + if (status & GNUTLS_CERT_SIGNER_NOT_CA) + return g_strdup(_("Certificate issuer is not a CA")); + + return NULL; +} +#endif + +#if USE_OPENSSL gboolean ssl_certificate_check (X509 *x509_cert, gchar *fqdn, gchar *host, gushort port) +#else +gboolean ssl_certificate_check (gnutls_x509_crt x509_cert, guint status, gchar *fqdn, gchar *host, gushort port) +#endif { SSLCertificate *current_cert = NULL; SSLCertificate *known_cert; @@ -404,7 +525,7 @@ gboolean ssl_certificate_check (X509 *x509_cert, gchar *fqdn, gchar *host, gusho gchar *fqdn_host = NULL; gchar *fingerprint; unsigned int n; - unsigned char md[EVP_MAX_MD_SIZE]; + unsigned char md[128]; if (fqdn) fqdn_host = g_strdup(fqdn); @@ -423,9 +544,18 @@ gboolean ssl_certificate_check (X509 *x509_cert, gchar *fqdn, gchar *host, gusho return FALSE; } +#if USE_GNUTLS + current_cert->status = status; +#endif /* fingerprint */ +#if USE_OPENSSL X509_digest(x509_cert, EVP_md5(), md, &n); fingerprint = readable_fingerprint(md, (int)n); +#else + n = 128; + gnutls_x509_crt_get_fingerprint(x509_cert, GNUTLS_DIG_MD5, md, &n); + fingerprint = readable_fingerprint(md, (int)n); +#endif known_cert = ssl_certificate_find_lookup (fqdn_host, port, fingerprint, FALSE); @@ -466,7 +596,11 @@ gboolean ssl_certificate_check (X509 *x509_cert, gchar *fqdn, gchar *host, gusho ssl_certificate_destroy(known_cert); return TRUE; } +#if USE_OPENSSL } else if (asn1toTime(X509_get_notAfter(current_cert->x509_cert)) < time(NULL)) { +#else + } else if (gnutls_x509_crt_get_expiration_time(current_cert->x509_cert) < time(NULL)) { +#endif gchar *tmp = g_strdup_printf("%s:%d", current_cert->host, current_cert->port); if (warned_expired == NULL) diff --git a/src/common/ssl_certificate.h b/src/common/ssl_certificate.h index da8039e04..932affe8d 100644 --- a/src/common/ssl_certificate.h +++ b/src/common/ssl_certificate.h @@ -25,10 +25,15 @@ # include "config.h" #endif +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) #if USE_OPENSSL - #include #include +#else +#include +#include +#endif + #include #define SSLCERT_ASK_HOOKLIST "sslcert_ask" @@ -37,10 +42,17 @@ typedef struct _SSLCertificate SSLCertificate; struct _SSLCertificate { +#if USE_OPENSSL X509 *x509_cert; +#else + gnutls_x509_crt x509_cert; +#endif gchar *host; gushort port; gchar *fingerprint; +#if USE_GNUTLS + guint status; +#endif }; typedef struct _SSLCertHookData SSLCertHookData; @@ -55,13 +67,20 @@ struct _SSLCertHookData SSLCertificate *ssl_certificate_find (gchar *host, gushort port, const gchar *fingerprint); SSLCertificate *ssl_certificate_find_lookup (gchar *host, gushort port, const gchar *fingerprint, gboolean lookup); +#if USE_OPENSSL gboolean ssl_certificate_check (X509 *x509_cert, gchar *fqdn, gchar *host, gushort port); -char* ssl_certificate_to_string(SSLCertificate *cert); +#else +gboolean ssl_certificate_check (gnutls_x509_crt x509_cert, guint status, gchar *fqdn, gchar *host, gushort port); +#endif void ssl_certificate_destroy(SSLCertificate *cert); void ssl_certificate_delete_from_disk(SSLCertificate *cert); char * readable_fingerprint(unsigned char *src, int len); +#if USE_OPENSSL char *ssl_certificate_check_signer (X509 *cert); time_t asn1toTime(ASN1_TIME *asn1Time); +#else +char *ssl_certificate_check_signer (gnutls_x509_crt cert, guint status); +#endif #endif /* USE_OPENSSL */ #endif /* SSL_CERTIFICATE_H */ diff --git a/src/crash.c b/src/crash.c index b2b6c08ae..46e0ab684 100644 --- a/src/crash.c +++ b/src/crash.c @@ -418,6 +418,9 @@ static const gchar *get_compiled_in_features(void) #if USE_OPENSSL " OpenSSL" #endif +#if USE_GNUTLS + " GnuTLS" +#endif #if USE_LDAP " LDAP" #endif diff --git a/src/etpan/Makefile.am b/src/etpan/Makefile.am index 8e7df70f1..c587cfb9c 100644 --- a/src/etpan/Makefile.am +++ b/src/etpan/Makefile.am @@ -4,14 +4,16 @@ noinst_LTLIBRARIES = libclawsetpan.la libclawsetpan_la_SOURCES = \ etpan-thread-manager.c \ - imap-thread.c + imap-thread.c \ + nntp-thread.c clawsetpanincludedir = $(pkgincludedir)/etpan clawsetpaninclude_HEADERS = \ etpan-thread-manager-types.h \ etpan-thread-manager.h \ etpan-errors.h \ - imap-thread.h + imap-thread.h \ + nntp-thread.h INCLUDES = \ -I$(top_srcdir)/src \ diff --git a/src/etpan/etpan-thread-manager-types.h b/src/etpan/etpan-thread-manager-types.h index 11dbb6ea0..8047b1f29 100644 --- a/src/etpan/etpan-thread-manager-types.h +++ b/src/etpan/etpan-thread-manager-types.h @@ -70,6 +70,7 @@ struct etpan_thread_op { void * result; int finished; mailimap *imap; + newsnntp *nntp; }; #endif diff --git a/src/etpan/etpan-thread-manager.c b/src/etpan/etpan-thread-manager.c index 212a19f66..7b8dce7bc 100644 --- a/src/etpan/etpan-thread-manager.c +++ b/src/etpan/etpan-thread-manager.c @@ -196,6 +196,7 @@ struct etpan_thread_op * etpan_thread_op_new(void) op->result = NULL; op->finished = 0; op->imap = NULL; + op->nntp = NULL; r = pthread_mutex_init(&op->lock, NULL); if (r != 0) diff --git a/src/etpan/imap-thread.c b/src/etpan/imap-thread.c index dd95a57f2..14355a8ab 100644 --- a/src/etpan/imap-thread.c +++ b/src/etpan/imap-thread.c @@ -247,7 +247,7 @@ static void imap_logger_append(int direction, const char * str, size_t size) } #define ETPAN_DEFAULT_NETWORK_TIMEOUT 60 -static gboolean etpan_skip_ssl_cert_check = FALSE; +gboolean etpan_skip_ssl_cert_check = FALSE; extern void mailsasl_ref(void); void imap_main_init(gboolean skip_ssl_cert_check) @@ -508,7 +508,7 @@ static int etpan_certificate_check(const unsigned char *certificate, int len, vo } cert = d2i_X509(NULL, (const unsigned char **)&certificate, len); if (cert == NULL) { - g_warning("can't get cert\n"); + g_warning("IMAP: can't get cert\n"); return 0; } else if (ssl_certificate_check(cert, NULL, (gchar *)param->server, (gushort)param->port) == TRUE) { @@ -518,9 +518,33 @@ static int etpan_certificate_check(const unsigned char *certificate, int len, vo X509_free(cert); return -1; } -#else - return 0; +#elif USE_GNUTLS + struct connect_param *param = (struct connect_param *)data; + gnutls_x509_crt cert = NULL; + gnutls_datum tmp; + + if (certificate == NULL || len < 0) { + g_warning("no cert presented.\n"); + return 0; + } + + tmp.data = malloc(len); + memcpy(tmp.data, certificate, len); + tmp.size = len; + gnutls_x509_crt_init(&cert); + if (gnutls_x509_crt_import(cert, &tmp, GNUTLS_X509_FMT_DER) < 0) { + g_warning("IMAP: can't get cert\n"); + return 0; + } else if (ssl_certificate_check(cert, (guint)-1, NULL, + (gchar *)param->server, (gushort)param->port) == TRUE) { + gnutls_x509_crt_deinit(cert); + return 0; + } else { + gnutls_x509_crt_deinit(cert); + return -1; + } #endif + return 0; } static void connect_ssl_run(struct etpan_thread_op * op) diff --git a/src/etpan/nntp-thread.c b/src/etpan/nntp-thread.c new file mode 100644 index 000000000..463e615b6 --- /dev/null +++ b/src/etpan/nntp-thread.c @@ -0,0 +1,946 @@ +/* + * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 2005-2007 DINH Viet Hoa and 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 . + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_LIBETPAN + +#include "nntp-thread.h" +#include "news.h" +#include +#include +#if (defined(__DragonFly__) || defined (__NetBSD__) || defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__CYGWIN__)) +#include +#endif +#include +#include +#include + +#include +#include +#include "etpan-thread-manager.h" +#include "utils.h" +#include "mainwindow.h" +#include "ssl_certificate.h" +#include "socket.h" +#include "remotefolder.h" + +#define DISABLE_LOG_DURING_LOGIN + +static struct etpan_thread_manager * thread_manager = NULL; +static chash * courier_workaround_hash = NULL; +static chash * nntp_hash = NULL; +static chash * session_hash = NULL; +static guint thread_manager_signal = 0; +static GIOChannel * io_channel = NULL; + +static void (*previous_stream_logger)(int direction, + const char * str, size_t size); + +static void nntp_logger(int direction, const char * str, size_t size) +{ + gchar *buf; + gchar **lines; + int i = 0; + + if (size > 256) { + log_print(LOG_PROTOCOL, "NNTP%c [data - %zd bytes]\n", direction?'>':'<', size); + return; + } + buf = malloc(size+1); + memset(buf, 0, size+1); + strncpy(buf, str, size); + buf[size] = '\0'; + + if (!strncmp(buf, "<<<<<<<", 7) + || !strncmp(buf, ">>>>>>>", 7)) { + free(buf); + return; + } + while (strstr(buf, "\r")) + *strstr(buf, "\r") = ' '; + while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n') + buf[strlen(buf)-1] = '\0'; + + lines = g_strsplit(buf, "\n", -1); + + while (lines[i] && *lines[i]) { + log_print(LOG_PROTOCOL, "NNTP%c %s\n", direction?'>':'<', lines[i]); + i++; + } + g_strfreev(lines); + free(buf); +} + +static void delete_nntp(Folder *folder, newsnntp *nntp) +{ + chashdatum key; + chashdatum value; + + key.data = &folder; + key.len = sizeof(folder); + value.data = nntp; + value.len = 0; + chash_delete(session_hash, &key, NULL); + + key.data = &nntp; + key.len = sizeof(nntp); + if (nntp && nntp->nntp_stream) { + /* we don't want libetpan to logout */ + mailstream_close(nntp->nntp_stream); + nntp->nntp_stream = NULL; + } + debug_print("removing newsnntp %p\n", nntp); + newsnntp_free(nntp); +} + +static gboolean thread_manager_event(GIOChannel * source, + GIOCondition condition, + gpointer data) +{ + etpan_thread_manager_loop(thread_manager); + + return TRUE; +} + +#define ETPAN_DEFAULT_NETWORK_TIMEOUT 60 +extern gboolean etpan_skip_ssl_cert_check; + +void nntp_main_init(gboolean skip_ssl_cert_check) +{ + int fd_thread_manager; + + etpan_skip_ssl_cert_check = skip_ssl_cert_check; + + nntp_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE); + session_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE); + courier_workaround_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE); + + thread_manager = etpan_thread_manager_new(); + + fd_thread_manager = etpan_thread_manager_get_fd(thread_manager); + + io_channel = g_io_channel_unix_new(fd_thread_manager); + + thread_manager_signal = g_io_add_watch_full(io_channel, 0, G_IO_IN, + thread_manager_event, + (gpointer) NULL, + NULL); +} + +void nntp_main_done(void) +{ + etpan_thread_manager_stop(thread_manager); + etpan_thread_manager_join(thread_manager); + + g_source_remove(thread_manager_signal); + g_io_channel_unref(io_channel); + + etpan_thread_manager_free(thread_manager); + + chash_free(session_hash); + chash_free(nntp_hash); +} + +void nntp_init(Folder * folder) +{ + struct etpan_thread * thread; + chashdatum key; + chashdatum value; + + thread = etpan_thread_manager_get_thread(thread_manager); + + key.data = &folder; + key.len = sizeof(folder); + value.data = thread; + value.len = 0; + + chash_set(nntp_hash, &key, &value, NULL); +} + +void nntp_done(Folder * folder) +{ + struct etpan_thread * thread; + chashdatum key; + chashdatum value; + int r; + + key.data = &folder; + key.len = sizeof(folder); + + r = chash_get(nntp_hash, &key, &value); + if (r < 0) + return; + + thread = value.data; + + etpan_thread_unbind(thread); + + chash_delete(nntp_hash, &key, NULL); + + debug_print("remove thread"); +} + +static struct etpan_thread * get_thread(Folder * folder) +{ + struct etpan_thread * thread; + chashdatum key; + chashdatum value; + + key.data = &folder; + key.len = sizeof(folder); + + chash_get(nntp_hash, &key, &value); + thread = value.data; + + return thread; +} + +static newsnntp * get_nntp(Folder * folder) +{ + newsnntp * nntp; + chashdatum key; + chashdatum value; + int r; + + key.data = &folder; + key.len = sizeof(folder); + + r = chash_get(session_hash, &key, &value); + if (r < 0) + return NULL; + + nntp = value.data; + debug_print("found nntp %p\n", nntp); + return nntp; +} + + +static void generic_cb(int cancelled, void * result, void * callback_data) +{ + struct etpan_thread_op * op; + + op = (struct etpan_thread_op *) callback_data; + + debug_print("generic_cb\n"); + op->finished = 1; +} + +static void threaded_run(Folder * folder, void * param, void * result, + void (* func)(struct etpan_thread_op * )) +{ + struct etpan_thread_op * op; + struct etpan_thread * thread; + + nntp_folder_ref(folder); + + op = etpan_thread_op_new(); + + op->nntp = get_nntp(folder); + op->param = param; + op->result = result; + + op->cancellable = 0; + op->run = func; + op->callback = generic_cb; + op->callback_data = op; + op->cleanup = NULL; + + op->finished = 0; + + previous_stream_logger = mailstream_logger; + mailstream_logger = nntp_logger; + + thread = get_thread(folder); + etpan_thread_op_schedule(thread, op); + + while (!op->finished) { + gtk_main_iteration(); + } + + mailstream_logger = previous_stream_logger; + + etpan_thread_op_free(op); + + nntp_folder_unref(folder); +} + + +/* connect */ + +struct connect_param { + newsnntp * nntp; + const char * server; + int port; +}; + +struct connect_result { + int error; +}; + +#define CHECK_NNTP() { \ + if (!param->nntp) { \ + result->error = NEWSNNTP_ERROR_BAD_STATE; \ + return; \ + } \ +} + +static void connect_run(struct etpan_thread_op * op) +{ + int r; + struct connect_param * param; + struct connect_result * result; + + param = op->param; + result = op->result; + + CHECK_NNTP(); + + r = newsnntp_socket_connect(param->nntp, + param->server, param->port); + + result->error = r; +} + + +int nntp_threaded_connect(Folder * folder, const char * server, int port) +{ + struct connect_param param; + struct connect_result result; + chashdatum key; + chashdatum value; + newsnntp * nntp, * oldnntp; + + oldnntp = get_nntp(folder); + + nntp = newsnntp_new(0, NULL); + + if (oldnntp) { + debug_print("deleting old nntp %p\n", oldnntp); + delete_nntp(folder, oldnntp); + } + + key.data = &folder; + key.len = sizeof(folder); + value.data = nntp; + value.len = 0; + chash_set(session_hash, &key, &value, NULL); + + param.nntp = nntp; + param.server = server; + param.port = port; + + refresh_resolvers(); + threaded_run(folder, ¶m, &result, connect_run); + + debug_print("connect ok %i with nntp %p\n", result.error, nntp); + + return result.error; +} + +static int etpan_certificate_check(const unsigned char *certificate, int len, void *data) +{ +#ifdef USE_OPENSSL + struct connect_param *param = (struct connect_param *)data; + X509 *cert = NULL; + + if (certificate == NULL || len < 0) { + g_warning("no cert presented.\n"); + return 0; + } + cert = d2i_X509(NULL, (const unsigned char **)&certificate, len); + if (cert == NULL) { + g_warning("nntp: can't get cert\n"); + return 0; + } else if (ssl_certificate_check(cert, NULL, + (gchar *)param->server, (gushort)param->port) == TRUE) { + X509_free(cert); + return 0; + } else { + X509_free(cert); + return -1; + } +#elif USE_GNUTLS + struct connect_param *param = (struct connect_param *)data; + gnutls_x509_crt cert = NULL; + gnutls_datum tmp; + + if (certificate == NULL || len < 0) { + g_warning("no cert presented.\n"); + return 0; + } + + tmp.data = malloc(len); + memcpy(tmp.data, certificate, len); + tmp.size = len; + gnutls_x509_crt_init(&cert); + if (gnutls_x509_crt_import(cert, &tmp, GNUTLS_X509_FMT_DER) < 0) { + g_warning("nntp: can't get cert\n"); + return 0; + } else if (ssl_certificate_check(cert, (guint)-1, NULL, + (gchar *)param->server, (gushort)param->port) == TRUE) { + gnutls_x509_crt_deinit(cert); + return 0; + } else { + gnutls_x509_crt_deinit(cert); + return -1; + } +#endif + return 0; +} + +static void connect_ssl_run(struct etpan_thread_op * op) +{ + int r; + struct connect_param * param; + struct connect_result * result; + + param = op->param; + result = op->result; + + CHECK_NNTP(); + + r = newsnntp_ssl_connect(param->nntp, + param->server, param->port); + result->error = r; +} + +int nntp_threaded_connect_ssl(Folder * folder, const char * server, int port) +{ + struct connect_param param; + struct connect_result result; + chashdatum key; + chashdatum value; + newsnntp * nntp, * oldnntp; + unsigned char *certificate = NULL; + int cert_len; + + oldnntp = get_nntp(folder); + + nntp = newsnntp_new(0, NULL); + + if (oldnntp) { + debug_print("deleting old nntp %p\n", oldnntp); + delete_nntp(folder, oldnntp); + } + + key.data = &folder; + key.len = sizeof(folder); + value.data = nntp; + value.len = 0; + chash_set(session_hash, &key, &value, NULL); + + param.nntp = nntp; + param.server = server; + param.port = port; + + refresh_resolvers(); + threaded_run(folder, ¶m, &result, connect_ssl_run); + + if (result.error == NEWSNNTP_NO_ERROR && !etpan_skip_ssl_cert_check) { + cert_len = (int)mailstream_ssl_get_certificate(nntp->nntp_stream, &certificate); + if (etpan_certificate_check(certificate, cert_len, ¶m) < 0) + return -1; + if (certificate) + free(certificate); + } + debug_print("connect %d with nntp %p\n", result.error, nntp); + + return result.error; +} + +void nntp_threaded_disconnect(Folder * folder) +{ + newsnntp * nntp; + + nntp = get_nntp(folder); + if (nntp == NULL) { + debug_print("was disconnected\n"); + return; + } + + debug_print("deleting old nntp %p\n", nntp); + delete_nntp(folder, nntp); + + debug_print("disconnect ok\n"); +} + +void nntp_threaded_cancel(Folder * folder) +{ + newsnntp * nntp; + + nntp = get_nntp(folder); + if (nntp->nntp_stream != NULL) + mailstream_cancel(nntp->nntp_stream); +} + + +struct login_param { + newsnntp * nntp; + const char * login; + const char * password; +}; + +struct login_result { + int error; +}; + +static void login_run(struct etpan_thread_op * op) +{ + struct login_param * param; + struct login_result * result; + int r; +#ifdef DISABLE_LOG_DURING_LOGIN + int old_debug; +#endif + + param = op->param; + result = op->result; + + CHECK_NNTP(); + +#ifdef DISABLE_LOG_DURING_LOGIN + old_debug = mailstream_debug; + mailstream_debug = 0; +#endif + + r = newsnntp_authinfo_username(param->nntp, param->login); + if (r == NEWSNNTP_NO_ERROR) { + r = newsnntp_authinfo_password(param->nntp, param->password); + } + + + +#ifdef DISABLE_LOG_DURING_LOGIN + mailstream_debug = old_debug; +#endif + + result->error = r; + debug_print("nntp login run - end %i\n", r); +} + +int nntp_threaded_login(Folder * folder, const char * login, const char * password) +{ + struct login_param param; + struct login_result result; + + debug_print("nntp login - begin\n"); + + param.nntp = get_nntp(folder); + param.login = login; + param.password = password; + + threaded_run(folder, ¶m, &result, login_run); + + debug_print("nntp login - end\n"); + + return result.error; +} + +struct date_param { + newsnntp * nntp; + struct tm * lt; +}; + +struct date_result { + int error; +}; + +static void date_run(struct etpan_thread_op * op) +{ + struct date_param * param; + struct date_result * result; + int r; + + param = op->param; + result = op->result; + + CHECK_NNTP(); + + r = newsnntp_date(param->nntp, param->lt); + + result->error = r; + debug_print("nntp date run - end %i\n", r); +} + +int nntp_threaded_date(Folder * folder, struct tm *lt) +{ + struct date_param param; + struct date_result result; + + debug_print("nntp date - begin\n"); + + param.nntp = get_nntp(folder); + param.lt = lt; + + threaded_run(folder, ¶m, &result, date_run); + + debug_print("nntp date - end\n"); + + return result.error; +} + +struct list_param { + newsnntp * nntp; + clist **grouplist; +}; + +struct list_result { + int error; +}; + +static void list_run(struct etpan_thread_op * op) +{ + struct list_param * param; + struct list_result * result; + int r; + + param = op->param; + result = op->result; + + CHECK_NNTP(); + + r = newsnntp_list(param->nntp, param->grouplist); + + result->error = r; + debug_print("nntp list run - end %i\n", r); +} + +int nntp_threaded_list(Folder * folder, clist **grouplist) +{ + struct list_param param; + struct list_result result; + + debug_print("nntp list - begin\n"); + + param.nntp = get_nntp(folder); + param.grouplist = grouplist; + + threaded_run(folder, ¶m, &result, list_run); + + debug_print("nntp list - end\n"); + + return result.error; +} + +struct post_param { + newsnntp * nntp; + char *contents; + size_t len; +}; + +struct post_result { + int error; +}; + +static void post_run(struct etpan_thread_op * op) +{ + struct post_param * param; + struct post_result * result; + int r; + + param = op->param; + result = op->result; + + CHECK_NNTP(); + + r = newsnntp_post(param->nntp, param->contents, param->len); + + result->error = r; + debug_print("nntp post run - end %i\n", r); +} + +int nntp_threaded_post(Folder * folder, char *contents, size_t len) +{ + struct post_param param; + struct post_result result; + + debug_print("nntp post - begin\n"); + + param.nntp = get_nntp(folder); + param.contents = contents; + param.len = len; + + threaded_run(folder, ¶m, &result, post_run); + + debug_print("nntp post - end\n"); + + return result.error; +} + +struct article_param { + newsnntp * nntp; + guint32 num; + char **contents; + size_t *len; +}; + +struct article_result { + int error; +}; + +static void article_run(struct etpan_thread_op * op) +{ + struct article_param * param; + struct article_result * result; + int r; + + param = op->param; + result = op->result; + + CHECK_NNTP(); + + r = newsnntp_article(param->nntp, param->num, param->contents, param->len); + + result->error = r; + debug_print("nntp article run - end %i\n", r); +} + +int nntp_threaded_article(Folder * folder, guint32 num, char **contents, size_t *len) +{ + struct article_param param; + struct article_result result; + + debug_print("nntp article - begin\n"); + + param.nntp = get_nntp(folder); + param.num = num; + param.contents = contents; + param.len = len; + + threaded_run(folder, ¶m, &result, article_run); + + debug_print("nntp post - end\n"); + + return result.error; +} + +struct group_param { + newsnntp * nntp; + const char *group; + struct newsnntp_group_info **info; +}; + +struct group_result { + int error; +}; + +static void group_run(struct etpan_thread_op * op) +{ + struct group_param * param; + struct group_result * result; + int r; + + param = op->param; + result = op->result; + + CHECK_NNTP(); + + r = newsnntp_group(param->nntp, param->group, param->info); + + result->error = r; + debug_print("nntp group run - end %i\n", r); +} + +int nntp_threaded_group(Folder * folder, const char *group, struct newsnntp_group_info **info) +{ + struct group_param param; + struct group_result result; + + debug_print("nntp group - begin\n"); + + param.nntp = get_nntp(folder); + param.group = group; + param.info = info; + + threaded_run(folder, ¶m, &result, group_run); + + debug_print("nntp group - end\n"); + + return result.error; +} + +struct mode_reader_param { + newsnntp * nntp; +}; + +struct mode_reader_result { + int error; +}; + +static void mode_reader_run(struct etpan_thread_op * op) +{ + struct mode_reader_param * param; + struct mode_reader_result * result; + int r; + + param = op->param; + result = op->result; + + CHECK_NNTP(); + + r = newsnntp_mode_reader(param->nntp); + + result->error = r; + debug_print("nntp mode_reader run - end %i\n", r); +} + +int nntp_threaded_mode_reader(Folder * folder) +{ + struct mode_reader_param param; + struct mode_reader_result result; + + debug_print("nntp mode_reader - begin\n"); + + param.nntp = get_nntp(folder); + + threaded_run(folder, ¶m, &result, mode_reader_run); + + debug_print("nntp mode_reader - end\n"); + + return result.error; +} + +struct xover_param { + newsnntp * nntp; + guint32 beg; + guint32 end; + struct newsnntp_xover_resp_item **result; + clist **msglist; +}; + +struct xover_result { + int error; +}; + +static void xover_run(struct etpan_thread_op * op) +{ + struct xover_param * param; + struct xover_result * result; + int r; + + param = op->param; + result = op->result; + + CHECK_NNTP(); + + if (param->result) { + r = newsnntp_xover_single(param->nntp, param->beg, param->result); + } else { + r = newsnntp_xover_range(param->nntp, param->beg, param->end, param->msglist); + } + + result->error = r; + debug_print("nntp xover run - end %i\n", r); +} + +int nntp_threaded_xover(Folder * folder, guint32 beg, guint32 end, struct newsnntp_xover_resp_item **single_result, clist **multiple_result) +{ + struct xover_param param; + struct xover_result result; + + debug_print("nntp xover - begin\n"); + + param.nntp = get_nntp(folder); + param.beg = beg; + param.end = end; + param.result = single_result; + param.msglist = multiple_result; + + threaded_run(folder, ¶m, &result, xover_run); + + debug_print("nntp xover - end\n"); + + return result.error; +} + +struct xhdr_param { + newsnntp * nntp; + const char *header; + guint32 beg; + guint32 end; + clist **hdrlist; +}; + +struct xhdr_result { + int error; +}; + +static void xhdr_run(struct etpan_thread_op * op) +{ + struct xhdr_param * param; + struct xhdr_result * result; + int r; + + param = op->param; + result = op->result; + + CHECK_NNTP(); + + if (param->beg == param->end) { + r = newsnntp_xhdr_single(param->nntp, param->header, param->beg, param->hdrlist); + } else { + r = -1; + g_warning("XHDR range not implemented\n"); + } + + result->error = r; + debug_print("nntp xhdr run - end %i\n", r); +} + +int nntp_threaded_xhdr(Folder * folder, const char *header, guint32 beg, guint32 end, clist **hdrlist) +{ + struct xhdr_param param; + struct xhdr_result result; + + debug_print("nntp xhdr - begin\n"); + + param.nntp = get_nntp(folder); + param.header = header; + param.beg = beg; + param.end = end; + param.hdrlist = hdrlist; + + threaded_run(folder, ¶m, &result, xhdr_run); + + debug_print("nntp xhdr - end\n"); + + return result.error; +} + + +#else + +void nntp_main_init(void) +{ +} +void nntp_main_done(void) +{ +} +void nntp_main_set_timeout(int sec) +{ +} + +void nntp_threaded_cancel(Folder * folder); +{ +} + +#endif diff --git a/src/etpan/nntp-thread.h b/src/etpan/nntp-thread.h new file mode 100644 index 000000000..be0066e62 --- /dev/null +++ b/src/etpan/nntp-thread.h @@ -0,0 +1,51 @@ +/* + * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 2005-2007 DINH Viet Hoa and 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 . + * + */ + +#ifndef NNTP_THREAD_H + +#define NNTP_THREAD_H + +#include +#include "folder.h" + +void nntp_main_set_timeout(int sec); +void nntp_main_init(gboolean skip_ssl_cert_check); +void nntp_main_done(void); + +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); + +void nntp_threaded_disconnect(Folder * folder); + +void nntp_threaded_cancel(Folder * folder); + +int nntp_threaded_login(Folder * folder, const char * login, const char * password); +int nntp_threaded_date(Folder * folder, struct tm *lt); +int nntp_threaded_list(Folder * folder, clist **grouplist); +int nntp_threaded_post(Folder * folder, char *contents, size_t len); +int nntp_threaded_article(Folder * folder, guint32 num, char **contents, size_t *len); +int nntp_threaded_group(Folder * folder, const char *group, struct newsnntp_group_info **info); +int nntp_threaded_mode_reader(Folder * folder); +int nntp_threaded_xover(Folder * folder, guint32 beg, guint32 end, struct newsnntp_xover_resp_item **single_result, clist **multiple_result); +int nntp_threaded_xhdr(Folder * folder, const char *header, guint32 beg, guint32 end, clist **hdrlist); + +#endif diff --git a/src/gtk/about.c b/src/gtk/about.c index 907a3b6b0..5f2597f0e 100644 --- a/src/gtk/about.c +++ b/src/gtk/about.c @@ -453,6 +453,16 @@ static GtkWidget *about_create_child_page_features(void) gtk_text_buffer_insert(buffer, &iter, (gchar *)Q_("OpenSSL|adds support for encrypted connections to servers\n"), -1); +#if USE_GNUTLS + gtk_text_buffer_insert_pixbuf(buffer, &iter, active_pixbuf); +#else + gtk_text_buffer_insert_pixbuf(buffer, &iter, inactive_pixbuf); +#endif + gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, (" GnuTLS "), -1, + "bold", NULL); + gtk_text_buffer_insert(buffer, &iter, + (gchar *)Q_("GnuTLS|is another mean of adding support for encrypted connections to servers\n"), -1); + #if USE_LDAP gtk_text_buffer_insert_pixbuf(buffer, &iter, active_pixbuf); #else diff --git a/src/gtk/sslcertwindow.c b/src/gtk/sslcertwindow.c index c4c060c54..83b0ba3fb 100644 --- a/src/gtk/sslcertwindow.c +++ b/src/gtk/sslcertwindow.c @@ -22,14 +22,25 @@ # include "config.h" #endif -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) +#if USE_OPENSSL #include +#else +#include +#include +#include +#include +#include +#include +#include +#endif #include #include #include #include "prefs_common.h" +#include "defs.h" #include "ssl_certificate.h" #include "utils.h" #include "alertpanel.h" @@ -51,17 +62,22 @@ static GtkWidget *cert_presenter(SSLCertificate *cert) GtkTable *status_table = NULL; GtkWidget *label = NULL; - char buf[100]; char *issuer_commonname, *issuer_location, *issuer_organization; char *subject_commonname, *subject_location, *subject_organization; char *fingerprint, *sig_status, *exp_date; unsigned int n; - unsigned char md[EVP_MAX_MD_SIZE]; + char buf[100]; + unsigned char md[128]; +#if USE_OPENSSL ASN1_TIME *validity; +#else + char *tmp; +#endif time_t exp_time_t; struct tm lt; /* issuer */ +#if USE_OPENSSL if (X509_NAME_get_text_by_NID(X509_get_issuer_name(cert->x509_cert), NID_commonName, buf, 100) >= 0) issuer_commonname = g_strdup(buf); @@ -114,17 +130,90 @@ static GtkWidget *cert_presenter(SSLCertificate *cert) } else { exp_time_t = (time_t)0; } - +#else + issuer_commonname = g_malloc(BUFFSIZE); + issuer_location = g_malloc(BUFFSIZE); + issuer_organization = g_malloc(BUFFSIZE); + subject_commonname = g_malloc(BUFFSIZE); + subject_location = g_malloc(BUFFSIZE); + subject_organization = g_malloc(BUFFSIZE); + + n = BUFFSIZE; + if (gnutls_x509_crt_get_issuer_dn_by_oid(cert->x509_cert, + GNUTLS_OID_X520_COMMON_NAME, 0, 0, issuer_commonname, &n)) + strncpy(issuer_commonname, _(""), BUFFSIZE); + n = BUFFSIZE; + + if (gnutls_x509_crt_get_issuer_dn_by_oid(cert->x509_cert, + GNUTLS_OID_X520_LOCALITY_NAME, 0, 0, issuer_location, &n)) { + if (gnutls_x509_crt_get_issuer_dn_by_oid(cert->x509_cert, + GNUTLS_OID_X520_COUNTRY_NAME, 0, 0, issuer_location, &n)) { + strncpy(issuer_location, _(""), BUFFSIZE); + } + } else { + tmp = g_malloc(BUFFSIZE); + if (gnutls_x509_crt_get_issuer_dn_by_oid(cert->x509_cert, + GNUTLS_OID_X520_COUNTRY_NAME, 0, 0, tmp, &n) == 0) { + strncat(issuer_location, ", ", BUFFSIZE-strlen(issuer_location)); + strncat(issuer_location, tmp, BUFFSIZE-strlen(issuer_location)); + } + g_free(tmp); + } + + n = BUFFSIZE; + if (gnutls_x509_crt_get_issuer_dn_by_oid(cert->x509_cert, + GNUTLS_OID_X520_ORGANIZATION_NAME, 0, 0, issuer_organization, &n)) + strncpy(issuer_organization, _(""), BUFFSIZE); + + n = BUFFSIZE; + if (gnutls_x509_crt_get_dn_by_oid(cert->x509_cert, + GNUTLS_OID_X520_COMMON_NAME, 0, 0, subject_commonname, &n)) + strncpy(subject_commonname, _(""), BUFFSIZE); + n = BUFFSIZE; + + if (gnutls_x509_crt_get_dn_by_oid(cert->x509_cert, + GNUTLS_OID_X520_LOCALITY_NAME, 0, 0, subject_location, &n)) { + if (gnutls_x509_crt_get_dn_by_oid(cert->x509_cert, + GNUTLS_OID_X520_COUNTRY_NAME, 0, 0, subject_location, &n)) { + strncpy(subject_location, _(""), BUFFSIZE); + } + } else { + tmp = g_malloc(BUFFSIZE); + if (gnutls_x509_crt_get_dn_by_oid(cert->x509_cert, + GNUTLS_OID_X520_COUNTRY_NAME, 0, 0, tmp, &n) == 0) { + strncat(subject_location, ", ", BUFFSIZE-strlen(subject_location)); + strncat(subject_location, tmp, BUFFSIZE-strlen(subject_location)); + } + g_free(tmp); + } + + n = BUFFSIZE; + if (gnutls_x509_crt_get_dn_by_oid(cert->x509_cert, + GNUTLS_OID_X520_ORGANIZATION_NAME, 0, 0, subject_organization, &n)) + strncpy(subject_organization, _(""), BUFFSIZE); + + exp_time_t = gnutls_x509_crt_get_expiration_time(cert->x509_cert); +#endif + memset(buf, 0, sizeof(buf)); strftime(buf, sizeof(buf)-1, prefs_common.date_format, localtime_r(&exp_time_t, <)); exp_date = buf? g_strdup(buf):g_strdup("?"); /* fingerprint */ +#if USE_OPENSSL X509_digest(cert->x509_cert, EVP_md5(), md, &n); fingerprint = readable_fingerprint(md, (int)n); /* signature */ sig_status = ssl_certificate_check_signer(cert->x509_cert); +#else + n = 128; + gnutls_x509_crt_get_fingerprint(cert->x509_cert, GNUTLS_DIG_MD5, md, &n); + fingerprint = readable_fingerprint(md, (int)n); + + /* signature */ + sig_status = ssl_certificate_check_signer(cert->x509_cert, cert->status); +#endif if (sig_status==NULL) sig_status = g_strdup(_("correct")); @@ -277,8 +366,11 @@ static gboolean sslcertwindow_ask_new_cert(SSLCertificate *cert) gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0); g_free(buf); +#if USE_OPENSSL sig_status = ssl_certificate_check_signer(cert->x509_cert); - +#else + sig_status = ssl_certificate_check_signer(cert->x509_cert, cert->status); +#endif if (sig_status==NULL) sig_status = g_strdup(_("correct")); @@ -317,7 +409,11 @@ static gboolean sslcertwindow_ask_expired_cert(SSLCertificate *cert) gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0); g_free(buf); +#if USE_OPENSSL sig_status = ssl_certificate_check_signer(cert->x509_cert); +#else + sig_status = ssl_certificate_check_signer(cert->x509_cert, cert->status); +#endif if (sig_status==NULL) sig_status = g_strdup(_("correct")); @@ -371,7 +467,11 @@ static gboolean sslcertwindow_ask_changed_cert(SSLCertificate *old_cert, SSLCert gtk_box_pack_start(GTK_BOX(vbox2), label, TRUE, TRUE, 0); g_free(buf); +#if USE_OPENSSL sig_status = ssl_certificate_check_signer(new_cert->x509_cert); +#else + sig_status = ssl_certificate_check_signer(new_cert->x509_cert, new_cert->status); +#endif if (sig_status==NULL) sig_status = g_strdup(_("correct")); diff --git a/src/gtk/sslcertwindow.h b/src/gtk/sslcertwindow.h index 3f2d33db5..9d4818d4c 100644 --- a/src/gtk/sslcertwindow.h +++ b/src/gtk/sslcertwindow.h @@ -25,10 +25,13 @@ # include "config.h" #endif -#if USE_OPENSSL - +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) +#ifdef USE_OPENSSL #include #include +#else +/* GNUTLS */ +#endif #include #include #include "ssl_certificate.h" diff --git a/src/imap.c b/src/imap.c index cd4fbb43b..dbb4f4768 100644 --- a/src/imap.c +++ b/src/imap.c @@ -45,7 +45,7 @@ # include #endif -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) # include "ssl.h" #endif @@ -153,7 +153,7 @@ typedef enum #define IMAP4_PORT 143 -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) #define IMAPS_PORT 993 #endif @@ -322,7 +322,7 @@ static gint imap_cmd_login (IMAPSession *session, const gchar *pass, const gchar *type); static gint imap_cmd_noop (IMAPSession *session); -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) static gint imap_cmd_starttls (IMAPSession *session); #endif static gint imap_cmd_select (IMAPSession *session, @@ -430,7 +430,7 @@ typedef struct _thread_data { gushort port; gboolean done; SockInfo *sock; -#ifdef USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) SSLType ssl_type; #endif } thread_data; @@ -836,7 +836,7 @@ static IMAPSession *imap_session_new(Folder * folder, int r; int authenticated = FALSE; -#ifdef USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) /* FIXME: IMAP over SSL only... */ SSLType ssl_type; @@ -870,7 +870,7 @@ static IMAPSession *imap_session_new(Folder * folder, port); } else { -#ifdef USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) if (ssl_type == SSL_TUNNEL) { r = imap_threaded_connect_ssl(folder, account->recv_server, @@ -894,7 +894,7 @@ static IMAPSession *imap_session_new(Folder * folder, } else { #if (LIBETPAN_VERSION_MAJOR > 0 || LIBETPAN_VERSION_MINOR > 48) -#ifdef USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) if (r == MAILIMAP_ERROR_SSL) log_error(LOG_PROTOCOL, _("SSL handshake failed\n")); #endif @@ -929,7 +929,7 @@ static IMAPSession *imap_session_new(Folder * folder, session->folder = folder; IMAP_FOLDER(session->folder)->last_seen_separator = 0; -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) if (account->ssl_imap == SSL_STARTTLS) { gint ok; @@ -3017,7 +3017,7 @@ static gint imap_cmd_login(IMAPSession *session, if (!strcmp(type, "LOGIN") && imap_has_capability(session, "LOGINDISABLED")) { gint ok = IMAP_ERROR; if (imap_has_capability(session, "STARTTLS")) { -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) log_warning(LOG_PROTOCOL, _("Server requires TLS to log in.\n")); ok = imap_cmd_starttls(session); if (ok != IMAP_SUCCESS) { @@ -3100,7 +3100,7 @@ static gint imap_cmd_noop(IMAPSession *session) return IMAP_SUCCESS; } -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) static gint imap_cmd_starttls(IMAPSession *session) { int r; diff --git a/src/inc.c b/src/inc.c index b40f18ff7..869afd9ec 100644 --- a/src/inc.c +++ b/src/inc.c @@ -785,7 +785,7 @@ static IncState inc_pop3_session_do(IncSession *session) g_free(buf); server = pop3_session->ac_prefs->recv_server; -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) port = pop3_session->ac_prefs->set_popport ? pop3_session->ac_prefs->popport : pop3_session->ac_prefs->ssl_pop == SSL_TUNNEL ? 995 : 110; diff --git a/src/main.c b/src/main.c index 59c5d0ec0..b9263600e 100644 --- a/src/main.c +++ b/src/main.c @@ -100,12 +100,13 @@ #include "tags.h" #ifdef HAVE_LIBETPAN #include "imap-thread.h" +#include "nntp-thread.h" #endif #include "stock_pixmap.h" #ifdef HAVE_VALGRIND #include "valgrind.h" #endif -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) # include "ssl.h" #endif @@ -1144,6 +1145,7 @@ int main(int argc, char *argv[]) #ifdef HAVE_LIBETPAN imap_main_init(prefs_common.skip_ssl_cert_check); imap_main_set_timeout(prefs_common.io_timeout_secs); + nntp_main_init(prefs_common.skip_ssl_cert_check); #endif account_set_missing_folder(); folder_set_missing_folders(); @@ -1407,6 +1409,7 @@ static void exit_claws(MainWindow *mainwin) #ifdef HAVE_LIBETPAN imap_main_done(); + nntp_main_done(); #endif /* delete crashfile */ if (!cmd.crash) diff --git a/src/mainwindow.c b/src/mainwindow.c index 3bc0368e3..66d1af028 100644 --- a/src/mainwindow.c +++ b/src/mainwindow.c @@ -448,7 +448,7 @@ static void prefs_post_processing_open_cb (MainWindow *mainwin, static void prefs_filtering_open_cb (MainWindow *mainwin, guint action, GtkWidget *widget); -#ifdef USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) static void ssl_manager_open_cb (MainWindow *mainwin, guint action, GtkWidget *widget); @@ -899,7 +899,7 @@ static GtkItemFactoryEntry mainwin_entries[] = NULL, delete_duplicated_all_cb, 0, NULL}, {N_("/_Tools/---"), NULL, NULL, 0, ""}, {N_("/_Tools/E_xecute"), "X", execute_summary_cb, 0, NULL}, -#ifdef USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) {N_("/_Tools/---"), NULL, NULL, 0, ""}, {N_("/_Tools/SSL cer_tificates..."), NULL, ssl_manager_open_cb, 0, NULL}, @@ -1810,7 +1810,7 @@ MainWindow *main_window_create() folderview_init(folderview); summary_init(summaryview); messageview_init(messageview); -#ifdef USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) sslcertwindow_register_hook(); #endif mainwin->lock_count = 0; @@ -4219,7 +4219,7 @@ static void prefs_tags_open_cb(MainWindow *mainwin, guint action, { prefs_tags_open(mainwin); } -#ifdef USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) static void ssl_manager_open_cb(MainWindow *mainwin, guint action, GtkWidget *widget) { diff --git a/src/news.c b/src/news.c index df66d4c00..b6dcf0887 100644 --- a/src/news.c +++ b/src/news.c @@ -21,6 +21,8 @@ # include "config.h" #endif +#ifdef HAVE_LIBETPAN + #include "defs.h" #include @@ -31,10 +33,12 @@ #include #include #include +#include +#include "nntp-thread.h" +#include "news.h" #include "news.h" #include "news_gtk.h" -#include "nntp.h" #include "socket.h" #include "recv.h" #include "procmsg.h" @@ -52,19 +56,20 @@ #include "remotefolder.h" #include "alertpanel.h" #include "inc.h" - -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) # include "ssl.h" #endif #define NNTP_PORT 119 -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) #define NNTPS_PORT 563 #endif typedef struct _NewsFolder NewsFolder; +typedef struct _NewsSession NewsSession; #define NEWS_FOLDER(obj) ((NewsFolder *)obj) +#define NEWS_SESSION(obj) ((NewsSession *)obj) struct _NewsFolder { @@ -72,11 +77,18 @@ struct _NewsFolder gboolean use_auth; gboolean lock_count; + guint refcnt; +}; + +struct _NewsSession +{ + Session session; + + gchar *group; }; -static void news_folder_init (Folder *folder, - const gchar *name, - const gchar *path); +static void news_folder_init(Folder *folder, const gchar *name, + const gchar *path); static Folder *news_folder_new (const gchar *name, const gchar *folder); @@ -88,34 +100,32 @@ static gchar *news_fetch_msg (Folder *folder, static void news_remove_cached_msg (Folder *folder, FolderItem *item, MsgInfo *msginfo); -#if USE_OPENSSL -static Session *news_session_new (const gchar *server, +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) +static Session *news_session_new (Folder *folder, + const gchar *server, gushort port, const gchar *userid, const gchar *passwd, SSLType ssl_type); #else -static Session *news_session_new (const gchar *server, +static Session *news_session_new (Folder *folder, + const gchar *server, gushort port, const gchar *userid, const gchar *passwd); #endif -static gint news_get_article_cmd (NNTPSession *session, - const gchar *cmd, - gint num, - gchar *filename); -static gint news_get_article (NNTPSession *session, +static gint news_get_article (Folder *folder, gint num, gchar *filename); -static gint news_select_group (NNTPSession *session, +static gint news_select_group (Folder *folder, const gchar *group, gint *num, gint *first, gint *last); -static MsgInfo *news_parse_xover (const gchar *xover_str); -static gchar *news_parse_xhdr (const gchar *xhdr_str, +static MsgInfo *news_parse_xover (struct newsnntp_xover_resp_item *item); +static gchar *news_parse_xhdr (clist *list, MsgInfo *msginfo); static gint news_get_num_list (Folder *folder, FolderItem *item, @@ -130,8 +140,6 @@ static GSList *news_get_msginfos (Folder *folder, static gboolean news_scan_required (Folder *folder, FolderItem *item); -static gint news_post_stream (Folder *folder, - FILE *fp); static gchar *news_folder_get_path (Folder *folder); static gchar *news_item_get_path (Folder *folder, FolderItem *item); @@ -172,6 +180,22 @@ FolderClass *news_get_class(void) return &news_class; } +guint nntp_folder_get_refcnt(Folder *folder) +{ + return ((NewsFolder *)folder)->refcnt; +} + +void nntp_folder_ref(Folder *folder) +{ + ((NewsFolder *)folder)->refcnt++; +} + +void nntp_folder_unref(Folder *folder) +{ + if (((NewsFolder *)folder)->refcnt > 0) + ((NewsFolder *)folder)->refcnt--; +} + static int news_remove_msg (Folder *folder, FolderItem *item, gint msgnum) @@ -226,11 +250,15 @@ static void news_folder_destroy(Folder *folder) { gchar *dir; + while (nntp_folder_get_refcnt(folder) > 0) + gtk_main_iteration(); + dir = news_folder_get_path(folder); if (is_dir_exist(dir)) remove_dir_recursive(dir); g_free(dir); + nntp_done(folder); folder_remote_folder_destroy(REMOTE_FOLDER(folder)); } @@ -240,29 +268,54 @@ static void news_folder_init(Folder *folder, const gchar *name, folder_remote_folder_init(folder, name, path); } -#if USE_OPENSSL -static Session *news_session_new(const gchar *server, gushort port, +static void news_session_destroy(Session *session) +{ + NewsSession *news_session = NEWS_SESSION(session); + + g_return_if_fail(session != NULL); + + if (news_session->group) + g_free(news_session->group); +} + +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) +static Session *news_session_new(Folder *folder, const gchar *server, gushort port, const gchar *userid, const gchar *passwd, SSLType ssl_type) #else -static Session *news_session_new(const gchar *server, gushort port, +static Session *news_session_new(Folder *folder, const gchar *server, gushort port, const gchar *userid, const gchar *passwd) #endif { - gchar buf[NNTPBUFSIZE]; - Session *session; - + NewsSession *session; + int r = 0; g_return_val_if_fail(server != NULL, NULL); log_message(LOG_PROTOCOL, _("creating NNTP connection to %s:%d ...\n"), server, port); -#if USE_OPENSSL - session = nntp_session_new(server, port, buf, userid, passwd, ssl_type); -#else - session = nntp_session_new(server, port, buf, userid, passwd); -#endif + session = g_new0(NewsSession, 1); + session_init(SESSION(session)); + SESSION(session)->type = SESSION_NEWS; + SESSION(session)->server = g_strdup(server); + SESSION(session)->sock = NULL; + SESSION(session)->destroy = news_session_destroy; + + nntp_init(folder); - return session; +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) + if (ssl_type != SSL_NONE) + r = nntp_threaded_connect_ssl(folder, server, port); + else +#endif + r = nntp_threaded_connect(folder, server, port); + + if (r != NEWSNNTP_NO_ERROR) { + log_error(LOG_PROTOCOL, _("Error logging in to %s:%d ...\n"), server, port); + session_destroy(SESSION(session)); + return NULL; + } + + return SESSION(session); } static Session *news_session_new_for_folder(Folder *folder) @@ -272,7 +325,6 @@ static Session *news_session_new_for_folder(Folder *folder) const gchar *userid = NULL; gchar *passwd = NULL; gushort port; - gchar buf[NNTPBUFSIZE]; g_return_val_if_fail(folder != NULL, NULL); g_return_val_if_fail(folder->account != NULL, NULL); @@ -287,10 +339,10 @@ static Session *news_session_new_for_folder(Folder *folder) userid); } -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) port = ac->set_nntpport ? ac->nntpport : ac->ssl_nntp ? NNTPS_PORT : NNTP_PORT; - session = news_session_new(ac->nntp_server, port, userid, passwd, + session = news_session_new(folder, ac->nntp_server, port, userid, passwd, ac->ssl_nntp); #else if (ac->ssl_nntp != SSL_NONE) { @@ -307,20 +359,27 @@ static Session *news_session_new_for_folder(Folder *folder) return NULL; } port = ac->set_nntpport ? ac->nntpport : NNTP_PORT; - session = news_session_new(ac->nntp_server, port, userid, passwd); + session = news_session_new(folder, ac->nntp_server, port, userid, passwd); #endif - if ((session != NULL) && ac->use_nntp_auth && ac->use_nntp_auth_onconnect) - nntp_forceauth(NNTP_SESSION(session), buf, userid, passwd); + if ((session != NULL) && ac->use_nntp_auth && ac->use_nntp_auth_onconnect) { + if (nntp_threaded_login(folder, userid, passwd) != + NEWSNNTP_NO_ERROR) { + log_error(LOG_PROTOCOL, _("Error authenticating to %s:%d ...\n"), ac->nntp_server, port); + session_destroy(SESSION(session)); + g_free(passwd); + return NULL; + } + } g_free(passwd); return session; } -static NNTPSession *news_session_get(Folder *folder) +static NewsSession *news_session_get(Folder *folder) { RemoteFolder *rfolder = REMOTE_FOLDER(folder); - + struct tm lt; g_return_val_if_fail(folder != NULL, NULL); g_return_val_if_fail(FOLDER_CLASS(folder) == &news_class, NULL); g_return_val_if_fail(folder->account != NULL, NULL); @@ -334,16 +393,16 @@ static NNTPSession *news_session_get(Folder *folder) if (!rfolder->session) { rfolder->session = news_session_new_for_folder(folder); - return NNTP_SESSION(rfolder->session); + return NEWS_SESSION(rfolder->session); } if (time(NULL) - rfolder->session->last_access_time < SESSION_TIMEOUT_INTERVAL) { - return NNTP_SESSION(rfolder->session); + return NEWS_SESSION(rfolder->session); } - if (nntp_mode(NNTP_SESSION(rfolder->session), FALSE) - != NN_SUCCESS) { + if (nntp_threaded_date(folder, <) + == NEWSNNTP_ERROR_STREAM) { log_warning(LOG_PROTOCOL, _("NNTP connection to %s:%d has been" " disconnected. Reconnecting...\n"), folder->account->nntp_server, @@ -352,11 +411,11 @@ static NNTPSession *news_session_get(Folder *folder) session_destroy(rfolder->session); rfolder->session = news_session_new_for_folder(folder); } - + if (rfolder->session) session_set_access_time(rfolder->session); - return NNTP_SESSION(rfolder->session); + return NEWS_SESSION(rfolder->session); } static void news_remove_cached_msg(Folder *folder, FolderItem *item, MsgInfo *msginfo) @@ -382,7 +441,7 @@ static void news_remove_cached_msg(Folder *folder, FolderItem *item, MsgInfo *ms static gchar *news_fetch_msg(Folder *folder, FolderItem *item, gint num) { gchar *path, *filename; - NNTPSession *session; + NewsSession *session; gint ok; g_return_val_if_fail(folder != NULL, NULL); @@ -405,9 +464,9 @@ static gchar *news_fetch_msg(Folder *folder, FolderItem *item, gint num) return NULL; } - ok = news_select_group(session, item->path, NULL, NULL, NULL); - if (ok != NN_SUCCESS) { - if (ok == NN_SOCKET) { + ok = news_select_group(folder, item->path, NULL, NULL, NULL); + if (ok != NEWSNNTP_NO_ERROR) { + if (ok == NEWSNNTP_ERROR_STREAM) { session_destroy(SESSION(session)); REMOTE_FOLDER(folder)->session = NULL; } @@ -416,11 +475,11 @@ static gchar *news_fetch_msg(Folder *folder, FolderItem *item, gint num) } debug_print("getting article %d...\n", num); - ok = news_get_article(NNTP_SESSION(REMOTE_FOLDER(folder)->session), + ok = news_get_article(folder, num, filename); - if (ok != NN_SUCCESS) { + if (ok != NEWSNNTP_NO_ERROR) { g_warning("can't read article %d\n", num); - if (ok == NN_SOCKET) { + if (ok == NEWSNNTP_ERROR_STREAM) { session_destroy(SESSION(session)); REMOTE_FOLDER(folder)->session = NULL; } @@ -463,7 +522,7 @@ GSList *news_get_group_list(Folder *folder) FILE *fp; GSList *list = NULL; GSList *last = NULL; - gchar buf[NNTPBUFSIZE]; + gchar buf[BUFFSIZE]; g_return_val_if_fail(folder != NULL, NULL); g_return_val_if_fail(FOLDER_CLASS(folder) == &news_class, NULL); @@ -475,26 +534,56 @@ GSList *news_get_group_list(Folder *folder) g_free(path); if ((fp = g_fopen(filename, "rb")) == NULL) { - NNTPSession *session; + NewsSession *session; gint ok; - + clist *grouplist = NULL; + clistiter *cur; + fp = fopen(filename, "wb"); + + if (!fp) { + g_free(filename); + return NULL; + } session = news_session_get(folder); if (!session) { + fclose(fp); g_free(filename); return NULL; } - ok = nntp_list(session); - if (ok != NN_SUCCESS) { - if (ok == NN_SOCKET) { + ok = nntp_threaded_list(folder, &grouplist); + + if (ok != NEWSNNTP_NO_ERROR) { + if (ok == NEWSNNTP_ERROR_STREAM) { session_destroy(SESSION(session)); REMOTE_FOLDER(folder)->session = NULL; } + fclose(fp); g_free(filename); return NULL; } - if (recv_write_to_file(SESSION(session)->sock, filename) < 0) { - log_warning(LOG_PROTOCOL, _("can't retrieve newsgroup list\n")); + + for (cur = clist_begin(grouplist); cur; cur = clist_next(cur)) { + struct newsnntp_group_info *info = (struct newsnntp_group_info *) + clist_content(cur); + if (fprintf(fp, "%s %d %d %c\n", + info->grp_name, + info->grp_last, + info->grp_first, + info->grp_type) < 0) { + log_error(LOG_PROTOCOL, ("Can't write newsgroup list\n")); + session_destroy(SESSION(session)); + REMOTE_FOLDER(folder)->session = NULL; + fclose(fp); + g_free(filename); + newsnntp_list_free(grouplist); + return NULL; + } + } + newsnntp_list_free(grouplist); + + if (fclose(fp) == EOF) { + log_error(LOG_PROTOCOL, ("Can't write newsgroup list\n")); session_destroy(SESSION(session)); REMOTE_FOLDER(folder)->session = NULL; g_free(filename); @@ -574,78 +663,46 @@ void news_remove_group_list_cache(Folder *folder) gint news_post(Folder *folder, const gchar *file) { - FILE *fp; - gint ok; - - g_return_val_if_fail(folder != NULL, -1); - g_return_val_if_fail(FOLDER_CLASS(folder) == &news_class, -1); - g_return_val_if_fail(file != NULL, -1); - - if ((fp = g_fopen(file, "rb")) == NULL) { - FILE_OP_ERROR(file, "fopen"); - return -1; - } - - ok = news_post_stream(folder, fp); - - fclose(fp); - - return ok; -} - -static gint news_post_stream(Folder *folder, FILE *fp) -{ - NNTPSession *session; gint ok; + char *contents = file_read_to_str(file); + NewsSession *session; g_return_val_if_fail(folder != NULL, -1); g_return_val_if_fail(FOLDER_CLASS(folder) == &news_class, -1); - g_return_val_if_fail(fp != NULL, -1); - + g_return_val_if_fail(contents != NULL, -1); + session = news_session_get(folder); - if (!session) return -1; - - ok = nntp_post(session, fp); - if (ok != NN_SUCCESS) { - log_warning(LOG_PROTOCOL, _("couldn't post article.\n")); - if (ok == NN_SOCKET) { - session_destroy(SESSION(session)); - REMOTE_FOLDER(folder)->session = NULL; - } + if (!session) { + g_free(contents); return -1; } - - return 0; -} - -static gint news_get_article_cmd(NNTPSession *session, const gchar *cmd, - gint num, gchar *filename) -{ - gchar *msgid; - gint ok; - - ok = nntp_get_article(session, cmd, num, &msgid); - if (ok != NN_SUCCESS) - return ok; - - debug_print("Message-ID = %s, num = %d\n", msgid, num); - g_free(msgid); - - ok = recv_write_to_file(SESSION(session)->sock, filename); - if (ok < 0) { - log_warning(LOG_PROTOCOL, _("couldn't retrieve article %d\n"), num); - if (ok == -2) - return NN_SOCKET; - else - return NN_IOERR; + + ok = nntp_threaded_post(folder, contents, strlen(contents)); + + g_free(contents); + if (ok == NEWSNNTP_ERROR_STREAM) { + session_destroy(SESSION(session)); + REMOTE_FOLDER(folder)->session = NULL; } - return NN_SUCCESS; + return ok; } -static gint news_get_article(NNTPSession *session, gint num, gchar *filename) +static gint news_get_article(Folder *folder, gint num, gchar *filename) { - return news_get_article_cmd(session, "ARTICLE", num, filename); + size_t len; + char *result = NULL; + int r; + + r = nntp_threaded_article(folder, num, &result, &len); + + if (r == NEWSNNTP_NO_ERROR) { + if (str_write_to_file(result, filename) < 0) + return -1; + } + + g_free(result); + return r; } /** @@ -661,15 +718,19 @@ static gint news_get_article(NNTPSession *session, gint num, gchar *filename) * * Return value: NNTP result code. **/ -static gint news_select_group(NNTPSession *session, const gchar *group, +static gint news_select_group(Folder *folder, const gchar *group, gint *num, gint *first, gint *last) { gint ok; gint num_, first_, last_; + struct newsnntp_group_info *info = NULL; + NewsSession *session = NEWS_SESSION(news_session_get(folder)); + g_return_val_if_fail(session != NULL, -1); + if (!num || !first || !last) { if (session->group && g_ascii_strcasecmp(session->group, group) == 0) - return NN_SUCCESS; + return NEWSNNTP_NO_ERROR; num = &num_; first = &first_; last = &last_; @@ -678,8 +739,25 @@ static gint news_select_group(NNTPSession *session, const gchar *group, g_free(session->group); session->group = NULL; - ok = nntp_group(session, group, num, first, last); - if (ok == NN_SUCCESS) + ok = nntp_threaded_group(folder, group, &info); + + if (ok != NEWSNNTP_NO_ERROR && + ok != NEWSNNTP_ERROR_STREAM && + ok != NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME) { + ok = nntp_threaded_mode_reader(folder); + if (ok == NEWSNNTP_NO_ERROR) + ok = nntp_threaded_group(folder, group, &info); + } + + if (ok == NEWSNNTP_NO_ERROR) { + *num = info->grp_first; + *first = info->grp_first; + *last = info->grp_last; + } + + newsnntp_group_free(info); + + if (ok == NEWSNNTP_NO_ERROR) session->group = g_strdup(group); else log_warning(LOG_PROTOCOL, _("couldn't select group: %s\n"), group); @@ -687,80 +765,45 @@ static gint news_select_group(NNTPSession *session, const gchar *group, return ok; } -#define PARSE_ONE_PARAM(p, srcp) \ -{ \ - p = strchr(srcp, '\t'); \ - if (!p) return NULL; \ - else \ - *p++ = '\0'; \ -} - -static MsgInfo *news_parse_xover(const gchar *xover_str) +static MsgInfo *news_parse_xover(struct newsnntp_xover_resp_item *item) { MsgInfo *msginfo; - gchar *subject, *sender, *size, *line, *date, *msgid, *ref, *tmp; - gchar *p; - gint num, size_int, line_int; - gchar *xover_buf; - - Xstrdup_a(xover_buf, xover_str, return NULL); - - PARSE_ONE_PARAM(subject, xover_buf); - PARSE_ONE_PARAM(sender, subject); - PARSE_ONE_PARAM(date, sender); - PARSE_ONE_PARAM(msgid, date); - PARSE_ONE_PARAM(ref, msgid); - PARSE_ONE_PARAM(size, ref); - PARSE_ONE_PARAM(line, size); - /* - * PARSE_ONE_PARAM(xref, line); - * - * if we parse extra headers we should first examine the - * LIST OVERVIEW.FMT response from the server. See - * RFC2980 for details - */ - - tmp = strchr(line, '\t'); - if (!tmp) tmp = strchr(line, '\r'); - if (!tmp) tmp = strchr(line, '\n'); - if (tmp) *tmp = '\0'; - - num = atoi(xover_str); - size_int = atoi(size); - line_int = atoi(line); /* set MsgInfo */ msginfo = procmsg_msginfo_new(); - msginfo->msgnum = num; - msginfo->size = size_int; + msginfo->msgnum = item->ovr_article; + msginfo->size = item->ovr_size; - msginfo->date = g_strdup(date); - msginfo->date_t = procheader_date_parse(NULL, date, 0); + msginfo->date = g_strdup(item->ovr_date); + msginfo->date_t = procheader_date_parse(NULL, item->ovr_date, 0); - msginfo->from = conv_unmime_header(sender, NULL); + msginfo->from = conv_unmime_header(item->ovr_author, NULL); msginfo->fromname = procheader_get_fromname(msginfo->from); - msginfo->subject = conv_unmime_header(subject, NULL); + msginfo->subject = conv_unmime_header(item->ovr_subject, NULL); remove_return(msginfo->from); remove_return(msginfo->fromname); remove_return(msginfo->subject); - if (msgid) { - extract_parenthesis(msgid, '<', '>'); - remove_space(msgid); - if (*msgid != '\0') - msginfo->msgid = g_strdup(msgid); + if (item->ovr_message_id) { + gchar *tmp = g_strdup(item->ovr_message_id); + extract_parenthesis(tmp, '<', '>'); + remove_space(tmp); + if (*tmp != '\0') + msginfo->msgid = g_strdup(tmp); + g_free(tmp); } /* FIXME: this is a quick fix; references' meaning was changed * into having the actual list of references in the References: header. * We need a GSList here, so msginfo_free() and msginfo_copy() can do * their things properly. */ - if (ref && strlen(ref)) { - gchar **ref_tokens = g_strsplit(ref, " ", -1); + if (item->ovr_references && *(item->ovr_references)) { + gchar **ref_tokens = g_strsplit(item->ovr_references, " ", -1); guint i = 0; - + char *tmp; + char *p; while (ref_tokens[i]) { gchar *cur_ref = ref_tokens[i]; msginfo->references = references_list_append(msginfo->references, @@ -769,40 +812,28 @@ static MsgInfo *news_parse_xover(const gchar *xover_str) } g_strfreev(ref_tokens); - eliminate_parenthesis(ref, '(', ')'); - if ((p = strrchr(ref, '<')) != NULL) { + tmp = g_strdup(item->ovr_references); + eliminate_parenthesis(tmp, '(', ')'); + if ((p = strrchr(tmp, '<')) != NULL) { extract_parenthesis(p, '<', '>'); remove_space(p); if (*p != '\0') msginfo->inreplyto = g_strdup(p); } + g_free(tmp); } return msginfo; } -static gchar *news_parse_xhdr(const gchar *xhdr_str, MsgInfo *msginfo) +static gchar *news_parse_xhdr(clist *hdrlist, MsgInfo *msginfo) { - gchar *p; - gchar *tmp; - gint num; - - p = strchr(xhdr_str, ' '); - if (!p) + struct newsnntp_xhdr_resp_item *hdr; + + hdr = clist_content(clist_begin(hdrlist)); + if (hdr->hdr_article != msginfo->msgnum) return NULL; - else - p++; - - num = atoi(xhdr_str); - if (msginfo->msgnum != num) return NULL; - - tmp = strchr(p, '\r'); - if (!tmp) tmp = strchr(p, '\n'); - - if (tmp) - return g_strndup(p, tmp - p); - else - return g_strdup(p); + return g_strdup(hdr->hdr_value); } gint news_cancel_article(Folder * folder, MsgInfo * msginfo) @@ -908,7 +939,7 @@ static gchar *news_item_get_path(Folder *folder, FolderItem *item) static gint news_get_num_list(Folder *folder, FolderItem *item, GSList **msgnum_list, gboolean *old_uids_valid) { - NNTPSession *session; + NewsSession *session; gint i, ok, num, first, last, nummsgs = 0; gchar *dir; @@ -923,8 +954,8 @@ static gint news_get_num_list(Folder *folder, FolderItem *item, GSList **msgnum_ news_folder_lock(NEWS_FOLDER(item->folder)); - ok = news_select_group(session, item->path, &num, &first, &last); - if (ok != NN_SUCCESS) { + ok = news_select_group(folder, item->path, &num, &first, &last); + if (ok != NEWSNNTP_NO_ERROR) { log_warning(LOG_PROTOCOL, _("couldn't set group: %s\n"), item->path); news_folder_unlock(NEWS_FOLDER(item->folder)); return -1; @@ -951,14 +982,6 @@ static gint news_get_num_list(Folder *folder, FolderItem *item, GSList **msgnum_ return nummsgs; } -#define READ_TO_LISTEND(hdr) \ - while (!(buf[0] == '.' && buf[1] == '\r')) { \ - if (sock_gets(SESSION(session)->sock, buf, sizeof(buf)) < 0) { \ - log_warning(LOG_PROTOCOL, _("error occurred while getting %s.\n"), hdr); \ - return msginfo; \ - } \ - } - static void news_set_msg_flags(FolderItem *item, MsgInfo *msginfo) { msginfo->flags.tmp_flags = 0; @@ -981,10 +1004,11 @@ static void news_set_msg_flags(FolderItem *item, MsgInfo *msginfo) static MsgInfo *news_get_msginfo(Folder *folder, FolderItem *item, gint num) { - NNTPSession *session; + NewsSession *session; MsgInfo *msginfo = NULL; - gchar buf[NNTPBUFSIZE]; gint ok; + struct newsnntp_xover_resp_item *result = NULL; + clist *hdrlist = NULL; session = news_session_get(folder); g_return_val_if_fail(session != NULL, NULL); @@ -994,13 +1018,12 @@ static MsgInfo *news_get_msginfo(Folder *folder, FolderItem *item, gint num) log_message(LOG_PROTOCOL, _("getting xover %d in %s...\n"), num, item->path); - ok = nntp_xover(session, num, num); - news_folder_lock(NEWS_FOLDER(item->folder)); - - if (ok != NN_SUCCESS) { + + ok = nntp_threaded_xover(folder, num, num, &result, NULL); + if (ok != NEWSNNTP_NO_ERROR) { log_warning(LOG_PROTOCOL, _("couldn't get xover\n")); - if (ok == NN_SOCKET) { + if (ok == NEWSNNTP_ERROR_STREAM) { session_destroy(SESSION(session)); REMOTE_FOLDER(item->folder)->session = NULL; } @@ -1008,19 +1031,12 @@ static MsgInfo *news_get_msginfo(Folder *folder, FolderItem *item, gint num) return NULL; } - if (sock_gets(SESSION(session)->sock, buf, sizeof(buf)) < 0) { - log_warning(LOG_PROTOCOL, _("error occurred while getting xover.\n")); - news_folder_unlock(NEWS_FOLDER(item->folder)); - return NULL; - } - - msginfo = news_parse_xover(buf); + msginfo = news_parse_xover(result); + xover_resp_item_free(result); if (!msginfo) { - log_warning(LOG_PROTOCOL, _("invalid xover line: %s\n"), buf); + log_warning(LOG_PROTOCOL, _("invalid xover line\n")); } - READ_TO_LISTEND("xover"); - if(!msginfo) { news_folder_unlock(NEWS_FOLDER(item->folder)); return NULL; @@ -1032,10 +1048,11 @@ static MsgInfo *news_get_msginfo(Folder *folder, FolderItem *item, gint num) msginfo->flags.tmp_flags |= MSG_NEWS; msginfo->newsgroups = g_strdup(item->path); - ok = nntp_xhdr(session, "to", num, num); - if (ok != NN_SUCCESS) { + ok = nntp_threaded_xhdr(folder, "to", num, num, &hdrlist); + + if (ok != NEWSNNTP_NO_ERROR) { log_warning(LOG_PROTOCOL, _("couldn't get xhdr\n")); - if (ok == NN_SOCKET) { + if (ok == NEWSNNTP_ERROR_STREAM) { session_destroy(SESSION(session)); REMOTE_FOLDER(item->folder)->session = NULL; } @@ -1043,20 +1060,14 @@ static MsgInfo *news_get_msginfo(Folder *folder, FolderItem *item, gint num) return msginfo; } - if (sock_gets(SESSION(session)->sock, buf, sizeof(buf)) < 0) { - log_warning(LOG_PROTOCOL, _("error occurred while getting xhdr.\n")); - news_folder_unlock(NEWS_FOLDER(item->folder)); - return msginfo; - } - - msginfo->to = news_parse_xhdr(buf, msginfo); - - READ_TO_LISTEND("xhdr (to)"); + msginfo->to = news_parse_xhdr(hdrlist, msginfo); + newsnntp_xhdr_free(hdrlist); - ok = nntp_xhdr(session, "cc", num, num); - if (ok != NN_SUCCESS) { + ok = nntp_threaded_xhdr(folder, "cc", num, num, &hdrlist); + + if (ok != NEWSNNTP_NO_ERROR) { log_warning(LOG_PROTOCOL, _("couldn't get xhdr\n")); - if (ok == NN_SOCKET) { + if (ok == NEWSNNTP_ERROR_STREAM) { session_destroy(SESSION(session)); REMOTE_FOLDER(item->folder)->session = NULL; } @@ -1064,62 +1075,47 @@ static MsgInfo *news_get_msginfo(Folder *folder, FolderItem *item, gint num) return msginfo; } - if (sock_gets(SESSION(session)->sock, buf, sizeof(buf)) < 0) { - log_warning(LOG_PROTOCOL, _("error occurred while getting xhdr.\n")); - news_folder_unlock(NEWS_FOLDER(item->folder)); - return msginfo; - } - - msginfo->cc = news_parse_xhdr(buf, msginfo); + msginfo->cc = news_parse_xhdr(hdrlist, msginfo); + newsnntp_xhdr_free(hdrlist); - READ_TO_LISTEND("xhdr (cc)"); news_folder_unlock(NEWS_FOLDER(item->folder)); return msginfo; } -static GSList *news_get_msginfos_for_range(NNTPSession *session, FolderItem *item, guint begin, guint end) +static GSList *news_get_msginfos_for_range(NewsSession *session, FolderItem *item, guint begin, guint end) { - gchar buf[NNTPBUFSIZE]; GSList *newlist = NULL; GSList *llast = NULL; MsgInfo *msginfo; - guint count = 0, lines = (end - begin) + 2; gint ok; - + clist *msglist = NULL; + clistiter *cur; g_return_val_if_fail(session != NULL, NULL); g_return_val_if_fail(item != NULL, NULL); log_message(LOG_PROTOCOL, _("getting xover %d - %d in %s...\n"), begin, end, item->path); - ok = nntp_xover(session, begin, end); - if (ok != NN_SUCCESS) { + + news_folder_lock(NEWS_FOLDER(item->folder)); + + ok = nntp_threaded_xover(item->folder, begin, end, NULL, &msglist); + + if (ok != NEWSNNTP_NO_ERROR) { log_warning(LOG_PROTOCOL, _("couldn't get xover\n")); - if (ok == NN_SOCKET) { + if (ok == NEWSNNTP_ERROR_STREAM) { session_destroy(SESSION(session)); REMOTE_FOLDER(item->folder)->session = NULL; } + news_folder_unlock(NEWS_FOLDER(item->folder)); return NULL; } - news_folder_lock(NEWS_FOLDER(item->folder)); - - for (;;) { - if (sock_gets(SESSION(session)->sock, buf, sizeof(buf)) < 0) { - log_warning(LOG_PROTOCOL, _("error occurred while getting xover.\n")); - news_folder_unlock(NEWS_FOLDER(item->folder)); - return newlist; - } - count++; - progressindicator_set_percentage - (PROGRESS_TYPE_NETWORK, - session->fetch_base_percentage + - (((gfloat) count) / ((gfloat) lines)) * session->fetch_total_percentage); - - if (buf[0] == '.' && buf[1] == '\r') break; - - msginfo = news_parse_xover(buf); + for (cur = clist_begin(msglist); cur; cur = clist_next(cur)) { + struct newsnntp_xover_resp_item *ritem = (struct newsnntp_xover_resp_item *)clist_content(cur); + msginfo = news_parse_xover(ritem); + if (!msginfo) { - log_warning(LOG_PROTOCOL, _("invalid xover line: %s\n"), buf); + log_warning(LOG_PROTOCOL, _("invalid xover line\n")); continue; } @@ -1135,70 +1131,8 @@ static GSList *news_get_msginfos_for_range(NNTPSession *session, FolderItem *ite llast = llast->next; } } + newsnntp_xover_resp_list_free(msglist); - ok = nntp_xhdr(session, "to", begin, end); - if (ok != NN_SUCCESS) { - log_warning(LOG_PROTOCOL, _("couldn't get xhdr\n")); - if (ok == NN_SOCKET) { - session_destroy(SESSION(session)); - REMOTE_FOLDER(item->folder)->session = NULL; - } - news_folder_unlock(NEWS_FOLDER(item->folder)); - return newlist; - } - - llast = newlist; - - for (;;) { - if (sock_gets(SESSION(session)->sock, buf, sizeof(buf)) < 0) { - log_warning(LOG_PROTOCOL, _("error occurred while getting xhdr.\n")); - news_folder_unlock(NEWS_FOLDER(item->folder)); - return newlist; - } - - if (buf[0] == '.' && buf[1] == '\r') break; - if (!llast) { - g_warning("llast == NULL\n"); - continue; - } - - msginfo = (MsgInfo *)llast->data; - msginfo->to = news_parse_xhdr(buf, msginfo); - - llast = llast->next; - } - - ok = nntp_xhdr(session, "cc", begin, end); - if (ok != NN_SUCCESS) { - log_warning(LOG_PROTOCOL, _("couldn't get xhdr\n")); - if (ok == NN_SOCKET) { - session_destroy(SESSION(session)); - REMOTE_FOLDER(item->folder)->session = NULL; - } - news_folder_unlock(NEWS_FOLDER(item->folder)); - return newlist; - } - - llast = newlist; - - for (;;) { - if (sock_gets(SESSION(session)->sock, buf, sizeof(buf)) < 0) { - log_warning(LOG_PROTOCOL, _("error occurred while getting xhdr.\n")); - news_folder_unlock(NEWS_FOLDER(item->folder)); - return newlist; - } - - if (buf[0] == '.' && buf[1] == '\r') break; - if (!llast) { - g_warning("llast == NULL\n"); - continue; - } - - msginfo = (MsgInfo *)llast->data; - msginfo->cc = news_parse_xhdr(buf, msginfo); - - llast = llast->next; - } news_folder_unlock(NEWS_FOLDER(item->folder)); session_set_access_time(SESSION(session)); @@ -1208,7 +1142,7 @@ static GSList *news_get_msginfos_for_range(NNTPSession *session, FolderItem *ite static GSList *news_get_msginfos(Folder *folder, FolderItem *item, GSList *msgnum_list) { - NNTPSession *session; + NewsSession *session; GSList *elem, *msginfo_list = NULL, *tmp_msgnum_list, *tmp_msginfo_list; guint first, last, next; guint tofetch, fetched; @@ -1236,8 +1170,9 @@ static GSList *news_get_msginfos(Folder *folder, FolderItem *item, GSList *msgnu for(elem = g_slist_next(tmp_msgnum_list); elem != NULL; elem = g_slist_next(elem)) { next = GPOINTER_TO_INT(elem->data); if(next != (last + 1)) { - session->fetch_base_percentage = ((gfloat) fetched) / ((gfloat) tofetch); +/* session->fetch_base_percentage = ((gfloat) fetched) / ((gfloat) tofetch); session->fetch_total_percentage = ((gfloat) (last - first + 1)) / ((gfloat) tofetch); +*/ tmp_msginfo_list = news_get_msginfos_for_range(session, item, first, last); msginfo_list = g_slist_concat(msginfo_list, tmp_msginfo_list); fetched = last - first + 1; @@ -1248,8 +1183,9 @@ static GSList *news_get_msginfos(Folder *folder, FolderItem *item, GSList *msgnu news_folder_unlock(NEWS_FOLDER(item->folder)); - session->fetch_base_percentage = ((gfloat) fetched) / ((gfloat) tofetch); +/* session->fetch_base_percentage = ((gfloat) fetched) / ((gfloat) tofetch); session->fetch_total_percentage = ((gfloat) (last - first + 1)) / ((gfloat) tofetch); +*/ tmp_msginfo_list = news_get_msginfos_for_range(session, item, first, last); msginfo_list = g_slist_concat(msginfo_list, tmp_msginfo_list); @@ -1289,3 +1225,82 @@ static gint news_remove_folder(Folder *folder, FolderItem *item) folder_item_remove(item); return 0; } + +#else +#include +#include +#include +#include "folder.h" +#include "alertpanel.h" + +static FolderClass news_class; + +static void warn_etpan(void) +{ + static gboolean missing_news_warning = TRUE; + if (missing_news_warning) { + missing_news_warning = FALSE; + alertpanel_error( + _("You have one or more News accounts " + "defined. However this version of " + "Claws Mail has been built without " + "News support; your News account(s) are " + "disabled.\n\n" + "You probably need to " + "install libetpan and recompile " + "Claws Mail.")); + } +} +static Folder *news_folder_new(const gchar *name, const gchar *path) +{ + warn_etpan(); + return NULL; +} +void news_group_list_free(GSList *group_list) +{ + warn_etpan(); +} +void news_remove_group_list_cache(Folder *folder) +{ + warn_etpan(); +} +int news_folder_locked(Folder *folder) +{ + warn_etpan(); + return 0; +} +gint news_post(Folder *folder, const gchar *file) +{ + warn_etpan(); + return -1; +} + +gint news_cancel_article(Folder * folder, MsgInfo * msginfo) +{ + warn_etpan(); + return -1; +} + +GSList *news_get_group_list(Folder *folder) +{ + warn_etpan(); + return NULL; +} + + +FolderClass *news_get_class(void) +{ + if (news_class.idstr == NULL) { + news_class.type = F_NEWS; + news_class.idstr = "news"; + news_class.uistr = "News"; + + /* Folder functions */ + news_class.new_folder = news_folder_new; + }; + + return &news_class; +} + + +#endif diff --git a/src/news.h b/src/news.h index dcb5353b0..6d9c9bb2d 100644 --- a/src/news.h +++ b/src/news.h @@ -47,4 +47,8 @@ gint news_cancel_article (Folder *folder, MsgInfo *msginfo); int news_folder_locked (Folder *folder); +guint nntp_folder_get_refcnt(Folder *folder); +void nntp_folder_ref(Folder *folder); +void nntp_folder_unref(Folder *folder); + #endif /* __NEWS_H__ */ diff --git a/src/pop.c b/src/pop.c index 36319085e..3ce3eb7a9 100644 --- a/src/pop.c +++ b/src/pop.c @@ -45,7 +45,7 @@ static gint pop3_greeting_recv (Pop3Session *session, static gint pop3_getauth_user_send (Pop3Session *session); static gint pop3_getauth_pass_send (Pop3Session *session); static gint pop3_getauth_apop_send (Pop3Session *session); -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) static gint pop3_stls_send (Pop3Session *session); static gint pop3_stls_recv (Pop3Session *session); #endif @@ -100,7 +100,7 @@ static gint pop3_greeting_recv(Pop3Session *session, const gchar *msg) return PS_SUCCESS; } -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) static gint pop3_stls_send(Pop3Session *session) { session->state = POP3_STLS; @@ -879,7 +879,7 @@ static Pop3ErrorValue pop3_ok(Pop3Session *session, const gchar *msg) ok = PS_ERROR; } else { switch (session->state) { -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) case POP3_STLS: log_error(LOG_PROTOCOL, _("couldn't start TLS session\n")); ok = PS_ERROR; @@ -943,7 +943,7 @@ static gint pop3_session_recv_msg(Session *session, const gchar *msg) case POP3_READY: case POP3_GREETING: pop3_greeting_recv(pop3_session, body); -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) if (pop3_session->ac_prefs->ssl_pop == SSL_STARTTLS) val = pop3_stls_send(pop3_session); else @@ -953,7 +953,7 @@ static gint pop3_session_recv_msg(Session *session, const gchar *msg) else val = pop3_getauth_user_send(pop3_session); break; -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) case POP3_STLS: if (pop3_stls_recv(pop3_session) != PS_SUCCESS) return -1; diff --git a/src/pop.h b/src/pop.h index 7d9ba2d39..cd95c1fd1 100644 --- a/src/pop.h +++ b/src/pop.h @@ -47,7 +47,7 @@ typedef struct _MailReceiveData MailReceiveData; typedef enum { POP3_READY, POP3_GREETING, -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) POP3_STLS, #endif POP3_GETAUTH_USER, diff --git a/src/prefs_account.c b/src/prefs_account.c index 52db93eb5..e37e43af7 100644 --- a/src/prefs_account.c +++ b/src/prefs_account.c @@ -286,7 +286,7 @@ static SendPage send_page; static ComposePage compose_page; static TemplatesPage templates_page; static PrivacyPage privacy_page; -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) static SSLPage ssl_page; #endif static AdvancedPage advanced_page; @@ -650,7 +650,7 @@ static PrefParam privacy_param[] = { }; static PrefParam ssl_param[] = { -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) {"ssl_pop", "0", &tmp_ac_prefs.ssl_pop, P_ENUM, &ssl_page.pop_nossl_radiobtn, prefs_account_enum_set_data_from_radiobtn, @@ -1037,7 +1037,7 @@ static void basic_create_widget_func(PrefsPage * _page, no_imap_warn_icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR); no_imap_warn_label = gtk_label_new(_("Warning: this version of Claws Mail\n" - "has been built without IMAP support.")); + "has been built without IMAP and News support.")); gtk_label_set_use_markup(GTK_LABEL(no_imap_warn_label), TRUE); gtk_box_pack_start(GTK_BOX (optmenubox), no_imap_warn_icon, FALSE, FALSE, 0); @@ -2186,7 +2186,7 @@ static void privacy_create_widget_func(PrefsPage * _page, page->page.widget = vbox1; } -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) #define CREATE_RADIO_BUTTON(box, btn, btn_p, label, data) \ { \ @@ -2709,7 +2709,7 @@ static gint prefs_privacy_apply(void) return 0; } -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) static gint prefs_ssl_apply(void) { prefs_set_data_from_dialog(ssl_param); @@ -2753,7 +2753,7 @@ static void privacy_destroy_widget_func(PrefsPage *_page) /* PrivacyPage *page = (PrivacyPage *) _page; */ } -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) static void ssl_destroy_widget_func(PrefsPage *_page) { /* SSLPage *page = (SSLPage *) _page; */ @@ -2825,7 +2825,7 @@ static gboolean privacy_can_close_func(PrefsPage *_page) return prefs_privacy_apply() >= 0; } -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) static gboolean ssl_can_close_func(PrefsPage *_page) { SSLPage *page = (SSLPage *) _page; @@ -2922,7 +2922,7 @@ static void privacy_save_func(PrefsPage *_page) cancelled = FALSE; } -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) static void ssl_save_func(PrefsPage *_page) { SSLPage *page = (SSLPage *) _page; @@ -3054,7 +3054,7 @@ static void register_privacy_page(void) prefs_account_register_page((PrefsPage *) &privacy_page); } -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) static void register_ssl_page(void) { static gchar *path[3]; @@ -3100,7 +3100,7 @@ void prefs_account_init() register_compose_page(); register_templates_page(); register_privacy_page(); -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) register_ssl_page(); #endif register_advanced_page(); @@ -3564,7 +3564,7 @@ static void prefs_account_protocol_set_optmenu(PrefParam *pparam) gtk_widget_hide(optmenu); gtk_widget_show(optlabel); #ifndef HAVE_LIBETPAN - if (protocol == A_IMAP4) { + if (protocol == A_IMAP4 || protocol == A_NNTP) { gtk_widget_show(protocol_optmenu->no_imap_warn_icon); gtk_widget_show(protocol_optmenu->no_imap_warn_label); } else { @@ -3712,8 +3712,13 @@ static void prefs_account_protocol_changed(GtkComboBox *combobox, gpointer data) gtk_widget_hide(protocol_optmenu->no_imap_warn_label); switch(protocol) { case A_NNTP: +#ifndef HAVE_LIBETPAN + gtk_widget_show(protocol_optmenu->no_imap_warn_icon); + gtk_widget_show(protocol_optmenu->no_imap_warn_label); +#else gtk_widget_hide(protocol_optmenu->no_imap_warn_icon); gtk_widget_hide(protocol_optmenu->no_imap_warn_label); +#endif gtk_widget_show(basic_page.nntpserv_label); gtk_widget_show(basic_page.nntpserv_entry); gtk_table_set_row_spacing (GTK_TABLE (basic_page.serv_table), @@ -3788,7 +3793,7 @@ static void prefs_account_protocol_changed(GtkComboBox *combobox, gpointer data) FALSE); } -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) gtk_widget_hide(ssl_page.pop_frame); gtk_widget_hide(ssl_page.imap_frame); gtk_widget_show(ssl_page.nntp_frame); @@ -3879,7 +3884,7 @@ static void prefs_account_protocol_changed(GtkComboBox *combobox, gpointer data) TRUE); } -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) gtk_widget_hide(ssl_page.pop_frame); gtk_widget_hide(ssl_page.imap_frame); gtk_widget_hide(ssl_page.nntp_frame); @@ -3975,7 +3980,7 @@ static void prefs_account_protocol_changed(GtkComboBox *combobox, gpointer data) FALSE); } -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) gtk_widget_hide(ssl_page.pop_frame); gtk_widget_show(ssl_page.imap_frame); gtk_widget_hide(ssl_page.nntp_frame); @@ -4064,7 +4069,7 @@ static void prefs_account_protocol_changed(GtkComboBox *combobox, gpointer data) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(receive_page.recvatgetall_checkbtn), FALSE); -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) gtk_widget_hide(ssl_page.pop_frame); gtk_widget_hide(ssl_page.imap_frame); gtk_widget_hide(ssl_page.nntp_frame); @@ -4159,7 +4164,7 @@ static void prefs_account_protocol_changed(GtkComboBox *combobox, gpointer data) TRUE); } -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) gtk_widget_show(ssl_page.pop_frame); gtk_widget_hide(ssl_page.imap_frame); gtk_widget_hide(ssl_page.nntp_frame); diff --git a/src/recv.c b/src/recv.c index ea75b21dd..8a5384fcb 100644 --- a/src/recv.c +++ b/src/recv.c @@ -41,103 +41,6 @@ static RecvUIFunc recv_ui_func; static gpointer recv_ui_func_data; -static gint recv_write (SockInfo *sock, - FILE *fp); - -gint recv_write_to_file(SockInfo *sock, const gchar *filename) -{ - FILE *fp; - gint ret; - - g_return_val_if_fail(filename != NULL, -1); - - if ((fp = g_fopen(filename, "wb")) == NULL) { - FILE_OP_ERROR(filename, "fopen"); - recv_write(sock, NULL); - return -1; - } - - if (change_file_mode_rw(fp, filename) < 0) - FILE_OP_ERROR(filename, "chmod"); - - if ((ret = recv_write(sock, fp)) < 0) { - fclose(fp); - g_unlink(filename); - return ret; - } - - if (fclose(fp) == EOF) { - FILE_OP_ERROR(filename, "fclose"); - g_unlink(filename); - return -1; - } - - return 0; -} - -static gint recv_write(SockInfo *sock, FILE *fp) -{ - gchar buf[BUFFSIZE]; - gint len; - gint count = 0; - gint bytes = 0; - struct timeval tv_prev, tv_cur; - - gettimeofday(&tv_prev, NULL); - - for (;;) { - if (sock_gets(sock, buf, sizeof(buf)) < 0) { - g_warning("error occurred while retrieving data.\n"); - return -2; - } - - len = strlen(buf); - if (len > 1 && buf[0] == '.' && buf[1] == '\r') { - if (recv_ui_func) - recv_ui_func(sock, count, bytes, - recv_ui_func_data); - break; - } - count++; - bytes += len; - - if (recv_ui_func) { - gettimeofday(&tv_cur, NULL); - /* if elapsed time from previous update is greater - than 50msec, update UI */ - if (tv_cur.tv_sec - tv_prev.tv_sec > 0 || - tv_cur.tv_usec - tv_prev.tv_usec > UI_REFRESH_INTERVAL) { - gboolean ret; - ret = recv_ui_func(sock, count, bytes, - recv_ui_func_data); - if (ret == FALSE) return -1; - gettimeofday(&tv_prev, NULL); - } - } - - if (len > 1 && buf[len - 1] == '\n' && buf[len - 2] == '\r') { - buf[len - 2] = '\n'; - buf[len - 1] = '\0'; - len--; - } - - if (buf[0] == '.' && buf[1] == '.') - memmove(buf, buf + 1, len--); - - if (!strncmp(buf, ">From ", 6)) - memmove(buf, buf + 1, len--); - - if (fp && fputs(buf, fp) == EOF) { - perror("fputs"); - g_warning("Can't write to file.\n"); - fp = NULL; - } - } - - if (!fp) return -1; - - return 0; -} void recv_set_ui_func(RecvUIFunc func, gpointer data) { diff --git a/src/recv.h b/src/recv.h index 2c2c8a482..ccec7a32f 100644 --- a/src/recv.h +++ b/src/recv.h @@ -29,9 +29,6 @@ typedef gboolean (*RecvUIFunc) (SockInfo *sock, gint read_bytes, gpointer data); -gint recv_write_to_file (SockInfo *sock, - const gchar *filename); - void recv_set_ui_func (RecvUIFunc func, gpointer data); diff --git a/src/send_message.c b/src/send_message.c index 3864f9af0..72b5b6a76 100644 --- a/src/send_message.c +++ b/src/send_message.c @@ -288,13 +288,13 @@ gint send_message_smtp_full(PrefsAccount *ac_prefs, GSList *to_list, FILE *fp, g smtp_session->pass = NULL; } - #if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) port = ac_prefs->set_smtpport ? ac_prefs->smtpport : ac_prefs->ssl_smtp == SSL_TUNNEL ? SSMTP_PORT : SMTP_PORT; session->ssl_type = ac_prefs->ssl_smtp; if (ac_prefs->ssl_smtp != SSL_NONE) session->nonblocking = ac_prefs->use_nonblocking_ssl; - #else +#else if (ac_prefs->ssl_smtp != SSL_NONE) { if (alertpanel_full(_("Insecure connection"), _("This connection is configured to be secured " @@ -311,7 +311,7 @@ gint send_message_smtp_full(PrefsAccount *ac_prefs, GSList *to_list, FILE *fp, g } } port = ac_prefs->set_smtpport ? ac_prefs->smtpport : SMTP_PORT; - #endif +#endif dialog = send_progress_dialog_create(); dialog->session = session; diff --git a/src/send_message.h b/src/send_message.h index f91923fe6..40612a015 100644 --- a/src/send_message.h +++ b/src/send_message.h @@ -25,7 +25,7 @@ #include "prefs_account.h" #define SMTP_PORT 25 -#if USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) #define SSMTP_PORT 465 #endif diff --git a/src/ssl_manager.c b/src/ssl_manager.c index 82e1e329e..b44256f30 100644 --- a/src/ssl_manager.c +++ b/src/ssl_manager.c @@ -21,7 +21,7 @@ # include "config.h" #endif -#ifdef USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) #include #include #include diff --git a/src/ssl_manager.h b/src/ssl_manager.h index 9fae65a8a..f6443f028 100644 --- a/src/ssl_manager.h +++ b/src/ssl_manager.h @@ -20,7 +20,7 @@ #ifndef SSL_MANAGER_H #define SSL_MANAGER_H -#ifdef USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) #include "mainwindow.h" void ssl_manager_create (void); diff --git a/src/wizard.c b/src/wizard.c index b0f20cb2e..78119b5eb 100644 --- a/src/wizard.c +++ b/src/wizard.c @@ -57,7 +57,7 @@ #include "setup.h" #include "folder.h" #include "alertpanel.h" -#ifdef USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) #include "ssl.h" #endif #include "prefs_common.h" @@ -116,7 +116,7 @@ typedef struct GtkWidget *recv_imap_subdir; GtkWidget *subsonly_checkbtn; GtkWidget *no_imap_warning; -#ifdef USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) GtkWidget *smtp_use_ssl; GtkWidget *recv_use_ssl; GtkWidget *smtp_use_tls; @@ -574,7 +574,7 @@ static gboolean wizard_write_config(WizardWindow *wizard) GtkWidget *menu, *menuitem; gchar *smtp_server, *recv_server; gint smtp_port, recv_port; -#ifdef USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) SSLType smtp_ssl_type, recv_ssl_type; #endif @@ -752,7 +752,7 @@ static gboolean wizard_write_config(WizardWindow *wizard) prefs_account->use_smtp_auth = TRUE; } -#ifdef USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) smtp_ssl_type = SSL_NONE; recv_ssl_type = SSL_NONE; @@ -1230,7 +1230,7 @@ static GtkWidget* smtp_page (WizardWindow * wizard) gtk_misc_set_alignment(GTK_MISC(wizard->smtp_password_label), 1, 0.5); gtk_box_pack_start(GTK_BOX(hbox), wizard->smtp_password_label, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), wizard->smtp_password, TRUE, TRUE, 0); -#ifdef USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) hbox = gtk_hbox_new(FALSE, VSPACING_NARROW); gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 0); wizard->smtp_use_ssl = gtk_check_button_new_with_label( @@ -1267,7 +1267,7 @@ static void wizard_protocol_change(WizardWindow *wizard, RecvProtocol protocol) gtk_widget_show(wizard->recv_username_label); gtk_widget_show(wizard->recv_password_label); gtk_widget_hide(wizard->no_imap_warning); -#ifdef USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) gtk_widget_show(wizard->recv_use_ssl); gtk_widget_show(wizard->recv_use_tls); #endif @@ -1291,7 +1291,7 @@ static void wizard_protocol_change(WizardWindow *wizard, RecvProtocol protocol) gtk_widget_show(wizard->recv_username_label); gtk_widget_show(wizard->recv_password_label); gtk_widget_hide(wizard->no_imap_warning); -#ifdef USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) gtk_widget_show(wizard->recv_use_ssl); gtk_widget_show(wizard->recv_use_tls); #endif @@ -1316,7 +1316,7 @@ static void wizard_protocol_change(WizardWindow *wizard, RecvProtocol protocol) gtk_widget_hide(wizard->mailbox_label); gtk_widget_hide(wizard->mailbox_name); } -#ifdef USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) gtk_widget_hide(wizard->recv_use_ssl); gtk_widget_hide(wizard->recv_use_tls); #endif @@ -1334,7 +1334,7 @@ static void wizard_protocol_change(WizardWindow *wizard, RecvProtocol protocol) gtk_widget_hide(wizard->recv_password); gtk_widget_hide(wizard->recv_username_label); gtk_widget_hide(wizard->recv_password_label); -#ifdef USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) gtk_widget_hide(wizard->recv_use_ssl); gtk_widget_hide(wizard->recv_use_tls); #endif @@ -1457,7 +1457,7 @@ static GtkWidget* recv_page (WizardWindow * wizard) gtk_box_pack_start(GTK_BOX(hbox), wizard->recv_password_label, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), wizard->recv_password, TRUE, TRUE, 0); -#ifdef USE_OPENSSL +#if (defined(USE_OPENSSL) || defined (USE_GNUTLS)) hbox = gtk_hbox_new(FALSE, VSPACING_NARROW); gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 0); wizard->recv_use_ssl = gtk_check_button_new_with_label( -- 2.25.1