[pan2: 248/268] Dumped OpenSSL, implemented GnuTLS
- From: Heinrich MÃller <henmull src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pan2: 248/268] Dumped OpenSSL, implemented GnuTLS
- Date: Mon, 2 Jan 2012 15:58:51 +0000 (UTC)
commit 6c0845861d0d60a29c4c9cf653242edbc5aa35cb
Author: Heinrich MÃller <henmull src gnome org>
Date: Mon Dec 19 15:56:06 2011 +0100
Dumped OpenSSL, implemented GnuTLS
configure.in | 32 ++-
pan/data-impl/Makefile.am | 2 +-
pan/data-impl/data-impl.h | 17 +-
pan/data-impl/server.cc | 34 +++-
pan/data/article-cache.cc | 2 +
pan/data/article.cc | 9 +
pan/data/cert-store.cc | 282 +++++++++++++++-------
pan/data/cert-store.h | 107 +++------
pan/data/data.h | 10 +-
pan/data/server-info.h | 5 +
pan/gui/Makefile.am | 6 +-
pan/gui/body-pane.cc | 195 ++++++++++++++-
pan/gui/body-pane.h | 42 +++-
pan/gui/e-cte-dialog.c | 13 +-
pan/gui/e-cte-dialog.h | 1 +
pan/gui/gui.cc | 40 ++--
pan/gui/gui.h | 17 +-
pan/gui/pan.cc | 4 +-
pan/gui/post-ui.cc | 3 +-
pan/gui/save-attach-ui.cc | 320 ++++++++++++++++++++++++
pan/gui/save-attach-ui.h | 82 +++++++
pan/gui/server-ui.cc | 76 +++---
pan/gui/task-pane.cc | 2 +
pan/tasks/Makefile.am | 4 +-
pan/tasks/decoder.cc | 18 +-
pan/tasks/decoder.h | 6 +-
pan/tasks/encoder.cc | 3 -
pan/tasks/nntp-pool.cc | 8 +-
pan/tasks/nntp-pool.h | 8 +-
pan/tasks/queue.h | 2 +-
pan/tasks/socket-impl-main.cc | 95 ++------
pan/tasks/socket-impl-main.h | 21 +--
pan/tasks/socket-impl-openssl.cc | 490 ++++++++++++++++++-------------------
pan/tasks/socket-impl-openssl.h | 44 ++--
pan/tasks/socket.h | 9 +-
pan/tasks/task-article.cc | 13 +-
pan/tasks/task-article.h | 26 +--
pan/usenet-utils/mime-utils.cc | 20 +-
pan/usenet-utils/ssl-utils.h | 499 ++++++--------------------------------
39 files changed, 1450 insertions(+), 1117 deletions(-)
---
diff --git a/configure.in b/configure.in
index f40f73c..247ef74 100644
--- a/configure.in
+++ b/configure.in
@@ -50,7 +50,7 @@ GMIME_REQUIRED=2.6.0
GTK_REQUIRED=2.16.0
GTK3_REQUIRED=3.0.0
GTKSPELL_REQUIRED=2.0.7
-OPENSSL_REQUIRED=1.0.0
+GNUTLS_REQUIRED=3.0.9
LIBNOTIFY_REQUIRED=0.4.1
LIBGSASL_REQUIRED=1.6.1
LIBGKR_REQUIRED=3.2.2
@@ -58,7 +58,7 @@ AC_SUBST(GLIB_REQUIRED)
AC_SUBST(GMIME_REQUIRED)
AC_SUBST(GTK_REQUIRED)
AC_SUBST(GTKSPELL_REQUIRED)
-AC_SUBST(OPENSSL_REQUIRED)
+AC_SUBST(GNUTLS_REQUIRED)
AC_SUBST(LIBNOTIFY_REQUIRED)
AC_SUBST(LIBGSASL_REQUIRED)
AC_SUBST(LIBGKR_REQUIRED)
@@ -109,16 +109,20 @@ if test "x$want_gtkspell" = "xyes" ; then
AC_MSG_RESULT(no)])
fi
-openssl_msg=no
-AC_ARG_WITH(openssl, AC_HELP_STRING([--with-openssl], [Enable OpenSSL support]), [want_openssl=$withval], [want_openssl=no])
-if test "x$want_openssl" = "xyes" ; then
- PKG_CHECK_MODULES([OPENSSL], [openssl >= $OPENSSL_REQUIRED],
- [openssl_msg=yes
- AC_DEFINE(HAVE_OPENSSL,[1],[OpenSSL 3.0])],
- [openssl_msg=no
- AC_MSG_RESULT(no)])
+
+gnutls_msg=no
+AC_ARG_WITH(gnutls, AC_HELP_STRING([--with-gnutls], [Enable GnuTLS support]), [want_gnutls=$withval], [want_gnutls=no])
+if test "x$want_gnutls" = "xyes" ; then
+ PKG_CHECK_MODULES([GNUTLS], [gnutls >= $GNUTLS_REQUIRED],
+ [gnutls_msg=yes,
+ AC_DEFINE(HAVE_GNUTLS,[1],[GnuTLS])],
+ [gnutls_msg=no
+ AC_MSG_RESULT(no)])
+ AC_SUBST([GNUTLS_CFLAGS])
+ AC_SUBST([GNUTLS_LIBS])
fi
+
dnl Check for libnotify if user-enabled for popup notifications
AC_ARG_ENABLE([libnotify],
AC_HELP_STRING([--enable-libnotify],[enable libnotify support]),[enable_libnotify=$enableval],[enable_libnotify=yes])
@@ -205,9 +209,9 @@ case $host_os in
esac
AM_CONDITIONAL([HAVE_WIN32],[test "$win32" = "yes"])
-CXXFLAGS="$CXXFLAGS -O0 -g -I/usr/lib/"
-CPPFLAGS="$CPPFLAGS -O0 -g -I/usr/lib/"
-CFLAGS="$CFLAGS -g -I/usr/lib/"
+CXXFLAGS="-O0 -g -I/usr/lib/"
+CPPFLAGS="-O0 -g -I/usr/lib/"
+CFLAGS="-g -O0 -I/usr/lib/"
dnl build the output files
AC_SUBST(panlocaledir)
@@ -237,6 +241,6 @@ Configuration:
Compiler: ${CXX}
With GtkSpell: ${gtkspell_msg}
With GTK3: ${gtk_msg}
- With OpenSSL 3.0: ${openssl_msg}
+ With GnuTLS: ${gnutls_msg}
"
diff --git a/pan/data-impl/Makefile.am b/pan/data-impl/Makefile.am
index e080653..dea396c 100644
--- a/pan/data-impl/Makefile.am
+++ b/pan/data-impl/Makefile.am
@@ -1,4 +1,4 @@
-AM_CPPFLAGS = -I top_srcdir@ @GMIME_CFLAGS@ @GLIB_CFLAGS@ @OPENSSL_CFLAGS@ @LIBGNOME_KEYRING_1_CFLAGS@
+AM_CPPFLAGS = -I top_srcdir@ @GMIME_CFLAGS@ @GLIB_CFLAGS@ @GNUTLS_CFLAGS@ @LIBGNOME_KEYRING_1_CFLAGS@
AM_LDFLAGS = @LIBGNOME_KEYRING_1_LIBS@
diff --git a/pan/data-impl/data-impl.h b/pan/data-impl/data-impl.h
index 2929477..10f271c 100644
--- a/pan/data-impl/data-impl.h
+++ b/pan/data-impl/data-impl.h
@@ -45,14 +45,9 @@
#include <pan/data-impl/profiles.h>
#include <pan/data-impl/memchunk.h>
-#ifdef HAVE_OPENSSL
+#ifdef HAVE_GNUTLS
#include <pan/data/cert-store.h>
- #include <openssl/crypto.h>
- #include <openssl/x509.h>
- #include <openssl/x509v3.h>
- #include <openssl/pem.h>
- #include <openssl/ssl.h>
- #include <openssl/err.h>
+ #include <gnutls/gnutls.h>
#endif
namespace pan
@@ -134,10 +129,11 @@ namespace pan
servers_t _servers;
- Server* find_server (const Quark& server);
+// Server* find_server (const Quark& server);
public:
virtual const Server* find_server (const Quark& server) const;
+ virtual Server* find_server (const Quark& server);
virtual bool find_server_by_hn (const Quark& server, Quark& setme) const;
public: // mutators
@@ -151,6 +147,9 @@ namespace pan
const StringView & username,
const StringView & password);
+ virtual void set_server_trust (const Quark & servername,
+ int setme);
+
virtual void set_server_addr (const Quark & server,
const StringView & host,
const int port);
@@ -182,6 +181,8 @@ namespace pan
std::string & setme_username,
std::string & setme_password) const;
+ virtual bool get_server_trust (const Quark & servername, int&) const;
+
virtual bool get_server_addr (const Quark & server,
std::string & setme_host,
int & setme_port) const;
diff --git a/pan/data-impl/server.cc b/pan/data-impl/server.cc
index 898f606..1082202 100644
--- a/pan/data-impl/server.cc
+++ b/pan/data-impl/server.cc
@@ -140,6 +140,15 @@ DataImpl :: set_server_auth (const Quark & server,
}
void
+DataImpl :: set_server_trust (const Quark & server,
+ const int setme)
+{
+ Server * s (find_server (server));
+ assert (s);
+ s->trust = setme;
+}
+
+void
DataImpl :: set_server_addr (const Quark & server,
const StringView & host,
int port)
@@ -186,10 +195,10 @@ void
DataImpl :: set_server_cert (const Quark & server,
const StringView & cert)
{
+
Server * s (find_server (server));
assert (s);
s->cert = cert;
- debug(s->cert<<" "<<cert);
}
@@ -238,11 +247,24 @@ DataImpl :: get_server_auth (const Quark & server,
}
#endif
}
+
return found;
}
bool
+DataImpl :: get_server_trust (const Quark & server, int& setme) const
+{
+ const Server * s (find_server (server));
+ const bool found (s);
+ if (found) {
+ setme = s->trust;
+ }
+
+ return found;
+}
+
+bool
DataImpl :: get_server_addr (const Quark & server,
std::string & setme_host,
int & setme_port) const
@@ -253,6 +275,7 @@ DataImpl :: get_server_addr (const Quark & server,
setme_host = s->host;
setme_port = s->port;
}
+
return found;
}
@@ -267,6 +290,7 @@ DataImpl :: get_server_address (const Quark& server) const
x << ":" << s->port;
str = x.str();
}
+
return str;
}
@@ -278,6 +302,7 @@ DataImpl :: get_server_ssl_support (const Quark & server) const
const Server * s (find_server (server));
if (s)
retval = (s->ssl_support != 0);
+
return retval;
}
@@ -289,6 +314,7 @@ DataImpl :: get_server_cert (const Quark & server) const
const Server * s (find_server (server));
if (s)
str = s->cert;
+
return str;
}
@@ -300,6 +326,7 @@ DataImpl :: get_server_limits (const Quark & server) const
const Server * s (find_server (server));
if (s)
retval = s->max_connections;
+
return retval;
}
@@ -311,6 +338,7 @@ DataImpl :: get_server_rank (const Quark & server) const
const Server * s (find_server (server));
if (s)
retval = s->rank;
+
return retval;
}
@@ -322,6 +350,7 @@ DataImpl :: get_server_article_expiration_age (const Quark & server) const
const Server * s (find_server (server));
if (s)
retval = s->article_expiration_age;
+
return retval;
}
@@ -426,6 +455,8 @@ DataImpl :: load_server_properties (const DataIO& source)
int ssl(to_int(kv["use-ssl"], 0));
s.ssl_support = ssl;
s.cert = kv["cert"];
+ int trust(to_int(kv["trust"], 0));
+ s.trust = trust;
s.newsrc_filename = kv["newsrc"];
if (s.newsrc_filename.empty()) { // set a default filename
std::ostringstream o;
@@ -481,6 +512,7 @@ DataImpl :: save_server_properties (DataIO& data_io) const
<< indent(depth) << "<newsrc>" << s->newsrc_filename << "</newsrc>\n"
<< indent(depth) << "<rank>" << s->rank << "</rank>\n"
<< indent(depth) << "<use-ssl>" << s->ssl_support << "</use-ssl>\n"
+ << indent(depth) << "<trust>" << s->trust << "</trust>\n"
<< indent(depth) << "<cert>" << s->cert << "</cert>\n";
*out << indent(--depth) << "</server>\n";
diff --git a/pan/data/article-cache.cc b/pan/data/article-cache.cc
index 2d82a31..035407b 100644
--- a/pan/data/article-cache.cc
+++ b/pan/data/article-cache.cc
@@ -438,6 +438,8 @@ ArticleCache :: get_filenames (const mid_sequence_t& mids)
char filename[PATH_MAX];
foreach_const (mid_sequence_t, mids, it)
if (get_filename (filename, sizeof(filename), *it))
+ {
ret.push_back (filename);
+ }
return ret;
}
diff --git a/pan/data/article.cc b/pan/data/article.cc
index 218957b..fa07591 100644
--- a/pan/data/article.cc
+++ b/pan/data/article.cc
@@ -97,10 +97,19 @@ Article :: get_part_mids () const
{
mid_sequence_t mids;
for (part_iterator it(pbegin()), end(pend()); it!=end; ++it)
+ {
mids.push_back (it.mid());
+ }
return mids;
}
+//const Quark&
+//Article :: get_attachment () const
+//{
+// for (part_iterator it(pbegin()), end(pend()); it!=end; ++it)
+// if (it.mid() == search)
+//}
+
void
Article :: clear ()
{
diff --git a/pan/data/cert-store.cc b/pan/data/cert-store.cc
index a5817fa..1d9da03 100644
--- a/pan/data/cert-store.cc
+++ b/pan/data/cert-store.cc
@@ -50,83 +50,207 @@ extern "C" {
using namespace pan;
-#ifdef HAVE_OPENSSL
+#ifdef HAVE_GNUTLS
+
namespace pan
{
int
- verify_callback(int ok, X509_STORE_CTX *store)
+ verify_callback(gnutls_session_t session)
{
- SSL * ssl = (SSL*)X509_STORE_CTX_get_ex_data(store, SSL_get_ex_data_X509_STORE_CTX_idx());
- mydata_t* mydata = (mydata_t*)SSL_get_ex_data(ssl, SSL_get_fd(ssl));
+ mydata_t* mydata = (mydata_t*)gnutls_session_get_ptr (session);
+
+ unsigned int status;
+ const gnutls_datum_t *cert_list;
+ unsigned int cert_list_size;
+ int ret;
+ gnutls_x509_crt_t cert;
+ bool fail(false);
+
+
+
+ ret = gnutls_certificate_verify_peers2 (session, &status);
+
+ if (ret < 0)
+ return GNUTLS_E_CERTIFICATE_ERROR;
+
+ if (status & GNUTLS_CERT_INVALID)
+ {
+ g_warning ("The certificate is not trusted.\n");
+ fail = !mydata->always_trust;
+ }
+
+ if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
+ {
+ fail = !mydata->always_trust;
+ g_warning ("The certificate hasn't got a known issuer.\n");
+ }
+
+ if (status & GNUTLS_CERT_REVOKED)
+ {
+ g_warning ("The certificate has been revoked.\n");
+ fail = true;
+ }
- if (!ok)
+ if (status & GNUTLS_CERT_EXPIRED)
{
- int err = X509_STORE_CTX_get_error(store);
-
- X509 *cert = X509_STORE_CTX_get_current_cert(store);
- CRYPTO_add (&(cert->references), 1, CRYPTO_LOCK_X509); // refcount +1
- if (err == X509_V_ERR_CERT_HAS_EXPIRED)
- if (!mydata->cs->is_ignored(cert))
- mydata->cs->ignore(cert);
- else return 1;
-
- /* accept user-override on self-signed certificates */
- if (err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ||
- err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
- err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY )
- mydata->cs->verify_failed(cert, mydata->server, mydata->cert_name, err);
- else
- g_warning("[[DEBUG:]] unknown error condition, please report me: %s", ssl_err_to_string(err).c_str());
+ g_warning ("The certificate has expired\n");
+ fail = true;
}
- return ok;
+ if (status & GNUTLS_CERT_NOT_ACTIVATED)
+ {
+ g_warning ("The certificate is not yet activated\n");
+ fail = true;
+ }
+
+ /* Up to here the process is the same for X.509 certificates and
+ * OpenPGP keys. From now on X.509 certificates are assumed. This can
+ * be easily extended to work with openpgp keys as well.
+ */
+ if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509)
+ {
+ g_warning ("The certificate is not a X509 certificate!\n");
+ goto _fail;
+ }
+
+ if (gnutls_x509_crt_init (&cert) < 0)
+ {
+ g_error ("Error in initialization\n");
+ goto _fail;
+ }
+
+ cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
+ if (cert_list == NULL)
+ {
+ g_error ("No certificate found!\n");
+ goto _fail;
+ }
+
+ /* TODO verify whole chain perhaps?
+ */
+ if (gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0)
+ {
+ g_error ("Error parsing certificate!\n");
+ goto _fail;
+ }
+
+ if (!gnutls_x509_crt_check_hostname (cert, mydata->hostname_full.c_str()))
+ {
+ g_error ("The certificate's owner does not match hostname '%s' !\n", mydata->hostname_full.c_str());
+ goto _fail;
+ }
+
+ if (fail) goto _fail;
+
+ /* auto-add new cert if we always trust this server */
+ if (mydata->always_trust)
+ mydata->cs->add(cert, mydata->host);
+ else
+ gnutls_x509_crt_deinit(cert);
+
+ /* notify gnutls to continue handshake normally */
+ return 0;
+
+ _fail:
+
+ if (cert)
+ mydata->cs->verify_failed (cert, mydata->host.c_str(), status);
+
+ return GNUTLS_E_CERTIFICATE_ERROR;
+
}
int
- CertStore :: get_all_certs_from_disk(std::set<X509*>& setme)
+ CertStore :: get_all_certs_from_disk()
{
int cnt(0);
quarks_t servers(_data.get_servers());
+ int ret(0);
+ size_t filelen;
+ char * buf;
+
foreach_const(quarks_t, servers, it)
{
- const Data::Server* s(_data.find_server(*it));
+ Data::Server* s(_data.find_server(*it));
if (!s) continue;
const char* filename(s->cert.c_str());
if (!filename) continue;
- FILE *fp = fopen(filename,"r");
+
+ FILE * fp = fopen(filename, "rb");
if (!fp) continue;
- X509 *x = X509_new();
- if (!x) { fclose(fp); continue; }
- PEM_read_X509(fp,&x, 0, 0);
- fclose(fp);
- setme.insert(x);
+
+ fseek (fp, 0, SEEK_END);
+ filelen = ftell (fp);
+ fseek (fp, 0, SEEK_SET);
+ buf = new char[filelen];
+ fread (buf, sizeof(char), filelen, fp);
+
+ gnutls_datum_t in;
+ in.data = (unsigned char*)buf;
+ in.size = filelen;
+ gnutls_x509_crt_t cert;
+ gnutls_x509_crt_init(&cert);
+ gnutls_x509_crt_import(cert, &in, GNUTLS_X509_FMT_PEM);
+
+ delete buf;
+
+ ret = gnutls_certificate_set_x509_trust(_creds, &cert, 1);
+ if (ret > 0) cnt += ret; else goto fail;
+
_certs.insert(*it);
- _cert_to_server[*it] = x;
- ++cnt;
+ _cert_to_server[*it] = cert;
+
+ continue;
+
+ fail:
+ s->cert.clear();
+ gnutls_x509_crt_deinit (cert);
+ _data.save_server_info(*it);
}
+ // get certs from ssl certs directory
+#ifdef SSL_DIR
+ GError* err(NULL);
+ const char * ssldir = SSL_DIR;
+ GDir * dir = g_dir_open (ssldir, 0, &err);
+ if (err != NULL)
+ {
+ Log::add_err_va (_("Error opening SSL certificate directory: \"%s\": %s"), _path.c_str(), err->message);
+ g_error_free (err);
+ }
+ else
+ {
+ char filename[PATH_MAX];
+ const char * fname;
+ struct stat stat_p;
+ while ((fname = g_dir_read_name (dir)))
+ {
+ struct stat stat_p;
+ g_snprintf (filename, sizeof(filename), "%s%c%s", ssldir, G_DIR_SEPARATOR, fname);
+ if (!stat (filename, &stat_p))
+ {
+ if (!S_ISREG(stat_p.st_mode)) continue;
+ ret = gnutls_certificate_set_x509_trust_file(_creds, filename, GNUTLS_X509_FMT_PEM);
+ if (ret > 0) cnt += ret;
+ }
+ }
+ g_dir_close (dir);
+ }
+#endif
return cnt;
}
void
- CertStore :: init_me()
+ CertStore :: init()
{
- assert (_ctx);
-
- _store = SSL_CTX_get_cert_store(_ctx);
-
- std::set<X509*> certs;
int r(0);
- get_all_certs_from_disk (certs);
- foreach_const (std::set<X509*>, certs, it)
- if (X509_STORE_add_cert(_store, *it) != 0) ++r;
+ r = get_all_certs_from_disk ();
if (r != 0) Log::add_info_va(_("Succesfully added %d SSL PEM certificate(s) to Certificate Store."), r);
- SSL_CTX_set_verify(_ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback);
}
@@ -141,17 +265,8 @@ namespace pan
void
CertStore :: remove (const Quark& server)
{
- debug("remove cert "<<server);
- if (_cert_to_server.count(server))
- {
- _cert_to_server.erase(server);
- _certs.erase(server);
- remove_hard(server);
- Quark setme;
- _data.set_server_cert(server, "");
- _data.save_server_info(server);
- }
-
+ _cert_to_server.erase(server);
+ remove_hard (server);
}
CertStore :: CertStore (Data& data): _data(data)
@@ -161,70 +276,69 @@ namespace pan
_path = buf;
if (!file::ensure_dir_exists (buf))
{
- std::cerr<<"Error initializing certstore. Check your permissions for the directory \"ssl-certs\" and main subfolder in your home directory! Fatal, exiting.";
+ std::cerr<<"Error initializing certstore. Check your permissions for the pan2 subfolder \"ssl-certs\" and "
+ "the pan2 folder in your Home directory! Fatal, exiting.";
file::print_file_info(std::cerr, buf);
exit(EXIT_FAILURE);
}
+
+ gnutls_certificate_allocate_credentials (&_creds);
+ gnutls_certificate_set_verify_function(_creds, verify_callback);
+
}
CertStore :: ~CertStore ()
- {}
+ {
+ gnutls_certificate_free_credentials (_creds);
+ foreach (certs_m, _cert_to_server, it)
+ gnutls_x509_crt_deinit(it->second);
+ }
bool
- CertStore :: add(X509* cert, const Quark& server)
+ CertStore :: add (gnutls_x509_crt_t cert, const Quark& server)
{
- debug(server<<" "<<cert);
+ debug("adding server cert "<<server<<" "<<cert);
if (!cert || server.empty()) return false;
- debug(X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0));
- X509_STORE_add_cert(get_store(),cert);
std::string addr; int port;
_data.get_server_addr(server, addr, port);
_certs.insert(server);
_cert_to_server[server] = cert;
- debug(server<<" "<<addr);
+ const char* buf(build_cert_name(addr).c_str());
- const char* buf(build_cert_name(addr.c_str()).c_str());
_data.set_server_cert(server, buf);
+
_data.save_server_info(server);
FILE * fp = fopen(buf, "wb");
if (!fp) return false;
- if (!PEM_write_X509(fp, cert)) { fclose(fp); return false; }
+ size_t outsize;
+
+ /* make up for dumbness of this function */
+ gnutls_x509_crt_export (cert, GNUTLS_X509_FMT_PEM, NULL, &outsize);
+ char* out = new char[outsize];
+ gnutls_x509_crt_export (cert, GNUTLS_X509_FMT_PEM, out, &outsize);
+
+ fputs ((const char*)out, fp);
+
fclose(fp);
- chmod (buf, 0600);
- debug(server<<" "<<buf);
+ delete out;
+
+ chmod (buf, 0600);
+ gnutls_certificate_set_x509_trust(_creds, &cert, 1); // for now, only 1 is saved
valid_cert_added(cert, server.c_str());
+
return true;
}
- X509*
- CertStore :: get_cert_to_server(const Quark& server) const
- {
- X509* ret(0);
- Quark serv;
-
- /* strip port from server if existing */
- std::string s(server);
- std::string::size_type idx = s.rfind(":");
- if(idx != std::string::npos)
- serv = s.substr(0,idx);
- else
- serv = server;
-
- if (_cert_to_server.count(serv))
- ret = _cert_to_server.find(serv)->second;
- return ret;
- }
-
std::string
- CertStore :: build_cert_name(std::string host)
+ CertStore :: build_cert_name(std::string& host)
{
char buf[2048];
g_snprintf(buf,sizeof(buf),"%s%cssl_certs%c%s.pem",file::get_pan_home().c_str(),
diff --git a/pan/data/cert-store.h b/pan/data/cert-store.h
index b60d351..9554ecc 100644
--- a/pan/data/cert-store.h
+++ b/pan/data/cert-store.h
@@ -23,13 +23,9 @@
#ifndef __CertStore_h__
#define __CertStore_h__
-#ifdef HAVE_OPENSSL
- #include <openssl/pem.h>
- #include <openssl/err.h>
- #include <openssl/pkcs12.h>
- #include <openssl/bio.h>
- #include <openssl/rand.h>
- #include <openssl/x509.h>
+#ifdef HAVE_GNUTLS
+ #include <gnutls/gnutls.h>
+ #include <gnutls/x509.h>
#endif
#include <pan/data/data.h>
@@ -49,70 +45,50 @@ namespace pan
class CertStore
{
-#ifdef HAVE_OPENSSL
+#ifdef HAVE_GNUTLS
public:
CertStore (Data& data) ;
virtual ~CertStore () ;
private:
- SSL_CTX* _ctx;
typedef std::set<Quark> certs_t;
- typedef std::set<X509*> certs_s;
certs_t _certs;
- certs_s _ignores;
- typedef std::map<Quark,X509*> certs_m;
- typedef std::pair<Quark,X509*> certs_p;
- certs_m _cert_to_server;
- X509_STORE* _store;
- std::string _path;
- std::vector<SSL_SESSION*> _sessions;
certs_t _blacklist;
+ typedef std::map<Quark,gnutls_x509_crt_t> certs_m;
+ typedef std::pair<Quark,gnutls_x509_crt_t> certs_p;
+ std::string _path;
+ certs_m _cert_to_server;
Data& _data;
+ gnutls_certificate_credentials_t _creds;
+
public:
- SSL_CTX* get_ctx() { return _ctx; }
- X509_STORE* get_store() const { return _store; }
- int get_all_certs_from_disk(std::set<X509*>& setme);
- X509* get_cert_to_server(const Quark& server) const;
- SSL_SESSION* get_session()
- {
- SSL_SESSION* ret(0);
- if (!_sessions.empty())
- {
- ret = _sessions.back();
- _sessions.pop_back();
- }
- return ret;
- }
- void add_session (SSL_SESSION* s)
- {
- if (!s) return;
- _sessions.push_back(s);
- }
+
+ int get_all_certs_from_disk();
bool in_blacklist (const Quark& s)
{
return _blacklist.count(s);
}
+
void blacklist (const Quark& s)
{
_blacklist.insert(s);
}
+
void whitelist (const Quark& s)
{
_blacklist.erase(s);
}
- void ignore (X509* cert)
+ gnutls_x509_crt_t get_cert_to_server (const Quark& s)
{
- _ignores.insert(cert);
- }
-
- bool is_ignored(X509* c)
- {
- foreach (certs_s, _ignores, it)
- if (X509_cmp(c, *it)==0) return true;
- return false;
+ if (_cert_to_server.count(s) > 0)
+ return _cert_to_server[s];
+ std::cerr<<"server "<<s<<" cert to server "<<_cert_to_server.count(s)<<"\n";
+ foreach (certs_m, _cert_to_server, it)
+ std::cerr<<it->first<<" "<<it->second<<"\n";
+ return 0;
}
private:
@@ -120,18 +96,20 @@ namespace pan
public:
- bool add(X509*, const Quark&) ;
+ bool add (gnutls_x509_crt_t, const Quark&) ;
void remove (const Quark&);
bool exist (const Quark& q) { return (_certs.count(q) > 0); }
- static std::string build_cert_name(std::string host);
+ static std::string build_cert_name(std::string& host);
+
+ gnutls_certificate_credentials_t get_creds() { return _creds; }
struct Listener
{
virtual ~Listener() {}
/* functions that other listeners listen on */
- virtual void on_verify_cert_failed (X509* cert UNUSED, std::string server UNUSED, std::string cert_name UNUSED, int nr UNUSED) = 0;
- virtual void on_valid_cert_added (X509* cert UNUSED, std::string server UNUSED) = 0;
+ virtual void on_verify_cert_failed (gnutls_x509_crt_t cert UNUSED, std::string server UNUSED, int nr UNUSED) = 0;
+ virtual void on_valid_cert_added (gnutls_x509_crt_t cert UNUSED, std::string server UNUSED) = 0;
};
typedef std::set<Listener*> listeners_t;
@@ -141,36 +119,29 @@ namespace pan
void remove_listener (Listener * l) { _listeners.erase(l); }
/* notify functions for listener list */
- void verify_failed (X509* c, std::string server, std::string cn, int nr)
+ void verify_failed (gnutls_x509_crt_t c, std::string server, int nr)
{
- debug("verify failed listeners");
for (listeners_t::iterator it(_listeners.begin()), end(_listeners.end()); it!=end; ++it)
- (*it)->on_verify_cert_failed (c, server, cn, nr);
+ (*it)->on_verify_cert_failed (c, server, nr);
}
- void valid_cert_added (X509* c, std::string server)
+ void valid_cert_added (gnutls_x509_crt_t c, std::string server)
{
for (listeners_t::iterator it(_listeners.begin()), end(_listeners.end()); it!=end; ++it)
(*it)->on_valid_cert_added (c, server);
}
- private:
- void init_me();
-
- protected:
- friend class SocketCreator;
- void set_ctx(SSL_CTX* c) { _ctx = c; init_me(); }
+ public:
+ void init();
};
struct mydata_t {
- SSL_CTX* ctx;
- int depth;
- int ignore_all;
+ gnutls_session_t session;
+ Quark host;
+ Quark hostname_full;
CertStore* cs;
- std::string server;
- std::string cert_name;
- CertStore::Listener* l;
-
+ int always_trust;
+ };
#else
public:
@@ -185,10 +156,8 @@ namespace pan
{
virtual ~Listener() {}
};
-
-#endif // HAVE_OPENSSL
};
-
+#endif // HAVE_GNUTLS
}
diff --git a/pan/data/data.h b/pan/data/data.h
index 02d9667..3ba0db5 100644
--- a/pan/data/data.h
+++ b/pan/data/data.h
@@ -194,10 +194,11 @@ namespace pan
int max_connections;
int rank;
int ssl_support;
+ int trust;
typedef sorted_vector<Quark,true,AlphabeticalQuarkOrdering> groups_t;
groups_t groups;
- Server(): port(STD_NNTP_PORT), article_expiration_age(31), max_connections(2), rank(1), ssl_support(0) {}
+ Server(): port(STD_NNTP_PORT), article_expiration_age(31), max_connections(2), rank(1), ssl_support(0), trust(0) {}
};
protected:
@@ -230,6 +231,8 @@ namespace pan
virtual const Server* find_server (const Quark& server) const = 0;
+ virtual Server* find_server (const Quark& server) = 0;
+
virtual quarks_t get_servers () const = 0;
virtual void delete_server (const Quark& server) = 0;
@@ -240,6 +243,9 @@ namespace pan
const StringView & username,
const StringView & password) = 0;
+ virtual void set_server_trust (const Quark & servername,
+ const int setme) = 0;
+
virtual void set_server_addr (const Quark & server,
const StringView & address,
const int port) = 0;
@@ -255,6 +261,8 @@ namespace pan
std::string & setme_username,
std::string & setme_password) const = 0;
+ virtual bool get_server_trust (const Quark & servername, int&) const = 0;
+
virtual std::string get_server_cert (const Quark & server) const = 0;
virtual int get_server_limits (const Quark & server) const = 0;
diff --git a/pan/data/server-info.h b/pan/data/server-info.h
index 81796e8..6ac87e5 100644
--- a/pan/data/server-info.h
+++ b/pan/data/server-info.h
@@ -48,6 +48,9 @@ namespace pan
const StringView & username,
const StringView & password) = 0;
+ virtual void set_server_trust (const Quark & servername,
+ const int setme) = 0;
+
virtual void set_server_addr (const Quark & servername,
const StringView & address,
const int port) = 0;
@@ -74,6 +77,8 @@ namespace pan
std::string & setme_username,
std::string & setme_password) const=0;
+ virtual bool get_server_trust (const Quark & servername, int&) const = 0;
+
virtual bool get_server_addr (const Quark & servername,
std::string & setme_address,
int & setme_port) const = 0;
diff --git a/pan/gui/Makefile.am b/pan/gui/Makefile.am
index 53ae102..0314f05 100644
--- a/pan/gui/Makefile.am
+++ b/pan/gui/Makefile.am
@@ -1,5 +1,5 @@
AM_CPPFLAGS = -I top_srcdir@ @GTKSPELL_CFLAGS@ @GTK_CFLAGS@ @GMIME_CFLAGS@ @GLIB_CFLAGS@ \
- @OPENSSL_CFLAGS@ @LIBNOTIFY_CFLAGS@ @LIBGNOME_KEYRING_1_CFLAGS@ -DPANLOCALEDIR=\""$(panlocaledir)"\"
+ @GNUTLS_CFLAGS@ @LIBNOTIFY_CFLAGS@ @LIBGNOME_KEYRING_1_CFLAGS@ -DPANLOCALEDIR=\""$(panlocaledir)"\"
noinst_LIBRARIES = libpangui.a
@@ -29,6 +29,7 @@ libpangui_a_SOURCES = \
profiles-dialog.cc \
render-bytes.cc \
save-ui.cc \
+ save-attach-ui.cc \
score-add-ui.cc \
score-view-ui.cc \
server-ui.cc \
@@ -70,6 +71,7 @@ noinst_HEADERS = \
progress-view.h \
render-bytes.h \
save-ui.h \
+ save-attach-ui.h \
score-add-ui.h \
score-view-ui.h \
server-ui.h \
@@ -97,7 +99,7 @@ endif
pan_SOURCES = gui.cc pan.cc $(WINRC)
pan_LDADD = ./libpangui.a $(WINRCOBJ) ../data-impl/libpandata.a ../tasks/libtasks.a ../data/libdata.a ../usenet-utils/libusenetutils.a ../general/libgeneralutils.a \
- ../../uulib/libuu.a @GTKSPELL_LIBS@ @GTK_LIBS@ @GMIME_LIBS@ @GLIB_LIBS@ @OPENSSL_LIBS@ @LIBNOTIFY_LIBS@ @LIBGNOME_KEYRING_1_LIBS@
+ ../../uulib/libuu.a @GTKSPELL_LIBS@ @GTK_LIBS@ @GMIME_LIBS@ @GLIB_LIBS@ @GNUTLS_LIBS@ @LIBNOTIFY_LIBS@ @LIBGNOME_KEYRING_1_LIBS@
if HAVE_WIN32
pan_LDFLAGS = -mwindows
endif
diff --git a/pan/gui/body-pane.cc b/pan/gui/body-pane.cc
index ea8697f..94b144e 100644
--- a/pan/gui/body-pane.cc
+++ b/pan/gui/body-pane.cc
@@ -45,6 +45,7 @@ extern "C" {
#include "xface.h"
#include "url.h"
#include "gtk_compat.h"
+#include "save-attach-ui.h"
#define FIRST_PICTURE "first-picture"
@@ -57,6 +58,11 @@ using namespace pan;
namespace
{
+ GtkWindow* get_window (GtkWidget* w)
+ {
+ return GTK_WINDOW (gtk_widget_get_toplevel (w));
+ }
+
enum Icons
{
ICON_SIG_OK,
@@ -366,6 +372,7 @@ namespace
const GtkAllocation * size,
GtkTextTag * apply_tag)
{
+
const int begin_offset (gtk_text_iter_get_offset (iter));
GdkPixbuf * original (0);
@@ -528,8 +535,6 @@ namespace
g_return_val_if_fail (GTK_IS_TEXT_VIEW(w), false);
-// if (event->keyval==GDK_KEY_Enter) return false;
-
const bool up = event->keyval==GDK_KEY_Up || event->keyval==GDK_KEY_KP_Up;
const bool down = event->keyval==GDK_KEY_Down || event->keyval==GDK_KEY_KP_Down;
@@ -713,6 +718,7 @@ namespace
bool do_markup,
bool do_urls)
{
+
g_return_if_fail (buffer!=0);
g_return_if_fail (GTK_IS_TEXT_BUFFER(buffer));
@@ -999,16 +1005,14 @@ BodyPane :: append_part (GMimeObject * parent, GMimeObject * obj, GtkAllocation
is_done = true;
}
- // otherwise, bitch and moan.
+ // otherwise, add to list of attachments
if (!is_done) {
const char * filename = g_mime_part_get_filename (part);
char * pch = (filename && *filename)
- ? g_strdup_printf (_("\nAttachment not shown: MIME type %s/%s; filename %s\n"), type->type, type->subtype, filename)
- : g_strdup_printf (_("\nAttachment not shown: MIME type %s/%s\n"), type->type, type->subtype);
- GtkTextIter iter;
- gtk_text_buffer_get_end_iter (_buffer, &iter);
- gtk_text_buffer_insert (_buffer, &iter, pch, -1);
- g_free (pch);
+ ? g_strdup_printf ("%s", filename)
+ : g_strdup_printf (_("Unnamed File"));
+ add_attachment_to_toolbar (pch);
+ _freeme.insert(pch);
}
}
@@ -1184,11 +1188,12 @@ BodyPane :: set_text_from_message (GMimeMessage * message)
g_free (headers);
}
+ clear_attachments();
+
// FIXME: need to set a mark here so that when user hits follow-up,
// the all-headers don't get included in the followup
// set the text buffer...
-
if (message)
g_mime_message_foreach (message, foreach_part_cb, this);
@@ -1319,9 +1324,10 @@ BodyPane :: clear ()
if (_message)
g_object_unref (_message);
_message = 0;
+
refresh ();
- update_sig_valid(-1);
+ update_sig_valid(-1);
}
void
@@ -1415,6 +1421,7 @@ BodyPane :: text_size_allocated_idle_cb (gpointer pane)
void
BodyPane :: text_size_allocated_idle ()
{
+
// prevent oscillation
const bool old_h (_hscroll_visible);
const bool old_v (_vscroll_visible);
@@ -1437,6 +1444,7 @@ BodyPane :: text_size_allocated_idle ()
if (gtk_text_iter_begins_tag (&iter, tag))
{
gtk_widget_get_allocation(_text, &aloc);
+ // BUG : resize
resize_picture_at_iter (buf, &iter, fullsize, &aloc, tag);
}
if (!gtk_text_iter_forward_char (&iter))
@@ -1496,25 +1504,178 @@ BodyPane :: populate_popup (GtkTextView *v G_GNUC_UNUSED, GtkMenu *m)
gtk_menu_shell_prepend (GTK_MENU_SHELL(m), mi);
}
+namespace
+{
+ static gboolean
+ attachment_clicked_cb (GtkWidget *w, GdkEventButton *event, gpointer p)
+ {
+ BodyPane * bp = static_cast<BodyPane*>(p);
+ const gchar * fn = (char*)g_object_get_data (G_OBJECT(w), "filename");
+ if (!fn) return TRUE;
+
+ bp->_current_attachment = fn;
+
+ if (event->type == GDK_BUTTON_PRESS && event->button == 3)
+ {
+ gtk_menu_popup
+ (GTK_MENU(bp->_menu), NULL, NULL, NULL, NULL,
+ (event ? event->button : 0),
+ (event ? event->time : 0));
+ }
+
+ return TRUE;
+ }
+}
+
+void
+BodyPane :: menu_clicked (const MenuSelection& ms)
+{
+ std::vector<Article> copies;
+ copies.push_back(_article);
+ GroupPrefs _group_prefs;
+ SaveAttachmentsDialog * dialog = new SaveAttachmentsDialog (
+ _prefs, _group_prefs, _data, _data, _cache,
+ _data, _queue, get_window(_root),
+ _header_pane->get_group(), copies,
+ ms == MENU_SAVE_ALL ? TaskArticle::SAVE_ALL : TaskArticle::SAVE_AS,
+ _current_attachment);
+ gtk_widget_show (dialog->root());
+}
+
+void
+BodyPane :: menu_clicked_as_cb (GtkWidget* w, gpointer ptr)
+{
+ BodyPane* p = static_cast<BodyPane*>(ptr);
+ if (!p) return;
+ p->menu_clicked(MENU_SAVE_AS);
+}
+
+void
+BodyPane :: menu_clicked_all_cb (GtkWidget* w, gpointer ptr)
+{
+ BodyPane* p = static_cast<BodyPane*>(ptr);
+ if (!p) return;
+ p->menu_clicked(MENU_SAVE_ALL);
+}
+
+
+GtkWidget*
+BodyPane :: new_attachment (const char* filename)
+{
+ if (!filename) return NULL;
+
+ GtkWidget* w = gtk_hbox_new(false, 0);
+ GtkWidget* attachment = gtk_label_new(filename);
+ GtkWidget * image = gtk_image_new_from_stock(GTK_STOCK_FILE, GTK_ICON_SIZE_MENU);
+
+ gtk_label_set_selectable (GTK_LABEL(attachment), true);
+ gtk_label_set_ellipsize (GTK_LABEL(attachment), PANGO_ELLIPSIZE_MIDDLE);
+
+ GtkWidget *event_box = gtk_event_box_new ();
+ gtk_container_add (GTK_CONTAINER (event_box), image);
+ g_object_set_data (G_OBJECT(event_box), "filename", (gpointer)filename);
+
+ gtk_box_pack_start (GTK_BOX(w), event_box, false, false, 0);
+ gtk_box_pack_start (GTK_BOX(w), attachment, false, false, 0);
+
+ g_signal_connect(event_box, "button_press_event", G_CALLBACK(attachment_clicked_cb), this);
+
+ return w;
+}
+
+
+void
+BodyPane :: clear_attachments()
+{
+ _cur_col = 0;
+ _cur_row = 0;
+ _attachments = 0;
+ _current_attachment = 0;
+
+ {
+ gtk_container_remove (GTK_CONTAINER (_att_frame), _att_toolbar);
+ if (G_IS_OBJECT(_att_toolbar)) g_object_unref(_att_toolbar);
+ (void)create_attachments_toolbar(_att_frame);
+ }
+
+}
+
+void
+BodyPane :: add_attachment_to_toolbar (const char* fn)
+{
+ if (!fn) return;
+
+ GtkWidget* w = new_attachment(fn);
+ guint cols(0), rows(0);
+ gtk_table_get_size (GTK_TABLE(_att_toolbar), &rows, &cols);
+
+ if (_attachments % 4 == 0 && _attachments != 0)
+ {
+ gtk_table_resize (GTK_TABLE(_att_toolbar), rows+1, cols);
+ ++_cur_row;
+ _cur_col = 0;
+ }
+
+ gtk_table_attach_defaults (GTK_TABLE(_att_toolbar), w, _cur_col, _cur_col+1, _cur_row,_cur_row+1);
+
+ ++_attachments;
+ ++_cur_col;
+
+ gtk_widget_show_all(_att_toolbar);
+}
+
+GtkWidget*
+BodyPane :: create_attachments_toolbar (GtkWidget* frame)
+{
+
+ _cur_col = 0;
+ _cur_row = 0;
+
+ GtkWidget * w = _att_toolbar = gtk_table_new(4,1,TRUE);
+ gtk_widget_set_size_request (w, -1, 20);
+ gtk_table_set_col_spacings (GTK_TABLE(w), PAD);
+ gtk_container_add (GTK_CONTAINER (frame), w);
+ gtk_widget_show_all (frame);
+
+ return frame;
+}
+
/***
****
***/
-BodyPane :: BodyPane (Data& data, ArticleCache& cache, Prefs& prefs):
+BodyPane :: BodyPane (Data& data, ArticleCache& cache, Prefs& prefs, GroupPrefs & gp, Queue& q, HeaderPane* hp):
_prefs (prefs),
+ _group_prefs(gp),
+ _queue(q),
+ _header_pane(hp),
_data (data),
_cache (cache),
_hscroll_visible (false),
_vscroll_visible (false),
_message (0),
- _gpgerr(GPG_DECODE)
+ _gpgerr(GPG_DECODE),
+ _attachments(0),
+ _current_attachment(0)
{
for (guint i=0; i<NUM_ICONS; ++i)
icons[i].pixbuf = gdk_pixbuf_new_from_inline (-1, icons[i].pixbuf_txt, FALSE, 0);
+ // signature pgp valid/invalid icon
_sig_icon = gtk_image_new();
+ // menu for popup menu for attachments
+ _menu = gtk_menu_new ();
+ GtkWidget* l = gtk_menu_item_new_with_label(_("Save attachment as ...."));
+ g_signal_connect (l, "activate", G_CALLBACK(menu_clicked_as_cb), this);
+ gtk_menu_shell_append (GTK_MENU_SHELL(_menu), l);
+ l = gtk_menu_item_new_with_label(_("Save all attachments"));
+ _selection = MENU_SAVE_ALL;
+ g_signal_connect (l, "activate", G_CALLBACK(menu_clicked_all_cb), this);
+ gtk_menu_shell_append (GTK_MENU_SHELL(_menu),l);
+ gtk_widget_show_all(_menu);
+
GtkWidget * vbox = gtk_vbox_new (false, PAD);
gtk_container_set_resize_mode (GTK_CONTAINER(vbox), GTK_RESIZE_QUEUE);
@@ -1575,6 +1736,11 @@ BodyPane :: BodyPane (Data& data, ArticleCache& cache, Prefs& prefs):
gtk_widget_show_all (vbox);
gtk_box_pack_start (GTK_BOX(vbox), _scroll, true, true, 0);
+ // add a toolbar for attachments
+ GtkWidget * frame = _att_frame = gtk_frame_new (_("Attachments"));
+ gtk_widget_set_size_request (frame, -1, 20);
+ gtk_box_pack_start (GTK_BOX(vbox), create_attachments_toolbar(frame), false, false, 0);
+
// set up the buffer tags
_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(_text));
set_text_buffer_tags (_buffer, _prefs);
@@ -1610,6 +1776,9 @@ BodyPane :: ~BodyPane ()
for (int i=0; i<NUM_ICONS; ++i)
g_object_unref (icons[i].pixbuf);
+
+ foreach (std::set<char*>, _freeme, it)
+ g_free(*it);
}
diff --git a/pan/gui/body-pane.h b/pan/gui/body-pane.h
index 8ced5d0..0bdda2f 100644
--- a/pan/gui/body-pane.h
+++ b/pan/gui/body-pane.h
@@ -27,7 +27,9 @@
#include <pan/data/article.h>
#include <pan/data/article-cache.h>
#include <pan/data/data.h>
+#include <pan/gui/header-pane.h>
#include "prefs.h"
+#include "group-prefs.h"
namespace pan
{
@@ -39,6 +41,9 @@ namespace pan
{
private:
Prefs& _prefs;
+ GroupPrefs& _group_prefs;
+ Queue& _queue;
+ HeaderPane* _header_pane;
Data& _data;
ArticleCache& _cache;
GtkWidget* _sig_icon;
@@ -53,7 +58,7 @@ namespace pan
gpointer data);
public:
- BodyPane (Data&, ArticleCache&, Prefs&);
+ BodyPane (Data&, ArticleCache&, Prefs&, GroupPrefs&, Queue&, HeaderPane*);
~BodyPane ();
GtkWidget* root () { return _root; }
GtkWidget* get_default_focus_widget() { return _text; }
@@ -83,6 +88,14 @@ namespace pan
return _message;
}
+
+ public:
+ enum MenuSelection
+ {
+ MENU_SAVE_AS,
+ MENU_SAVE_ALL
+ };
+
public:
void set_character_encoding (const char * character_encoding);
@@ -107,11 +120,17 @@ namespace pan
void populate_popup (GtkTextView*, GtkMenu*);
static void copy_url_cb (GtkMenuItem*, gpointer);
void copy_url ();
+
+ GtkWidget* create_attachments_toolbar(GtkWidget*);
+ void add_attachment_to_toolbar (const char* fn);
+ void clear_attachments();
+ GtkWidget* new_attachment (const char* filename);
+
static gboolean mouse_button_pressed_cb (GtkWidget*, GdkEventButton*, gpointer);
gboolean mouse_button_pressed (GtkWidget*, GdkEventButton*);
-
- /* updated with values from gmimemessage */
- public:
+ void menu_clicked (const MenuSelection& ms);
+ static void menu_clicked_as_cb (GtkWidget* w, gpointer p);
+ static void menu_clicked_all_cb (GtkWidget* w, gpointer p);
private:
std::string _hover_url;
@@ -125,13 +144,28 @@ namespace pan
GtkWidget * _root;
GtkWidget * _text;
GtkWidget * _scroll;
+ GtkWidget * _att_toolbar;
+ GtkWidget * _att_frame;
bool _hscroll_visible;
bool _vscroll_visible;
Article _article;
GMimeMessage * _message;
TextMassager _tm;
std::string _charset;
+
GPGDecErr _gpgerr;
+
+ int _attachments;
+ int _cur_col, _cur_row;
+ std::set<char*> _freeme;
+ MenuSelection _selection;
+
+ public:
+ const char* _current_attachment;
+
+
+ public:
+ GtkWidget* _menu;
};
}
diff --git a/pan/gui/e-cte-dialog.c b/pan/gui/e-cte-dialog.c
index c452d2d..efa36e6 100644
--- a/pan/gui/e-cte-dialog.c
+++ b/pan/gui/e-cte-dialog.c
@@ -20,9 +20,6 @@
#include "e-cte-dialog.h"
-#include <gmime/gmime.h>
-#include <glib/gi18n.h>
-
/**
* e_cte_dialog:
* @title: title for the dialog box
@@ -44,11 +41,11 @@ e_cte_dialog (const char *title, const char *prompt, GMimeContentEncoding now, G
GMimeContentEncoding ret = GMIME_CONTENT_ENCODING_8BIT;
dialog = GTK_DIALOG (gtk_dialog_new_with_buttons (title,
- parent,
- GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_OK, GTK_RESPONSE_OK,
- NULL));
+ parent,
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OK, GTK_RESPONSE_OK,
+ NULL));
//gtk_dialog_set_has_separator (dialog, FALSE);
gtk_dialog_set_default_response (dialog, GTK_RESPONSE_OK);
diff --git a/pan/gui/e-cte-dialog.h b/pan/gui/e-cte-dialog.h
index fa610d5..5bd5100 100644
--- a/pan/gui/e-cte-dialog.h
+++ b/pan/gui/e-cte-dialog.h
@@ -4,6 +4,7 @@
#include <config.h>
#include <gmime/gmime.h>
#include <gtk/gtk.h>
+#include <glib/gi18n.h>
G_BEGIN_DECLS
diff --git a/pan/gui/gui.cc b/pan/gui/gui.cc
index 74462e4..4c8f0d7 100644
--- a/pan/gui/gui.cc
+++ b/pan/gui/gui.cc
@@ -207,7 +207,7 @@ GUI :: GUI (Data& data, Queue& queue, Prefs& prefs, GroupPrefs& group_prefs):
_group_pane = new GroupPane (*this, data, _prefs);
_header_pane = new HeaderPane (*this, data, _queue, _cache, _prefs, _group_prefs, *this, *this);
- _body_pane = new BodyPane (data, _cache, _prefs);
+ _body_pane = new BodyPane (data, _cache, _prefs, _group_prefs, _queue, _header_pane);
std::string path = "/ui/main-window-toolbar";
GtkWidget * toolbar = gtk_ui_manager_get_widget (_ui_manager, path.c_str());
@@ -1073,7 +1073,7 @@ void GUI :: do_show_servers_dialog ()
void GUI :: do_show_sec_dialog ()
{
-#ifdef HAVE_OPENSSL
+#ifdef HAVE_GNUTLS
GtkWidget * w = sec_dialog_new (_data, _queue, get_window(_root));
g_signal_connect (w, "destroy", G_CALLBACK(sec_dialog_destroyed_cb), this);
gtk_widget_show_all (w);
@@ -1186,7 +1186,6 @@ GUI :: do_last_flag ()
void
GUI :: do_invert_selection ()
{
-// std::cerr<<__LINE__<< " "<<__FILE__<<" : implement me.\n";
_header_pane->invert_selection();
}
@@ -1372,21 +1371,22 @@ bool GUI::deletion_confirmation_dialog()
return ret;
}
-#ifdef HAVE_OPENSSL
-bool GUI :: confirm_accept_new_cert_dialog(GtkWindow * parent, X509* cert, const Quark& server)
+#ifdef HAVE_GNUTLS
+bool GUI :: confirm_accept_new_cert_dialog(GtkWindow * parent, gnutls_x509_crt_t cert, const Quark& server)
{
- bool ret(false);
- char buf[4096];
+ char buf[4096*256];
std::string host; int port;
_data.get_server_addr(server,host,port);
- pretty_print_x509(buf,sizeof(buf), host, cert,true);
+ pretty_print_x509(buf,sizeof(buf), host, cert, true);
GtkWidget * d = gtk_message_dialog_new (
parent,
GtkDialogFlags(GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT),
GTK_MESSAGE_WARNING,
GTK_BUTTONS_NONE, NULL);
+ gtk_dialog_add_button (GTK_DIALOG(d), _("Always trust"), -66);
+
HIG :: message_dialog_set_text (GTK_MESSAGE_DIALOG(d), buf,
_("Do you want to accept it permanently (deletable afterwards) ?"));
gtk_dialog_add_buttons (GTK_DIALOG(d),
@@ -1395,10 +1395,17 @@ bool GUI :: confirm_accept_new_cert_dialog(GtkWindow * parent, X509* cert, const
NULL);
gtk_dialog_set_default_response (GTK_DIALOG(d), GTK_RESPONSE_NO);
- debug("confirm cert gui");
- ret = gtk_dialog_run (GTK_DIALOG(d)) == GTK_RESPONSE_YES;
+ gint ret_code = gtk_dialog_run (GTK_DIALOG(d));
+
+ if (ret_code == -66)
+ {
+ _data.set_server_trust (server, 1);
+ _data.save_server_info(server);
+ }
+
gtk_widget_destroy(d);
- return ret;
+
+ return ret_code == GTK_RESPONSE_YES || ret_code == -66;
}
#endif
@@ -2170,7 +2177,7 @@ GUI :: on_prefs_string_changed (const StringView& key, const StringView& value)
prev_path.assign (value.str, value.len);
}
-#ifdef HAVE_OPENSSL
+#ifdef HAVE_GNUTLS
void
GUI :: do_show_cert_failed_dialog(VerifyData* data)
@@ -2194,16 +2201,14 @@ GUI :: show_cert_failed_cb(gpointer gp)
}
void
-GUI :: on_verify_cert_failed(X509* cert, std::string server, std::string cert_name, int nr)
+GUI :: on_verify_cert_failed(gnutls_x509_crt_t cert, std::string server, int nr)
{
- debug("on verify failed GUI ("<<cert<<") ("<<cert_name<<") ("<<server<<")");
+ debug("on verify failed GUI ("<<cert<<") ("<<server<<")");
if (!cert || server.empty()) return;
- debug(X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0));
VerifyData* data = new VerifyData();
data->cert = cert;
data->server = server;
- data->cert_name = cert_name;
data->nr = nr;
data->gui = this;
g_idle_add(show_cert_failed_cb, data);
@@ -2211,10 +2216,9 @@ GUI :: on_verify_cert_failed(X509* cert, std::string server, std::string cert_na
}
void
-GUI :: on_valid_cert_added (X509* cert, std::string server)
+GUI :: on_valid_cert_added (gnutls_x509_crt_t cert, std::string server)
{
/* whitelist to make avaible for nntp-pool */
- X509_free(cert); // refcount -1
_certstore.whitelist(server);
}
diff --git a/pan/gui/gui.h b/pan/gui/gui.h
index 9bb36ad..4ceb442 100644
--- a/pan/gui/gui.h
+++ b/pan/gui/gui.h
@@ -66,8 +66,8 @@ namespace pan
struct VerifyData
{
-#ifdef HAVE_OPENSSL
- X509* cert;
+#ifdef HAVE_GNUTLS
+ gnutls_x509_crt_t cert;
#endif
std::string server;
std::string cert_name;
@@ -182,9 +182,9 @@ namespace pan
virtual void do_refresh_groups ();
virtual void do_subscribe_selected_groups ();
virtual void do_unsubscribe_selected_groups ();
-#ifdef HAVE_OPENSSL
+#ifdef HAVE_GNUTLS
void do_show_cert_failed_dialog(VerifyData* data);
- bool confirm_accept_new_cert_dialog(GtkWindow*, X509*, const Quark&);
+ bool confirm_accept_new_cert_dialog(GtkWindow*, gnutls_x509_crt_t, const Quark&);
#endif
void step_bookmarks(int step);
@@ -205,10 +205,10 @@ namespace pan
virtual void on_queue_size_changed (Queue&, int active, int total);
virtual void on_queue_online_changed (Queue&, bool online);
virtual void on_queue_error (Queue&, const StringView& message);
-#ifdef HAVE_OPENSSL
+#ifdef HAVE_GNUTLS
private: // CertStore::Listener
- virtual void on_verify_cert_failed(X509*, std::string, std::string, int);
- virtual void on_valid_cert_added (X509*, std::string);
+ virtual void on_verify_cert_failed(gnutls_x509_crt_t, std::string, int);
+ virtual void on_valid_cert_added (gnutls_x509_crt_t, std::string);
#endif
private: // Log::Listener
virtual void on_log_entry_added (const Log::Entry& e);
@@ -280,9 +280,8 @@ namespace pan
static void prefs_dialog_destroyed_cb (GtkWidget * w, gpointer self);
void prefs_dialog_destroyed (GtkWidget* w);
int score_int_from_string(std::string val, const char* rules[]);
-#ifdef HAVE_OPENSSL
+#ifdef HAVE_GNUTLS
static gboolean show_cert_failed_cb(gpointer gp);
-// static void cert_failed_dty(gpointer gp);
#endif
public:
GtkUIManager* get_ui_manager() { return _ui_manager; }
diff --git a/pan/gui/pan.cc b/pan/gui/pan.cc
index f7b20c6..013d63c 100644
--- a/pan/gui/pan.cc
+++ b/pan/gui/pan.cc
@@ -47,7 +47,7 @@ extern "C" {
#include <pan/general/file-util.h>
#include <pan/general/worker-pool.h>
-#ifdef HAVE_OPENSSL
+#ifdef HAVE_GNUTLS
#include <pan/tasks/socket-impl-openssl.h>
#endif
@@ -841,7 +841,7 @@ main (int argc, char *argv[])
&error);
if (!error)
{
- std::cerr<<"Added "<<nzb_files.size()<<" files to the queue. Exiting.\n";
+ std::cout<<"Added "<<nzb_files.size()<<" files to the queue. Exiting.\n";
exit(EXIT_SUCCESS);
}
#endif
diff --git a/pan/gui/post-ui.cc b/pan/gui/post-ui.cc
index 4db69a5..cea6721 100644
--- a/pan/gui/post-ui.cc
+++ b/pan/gui/post-ui.cc
@@ -1509,9 +1509,10 @@ PostUI :: new_message_from_ui (Mode mode, bool copy_body)
? GNKSA::generate_message_id (profile.fqdn)
: GNKSA::generate_message_id_from_email_address (profile.address);
pan_g_mime_message_set_message_id (msg, message_id.c_str());
+
}
- // body & charset
+ // body & charset
{
std::string body;
if (copy_body) body = get_body();
diff --git a/pan/gui/save-attach-ui.cc b/pan/gui/save-attach-ui.cc
new file mode 100644
index 0000000..5145bb7
--- /dev/null
+++ b/pan/gui/save-attach-ui.cc
@@ -0,0 +1,320 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Pan - A Newsreader for Gtk+
+ * Copyright (C) 2002-2006 Charles Kerr <charles rebelbase com>
+ *
+ * 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; version 2 of the License.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <config.h>
+extern "C" {
+ #include <glib/gi18n.h>
+ #include <gtk/gtk.h>
+}
+#include <pan/general/debug.h>
+#include <pan/general/macros.h>
+#include <pan/icons/pan-pixbufs.h>
+#include <pan/tasks/task-article.h>
+#include <pan/tasks/queue.h>
+#include <pan/usenet-utils/text-massager.h>
+#include "hig.h"
+#include "pad.h"
+#include "pan-file-entry.h"
+#include "save-attach-ui.h"
+#include "gtk_compat.h"
+
+using namespace pan;
+
+namespace
+{
+ std::string expand_download_dir (const char * dir, const StringView& group)
+ {
+ std::string val (dir);
+ std::string::size_type pos;
+
+ while (((pos = val.find ("%g"))) != val.npos)
+ val.replace (pos, 2, group.str, group.len);
+
+ std::string tmp (group.str, group.len);
+ std::replace (tmp.begin(), tmp.end(), '.', G_DIR_SEPARATOR);
+ while (((pos = val.find ("%G"))) != val.npos)
+ val.replace (pos, 2, tmp);
+
+ return val;
+ }
+
+ std::string expand_download_dir_subject (const char * dir, const char * subjectline, const std::string &sep)
+ {
+ std::string val (dir);
+ std::string sub (subject_to_path(subjectline, false, sep));
+ std::string::size_type pos;
+
+ while (((pos = val.find ("%s"))) != val.npos)
+ val.replace (pos, 2, sub);
+
+ sub = subject_to_path(subjectline, true, sep);
+ while (((pos = val.find ("%S"))) != val.npos)
+ val.replace (pos, 2, sub);
+
+ return val;
+ }
+
+
+ void
+ show_group_substitution_help_dialog (gpointer window)
+ {
+ const char * str = _("%g - group as one directory (alt.binaries.pictures.trains)\n"
+ "%G - group as nested directory (/alt/binaries/pictures/trains)\n"
+ "%s - subject line excerpt\n"
+ "%S - subject line\n"
+ " \n"
+ "\"/home/user/News/Pan/%g\" becomes\n"
+ "\"/home/user/News/Pan/alt.binaries.pictures.trains\", and\n"
+ "\"/home/user/News/Pan/%G\" becomes\n"
+ "\"/home/user/News/Pan/alt/binaries/pictures/trains\",");
+ GtkWidget * w = gtk_message_dialog_new (GTK_WINDOW(window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_CLOSE, "%s", str);
+ g_signal_connect_swapped (GTK_OBJECT(w), "response",
+ G_CALLBACK(gtk_widget_destroy), GTK_OBJECT (w));
+ gtk_widget_show_all (w);
+ }
+
+ void delete_save_dialog (gpointer castme)
+ {
+ delete static_cast<SaveAttachmentsDialog*>(castme);
+ }
+
+ enum { PATH_GROUP, PATH_ENTRY };
+
+ int path_mode (PATH_GROUP);
+}
+
+void
+SaveAttachmentsDialog :: response_cb (GtkDialog * dialog,
+ int response,
+ gpointer user_data)
+{
+
+ if (response == GTK_RESPONSE_OK)
+ {
+ SaveAttachmentsDialog * self (static_cast<SaveAttachmentsDialog*>(user_data));
+
+ bool subject_in_path = false;
+
+ // set the path mode based on what widgets exist & are set
+ GtkWidget * gr (self->_save_group_path_radio);
+ GtkWidget * er (self->_save_custom_path_radio);
+ if (gr && er)
+ path_mode = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gr)) ? PATH_GROUP : PATH_ENTRY;
+ else
+ path_mode = PATH_ENTRY;
+
+ // get the save path
+ std::string path, opath;
+ if (path_mode == PATH_GROUP)
+ path = (const char*) g_object_get_data (G_OBJECT(gr), "default-group-save-path");
+ else if (path_mode == PATH_ENTRY) {
+ path = pan :: file_entry_get (self->_save_path_entry);
+ self->_prefs.set_string ("default-save-attachments-path", path);
+ }
+ path = opath = expand_download_dir (path.c_str(), self->_group.to_view());
+ if ((path.find("%s") != path.npos) || (path.find("%S") != path.npos))
+ subject_in_path = true;
+
+ std::string sep( self->_prefs.get_string("save-subj-seperator", "-") );
+
+ // make the tasks...
+ Queue::tasks_t tasks;
+ foreach_const (std::vector<Article>, self->_articles, it)
+ {
+ if (subject_in_path)
+ path = expand_download_dir_subject(opath.c_str(), it->subject, sep);
+ tasks.push_back (new TaskArticle (self->_server_rank,
+ self->_group_server,
+ *it,
+ self->_cache,
+ self->_read,
+ 0,
+ TaskArticle::DECODE,
+ path,
+ self->_filename,
+ self->_options));
+ }
+
+ // get the queue mode...
+ Queue::AddMode queue_mode;
+ std::string s = self->_prefs.get_string ("save-article-priority", "age");
+ if (s == "top") queue_mode = Queue::TOP;
+ else if (s == "bottom") queue_mode = Queue::BOTTOM;
+ else queue_mode = Queue::AGE;
+
+ // queue up the tasks...
+ if (!tasks.empty())
+ self->_queue.add_tasks (tasks, queue_mode);
+ }
+
+ gtk_widget_destroy (GTK_WIDGET(dialog));
+}
+
+namespace
+{
+ void entry_changed_cb (GtkEditable*, gpointer radio_or_null)
+ {
+ if (radio_or_null)
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(radio_or_null), true);
+ }
+
+ void combo_box_selection_changed (GtkComboBox * combo, gpointer prefs, const char * key)
+ {
+ GtkTreeIter iter;
+ gtk_combo_box_get_active_iter (combo, &iter);
+ GtkTreeModel * model (gtk_combo_box_get_model (combo));
+ char * s (0);
+ gtk_tree_model_get (model, &iter, 0, &s, -1);
+ static_cast<Prefs*>(prefs)->set_string (key, s);
+ g_free (s);
+ }
+
+ void priority_combo_box_selection_changed (GtkComboBox * combo, gpointer prefs)
+ {
+ combo_box_selection_changed (combo, prefs, "save-article-priority");
+ }
+
+ GtkWidget* create_combo_box (Prefs& prefs, const char * key, const char * fallback, ...)
+ {
+ const std::string active_str (prefs.get_string (key, fallback));
+ int active (-1);
+ GtkListStore * store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
+ va_list args;
+ va_start (args, fallback);
+ for (int i=0;; ++i) {
+ const char * key_str = va_arg (args, const char*);
+ if (!key_str) break;
+ const char * gui_str = va_arg (args, const char*);
+ GtkTreeIter iter;
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, 0, key_str, 1, gui_str, -1);
+ if (active_str == key_str) active = i;
+ }
+ GtkWidget * w = gtk_combo_box_new_with_model (GTK_TREE_MODEL(store));
+ GtkCellRenderer * renderer (gtk_cell_renderer_text_new ());
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (w), renderer, true);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (w), renderer, "text", 1, NULL);
+ gtk_combo_box_set_active (GTK_COMBO_BOX(w), active);
+ return w;
+ }
+
+ GtkWidget* create_priority_combo_box (Prefs& prefs)
+ {
+ return create_combo_box (prefs, "save-article-priority", "age",
+ "age", _("Add to the queue sorted by date posted"),
+ "top", _("Add to the front of the queue"),
+ "bottom", _("Add to the back of the queue"),
+ NULL);
+ }
+}
+
+SaveAttachmentsDialog :: SaveAttachmentsDialog
+ (Prefs & prefs,
+ const GroupPrefs & group_prefs,
+ const ServerRank & server_rank,
+ const GroupServer & group_server,
+ ArticleCache & cache,
+ ArticleRead & read,
+ Queue & queue,
+ GtkWindow * parent_window,
+ const Quark & group,
+ const std::vector<Article> & articles,
+ const TaskArticle::SaveOptions & options,
+ const char * filename):
+ _prefs(prefs),
+ _server_rank (server_rank),
+ _group_server (group_server),
+ _cache (cache),
+ _read (read),
+ _queue (queue),
+ _group (group),
+ _root (0),
+ _save_custom_path_radio (0),
+ _save_group_path_radio (0),
+ _articles (articles),
+ _options (options),
+ _filename (filename)
+{
+ GtkWidget * dialog = gtk_dialog_new_with_buttons (_("Pan: Save Attachments"),
+ parent_window,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ NULL);
+ gtk_dialog_add_button (GTK_DIALOG(dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+ GtkWidget * focus = gtk_dialog_add_button (GTK_DIALOG(dialog), GTK_STOCK_SAVE, GTK_RESPONSE_OK);
+ gtk_window_set_role (GTK_WINDOW(dialog), "pan-save-attachments-dialog");
+ gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_OK);
+ g_signal_connect (dialog, "response", G_CALLBACK(response_cb), this);
+ g_signal_connect_swapped (dialog, "destroy", G_CALLBACK(delete_save_dialog), this);
+
+ const std::string group_path (group_prefs.get_string (group, "default-group-save-path", ""));
+ const bool have_group_default (!group_path.empty());
+
+ int row (0);
+ GtkWidget *t, *w, *h;
+ t = HIG :: workarea_create ();
+
+ HIG :: workarea_add_section_spacer (t, row, have_group_default ? 4 : 3);
+
+ if (path_mode==PATH_GROUP && !have_group_default)
+ path_mode = PATH_ENTRY;
+
+ h = gtk_hbox_new (FALSE, 0);
+ if (have_group_default) {
+ w = _save_custom_path_radio = gtk_radio_button_new_with_mnemonic (NULL, _("_Location:"));
+ gtk_box_pack_start (GTK_BOX(h), w, false, false, 0);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(w), path_mode==PATH_ENTRY);
+ }
+ w = _save_path_entry = file_entry_new (_("Save Articles"));
+ gtk_box_pack_start (GTK_BOX(h), w, true, true, 0);
+ std::string path (_prefs.get_string ("default-save-attachments-path", ""));
+ if (path.empty())
+ path = g_get_home_dir ();
+ file_entry_set (w, path.c_str());
+ g_signal_connect (file_entry_gtk_entry(w), "changed", G_CALLBACK(entry_changed_cb), _save_custom_path_radio);
+ gtk_widget_set_size_request (GTK_WIDGET(w), 400, 0);
+ w = gtk_button_new_from_stock (GTK_STOCK_HELP);
+ gtk_box_pack_start (GTK_BOX(h), w, false, false, 0);
+ g_signal_connect_swapped (w, "clicked", G_CALLBACK (show_group_substitution_help_dialog), dialog);
+ if (have_group_default)
+ HIG :: workarea_add_wide_control (t, &row, h);
+ else
+ HIG :: workarea_add_row (t, &row, _("_Location:"), h, file_entry_gtk_entry(_save_path_entry));
+
+ if (have_group_default) {
+ char * pch = g_strdup_printf (_("_Group's path: %s"), group_path.c_str());
+ w = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON(_save_custom_path_radio), pch);
+ _save_group_path_radio = w;
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(w), path_mode==PATH_GROUP);
+ g_object_set_data_full (G_OBJECT(w), "default-group-save-path", g_strdup(group_path.c_str()), g_free);
+ g_free (pch);
+ HIG :: workarea_add_wide_control (t, &row, w);
+ }
+
+ w = create_priority_combo_box (prefs);
+ g_signal_connect (w, "changed", G_CALLBACK(priority_combo_box_selection_changed), &prefs);
+ w = HIG :: workarea_add_row (t, &row, _("_Priority:"), w);
+
+ gtk_widget_show_all (t);
+ gtk_box_pack_start (GTK_BOX( gtk_dialog_get_content_area( GTK_DIALOG(dialog))), t, true, true, 0);
+ gtk_widget_grab_focus (focus);
+ _root = dialog;
+}
diff --git a/pan/gui/save-attach-ui.h b/pan/gui/save-attach-ui.h
new file mode 100644
index 0000000..8a455e7
--- /dev/null
+++ b/pan/gui/save-attach-ui.h
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Pan - A Newsreader for Gtk+
+ * Copyright (C) 2002-2006 Charles Kerr <charles rebelbase com>
+ *
+ * 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; version 2 of the License.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __SaveAttachUI_h__
+#define __SaveattachUI_h__
+
+#include <string>
+#include <vector>
+#include <pan/general/quark.h>
+#include <pan/data/article.h>
+#include <pan/data/article-cache.h>
+#include <pan/data/data.h>
+#include <pan/tasks/task-article.h>
+#include <gtk/gtk.h>
+#include "group-prefs.h"
+#include "prefs.h"
+
+namespace pan
+{
+ class SaveAttachmentsDialog
+ {
+ public:
+
+ SaveAttachmentsDialog (Prefs & prefs,
+ const GroupPrefs & group_prefs,
+ const ServerRank & server_rank,
+ const GroupServer & group_server,
+ ArticleCache & cache,
+ ArticleRead & read,
+ Queue & queue,
+ GtkWindow * parent_window,
+ const Quark & group,
+ const std::vector<Article> & articles,
+ const TaskArticle::SaveOptions & options,
+ const char * filename=0
+ );
+
+
+ ~SaveAttachmentsDialog () {}
+ GtkWidget * root() { return _root; }
+
+ private:
+ Prefs& _prefs;
+ const ServerRank& _server_rank;
+ const GroupServer& _group_server;
+ ArticleCache& _cache;
+ ArticleRead& _read;
+ Queue& _queue;
+ const Quark _group;
+ GtkWidget * _root;
+ GtkWidget * _save_path_entry;
+ GtkWidget * _save_custom_path_radio;
+ GtkWidget * _save_group_path_radio;
+ std::vector<Article> _articles;
+ TaskArticle::SaveOptions _options;
+ const char* _filename;
+
+ private:
+ static void response_cb (GtkDialog*, int, gpointer);
+
+ private:
+ static bool _save_text;
+ static bool _save_attachments;
+ };
+}
+#endif
diff --git a/pan/gui/server-ui.cc b/pan/gui/server-ui.cc
index 826872e..8b58427 100644
--- a/pan/gui/server-ui.cc
+++ b/pan/gui/server-ui.cc
@@ -38,15 +38,9 @@ extern "C" {
#include "hig.h"
#include "gtk_compat.h"
-#ifdef HAVE_OPENSSL
-
+#ifdef HAVE_GNUTLS
#include <pan/data/cert-store.h>
- #include <openssl/crypto.h>
- #include <openssl/x509.h>
- #include <openssl/x509v3.h>
- #include <openssl/pem.h>
- #include <openssl/ssl.h>
- #include <openssl/err.h>
+ #include <gnutls/gnutls.h>
#endif
using namespace pan;
@@ -73,6 +67,7 @@ namespace
GtkWidget * expiration_age_combo;
GtkWidget * rank_combo;
GtkWidget * ssl_combo;
+ GtkWidget * always_trust_checkbox;
ServerEditDialog (Data& d, Queue& q): data(d), queue(q) {}
};
@@ -103,7 +98,7 @@ namespace
void ssl_changed_cb(GtkComboBox* w, ServerEditDialog* d)
{
int ssl(0);
-#ifdef HAVE_OPENSSL
+#ifdef HAVE_GNUTLS
GtkTreeIter iter;
if (gtk_combo_box_get_active_iter (w, &iter))
gtk_tree_model_get (gtk_combo_box_get_model(w), &iter, 1, &ssl, -1);
@@ -120,7 +115,7 @@ namespace
d->server = server;
- int port(STD_NNTP_PORT), max_conn(4), age(31*3), rank(1), ssl(0);
+ int port(STD_NNTP_PORT), max_conn(4), age(31*3), rank(1), ssl(0), trust(0);
std::string addr, user, pass, cert;
if (!server.empty()) {
d->data.get_server_addr (server, addr, port);
@@ -130,6 +125,7 @@ namespace
max_conn = d->data.get_server_limits (server);
ssl = d->data.get_server_ssl_support(server);
cert = d->data.get_server_cert(server);
+ d->data.get_server_trust (server, trust);
}
pan_entry_set_text (d->address_entry, addr);
@@ -164,7 +160,7 @@ namespace
}
} while (gtk_tree_model_iter_next(model, &iter));
-#ifdef HAVE_OPENSSL
+#ifdef HAVE_GNUTLS
// set ssl combo
combo = GTK_COMBO_BOX (d->ssl_combo);
model = gtk_combo_box_get_model (combo);
@@ -176,8 +172,9 @@ namespace
break;
}
} while (gtk_tree_model_iter_next(model, &iter));
-#endif
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(d->always_trust_checkbox), trust);
+#endif
}
void
@@ -208,13 +205,15 @@ namespace
if (gtk_combo_box_get_active_iter (combo, &iter))
gtk_tree_model_get (gtk_combo_box_get_model(combo), &iter, 1, &rank, -1);
int ssl(0);
+ int trust(0);
StringView cert(d->cert);
-#ifdef HAVE_OPENSSL
+#ifdef HAVE_GNUTLS
combo = GTK_COMBO_BOX (d->ssl_combo);
if (gtk_combo_box_get_active_iter (combo, &iter))
gtk_tree_model_get (gtk_combo_box_get_model(combo), &iter, 1, &ssl, -1);
+ trust = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(d->always_trust_checkbox)) ? 1 : 0;
#endif
const char * err_msg (0);
@@ -240,6 +239,7 @@ namespace
d->data.set_server_rank (d->server, rank);
d->data.set_server_ssl_support(d->server, ssl);
d->data.set_server_cert(d->server,cert);
+ d->data.set_server_trust(d->server,trust);
d->data.save_server_info(d->server);
d->queue.upkeep ();
}
@@ -390,7 +390,7 @@ pan :: server_edit_dialog_new (Data& data, Queue& queue, GtkWindow * window, con
HIG::workarea_add_row (t, &row, e, w);
// ssl 3.0 option
-#ifdef HAVE_OPENSSL
+#ifdef HAVE_GNUTLS
// select ssl/plaintext
HIG::workarea_add_section_divider (t, &row);
HIG::workarea_add_section_title (t, &row, _("Security"));
@@ -424,6 +424,10 @@ pan :: server_edit_dialog_new (Data& data, Queue& queue, GtkWindow * window, con
"If you enable SSL/TLS, your data is encrypted and secure. "
"It is encouraged to use this option for privacy reasons."));
HIG::workarea_add_row (t, &row, e, w);
+
+ d->always_trust_checkbox = w = gtk_check_button_new_with_label (_("Always trust this server's certificate"));
+ HIG::workarea_add_row (t, &row, NULL, w, NULL);
+
#endif
d->server = server;
@@ -659,7 +663,7 @@ namespace
}
}
-#ifdef HAVE_OPENSSL
+#ifdef HAVE_GNUTLS
/* security dialog */
namespace
{
@@ -680,7 +684,7 @@ namespace
char buf[4096] ;
if (!selected_server.empty()) {
- X509* cert (store.get_cert_to_server(selected_server));
+ const gnutls_x509_crt_t cert (store.get_cert_to_server(selected_server));
if (cert)
{
pretty_print_x509(buf,sizeof(buf),addr, cert,false);
@@ -755,25 +759,25 @@ namespace
const Quark selected_server (get_selected_server (d));
CertStore& store (d->data.get_certstore());
- if (!ret.empty() )
- {
- std::string addr; int port;
- FILE *fp = fopen(ret.c_str(),"rb");
- X509 *x;
- if (!fp) goto _err;
- x = X509_new();
- if (!x) { fclose(fp); goto _err; }
- PEM_read_X509(fp,&x, 0, 0);
- fclose(fp);
- d->data.get_server_addr(selected_server, addr, port);
- if (!store.add(x,selected_server))
- {
- _err:
- Log::add_err_va("Error adding certificate of server '%s' to CertStore. Check the console output!", addr.c_str());
- file::print_file_info(std::cerr,ret.c_str());
- }
- sec_tree_view_refresh (d);
- }
+// if (!ret.empty() )
+// {
+// std::string addr; int port;
+// FILE *fp = fopen(ret.c_str(),"rb");
+// X509 *x;
+// if (!fp) goto _err;
+// x = X509_new();
+// if (!x) { fclose(fp); goto _err; }
+// PEM_read_X509(fp,&x, 0, 0);
+// fclose(fp);
+// d->data.get_server_addr(selected_server, addr, port);
+// if (!store.add(x,selected_server))
+// {
+// _err:
+// Log::add_err_va("Error adding certificate of server '%s' to CertStore. Check the console output!", addr.c_str());
+// file::print_file_info(std::cerr,ret.c_str());
+// }
+// sec_tree_view_refresh (d);
+// }
}
@@ -908,7 +912,7 @@ pan :: render_cert_flag (GtkTreeViewColumn * ,
GtkWidget*
pan :: sec_dialog_new (Data& data, Queue& queue, GtkWindow* parent)
{
-#ifdef HAVE_OPENSSL
+#ifdef HAVE_GNUTLS
ServerListDialog * d = new ServerListDialog (data, queue);
for (guint i=0; i<ICON_QTY; ++i)
diff --git a/pan/gui/task-pane.cc b/pan/gui/task-pane.cc
index c1cd93c..89f9a50 100644
--- a/pan/gui/task-pane.cc
+++ b/pan/gui/task-pane.cc
@@ -166,6 +166,8 @@ TaskPane:: on_tooltip_query(GtkWidget *widget,
}
gtk_tree_path_free (path);
+ g_free (date);
+
return true;
}
diff --git a/pan/tasks/Makefile.am b/pan/tasks/Makefile.am
index 54e5145..cca353d 100644
--- a/pan/tasks/Makefile.am
+++ b/pan/tasks/Makefile.am
@@ -1,6 +1,6 @@
-AM_CPPFLAGS = -I top_srcdir@ @GMIME_CFLAGS@ @GLIB_CFLAGS@ @OPENSSL_CFLAGS@
+AM_CPPFLAGS = -I top_srcdir@ @GMIME_CFLAGS@ @GLIB_CFLAGS@ @GNUTLS_CFLAGS@ @GTK_CFLAGS@
-AM_LDFLAGS = ../../uulib/libuu.a @OPENSSL_LIBS@
+AM_LDFLAGS = ../../uulib/libuu.a @GNUTLS_LIBS@
noinst_LIBRARIES = libtasks.a
diff --git a/pan/tasks/decoder.cc b/pan/tasks/decoder.cc
index 57be091..bc09d16 100644
--- a/pan/tasks/decoder.cc
+++ b/pan/tasks/decoder.cc
@@ -55,10 +55,12 @@ Decoder :: ~Decoder()
***/
void
-Decoder :: enqueue (TaskArticle * task,
- const Quark & save_path,
- const strings_t & input_files,
- const TaskArticle::SaveMode & save_mode)
+Decoder :: enqueue (TaskArticle * task,
+ const Quark & save_path,
+ const strings_t & input_files,
+ const TaskArticle::SaveMode & save_mode,
+ const TaskArticle::SaveOptions & options,
+ const StringView & filename)
{
disable_progress_update ();
@@ -66,6 +68,8 @@ Decoder :: enqueue (TaskArticle * task,
this->save_path = save_path;
this->input_files = input_files;
this->save_mode = save_mode;
+ this->options = options;
+ this->attachment_filename = filename;
mark_read = false;
percent = 0;
@@ -141,6 +145,7 @@ Decoder :: do_work()
int i (0);
foreach_const (strings_t, input_files, it)
{
+
if (was_cancelled()) break;
if ((res = UULoadFileWithPartNo (const_cast<char*>(it->c_str()), 0, 0, ++i)) != UURET_OK) {
g_snprintf(buf, bufsz,
@@ -162,6 +167,11 @@ Decoder :: do_work()
i = 0;
while ((item = UUGetFileListItem (i++)))
{
+ // skip all other attachments in SAVE_AS mode (single attachment download)
+ /// DBG why is this failing if article isn't cached????
+ if (!attachment_filename.empty())
+ if(strcmp(item->filename, attachment_filename.str) != 0 && options == TaskArticle::SAVE_AS) continue;
+
file_errors.clear ();
if (was_cancelled()) break; // poll WorkerPool::Worker stop flag
diff --git a/pan/tasks/decoder.h b/pan/tasks/decoder.h
index beaabc6..b34b790 100644
--- a/pan/tasks/decoder.h
+++ b/pan/tasks/decoder.h
@@ -59,7 +59,9 @@ namespace pan
void enqueue (TaskArticle * task,
const Quark & save_path,
const strings_t & input_files,
- const TaskArticle::SaveMode & save_mode);
+ const TaskArticle::SaveMode & save_mode,
+ const TaskArticle::SaveOptions & options,
+ const StringView & filename);
public:
@@ -77,6 +79,8 @@ namespace pan
std::string save_path;
strings_t input_files;
TaskArticle::SaveMode save_mode;
+ TaskArticle::SaveOptions options;
+ StringView attachment_filename;
// These are set in the worker thread and polled in the main thread.
Mutex mut;
diff --git a/pan/tasks/encoder.cc b/pan/tasks/encoder.cc
index c9028e2..25c1c69 100644
--- a/pan/tasks/encoder.cc
+++ b/pan/tasks/encoder.cc
@@ -141,9 +141,6 @@ Encoder :: do_work()
/* build real subject line for article*/
tmp->subject = subject;
- // DBG
- // fp = fopen("/home/imhotep/test.pdf", "wb+");
-
for (TaskUpload::needed_t::iterator it = needed->begin(); it != needed->end(); ++it, ++cnt)
{
g_snprintf(buf,sizeof(buf),"%s.%d",basename.c_str(), cnt);
diff --git a/pan/tasks/nntp-pool.cc b/pan/tasks/nntp-pool.cc
index a82b694..e4ca0ec 100644
--- a/pan/tasks/nntp-pool.cc
+++ b/pan/tasks/nntp-pool.cc
@@ -289,7 +289,7 @@ NNTP_Pool :: request_nntp (WorkerPool& threadpool)
{
++_pending_connections;
const bool ssl(_server_info.get_server_ssl_support(_server));
- _socket_creator->create_socket (_server_info,address, port, threadpool, this, ssl);
+ _socket_creator->create_socket (_server_info, address, port, threadpool, this, ssl);
}
}
}
@@ -351,14 +351,14 @@ NNTP_Pool :: idle_upkeep ()
}
}
-#ifdef HAVE_OPENSSL
+#ifdef HAVE_GNUTLS
void
-NNTP_Pool:: on_verify_cert_failed(X509* cert, std::string server, std::string cert_name, int nr)
+NNTP_Pool:: on_verify_cert_failed(gnutls_x509_crt_t cert, std::string server, int nr)
{
}
void
-NNTP_Pool :: on_valid_cert_added (X509* cert, std::string server)
+NNTP_Pool :: on_valid_cert_added (gnutls_x509_crt_t cert, std::string server)
{
}
#endif
diff --git a/pan/tasks/nntp-pool.h b/pan/tasks/nntp-pool.h
index f173863..4a976cb 100644
--- a/pan/tasks/nntp-pool.h
+++ b/pan/tasks/nntp-pool.h
@@ -28,7 +28,7 @@
#include <pan/tasks/nntp.h>
#include <pan/tasks/socket-impl-main.h>
-#ifdef HAVE_OPENSSL
+#ifdef HAVE_GNUTLS
#include <pan/data/cert-store.h>
#endif
@@ -86,11 +86,11 @@ namespace pan
private: // Socket::Creator::Listener
virtual void on_socket_created (const StringView& host, int port, bool ok, Socket*);
virtual void on_socket_shutdown (const StringView& host, int port, Socket*) {}
-#ifdef HAVE_OPENSSL
+#ifdef HAVE_GNUTLS
private:
// CertStore::Listener
- virtual void on_verify_cert_failed (X509*, std::string, std::string, int) ;
- virtual void on_valid_cert_added (X509*, std::string );
+ virtual void on_verify_cert_failed (gnutls_x509_crt_t, std::string, int) ;
+ virtual void on_valid_cert_added (gnutls_x509_crt_t, std::string );
#endif
private:
diff --git a/pan/tasks/queue.h b/pan/tasks/queue.h
index 6b1c9c5..6a1f32d 100644
--- a/pan/tasks/queue.h
+++ b/pan/tasks/queue.h
@@ -36,7 +36,7 @@
#include <pan/tasks/task-weak-ordering.h>
#include <pan/tasks/socket-impl-main.h>
-#ifdef HAVE_OPENSSL
+#ifdef HAVE_GNUTLS
#include <pan/data/cert-store.h>
#endif
diff --git a/pan/tasks/socket-impl-main.cc b/pan/tasks/socket-impl-main.cc
index 24ddff7..589dacb 100644
--- a/pan/tasks/socket-impl-main.cc
+++ b/pan/tasks/socket-impl-main.cc
@@ -37,7 +37,8 @@
#include <cerrno>
#include <cstring>
-#ifdef HAVE_OPENSSL
+#ifdef HAVE_GNUTLS
+ #include <gcrypt.h>
#include <pan/usenet-utils/ssl-utils.h>
#endif
#include <pan/general/debug.h>
@@ -74,13 +75,11 @@ namespace
std::string err;
bool use_ssl;
const Quark server;
-#ifdef HAVE_OPENSSL
- std::multimap<std::string, Socket*>& socket_map;
- SSL_CTX * context;
+#ifdef HAVE_GNUTLS
CertStore& store;
ThreadWorker (ServerInfo& d, const Quark& s, const StringView& h, int p, Socket::Creator::Listener *l,
- bool ssl, SSL_CTX* ctx, CertStore& cs, std::multimap<std::string, Socket*>& m):
- data(d), server(s), host(h), port(p), listener(l), ok(false), socket(0), use_ssl(ssl), context(ctx), store(cs), socket_map(m) {}
+ bool ssl, CertStore& cs):
+ data(d), server(s), host(h), port(p), listener(l), ok(false), socket(0), use_ssl(ssl), store(cs) {}
#else
ThreadWorker (ServerInfo& d, const Quark& s, const StringView& h, int p, Socket::Creator::Listener *l):
data(d), server(s), host(h), port(p), listener(l), ok(false), socket(0), use_ssl(false) {}
@@ -88,11 +87,10 @@ namespace
void do_work ()
{
-#ifdef HAVE_OPENSSL
+#ifdef HAVE_GNUTLS
if (use_ssl)
{
- socket = new GIOChannelSocketSSL (data, server, context, store);
- socket_map.insert(std::pair<std::string, Socket*>(host, socket));
+ socket = new GIOChannelSocketGnuTLS (data, server, store);
}
else
#endif
@@ -110,81 +108,22 @@ namespace
};
}
-#ifdef HAVE_OPENSSL
-
-// TODO remove this later if it works with GMutex
-#ifdef G_OS_WIN32
- #define MUTEX_TYPE HANDLE
- #define MUTEX_LOCK(x) WaitForSingleObject((x), INFINITE)
- #define MUTEX_UNLOCK(x) ReleaseMutex(x)
- #define THREAD_ID GetCurrentThreadId( )
-#else
- #define MUTEX_TYPE Mutex
- #define MUTEX_LOCK(x) x.lock()
- #define MUTEX_UNLOCK(x) x.unlock()
- #define THREAD_ID pthread_self( )
-#endif
- #define MUTEX_SETUP(x) (x) = new MUTEX_TYPE[CRYPTO_num_locks()];
- #define MUTEX_CLEANUP(x) delete [] x
-namespace
-{
- static MUTEX_TYPE* mutex;
-
- void gio_lock(int mode, int type, const char *file, int line)
- {
- if (mode & CRYPTO_LOCK)
- MUTEX_LOCK(mutex[type]);//.lock();
- else
- MUTEX_UNLOCK(mutex[type]);//.unlock();
- }
-
- void ssl_thread_setup() {
- MUTEX_SETUP(mutex);
-#ifdef G_OS_WIN32
- for (int i = 0; i < CRYPTO_num_locks(); ++i) mutex[i] = CreateMutex(NULL, FALSE, NULL);
-#endif
- CRYPTO_set_locking_callback(gio_lock);
- }
-
- void ssl_thread_cleanup() {
-#ifdef G_OS_WIN32
- for (int i = 0; i < CRYPTO_num_locks(); ++i) CloseHandle(mutex[i]);
-#endif
- MUTEX_CLEANUP(mutex);
- CRYPTO_set_locking_callback(0);
- }
-
-}
-#endif
-
SocketCreator :: SocketCreator(Data& d, CertStore& cs) : data(d), store(cs)
{
-#ifdef HAVE_OPENSSL
- SSL_library_init();
- SSL_load_error_strings();
- OpenSSL_add_all_algorithms();
- ERR_load_crypto_strings();
-
- /* init static locks for threads */
- ssl_thread_setup();
- ssl_ctx = SSL_CTX_new(SSLv3_client_method());
- cs.set_ctx(ssl_ctx);
- SSL_CTX_set_mode(ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_AUTO_RETRY);
- SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_CLIENT);
-
+#ifdef HAVE_GNUTLS
+ gnutls_global_init();
cs.add_listener(this);
+ cs.init();
#endif
}
SocketCreator :: ~SocketCreator()
{
-#ifdef HAVE_OPENSSL
+#ifdef HAVE_GNUTLS
+ gnutls_global_deinit();
store.remove_listener(this);
-
- ssl_thread_cleanup();
- if (ssl_ctx) SSL_CTX_free(ssl_ctx);
#endif
}
@@ -200,20 +139,20 @@ SocketCreator :: create_socket (ServerInfo& info,
data.find_server_by_hn(host, server);
ensure_module_init ();
if (store.in_blacklist(server)) return;
-#ifdef HAVE_OPENSSL
- ThreadWorker * w = new ThreadWorker (info, server, host, port, listener, use_ssl, ssl_ctx, store, socket_map);
+#ifdef HAVE_GNUTLS
+ ThreadWorker * w = new ThreadWorker (info, server, host, port, listener, use_ssl, store);
#else
ThreadWorker * w = new ThreadWorker (info, server, host, port, listener);
#endif
threadpool.push_work (w, w, true);
}
-#ifdef HAVE_OPENSSL
+#ifdef HAVE_GNUTLS
void
-SocketCreator :: on_verify_cert_failed(X509* cert, std::string server, std::string cert_name, int nr)
+SocketCreator :: on_verify_cert_failed(gnutls_x509_crt_t cert, std::string server, int nr)
{}
void
-SocketCreator :: on_valid_cert_added (X509* cert, std::string server)
+SocketCreator :: on_valid_cert_added (gnutls_x509_crt_t cert, std::string server)
{}
#endif
diff --git a/pan/tasks/socket-impl-main.h b/pan/tasks/socket-impl-main.h
index 0699a12..e0f0643 100644
--- a/pan/tasks/socket-impl-main.h
+++ b/pan/tasks/socket-impl-main.h
@@ -39,9 +39,8 @@
#include <pan/general/worker-pool.h>
#include "socket.h"
-#ifdef HAVE_OPENSSL
- #include <openssl/crypto.h>
- #include <openssl/ssl.h>
+#ifdef HAVE_GNUTLS
+ #include <gnutls/gnutls.h>
#include "socket-impl-openssl.h"
#endif
@@ -131,20 +130,12 @@ namespace pan
private:
//socket::creator::Listener
virtual void on_socket_created (const StringView& host, int port, bool ok, Socket*) {}
- virtual void on_socket_shutdown (const StringView& host, int port, Socket*)
- {
-#ifdef HAVE_OPENSSL
-
-#endif
- }
-
-#ifdef HAVE_OPENSSL
- SSL_CTX* ssl_ctx;
- std::multimap<std::string, Socket*> socket_map;
+ virtual void on_socket_shutdown (const StringView& host, int port, Socket*) {}
+#ifdef HAVE_GNUTLS
// CertStore::Listener
- virtual void on_verify_cert_failed(X509*, std::string, std::string, int);
- virtual void on_valid_cert_added (X509*, std::string );
+ virtual void on_verify_cert_failed(gnutls_x509_crt_t, std::string, int);
+ virtual void on_valid_cert_added (gnutls_x509_crt_t, std::string );
#endif
CertStore & store;
Data& data;
diff --git a/pan/tasks/socket-impl-openssl.cc b/pan/tasks/socket-impl-openssl.cc
index fec8cfd..74d48a6 100644
--- a/pan/tasks/socket-impl-openssl.cc
+++ b/pan/tasks/socket-impl-openssl.cc
@@ -5,7 +5,6 @@
*
* This file
* Copyright (C) 2011 Heinrich Mü<sphemuel stud informatik uni-erlangen de>
- * SSL functions : Copyright (C) 2002 vjt (irssi project)
*
* 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
@@ -65,6 +64,7 @@ extern "C" {
// return buf;
// }
+
const char*
get_last_error (int err)
{
@@ -116,32 +116,34 @@ extern t_freeaddrinfo p_freeaddrinfo;
*****
****/
-#ifdef HAVE_OPENSSL // without libssl this class is just a stub....
+namespace
+{
+ static gboolean gnutls_inited = FALSE;
+}
-GIOChannelSocketSSL :: GIOChannelSocketSSL (ServerInfo& data, const Quark& server, SSL_CTX* ctx, CertStore& cs):
+#ifdef HAVE_GNUTLS // without gnutls this class is just a stub....
+
+GIOChannelSocketGnuTLS :: GIOChannelSocketGnuTLS (ServerInfo& data, const Quark& server, CertStore& cs):
_channel (0),
_tag_watch (0),
_tag_timeout (0),
- _handshake_timeout_tag(0),
_listener (0),
_out_buf (g_string_new (0)),
_in_buf (g_string_new (0)),
_io_performed (false),
- _ctx(ctx),
_certstore(cs),
- _rehandshake(false),
_server(server),
_done(false),
_data(data)
{
- debug ("GIOChannelSocketSSL ctor " << (void*)this);
+
+ debug ("GIOChannelSocketGnuTLS ctor " << (void*)this);
cs.add_listener(this);
- _session = cs.get_session();
}
GIOChannel *
-GIOChannelSocketSSL :: create_channel (const StringView& host_in, int port, std::string& setme_err)
+GIOChannelSocketGnuTLS :: create_channel (const StringView& host_in, int port, std::string& setme_err)
{
int err;
int sockfd;
@@ -268,8 +270,8 @@ GIOChannelSocketSSL :: create_channel (const StringView& host_in, int port, std:
g_io_channel_set_encoding (channel, 0, 0);
g_io_channel_set_buffered (channel,true);
g_io_channel_set_line_term (channel, "\n", 1);
- GIOChannel* ret (ssl_get_iochannel(channel));
- debug ("SocketSSL "<<ret);
+ GIOChannel* ret (gnutls_get_iochannel(channel, host_in.str));
+ debug ("########### SocketSSL "<<ret);
return ret;
}
@@ -291,24 +293,25 @@ namespace
GIOChannel pad;
gint fd;
GIOChannel *giochan;
- SSL *ssl;
- SSL_CTX *ctx;
char* host;
- unsigned int verify;
- } GIOSSLChannel;
+ bool verify;
+ gnutls_session_t session;
+ gnutls_certificate_credentials_t cred;
+ bool established;
+ } GIOGnuTLSChannel;
- void ssl_free(GIOChannel *handle)
+ void _gnutls_free(GIOChannel *handle)
{
- GIOSSLChannel *chan = (GIOSSLChannel *)handle;
+ GIOGnuTLSChannel *chan = (GIOGnuTLSChannel *)handle;
g_io_channel_unref(chan->giochan);
- SSL_shutdown(chan->ssl);
- SSL_free(chan->ssl);
+ gnutls_deinit (chan->session);
+ g_free(chan->host);
g_free(chan);
}
}
-GIOChannelSocketSSL :: ~GIOChannelSocketSSL ()
+GIOChannelSocketGnuTLS :: ~GIOChannelSocketGnuTLS ()
{
_certstore.remove_listener(this);
@@ -317,15 +320,12 @@ GIOChannelSocketSSL :: ~GIOChannelSocketSSL ()
remove_source (_tag_watch);
remove_source (_tag_timeout);
- remove_source (_handshake_timeout_tag);
if (_channel)
{
- GIOSSLChannel *chan = (GIOSSLChannel *)_channel;
- _session = SSL_get1_session(chan->ssl);
- _certstore.add_session(_session);
+ GIOGnuTLSChannel *chan = (GIOGnuTLSChannel *)_channel;
g_io_channel_shutdown (_channel, true, 0);
- ssl_free(_channel);
+ _gnutls_free(_channel);
g_string_free(_channel->read_buf,true);
_channel = 0;
}
@@ -338,7 +338,7 @@ GIOChannelSocketSSL :: ~GIOChannelSocketSSL ()
}
bool
-GIOChannelSocketSSL :: open (const StringView& address, int port, std::string& setme_err)
+GIOChannelSocketGnuTLS :: open (const StringView& address, int port, std::string& setme_err)
{
_host.assign (address.str, address.len);
_channel = create_channel (address, port, setme_err);
@@ -346,13 +346,13 @@ GIOChannelSocketSSL :: open (const StringView& address, int port, std::string& s
}
void
-GIOChannelSocketSSL :: get_host (std::string& setme) const
+GIOChannelSocketGnuTLS :: get_host (std::string& setme) const
{
setme = _host;
}
void
-GIOChannelSocketSSL :: write_command (const StringView& command, Socket::Listener * l)
+GIOChannelSocketGnuTLS :: write_command (const StringView& command, Socket::Listener * l)
{
_partial_read.clear ();
_listener = l;
@@ -371,11 +371,13 @@ GIOChannelSocketSSL :: write_command (const StringView& command, Socket::Listene
namespace
{
- static void set_blocking(SSL * ssl, bool val)
+ static void set_blocking(gnutls_session_t& session, bool val)
{
- int fd, flags;
- /* SSL_get_rfd returns -1 on error */
- if(fd = SSL_get_fd(ssl))
+ int fd(-1), flags;
+ gnutls_transport_ptr_t tmp = gnutls_transport_get_ptr (session);
+ fd = GPOINTER_TO_INT (tmp);
+
+ if(fd)
{
#ifndef G_OS_WIN32
flags = fcntl(fd, F_GETFL);
@@ -390,222 +392,206 @@ namespace
ioctlsocket(fd, FIONBIO, &block);
}
#endif
-
}
+ GIOStatus _gnutls_read(GIOChannel *handle, gchar *buf, gsize len, gsize *ret, GError **gerr)
+ {
+ return G_IO_STATUS_NORMAL;
+ }
- static GIOStatus ssl_errno(gint e)
+ GIOStatus _gnutls_write(GIOChannel *handle, const gchar *buf, gsize len, gsize *ret, GError **gerr)
{
- switch(e)
- {
- case EINVAL:
- return G_IO_STATUS_ERROR;
- case EINTR:
- case EAGAIN:
- return G_IO_STATUS_AGAIN;
- default:
- return G_IO_STATUS_ERROR;
- }
- return G_IO_STATUS_ERROR;
+ return G_IO_STATUS_NORMAL;
}
+ GIOStatus gnutls_seek(GIOChannel *handle, gint64 offset, GSeekType type, GError **gerr)
+ {
+ GIOGnuTLSChannel *chan = (GIOGnuTLSChannel *)handle;
+ GIOError e;
+ e = g_io_channel_seek(chan->giochan, offset, type);
+ return (e == G_IO_ERROR_NONE) ? G_IO_STATUS_NORMAL : G_IO_STATUS_ERROR;
+ }
- int ssl_handshake(ServerInfo& data, const Quark& server, GIOChannel *handle, CertStore::Listener* listener,
- CertStore* cs, std::string host, SSL_SESSION* session, bool rehandshake)
+ GIOStatus gnutls_close(GIOChannel *handle, GError **gerr)
{
+ debug("gnutls close "<<handle);
- GIOSSLChannel *chan = (GIOSSLChannel *)handle;
- int ret(0);
- int err(0);
- X509 *cert;
- const char *errstr;
-
- /* init custom data for callback */
- mydata_t mydata;
- mydata.ctx = chan->ctx;
- mydata.cs = cs;
- mydata.ignore_all = 0;
- mydata.l = listener;
- /* build cert name from scratch or from Server* */
- Quark setme;
- data.find_server_by_hn(host, setme);
- mydata.cert_name = data.get_server_cert(setme);
- mydata.server = server;
- SSL_set_ex_data(chan->ssl, SSL_get_fd(chan->ssl), &mydata);
-
- if (session) ret = SSL_set_session(chan->ssl, session);
-// if (rehandshake)
-// {
-// /* Stop the client from just resuming the un-authenticated session */
-// SSL_set_session_id_context(chan->ssl, (void *)&s_server_auth_session_id_context, sizeof(s_server_auth_session_id_context));
-//
-// if(SSL_renegotiate(ssl)<=0)
-// return 1;
-// if(SSL_do_handshake(ssl)<=0)
-// ssl->state=SSL_ST_ACCEPT;
-// if(SSL_do_handshake(ssl)<=0)
-// return 1;
-// }
-
- ret = SSL_connect(chan->ssl);
- if (ret <= 0) {
- err = SSL_get_error(chan->ssl, ret);
- return ret;
- switch (err) {
- case SSL_ERROR_WANT_READ:
- debug("SSL handshake failed: wants to read");
- if (SSL_pending (chan->ssl)) return 1;
- return 1;
- case SSL_ERROR_WANT_WRITE:
- debug("SSL handshake failed: wants to write");
- if (SSL_pending (chan->ssl)) return 1;
- return 3;
- case SSL_ERROR_ZERO_RETURN:
- debug("SSL handshake failed: server closed connection");
- return -1;
- case SSL_ERROR_SYSCALL:
- errstr = ERR_reason_error_string(ERR_get_error());
- if (errstr == NULL && ret == -1)
- errstr = strerror(errno);
- debug("SSL handshake failed: "<<(errstr != NULL ? errstr : "server closed connection unexpectedly"));
- return -1;
- default:
- errstr = ERR_reason_error_string(ERR_get_error());
- debug("SSL handshake failed: "<<(errstr != NULL ? errstr : "unknown SSL error"));
- return -1;
- }
- }
+ GIOGnuTLSChannel *chan = (GIOGnuTLSChannel *) handle;
- cert = SSL_get_peer_certificate(chan->ssl);
- if (!cert) {
- debug("SSL server supplied no certificate");
- return -1;
- }
+ if (chan->established) {
+ int ret;
- ret = !chan->verify || ssl_verify(cs, chan->ssl, chan->ctx, host.c_str(), cert);
- X509_free(cert);
- return ret ? 0 : -1;
+ do {
+ ret = gnutls_bye (chan->session, GNUTLS_SHUT_WR);
+ } while (ret == GNUTLS_E_INTERRUPTED);
+ }
+ return chan->giochan->funcs->io_close (handle, gerr);
}
- GIOStatus ssl_read(GIOChannel *handle, gchar *buf, gsize len, gsize *ret, GError **gerr)
+ GSource *gnutls_create_watch(GIOChannel *handle, GIOCondition cond)
{
- return G_IO_STATUS_NORMAL;
+ GIOGnuTLSChannel *chan = (GIOGnuTLSChannel *)handle;
+
+ return chan->giochan->funcs->io_create_watch(handle, cond);
}
- GIOStatus ssl_read_line_string(GIOChannel *handle, GString* g, gsize *ret, GError **gerr)
+ GIOStatus gnutls_set_flags(GIOChannel *handle, GIOFlags flags, GError **gerr)
{
+ GIOGnuTLSChannel *chan = (GIOGnuTLSChannel *)handle;
- GIOSSLChannel *chan = (GIOSSLChannel *)handle;
- gint err;
- const size_t tmp_size(4096*128);
- char tmp[tmp_size];
- g_string_set_size(g,0);
+ return chan->giochan->funcs->io_set_flags(handle, flags, gerr);
+ }
- if (handle->read_buf->len == 0)
- {
- err = SSL_read(chan->ssl, tmp, tmp_size*sizeof(char));
- if (ret) *ret = err < 0 ? 0 : err;
- if(err <= 0)
- {
- if(SSL_get_error(chan->ssl, err) == SSL_ERROR_WANT_READ)
- return G_IO_STATUS_AGAIN;
- return ssl_errno(errno);
- }
- else
- g_string_append_len (handle->read_buf,tmp,err);
- }
+ GIOFlags gnutls_get_flags(GIOChannel *handle)
+ {
+ GIOGnuTLSChannel *chan = (GIOGnuTLSChannel *)handle;
- //fill in from read_buf
- char * buf = handle->read_buf->str;
- int pos(0);
- bool found(false);
- while (*buf) { if (*buf == '\n') { found = true; break; } ++pos; ++buf; }
- if (found) {
- int _pos(std::min(pos+1,(int)handle->read_buf->len));
- g_string_append_len(g, handle->read_buf->str, _pos);
- g_string_erase (handle->read_buf, 0, _pos);
- return G_IO_STATUS_NORMAL;
- }
- // no linebreak, partial line. retry later...
- return G_IO_STATUS_AGAIN;
+ return chan->giochan->funcs->io_get_flags(handle);
}
- GIOStatus ssl_write(GIOChannel *handle, const gchar *buf, gsize len, gsize *ret, GError **gerr)
- {
- GIOSSLChannel *chan = (GIOSSLChannel *)handle;
- gint err;
+ GIOFuncs gnutls_channel_funcs = {
+ _gnutls_read,
+ _gnutls_write,
+ gnutls_seek,
+ gnutls_close,
+ gnutls_create_watch,
+ _gnutls_free,
+ gnutls_set_flags,
+ gnutls_get_flags
+ };
- err = SSL_write(chan->ssl, (const char *)buf, len);
- if(err < 0)
- {
- *ret = 0;
- if(SSL_get_error(chan->ssl, err) == SSL_ERROR_WANT_READ)
- return G_IO_STATUS_AGAIN;
- return ssl_errno(errno);
- }
- else
- {
- *ret = err;
- return G_IO_STATUS_NORMAL;
- }
- return G_IO_STATUS_ERROR;
+
+}
+
+/***
+****
+***/
+
+GIOStatus
+GIOChannelSocketGnuTLS :: gnutls_write_line(GIOChannel *handle, const gchar *buf, gsize len, gsize *ret, GError **gerr)
+{
+
+ *ret = 0;
+
+ GIOGnuTLSChannel *chan = (GIOGnuTLSChannel *)handle;
+ gint err;
+ GIOStatus result;
+
+ if (!chan->established) {
+ result = _gnutls_handshake (handle);
+
+ if (result == G_IO_STATUS_AGAIN ||
+ result == G_IO_STATUS_ERROR)
+ return result;
+ chan->established = TRUE;
}
- GIOStatus ssl_seek(GIOChannel *handle, gint64 offset, GSeekType type, GError **gerr)
+ err = gnutls_record_send (chan->session, (const char *)buf, len);
+ if(err < 0)
{
- GIOSSLChannel *chan = (GIOSSLChannel *)handle;
- GIOError e;
- e = g_io_channel_seek(chan->giochan, offset, type);
- return (e == G_IO_ERROR_NONE) ? G_IO_STATUS_NORMAL : G_IO_STATUS_ERROR;
+ if ((err == GNUTLS_E_INTERRUPTED) ||
+ (err == GNUTLS_E_AGAIN))
+ return G_IO_STATUS_AGAIN;
+ g_set_error (gerr, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Received corrupted data");
}
-
- GIOStatus ssl_close(GIOChannel *handle, GError **gerr)
+ else
{
- GIOSSLChannel *chan = (GIOSSLChannel *)handle;
- g_io_channel_close(chan->giochan);
+ *ret = err;
return G_IO_STATUS_NORMAL;
}
+ return G_IO_STATUS_ERROR;
+}
- GSource *ssl_create_watch(GIOChannel *handle, GIOCondition cond)
- {
- GIOSSLChannel *chan = (GIOSSLChannel *)handle;
+GIOStatus
+GIOChannelSocketGnuTLS :: gnutls_read_line(GString* g, gsize *ret, GError **gerr)
+{
- return chan->giochan->funcs->io_create_watch(handle, cond);
- }
+ *ret = 0;
- GIOStatus ssl_set_flags(GIOChannel *handle, GIOFlags flags, GError **gerr)
- {
- GIOSSLChannel *chan = (GIOSSLChannel *)handle;
+ GIOGnuTLSChannel *chan = (GIOGnuTLSChannel *)_channel;
- return chan->giochan->funcs->io_set_flags(handle, flags, gerr);
+ if (!chan->established) {
+ GIOStatus result = _gnutls_handshake (_channel);
+
+ if (result == G_IO_STATUS_AGAIN ||
+ result == G_IO_STATUS_ERROR)
+ return result;
+
+ chan->established = true;
}
- GIOFlags ssl_get_flags(GIOChannel *handle)
- {
- GIOSSLChannel *chan = (GIOSSLChannel *)handle;
+ gint err;
+ const size_t tmp_size(4096*128);
+ char tmp[tmp_size];
+ g_string_set_size(g,0);
- return chan->giochan->funcs->io_get_flags(handle);
+ if (_channel->read_buf->len == 0)
+ {
+ err = gnutls_record_recv (chan->session, tmp, tmp_size);
+ if (ret) *ret = err < 0 ? 0 : err;
+ if(err < 0)
+ {
+ if ((err == GNUTLS_E_INTERRUPTED) ||
+ (err == GNUTLS_E_AGAIN))
+ return G_IO_STATUS_AGAIN;
+ g_set_error (gerr, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Received corrupted data");
+ return G_IO_STATUS_ERROR;
+ }
+ else
+ g_string_append_len (_channel->read_buf,tmp,err);
}
- GIOFuncs ssl_channel_funcs = {
- ssl_read,
- ssl_write,
- ssl_seek,
- ssl_close,
- ssl_create_watch,
- ssl_free,
- ssl_set_flags,
- ssl_get_flags
- };
+ //fill in from read_buf
+ char * buf = _channel->read_buf->str;
+ int pos(0);
+ bool found(false);
+ while (*buf) { if (*buf == '\n') { found = true; break; } ++pos; ++buf; }
+ if (found) {
+ int _pos(std::min(pos+1,(int)_channel->read_buf->len));
+ g_string_append_len(g, _channel->read_buf->str, _pos);
+ g_string_erase (_channel->read_buf, 0, _pos);
+ return G_IO_STATUS_NORMAL;
+ }
+ //no linebreak, partial line. retry later...
+ return G_IO_STATUS_AGAIN;
}
-/***
-****
-***/
-GIOChannelSocketSSL :: DoResult
-GIOChannelSocketSSL :: do_read ()
+GIOStatus
+GIOChannelSocketGnuTLS :: _gnutls_handshake (GIOChannel *channel)
+{
+
+ GIOGnuTLSChannel *chan = (GIOGnuTLSChannel *)channel;
+
+ g_return_val_if_fail (channel, G_IO_STATUS_ERROR);
+ g_return_val_if_fail (chan, G_IO_STATUS_ERROR);
+ g_return_val_if_fail (chan->session, G_IO_STATUS_ERROR);
+
+ /* init custom data for callback */
+ mydata_t mydata;
+
+ mydata.cs = &_certstore;
+ Quark setme;
+ _data.find_server_by_hn(_host.c_str(), setme);
+ mydata.host = setme;
+ mydata.hostname_full = _host;
+ int res(0); // always trust server cert
+ _data.get_server_trust (setme, res);
+ mydata.always_trust = res;
+ gnutls_session_set_ptr (chan->session, (void *) &mydata);
+
+ int status = gnutls_handshake (chan->session);
+
+ bool r = !chan->verify || status == 0;
+ if (r) chan->established = true;
+
+ return r ? G_IO_STATUS_NORMAL : G_IO_STATUS_ERROR;
+
+}
+
+GIOChannelSocketGnuTLS :: DoResult
+GIOChannelSocketGnuTLS :: do_read ()
{
g_assert (!_out_buf->len);
@@ -614,13 +600,13 @@ GIOChannelSocketSSL :: do_read ()
bool more (true);
- GIOSSLChannel * chan = (GIOSSLChannel*)_channel;
+ GIOGnuTLSChannel * chan = (GIOGnuTLSChannel*)_channel;
while (more && !_abort_flag)
{
_io_performed = true;
gsize ret;
- const GIOStatus status (ssl_read_line_string(_channel, g, &ret, &err));
+ const GIOStatus status (gnutls_read_line(g, &ret, &err));
if (status == G_IO_STATUS_NORMAL)
{
@@ -656,8 +642,8 @@ GIOChannelSocketSSL :: do_read ()
}
-GIOChannelSocketSSL :: DoResult
-GIOChannelSocketSSL :: do_write ()
+GIOChannelSocketGnuTLS :: DoResult
+GIOChannelSocketGnuTLS :: do_write ()
{
g_assert (_partial_read.empty());
@@ -674,7 +660,7 @@ GIOChannelSocketSSL :: do_write ()
GError * err = 0;
gsize out = 0;
GIOStatus status = g->len
- ? ssl_write(_channel, g->str, g->len, &out, &err)
+ ? gnutls_write_line(_channel, g->str, g->len, &out, &err)
: G_IO_STATUS_NORMAL;
debug ("socket " << this << " channel " << _channel
<< " maybe wrote [" << g->str << "]; status was " << status);
@@ -700,9 +686,9 @@ GIOChannelSocketSSL :: do_write ()
}
gboolean
-GIOChannelSocketSSL :: timeout_func (gpointer sock_gp)
+GIOChannelSocketGnuTLS :: timeout_func (gpointer sock_gp)
{
- GIOChannelSocketSSL * self (static_cast<GIOChannelSocketSSL*>(sock_gp));
+ GIOChannelSocketGnuTLS * self (static_cast<GIOChannelSocketGnuTLS*>(sock_gp));
if (!self->_io_performed)
{
@@ -717,15 +703,15 @@ GIOChannelSocketSSL :: timeout_func (gpointer sock_gp)
}
gboolean
-GIOChannelSocketSSL :: gio_func (GIOChannel * channel,
+GIOChannelSocketGnuTLS :: gio_func (GIOChannel * channel,
GIOCondition cond,
gpointer sock_gp)
{
- return static_cast<GIOChannelSocketSSL*>(sock_gp)->gio_func (channel, cond);
+ return static_cast<GIOChannelSocketGnuTLS*>(sock_gp)->gio_func (channel, cond);
}
gboolean
-GIOChannelSocketSSL :: gio_func (GIOChannel * channel,
+GIOChannelSocketGnuTLS :: gio_func (GIOChannel * channel,
GIOCondition cond)
{
set_watch_mode (IGNORE_NOW);
@@ -757,9 +743,9 @@ namespace
}
void
-GIOChannelSocketSSL :: set_watch_mode (WatchMode mode)
+GIOChannelSocketGnuTLS :: set_watch_mode (WatchMode mode)
{
- GIOSSLChannel *chan = (GIOSSLChannel *)_channel;
+ GIOGnuTLSChannel *chan = (GIOGnuTLSChannel *)_channel;
debug ("socket " << this << " calling set_watch_mode " << mode << "; _channel is " << chan->giochan);
remove_source (_tag_watch);
remove_source (_tag_timeout);
@@ -793,71 +779,67 @@ GIOChannelSocketSSL :: set_watch_mode (WatchMode mode)
}
GIOChannel *
-GIOChannelSocketSSL :: ssl_get_iochannel(GIOChannel *handle, gboolean verify)
+GIOChannelSocketGnuTLS :: gnutls_get_iochannel(GIOChannel* channel, const char* host, gboolean verify)
{
- GIOSSLChannel *chan(0);
+ g_return_val_if_fail(channel, 0);
+
+ GIOGnuTLSChannel *chan(0);
GIOChannel *gchan(0);
int err(0), fd(0);
- SSL *ssl(0);
- SSL_CTX *ctx(_ctx);
- g_return_val_if_fail(handle != 0, 0);
- g_return_val_if_fail(ctx != 0, 0);
+ chan = g_new0(GIOGnuTLSChannel, 1);
+ g_return_val_if_fail(chan, 0);
- if(!(fd = g_io_channel_unix_get_fd(handle)))
- {
- return 0;
- }
+ gnutls_session_t session(NULL);
+
+ if(!(fd = g_io_channel_unix_get_fd(channel))) return 0;
- if(!(ssl = SSL_new(ctx)))
- {
- g_warning("Failed to allocate SSL structure");
- return 0;
- }
- SSL_set_verify(ssl,SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,0);
+ if (gnutls_init (&session, GNUTLS_CLIENT | GNUTLS_NONBLOCK) != 0) return 0;
+ if (gnutls_set_default_priority (session) != 0) return 0;
- if(!(err = SSL_set_fd(ssl, fd)))
- {
- g_warning("Failed to associate socket to SSL stream");
- SSL_free(ssl);
- return 0;
- }
+ gnutls_priority_set_direct (
+ session,
+ // "NONE:+VERS-SSL3.0:+CIPHER-ALL:+COMP-ALL:+RSA:+DHE-RSA:+DHE-DSS:+MAC-ALL"
+ "NONE:+VERS-TLS1.0:+CIPHER-ALL:+COMP-ALL:+RSA:+DHE-RSA:+DHE-DSS:+MAC-ALL", NULL);
- chan = g_new0(GIOSSLChannel, 1);
- if (!chan) return 0;
+ gnutls_certificate_credentials_t creds = _certstore.get_creds();
+ gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, creds);
+ gnutls_transport_set_ptr (session, GINT_TO_POINTER (fd));
+ chan->host = g_strdup(host);
+ chan->session = session;
chan->fd = fd;
- chan->giochan = handle;
- chan->ssl = ssl;
- chan->ctx = ctx;
- chan->verify = verify ? 1 : 0;
+ chan->giochan = channel;
+ chan->verify = verify;
gchan = (GIOChannel *)chan;
- gchan->funcs = &ssl_channel_funcs;
+ gchan->funcs = &gnutls_channel_funcs;
g_io_channel_init(gchan);
gchan->read_buf = g_string_sized_new(4096*128);
int ret;
- set_blocking(ssl, true);
- if (ssl_handshake(_data, _server, gchan, this, &_certstore,_host, _session,_rehandshake) == 0)
+ set_blocking(session, true);
+
+ if (_gnutls_handshake(gchan) == G_IO_STATUS_NORMAL)
{
- set_blocking(chan->ssl, false);
+ set_blocking(session, false);
return gchan;
}
- set_blocking(chan->ssl, false);
+
+ set_blocking(session, false);
+
return 0;
}
void
-GIOChannelSocketSSL :: on_verify_cert_failed (X509* cert, std::string server,
- std::string cert_name, int nr)
+GIOChannelSocketGnuTLS :: on_verify_cert_failed (gnutls_x509_crt_t cert, std::string server, int nr)
{
_certstore.blacklist(server);
}
void
-GIOChannelSocketSSL :: on_valid_cert_added (X509* cert, std::string server)
+GIOChannelSocketGnuTLS :: on_valid_cert_added (gnutls_x509_crt_t cert, std::string server)
{}
-#endif //HAVE_OPENSSL
+#endif //HAVE_GNUTLS
diff --git a/pan/tasks/socket-impl-openssl.h b/pan/tasks/socket-impl-openssl.h
index fbb877a..ff1da0d 100644
--- a/pan/tasks/socket-impl-openssl.h
+++ b/pan/tasks/socket-impl-openssl.h
@@ -31,15 +31,12 @@
#include <pan/general/quark.h>
#include <pan/tasks/socket.h>
#include <pan/tasks/socket-impl-gio.h>
+#include <pan/tasks/socket-impl-main.h>
-#ifdef HAVE_OPENSSL
+#ifdef HAVE_GNUTLS
#include <pan/data/cert-store.h>
- #include <openssl/crypto.h>
- #include <openssl/x509.h>
- #include <openssl/x509v3.h>
- #include <openssl/pem.h>
- #include <openssl/ssl.h>
- #include <openssl/err.h>
+ #include <gnutls/gnutls.h>
+ #include <gnutls/x509.h>
#endif
@@ -50,14 +47,14 @@ namespace pan
*
* @ingroup tasks
*/
-#ifdef HAVE_OPENSSL
- class GIOChannelSocketSSL:
+#ifdef HAVE_GNUTLS
+ class GIOChannelSocketGnuTLS:
public Socket,
private CertStore::Listener
{
public:
- virtual ~GIOChannelSocketSSL ();
- GIOChannelSocketSSL (ServerInfo&, const Quark&, SSL_CTX* ctx, CertStore& cs);
+ virtual ~GIOChannelSocketGnuTLS ();
+ GIOChannelSocketGnuTLS (ServerInfo&, const Quark&, CertStore& cs);
virtual bool open (const StringView& address, int port, std::string& setme_err);
virtual void write_command (const StringView& chars, Socket::Listener *);
@@ -68,24 +65,17 @@ namespace pan
GIOChannel * _channel;
unsigned int _tag_watch;
unsigned int _tag_timeout;
- unsigned int _handshake_timeout_tag;
Socket::Listener * _listener;
GString * _out_buf;
GString * _in_buf;
std::string _partial_read;
std::string _host;
bool _io_performed;
- SSL_CTX * _ctx;
CertStore& _certstore;
- SSL_SESSION* _session;
bool _rehandshake;
Quark _server;
bool _done;
- public:
- void set_rehandshake (bool setme) { _rehandshake = setme; }
- bool get_done() { return _done; }
-
private:
enum WatchMode { READ_NOW, WRITE_NOW, IGNORE_NOW };
void set_watch_mode (WatchMode mode);
@@ -97,23 +87,27 @@ namespace pan
DoResult do_write ();
// CertStore::Listener
- virtual void on_verify_cert_failed (X509*, std::string, std::string, int) ;
- virtual void on_valid_cert_added (X509*, std::string );
+ virtual void on_verify_cert_failed (gnutls_x509_crt_t, std::string, int) ;
+ virtual void on_valid_cert_added (gnutls_x509_crt_t, std::string );
GIOChannel * create_channel (const StringView& host_in, int port, std::string& setme_err);
void gio_lock(int mode, int type, const char *file, int line);
private:
- GIOChannel* ssl_get_iochannel(GIOChannel *handle, gboolean verify=true);
+ GIOChannel* gnutls_get_iochannel(GIOChannel* channel, const char* host, gboolean verify=true);
+ GIOStatus _gnutls_handshake (GIOChannel *channel);
+ gboolean verify_certificate (gnutls_session_t session, GError **err);
static gboolean handshake_cb(gpointer ptr);
+ GIOStatus gnutls_read_line(GString* g, gsize *ret, GError **gerr);
+ GIOStatus gnutls_write_line(GIOChannel *handle, const gchar *buf, gsize len, gsize *ret, GError **gerr);
#else
- class GIOChannelSocketSSL
+ class GIOChannelSocketGnuTLS
{
public:
- virtual ~GIOChannelSocketSSL ();
- GIOChannelSocketSSL () { debug("SocketSSL stub ctor"); }
-#endif // HAVE_OPENSSL
+ virtual ~GIOChannelSocketGnuTLS ();
+ GIOChannelSocketGnuTLS () { debug("SocketSSL stub ctor"); }
+#endif // HAVE_GNUTLS
};
}
diff --git a/pan/tasks/socket.h b/pan/tasks/socket.h
index efdf1f8..6947229 100644
--- a/pan/tasks/socket.h
+++ b/pan/tasks/socket.h
@@ -23,13 +23,8 @@
#include <string>
#include <config.h>
-#ifdef HAVE_OPENSSL
- #include <openssl/crypto.h>
- #include <openssl/x509.h>
- #include <openssl/x509v3.h>
- #include <openssl/pem.h>
- #include <openssl/ssl.h>
- #include <openssl/err.h>
+#ifdef HAVE_GNUTLS
+ #include <gnutls/gnutls.h>
#endif
namespace pan
diff --git a/pan/tasks/task-article.cc b/pan/tasks/task-article.cc
index 161f069..6a0bb8f 100644
--- a/pan/tasks/task-article.cc
+++ b/pan/tasks/task-article.cc
@@ -79,7 +79,9 @@ TaskArticle :: TaskArticle (const ServerRank & server_rank,
ArticleRead & read,
Progress::Listener * listener,
SaveMode save_mode,
- const Quark & save_path):
+ const Quark & save_path,
+ const char * filename,
+ const SaveOptions & options):
Task (save_path.empty() ? "BODIES" : "SAVE", get_description (article, !save_path.empty())),
_save_path (save_path),
_server_rank (server_rank),
@@ -90,8 +92,11 @@ TaskArticle :: TaskArticle (const ServerRank & server_rank,
_save_mode (save_mode),
_decoder(0),
_decoder_has_run (false),
- _groups(get_groups_str(article))
+ _groups(get_groups_str(article)),
+ _attachment(filename),
+ _options(options)
{
+
cache.reserve (article.get_part_mids());
if (listener != 0)
@@ -330,8 +335,8 @@ TaskArticle :: use_decoder (Decoder* decoder)
init_steps(100);
_state.set_working();
const Article::mid_sequence_t mids (_article.get_part_mids());
- const ArticleCache :: strings_t filenames (_cache.get_filenames (mids));
- _decoder->enqueue (this, _save_path, filenames, _save_mode);
+ ArticleCache :: strings_t filenames (_cache.get_filenames (mids));
+ _decoder->enqueue (this, _save_path, filenames, _save_mode, _options, _attachment);
set_status_va (_("Decoding %s"), _article.subject.c_str());
debug ("decoder thread was free, enqueued work");
}
diff --git a/pan/tasks/task-article.h b/pan/tasks/task-article.h
index 01afcf6..4494161 100644
--- a/pan/tasks/task-article.h
+++ b/pan/tasks/task-article.h
@@ -48,6 +48,12 @@ namespace pan
{
public: // life cycle
+ enum SaveOptions
+ {
+ SAVE_ALL,
+ SAVE_AS
+ };
+
enum SaveMode { NONE=0, DECODE=(1<<0), RAW=(1<<1) };
TaskArticle (const ServerRank & server_rank,
@@ -57,7 +63,9 @@ namespace pan
ArticleRead & read,
Progress::Listener* l=0,
SaveMode save_mode = NONE,
- const Quark & save_path = Quark());
+ const Quark & save_path = Quark(),
+ const char * filename=0,
+ const SaveOptions & options=SAVE_ALL);
virtual ~TaskArticle ();
time_t get_time_posted () const { return _time_posted; }
const Quark& get_save_path () const { return _save_path; }
@@ -95,6 +103,7 @@ namespace pan
quarks_t _servers;
const Article _article;
const time_t _time_posted;
+ StringView _attachment;
private: // implementation
const SaveMode _save_mode;
@@ -102,20 +111,7 @@ namespace pan
Decoder * _decoder;
bool _decoder_has_run;
std::string _groups;
-
- private:
-
-// typedef std::pair<std::string,StringView> lines_p;
-// typedef std::vector<lines_p> lines_v;
-//
-// struct CacheAdder
-// {
-// lines_v lines;
-// void add(std::string& q, const StringView& v)
-// { lines.push_back(lines_p(q,v)); }
-// };
-//
-// CacheAdder adder;
+ const SaveOptions _options;
struct Needed {
std::string message_id;
diff --git a/pan/usenet-utils/mime-utils.cc b/pan/usenet-utils/mime-utils.cc
index 34179ef..0433b53 100644
--- a/pan/usenet-utils/mime-utils.cc
+++ b/pan/usenet-utils/mime-utils.cc
@@ -1617,11 +1617,13 @@ namespace pan
if (info.type == GPG_VERIFY)
{
- GMimeSignatureList * sig_list = g_mime_multipart_signed_verify (mps, gpg_ctx, &info.err);
- if (sig_list) info.no_sigs = false;
- if (!sig_list) return false;
- fill_signer_info(info.signers, sig_list);
-
+ GMimeSignatureList * sigs = g_mime_multipart_signed_verify (mps, gpg_ctx, &info.err);
+ if (info.err || !sigs) return false;
+ if (sigs) info.no_sigs = false;
+ fill_signer_info(info.signers, sigs);
+ bool status = get_sig_status(sigs) == GMIME_SIGNATURE_STATUS_GOOD;
+ g_object_unref(sigs);
+ return status;
}
if (info.type == GPG_DECODE)
@@ -1635,12 +1637,14 @@ namespace pan
{
info.no_sigs = false;
fill_signer_info(info.signers, sigs);
+ bool status = get_sig_status(info.result->signatures) == GMIME_SIGNATURE_STATUS_GOOD;
+ g_object_unref(sigs);
+ return status;
}
-
+ return !info.err;
}
- return get_sig_status(info.result->signatures) == GMIME_SIGNATURE_STATUS_GOOD || !info.err;
-
+ return true;
}
enum
diff --git a/pan/usenet-utils/ssl-utils.h b/pan/usenet-utils/ssl-utils.h
index 51bf9a5..25ce687 100644
--- a/pan/usenet-utils/ssl-utils.h
+++ b/pan/usenet-utils/ssl-utils.h
@@ -5,11 +5,15 @@
* Copyright (C) 2002-2006 Charles Kerr <charles rebelbase com>
*
* This file
- * Copyright (C) 2011 Heinrich Mïller <sphemuel stud informatik uni-erlangen de>
+ * Copyright (C) 2011 Heinrich MÃller <sphemuel stud informatik uni-erlangen de>
* SSL functions : Copyright (C) 2002 vjt (irssi project)
* getTimeFromASN1 : Copyright (C) 2003 Jay Case,
* taken from : http://www.mail-archive.com/openssl-users openssl org/msg33365.html
*
+ * GnuTLS functions and code
+ * Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2010 Free Software
+ * Foundation, Inc.
+ *
* 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; version 2 of the License.
@@ -27,7 +31,7 @@
#ifndef _SSL_UTILS_H_
#define _SSL_UTILS_H_
-#ifdef HAVE_OPENSSL
+#ifdef HAVE_GNUTLS
#include <pan/data/cert-store.h>
#include <pan/tasks/socket.h>
@@ -36,15 +40,12 @@
#include <pan/general/string-view.h>
#include <pan/tasks/socket.h>
#include <pan/general/e-util.h>
-#include <openssl/crypto.h>
-#include <openssl/x509.h>
-#include <openssl/x509v3.h>
-#include <openssl/pem.h>
-#include <openssl/ssl.h>
-#include <openssl/err.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/openssl.h>
+#include <gnutls/x509.h>
#include <map>
-#include <iostream>
#include <sstream>
+#include <iostream>
extern "C" {
#include <glib/gi18n.h>
}
@@ -52,385 +53,56 @@ extern "C" {
namespace pan
{
- /* Checks if the given string has internal NUL characters. */
- static gboolean has_internal_nul(const char* str, int len) {
- /* Remove trailing nul characters. They would give false alarms */
- while (len > 0 && str[len-1] == 0)
- len--;
- return strlen(str) != len;
- }
-
- /* tls_dns_name - Extract valid DNS name from subjectAltName value */
- static const char *tls_dns_name(const GENERAL_NAME * gn)
- {
- const char *dnsname;
-
- /* We expect the OpenSSL library to construct GEN_DNS extension objects as
- ASN1_IA5STRING values. Check we got the right union member. */
- if (ASN1_STRING_type(gn->d.ia5) != V_ASN1_IA5STRING) {
- g_warning("Invalid ASN1 value type in subjectAltName");
- return NULL;
- }
-
- /* Safe to treat as an ASCII string possibly holding a DNS name */
- dnsname = (char *) ASN1_STRING_data(gn->d.ia5);
-
- if (has_internal_nul(dnsname, ASN1_STRING_length(gn->d.ia5))) {
- g_warning("Internal NUL in subjectAltName");
- return NULL;
- }
-
- return dnsname;
- }
-
- /* tls_text_name - extract certificate property value by name */
- static char *tls_text_name(X509_NAME *name, int nid)
- {
- int pos;
- X509_NAME_ENTRY *entry;
- ASN1_STRING *entry_str;
- int utf8_length;
- unsigned char *utf8_value;
- char *result;
-
- if (name == 0 || (pos = X509_NAME_get_index_by_NID(name, nid, -1)) < 0) {
- return NULL;
- }
-
- entry = X509_NAME_get_entry(name, pos);
- g_return_val_if_fail(entry != NULL, NULL);
- entry_str = X509_NAME_ENTRY_get_data(entry);
- g_return_val_if_fail(entry_str != NULL, NULL);
-
- /* Convert everything into UTF-8. It's up to OpenSSL to do something
- reasonable when converting ASCII formats that contain non-ASCII
- content. */
- if ((utf8_length = ASN1_STRING_to_UTF8(&utf8_value, entry_str)) < 0) {
- g_warning("Error decoding ASN.1 type=%d", ASN1_STRING_type(entry_str));
- return NULL;
- }
-
- if (has_internal_nul((char *)utf8_value, utf8_length)) {
- g_warning("NUL character in hostname in certificate");
- OPENSSL_free(utf8_value);
- return NULL;
- }
-
- result = g_strdup((char *) utf8_value);
- OPENSSL_free(utf8_value);
- return result;
- }
-
-
- /** check if a hostname in the certificate matches the hostname we used for the connection */
- static gboolean match_hostname(const char *cert_hostname, const char *hostname)
- {
- const char *hostname_left;
-
- if (!strcasecmp(cert_hostname, hostname)) { /* exact match */
- return TRUE;
- } else if (cert_hostname[0] == '*' && cert_hostname[1] == '.' && cert_hostname[2] != 0) { /* wildcard match */
- /* The initial '*' matches exactly one hostname component */
- hostname_left = strchr(hostname, '.');
- if (hostname_left != NULL && ! strcasecmp(hostname_left + 1, cert_hostname + 2)) {
- return TRUE;
- }
- }
- return FALSE;
- }
-
- static gboolean ssl_verify_hostname(X509 *cert, const char *hostname)
- {
- int gen_index, gen_count;
- gboolean matched = FALSE, has_dns_name = FALSE;
- const char *cert_dns_name;
- char *cert_subject_cn;
- const GENERAL_NAME *gn;
- STACK_OF(GENERAL_NAME) * gens;
-
- /* Verify the dNSName(s) in the peer certificate against the hostname. */
- gens = (STACK_OF(GENERAL_NAME) *) X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0);
- if (gens) {
- gen_count = sk_GENERAL_NAME_num(gens);
- for (gen_index = 0; gen_index < gen_count && !matched; ++gen_index) {
- gn = sk_GENERAL_NAME_value(gens, gen_index);
- if (gn->type != GEN_DNS)
- continue;
-
- /* Even if we have an invalid DNS name, we still ultimately
- ignore the CommonName, because subjectAltName:DNS is
- present (though malformed). */
- has_dns_name = TRUE;
- cert_dns_name = tls_dns_name(gn);
- if (cert_dns_name && *cert_dns_name) {
- matched = match_hostname(cert_dns_name, hostname);
- }
- }
-
- /* Free stack *and* member GENERAL_NAME objects */
- sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
- }
-
- if (has_dns_name) {
- if (! matched) {
- /* The CommonName in the issuer DN is obsolete when SubjectAltName is available. */
- g_warning("None of the Subject Alt Names in the certificate match hostname '%s'", hostname);
- }
- return matched;
- } else { /* No subjectAltNames, look at CommonName */
- cert_subject_cn = tls_text_name(X509_get_subject_name(cert), NID_commonName);
- if (cert_subject_cn && *cert_subject_cn) {
- matched = match_hostname(cert_subject_cn, hostname);
- if (! matched) {
- g_warning("SSL certificate common name '%s' doesn't match host name '%s'", cert_subject_cn, hostname);
- }
- } else {
- g_warning("No subjectAltNames and no valid common name in certificate");
- }
- free(cert_subject_cn);
- }
-
- return matched;
- }
-
- static gboolean ssl_verify(CertStore* cs, SSL *ssl, SSL_CTX *ctx, const char* hostname, X509 *cert)
- {
- long result;
-
- result = SSL_get_verify_result(ssl);
- if (result == X509_V_ERR_CERT_HAS_EXPIRED && cs->is_ignored(cert)) return true;
- if (result != X509_V_OK) {
- unsigned char md[EVP_MAX_MD_SIZE];
- unsigned int n;
- char *str(0);
-
- g_warning("Could not verify SSL servers certificate: %s",
- X509_verify_cert_error_string(result));
- if ((str = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0)) == NULL)
- g_warning(" Could not get subject-name from peer certificate");
- else {
- g_warning(" Subject : %s", str);
- free(str);
- }
- if ((str = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0)) == NULL)
- g_warning(" Could not get issuer-name from peer certificate");
- else {
- g_warning(" Issuer : %s", str);
- free(str);
- }
- if (! X509_digest(cert, EVP_md5(), md, &n))
- g_warning(" Could not get fingerprint from peer certificate");
- else {
- char hex[] = "0123456789ABCDEF";
- char fp[EVP_MAX_MD_SIZE*3];
- if (n < sizeof(fp)) {
- unsigned int i;
- for (i = 0; i < n; i++) {
- fp[i*3+0] = hex[(md[i] >> 4) & 0xF];
- fp[i*3+1] = hex[(md[i] >> 0) & 0xF];
- fp[i*3+2] = i == n - 1 ? '\0' : ':';
- }
- g_warning(" MD5 Fingerprint : %s", fp);
- }
- }
- return FALSE;
- } else if (! ssl_verify_hostname(cert, hostname)){
- return FALSE;
- }
- return TRUE;
- }
-
- static std::map<int, Quark> ssl_err;
- static int map_init(0);
- typedef std::pair<int, Quark> err_p;
-
- static void init_err_map()
- {
- ssl_err.insert(err_p(2,"X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT"));
- ssl_err.insert(err_p(3,"X509_V_ERR_UNABLE_TO_GET_CRL"));
- ssl_err.insert(err_p(4,"X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE"));
- ssl_err.insert(err_p(5,"X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE"));
- ssl_err.insert(err_p(6,"X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY"));
- ssl_err.insert(err_p(7,"X509_V_ERR_CERT_SIGNATURE_FAILURE"));
- ssl_err.insert(err_p(8,"X509_V_ERR_CRL_SIGNATURE_FAILURE"));
- ssl_err.insert(err_p(9,"X509_V_ERR_CERT_NOT_YET_VALID"));
- ssl_err.insert(err_p(10,"X509_V_ERR_CERT_HAS_EXPIRED"));
- ssl_err.insert(err_p(11,"X509_V_ERR_CRL_NOT_YET_VALID"));
- ssl_err.insert(err_p(12,"X509_V_ERR_CRL_HAS_EXPIRED"));
- ssl_err.insert(err_p(13,"X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD"));
- ssl_err.insert(err_p(14,"X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD"));
- ssl_err.insert(err_p(15,"X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD"));
- ssl_err.insert(err_p(16,"X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD"));
- ssl_err.insert(err_p(17,"X509_V_ERR_OUT_OF_MEM"));
- ssl_err.insert(err_p(18,"X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT"));
- ssl_err.insert(err_p(19,"X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN"));
- ssl_err.insert(err_p(20,"X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY "));
- ssl_err.insert(err_p(21,"X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE "));
- ssl_err.insert(err_p(22,"X509_V_ERR_CERT_CHAIN_TOO_LONG"));
- ssl_err.insert(err_p(23,"X509_V_ERR_CERT_REVOKED"));
- ssl_err.insert(err_p(24,"X509_V_ERR_INVALID_CA"));
- ssl_err.insert(err_p(25,"X509_V_ERR_PATH_LENGTH_EXCEEDED"));
- ssl_err.insert(err_p(26,"X509_V_ERR_INVALID_PURPOSE"));
- ssl_err.insert(err_p(27,"X509_V_ERR_CERT_UNTRUSTED"));
- ssl_err.insert(err_p(28,"X509_V_ERR_CERT_REJECTED"));
- }
-
- static const Quark
- ssl_err_to_string(int i)
- {
- if (map_init++ == 0) init_err_map();
- Quark ret;
- if (ssl_err.count(i)) return ssl_err[i];
- return ret;
- }
-
- static time_t
- getTimeFromASN1(const ASN1_TIME * aTime)
- {
- time_t lResult = 0;
- char lBuffer[24];
- char * pBuffer = lBuffer;
- size_t lTimeLength = aTime->length;
- char * pString = (char *)aTime->data;
-
- if (aTime->type == V_ASN1_UTCTIME)
- {
- if ((lTimeLength < 11) || (lTimeLength > 17)) return 0;
- memcpy(pBuffer, pString, 10);
- pBuffer += 10;
- pString += 10;
- }
- else
- {
- if (lTimeLength < 13) return 0;
- memcpy(pBuffer, pString, 12);
- pBuffer += 12;
- pString += 12;
- }
-
-
- if ((*pString == 'Z') || (*pString == '-') || (*pString == '+'))
- {
- *(pBuffer++) = '0';
- *(pBuffer++) = '0';
- }
- else
- {
- *(pBuffer++) = *(pString++);
- *(pBuffer++) = *(pString++);
- // Skip any fractional seconds...
- if (*pString == '.')
- {
- pString++;
- while ((*pString >= '0') && (*pString <= '9'))
- pString++;
- }
- }
-
- *(pBuffer++) = 'Z';
- *(pBuffer++) = '\0';
-
- time_t lSecondsFromUCT;
- if (*pString == 'Z')
- lSecondsFromUCT = 0;
- else
- {
- if ((*pString != '+') && (pString[5] != '-')) return 0;
- lSecondsFromUCT = ((pString[1]-'0') * 10 + (pString[2]-'0')) * 60;
- lSecondsFromUCT += (pString[3]-'0') * 10 + (pString[4]-'0');
- if (*pString == '-')
- lSecondsFromUCT = -lSecondsFromUCT;
- }
-
- tm lTime;
- lTime.tm_sec = ((lBuffer[10] - '0') * 10) + (lBuffer[11] - '0');
- lTime.tm_min = ((lBuffer[8] - '0') * 10) + (lBuffer[9] - '0');
- lTime.tm_hour = ((lBuffer[6] - '0') * 10) + (lBuffer[7] - '0');
- lTime.tm_mday = ((lBuffer[4] - '0') * 10) + (lBuffer[5] - '0');
- lTime.tm_mon = (((lBuffer[2] - '0') * 10) + (lBuffer[3] - '0')) - 1;
- lTime.tm_year = ((lBuffer[0] - '0') * 10) + (lBuffer[1] - '0');
- if (lTime.tm_year < 50)
- lTime.tm_year += 100; // RFC 2459
- lTime.tm_wday = 0;
- lTime.tm_yday = 0;
- lTime.tm_isdst = 0; // No DST adjustment requested
-
- lResult = mktime(&lTime);
-
- if ((time_t)-1 != lResult)
- {
- if (0 != lTime.tm_isdst)
- lResult -= 3600; // mktime may adjust for DST (OS dependent)
- lResult += lSecondsFromUCT;
- }
- else
- lResult = 0;
- return lResult;
- }
-
-
- static std::string
- get_x509_fingerpint_md5(X509* cert)
- {
- std::string res;
- unsigned char md[EVP_MAX_MD_SIZE];
- unsigned int n;
-
- if (! X509_digest(cert, EVP_md5(), md, &n))
- res = _("Not available.");
- else {
- char hex[] = "0123456789ABCDEF";
- char fp[EVP_MAX_MD_SIZE*3];
- if (n < sizeof(fp)) {
- unsigned int i;
- for (i = 0; i < n; i++) {
- fp[i*3+0] = hex[(md[i] >> 4) & 0xF];
- fp[i*3+1] = hex[(md[i] >> 0) & 0xF];
- fp[i*3+2] = i == n - 1 ? '\0' : ':';
- }
- res = fp;
- }
- }
- return res;
- }
-
typedef std::pair<Quark,Quark> quarks_p;
typedef std::map<Quark,Quark>::iterator tags_it;
const static char* tags_idx[] =
{
- "/L=",
- "/CN=",
- "/C=",
- "/OU=",
- "/O=",
- "/ST=",
- "/EMAIL=",
- "/emailAddress="
+ ",L=",
+ ",CN=",
+ ",C=",
+ ",OU=",
+ ",O=",
+ ",ST=",
+ ",EMAIL=",
+ ",emailAddress=",
+ ",serialNumber="
};
const static char* cleaned_tags[] =
{
- "L", "CN", "C", "OU", "O", "ST", "EMAIL", "emailAdress"
+ "L", "CN", "C", "OU", "O", "ST", "EMAIL", "emailAdress", "serialNumber"
};
struct CertParser
{
- X509* cert;
std::map<Quark, Quark> tags;
- char* issuer, * subject;
std::string iss, sub;
int pos1, pos2, tmp_pos1, idx;
- char buf[256];
+ char buf[2048];
+ char * dn_buf;
size_t num_tags;
const char delim;
+ size_t len;
+ gnutls_datum_t d;
+ gnutls_x509_crt_t cert;
+ gnutls_x509_dn_t dn;
+ size_t size;
- CertParser(X509* c) : cert(c), delim('/'), pos1(0), pos2(0), idx(0), num_tags(G_N_ELEMENTS(tags_idx))
+ CertParser(gnutls_x509_crt_t c) : cert(c), delim(','), pos1(0), pos2(0), idx(0), num_tags(G_N_ELEMENTS(tags_idx))
{
- issuer = X509_NAME_oneline(X509_get_issuer_name(c),0, 0);
- subject = X509_NAME_oneline(X509_get_subject_name(c), 0, 0);
- iss = issuer;
- sub = subject;
+
+ gnutls_x509_crt_get_issuer_dn(cert,NULL, &size);
+ dn_buf = new char[size];
+ gnutls_x509_crt_get_issuer_dn(cert,dn_buf, &size);
+ iss = dn_buf;
+ delete dn_buf;
+
+ gnutls_x509_crt_get_subject_unique_id(cert, NULL, &size);
+ dn_buf = new char[size];
+ gnutls_x509_crt_get_subject_unique_id(cert, dn_buf, &size);
+ sub = dn_buf;
+ delete dn_buf;
/* init map */
int i(0);
@@ -442,11 +114,12 @@ namespace pan
tags.insert(quarks_p(cleaned_tags[i++],"State"));
tags.insert(quarks_p(cleaned_tags[i++],"Email Address"));
tags.insert(quarks_p(cleaned_tags[i],"Email Address"));
+ tags.insert(quarks_p(cleaned_tags[i],"serialNumber"));
}
void parse(std::vector<quarks_p>& i, std::vector<quarks_p>& s)
{
- while(idx<num_tags)
+ while(idx < num_tags)
{
std::string::size_type index = iss.find(tags_idx[idx]);
if(index != std::string::npos)
@@ -505,29 +178,35 @@ namespace pan
~CertParser ()
{
- free(issuer);
- free(subject);
}
};
+ static std::string escaped (const std::string& s)
+ {
+ char * pch = g_markup_escape_text (s.c_str(), s.size());
+ const std::string ret (pch);
+ g_free (pch);
+ return ret;
+ }
+
static void
- pretty_print_x509 (char* buf, size_t size, const Quark& server, X509* cert, bool on_connect)
+ pretty_print_x509 (char* buf, size_t size, const Quark& server, gnutls_x509_crt_t c, bool on_connect)
{
- if (!cert)
+ if (!c)
{
g_snprintf(buf,size, _("Error printing the server certificate for '%s'"), server.c_str());
return;
}
- struct CertParser cp(cert);
+ CertParser cp(c);
std::vector<quarks_p> p_issuer, p_subject;
cp.parse(p_issuer, p_subject);
- time_t t = getTimeFromASN1(cert->cert_info->validity->notAfter);
- time_t t2 = getTimeFromASN1(cert->cert_info->validity->notBefore);
+ time_t t = gnutls_x509_crt_get_expiration_time(c);
+ time_t t2 = gnutls_x509_crt_get_activation_time(c);
EvolutionDateMaker date_maker;
char * until = date_maker.get_date_string (t);
char * before = date_maker.get_date_string (t2);
@@ -536,54 +215,32 @@ namespace pan
char tmp1[2048], tmp2[2048];
g_snprintf(tmp1,sizeof(tmp1), "The current server <b>'%s'</b> sent this security certificate :\n\n", server.c_str());
g_snprintf(tmp2,sizeof(tmp2), "Certificate information for server <b>'%s'</b> :\n\n", server.c_str());
+ size_t md5_size;
+ gnutls_x509_crt_get_fingerprint(c, GNUTLS_DIG_MD5, NULL, &md5_size);
+ char * md5_buf = new char[size];
+ gnutls_x509_crt_get_fingerprint(c, GNUTLS_DIG_MD5, md5_buf, &md5_size);
+
+ g_snprintf(buf,size, _("%s"
+ "<b>Issuer information:</b>\n"
+ "%s\n"
+ //"<b>Subject information: </b>\n"
+ //"%s\n"
+ "<b>Valid until : </b>%s\n\n"
+ "<b>Not valid before : </b>%s\n\n"),
+ //"<b>Fingerprint (MD5) : </b>\n%s\n\n"),
+ on_connect ? tmp1 : tmp2,
+ cp.build_complete(p_issuer).c_str(),
+ //cp.build_complete(p_subject).c_str(),
+ until,
+ before);
+// md5_buf);
+
+ g_free (before);
+ g_free (until);
+ delete md5_buf;
- g_snprintf(buf,size, _( "%s"
- "<b>Issuer information:</b>\n"
- "%s\n"
- "<b>Subject information: </b>\n"
- "%s\n"
- "<b>Valid until : </b>%s\n\n"
- "<b>Not valid before : </b>%s\n\n"
- "<b>Fingerprint (MD5) : </b>\n%s\n\n"),
- on_connect ? tmp1 : tmp2,
- cp.build_complete(p_issuer).c_str(),
- cp.build_complete(p_subject).c_str(),
- until,
- before,
- get_x509_fingerpint_md5(cert).c_str());
-
- }
-
-
- typedef std::multimap<std::string, Socket*> socks_m;
- typedef std::pair<std::string, Socket*> socks_p;
-
- static void delete_all_socks(socks_m& socket_map, std::string server)
- {
-
- for (socks_m::iterator it = socket_map.begin(); it != socket_map.end();)
- {
- std::cerr<<it->first<<" "<<it->second<<std::endl;
- if (it->first == server)
- {
- it->second->set_abort_flag(true);
- socket_map.erase(it++);
- } else
- ++it;
- }
}
- static void delete_sock(socks_m& socket_map, Socket* sock)
- {
- for (socks_m::iterator it = socket_map.begin(); it != socket_map.end();)
- {
- if (it->second == sock)
- {
- delete it->second;
- socket_map.erase(it);
- }
- }
- }
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]