[balsa] IMAP goes GIO



commit d964df60bbd85b00269da62b99bf2ce57ae442cc
Author: Albrecht Dreß <albrecht dress arcor de>
Date:   Tue Jun 5 22:05:31 2018 -0400

    IMAP goes GIO
    
    Changes to libnetclient/*:
    As I mentioned above, in the libnetclient library I added a module
    which “simulates” the character-buffering methods of libbalsa/imap/siobuf.[hc].
    Other improvements include:
    - transparent compression (RFC 4978) support – which revealed a bug
      in GIO sending crap when finalising the connection.
      This is not really harmful, but may confuse a network-based IDS
      (see <https://bugzilla.gnome.org/show_bug.cgi?id=795985>);
    - helper function for wiping auth data with random chars
      before freeing the string;
    - improved unit tests.
    
    Changes to libbalsa/imap/*:
    - siobuf.[hc] are removed, siobuf-nc.h providing a “glue layer”
      for libnetclient is added
    - auth-cram.c, imap-auth.[ch]: partly re-written; uses libnetclient signals;
      replace fixed-length strings by dynamically allocated glib strings
      which is safer; simplifications by using libnetclient functions
    - auth-gssapi.c: simplified by using libnetclient helpers;
      glib strings as above
    - imap-commands.c, imap-handle.[ch], imap_search.c, imap_tst.c:
      simplifications by using libnetclient functions, removed some unused functions
    - imap-tls.c, imap_compress.[ch]: massive simplification
      as all “real” work is implemented in GIO via libnetclient
    - imap_private.h: modification of struct _ImapMboxHandle
      to use libnetclient stuff, and remove obsolete fields
    - util.c: simplified quoting function, removed unused unquoting
    In all modules, I replaced the mixture of debugging functions ([f]printf)
    by g_debug etc.
    
    Changes to libbalsa/*:
    - imap-server.c: cleaned up unused monitor cb, use unified security
      (from libnetclient) instead of separate ssl/tls settings
    - libbalsa.c: replace OpenSSL-based certificate functions
      by GTlsCertificate and GnuTLS (if GCR is not available,
      remember that GIO is based on GnuTLS)
    - misc.c: tiny improvement for assuring ~/.balsa
    - server.[ch]: use NetClientCryptMode instead of use_ssl and tls_mode;
      remove obsolete libbalsa_server_user_cb (replaced by libnetclient's signals);
      simplify libbalsa_server_check_cert
    - smtp-server.c: use changed server api
    
    Changes to libinit_balsa/*:
    - assistant_page_user.c: use changed server api
    
    Changes to src/*:
    - folder-conf.c: configure IMAP according to changed server api
      (note: widget (de)activation logic not yet fully functional)
    - src/mailbox-conf.[ch]: ditto, but with a working (de)activation logic
      (I think)
    - mailbox-node.c: use g_debug instead of printf
    - main.c: remove IMAP debug option (use G_MESSAGES_DEBUG, as always)
    - save-restore.c: remove obsolete item
    
    On the top-level:
    - the configure/meson checks for OpenSSL and ZLib have been removed
    
    Signed-off-by: Peter Bloomfield <PeterBloomfield bellsouth net>

 ChangeLog                              |  61 +++
 configure.ac                           |  16 -
 libbalsa/imap-server.c                 |  85 +---
 libbalsa/imap-server.h                 |   1 -
 libbalsa/imap/Makefile.am              |   4 +-
 libbalsa/imap/auth-cram.c              |  55 ++-
 libbalsa/imap/auth-gssapi.c            | 393 +++++-------------
 libbalsa/imap/imap-auth.c              | 154 ++++---
 libbalsa/imap/imap-auth.h              |   2 -
 libbalsa/imap/imap-commands.c          |  48 +--
 libbalsa/imap/imap-handle.c            | 689 +++++++++++--------------------
 libbalsa/imap/imap-handle.h            |  16 +-
 libbalsa/imap/imap-tls.c               | 357 +---------------
 libbalsa/imap/imap_compress.c          | 171 +-------
 libbalsa/imap/imap_compress.h          |  14 -
 libbalsa/imap/imap_private.h           |  41 +-
 libbalsa/imap/imap_search.c            |  28 +-
 libbalsa/imap/imap_tst.c               | 101 ++---
 libbalsa/imap/libimap.h                |   8 -
 libbalsa/imap/siobuf.c                 | 728 ---------------------------------
 libbalsa/imap/siobuf.h                 |  88 ----
 libbalsa/imap/util.c                   |  81 +---
 libbalsa/imap/util.h                   |   6 +-
 libbalsa/libbalsa.c                    | 398 +++++++++---------
 libbalsa/libbalsa.h                    |   6 +-
 libbalsa/misc.c                        |   4 +-
 libbalsa/send.c                        |   2 +-
 libbalsa/server.c                      | 199 +++------
 libbalsa/server.h                      |  16 +-
 libbalsa/smtp-server.c                 |   4 +-
 libinit_balsa/assistant_page_user.c    |  20 +-
 libnetclient/Makefile.am               |   2 +
 libnetclient/meson.build               |   2 +
 libnetclient/net-client-pop.c          |  26 +-
 libnetclient/net-client-smtp.c         |  20 +-
 libnetclient/net-client-utils.c        |  25 +-
 libnetclient/net-client-utils.h        |  10 +
 libnetclient/net-client.c              | 103 ++++-
 libnetclient/net-client.h              |  34 ++
 libnetclient/test/Makefile.am          |   5 +-
 libnetclient/test/echoserver.py        |  12 +-
 libnetclient/test/start-test-env.sh.in |   4 +-
 libnetclient/test/tests.c              | 193 ++++++++-
 meson.build                            |  37 --
 src/ab-window.c                        |   1 +
 src/folder-conf.c                      |  57 ++-
 src/mailbox-conf.c                     | 242 ++++-------
 src/mailbox-conf.h                     |  14 +-
 src/mailbox-node.c                     |   5 +-
 src/main.c                             |   2 -
 src/save-restore.c                     |   3 -
 51 files changed, 1441 insertions(+), 3152 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index ead4e43c..5c273bad 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,64 @@
+2018-06-05  Albrecht Dreß <albrecht dress arcor de>
+
+       IMAP goes GIO
+
+       Changes to libnetclient/*:
+       As I mentioned above, in the libnetclient library I added a module
+       which “simulates” the character-buffering methods of libbalsa/imap/siobuf.[hc].
+       Other improvements include:
+       - transparent compression (RFC 4978) support – which revealed a bug
+         in GIO sending crap when finalising the connection.
+         This is not really harmful, but may confuse a network-based IDS
+         (see <https://bugzilla.gnome.org/show_bug.cgi?id=795985>);
+       - helper function for wiping auth data with random chars
+         before freeing the string;
+       - improved unit tests.
+
+       Changes to libbalsa/imap/*:
+       - siobuf.[hc] are removed, siobuf-nc.h providing a “glue layer”
+         for libnetclient is added
+       - auth-cram.c, imap-auth.[ch]: partly re-written; uses libnetclient signals;
+         replace fixed-length strings by dynamically allocated glib strings
+         which is safer; simplifications by using libnetclient functions
+       - auth-gssapi.c: simplified by using libnetclient helpers;
+         glib strings as above
+       - imap-commands.c, imap-handle.[ch], imap_search.c, imap_tst.c:
+         simplifications by using libnetclient functions, removed some unused functions
+       - imap-tls.c, imap_compress.[ch]: massive simplification
+         as all “real” work is implemented in GIO via libnetclient
+       - imap_private.h: modification of struct _ImapMboxHandle
+         to use libnetclient stuff, and remove obsolete fields
+       - util.c: simplified quoting function, removed unused unquoting
+       In all modules, I replaced the mixture of debugging functions ([f]printf)
+       by g_debug etc.
+
+       Changes to libbalsa/*:
+       - imap-server.c: cleaned up unused monitor cb, use unified security
+         (from libnetclient) instead of separate ssl/tls settings
+       - libbalsa.c: replace OpenSSL-based certificate functions
+         by GTlsCertificate and GnuTLS (if GCR is not available,
+         remember that GIO is based on GnuTLS)
+       - misc.c: tiny improvement for assuring ~/.balsa
+       - server.[ch]: use NetClientCryptMode instead of use_ssl and tls_mode;
+         remove obsolete libbalsa_server_user_cb (replaced by libnetclient's signals);
+         simplify libbalsa_server_check_cert
+       - smtp-server.c: use changed server api
+
+       Changes to libinit_balsa/*:
+       - assistant_page_user.c: use changed server api
+
+       Changes to src/*:
+       - folder-conf.c: configure IMAP according to changed server api
+         (note: widget (de)activation logic not yet fully functional)
+       - src/mailbox-conf.[ch]: ditto, but with a working (de)activation logic
+         (I think)
+       - mailbox-node.c: use g_debug instead of printf
+       - main.c: remove IMAP debug option (use G_MESSAGES_DEBUG, as always)
+       - save-restore.c: remove obsolete item
+
+       On the top-level:
+       - the configure/meson checks for OpenSSL and ZLib have been removed
+
 2018-06-05  Peter Bloomfield  <pbloomfield bellsouth net>
 
        * libbalsa/address-book-rubrica.c (extract_net): Fix a typo that
diff --git a/configure.ac b/configure.ac
index 8545a5f6..125af2e0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -233,9 +233,6 @@ dnl #####################################################################
 dnl 4. Libraries.
 dnl #####################################################################
 
-dnl Make sure ld finds zlib:
-LIBS="$LIBS -lz"
-
 PKG_CHECK_MODULES(BALSA, [
 glib-2.0 >= 2.40.0
 gtk+-3.0 >= 3.10.0
@@ -451,18 +448,6 @@ else
     AC_MSG_RESULT([no])
 fi
 
-# OpenSSL configuration.
-#
-PKG_CHECK_MODULES(OPENSSL, [openssl],
-   [BALSA_CFLAGS="$OPENSSL_CFLAGS $BALSA_CFLAGS"
-    BALSA_LIBS="$OPENSSL_LIBS $BALSA_LIBS"],
-   [ AC_CHECK_HEADERS([openssl/ssl.h], [],
-                      [AC_MSG_ERROR([OpenSSL headers not found])], [])
-     AC_SEARCH_LIBS(SSL_library_init, ssl,
-                    [BALSA_LIBS="$BALSA_LIBS -lssl -lcrypto"],
-                    [AC_MSG_ERROR([libssl not found])], [-lcrypto]) ]
-)
-
 # KRB5/GSSAPI configuration.
 #
 if test "x$with_gss" != xno  ; then
@@ -626,7 +611,6 @@ AC_STDC_HEADERS
 
 AC_CHECK_DECLS([ctime_r], [], [], [[#include <time.h>]])
 AC_CHECK_FUNCS([ctime_r])
-AC_CHECK_HEADER([zlib.h],,AC_MSG_ERROR([zlib library required]))
 
 # more warnings.
 #
diff --git a/libbalsa/imap-server.c b/libbalsa/imap-server.c
index 6a8ad02b..638b350e 100644
--- a/libbalsa/imap-server.c
+++ b/libbalsa/imap-server.c
@@ -42,8 +42,6 @@
 #include "imap-commands.h"
 #include <glib/gi18n.h>
 
-#define REQ_SSL(s) (LIBBALSA_SERVER(s)->use_ssl)
-
 /** wait 60 seconds for packets */
 #define IMAP_CMD_TIMEOUT (60*1000)
 
@@ -150,8 +148,9 @@ static void libbalsa_imap_server_set_username(LibBalsaServer * server,
     (parent_class)->set_username(server, name);
 }
 static void
-libbalsa_imap_server_set_host(LibBalsaServer * server,
-                              const gchar * host, gboolean use_ssl)
+libbalsa_imap_server_set_host(LibBalsaServer     *server,
+                              const gchar        *host,
+                                                         NetClientCryptMode  security)
 {
     if(server->user && host) { /* we have been initialized... */
         LibBalsaImapServer *imap_server = LIBBALSA_IMAP_SERVER(server);
@@ -162,7 +161,7 @@ libbalsa_imap_server_set_host(LibBalsaServer * server,
         g_hash_table_insert(imap_servers, imap_server->key, imap_server);
         g_mutex_unlock(&imap_servers_lock);
     }
-    (parent_class)->set_host(server, host, use_ssl);
+    (parent_class)->set_host(server, host, security);
 }
 static void
 libbalsa_imap_server_class_init(LibBalsaImapServerClass * klass)
@@ -224,55 +223,6 @@ libbalsa_imap_server_finalize(GObject * object)
     G_OBJECT_CLASS(parent_class)->finalize(object);
 }
 
-gint ImapDebug = 0;
-#define BALSA_TEST_IMAP 1
-
-static void
-monitor_cb(const char *buffer, int length, int direction, void *arg)
-{
-#if BALSA_TEST_IMAP
-  if (ImapDebug) {
-    const gchar *passwd = NULL;
-    int i;
-
-    if (direction) {
-      const gchar *login;
-      int login_length;
-          
-      login = g_strstr_len(buffer, length, "LOGIN ");
-      if (login) {
-        login_length = 6;
-      } else {
-        login = g_strstr_len(buffer, length, "AUTHENTICATE PLAIN");
-        login_length = 18;
-      }
-
-      if (login) {
-        const gchar *user = login + login_length;
-        passwd = g_strstr_len(user, length - (user - buffer), " ");
-        if (passwd) {
-          int new_len = ++passwd - buffer;
-          if (new_len < length)
-            length = new_len;
-          else
-            passwd = NULL;
-        }
-      }
-    }
-
-    printf("IMAP %c: ", direction ? 'C' : 'S');
-    for (i = 0; i < length; i++)
-      putchar(buffer[i]);
-
-    if (passwd)
-      puts("(password hidden)");
-
-    fflush(NULL);
-  }
-#endif                          /* BALSA_TEST_IMAP */
-  if (direction)
-    ((struct handle_info *) arg)->last_used = time(NULL);
-}
 
 static void
 is_info_cb(ImapMboxHandle *h, ImapResponse rc, const gchar* str, void *arg)
@@ -307,7 +257,6 @@ lb_imap_server_info_new(LibBalsaServer *server)
 {
     ImapMboxHandle *handle;
     struct handle_info *info;
-    ImapTlsMode mode;
 
     /* We do not ask for password now since the authentication might
      * not require it. Instead, we handle authentication requiests in
@@ -317,16 +266,10 @@ lb_imap_server_info_new(LibBalsaServer *server)
     imap_handle_set_timeout(handle, IMAP_CMD_TIMEOUT);
     info = g_new0(struct handle_info, 1);
     info->handle = handle;
-    imap_handle_set_monitorcb(handle, monitor_cb, info);
     imap_handle_set_infocb(handle,    is_info_cb, server);
-    imap_handle_set_usercb(handle,    libbalsa_server_user_cb, server);
-    switch(server->tls_mode) {
-    case LIBBALSA_TLS_DISABLED: mode = IMAP_TLS_DISABLED; break;
-    default:
-    case LIBBALSA_TLS_ENABLED : mode = IMAP_TLS_ENABLED;  break;
-    case LIBBALSA_TLS_REQUIRED: mode = IMAP_TLS_REQUIRED; break;
-    }
-    imap_handle_set_tls_mode(handle, mode);
+    imap_handle_set_authcb(handle, G_CALLBACK(libbalsa_server_get_auth), server);
+    imap_handle_set_certcb(handle, G_CALLBACK(libbalsa_server_check_cert));
+    imap_handle_set_tls_mode(handle, server->security);
     imap_handle_set_option(handle, IMAP_OPT_ANONYMOUS, server->try_anonymous);
     imap_handle_set_option(handle, IMAP_OPT_CLIENT_SORT, TRUE);
 #ifdef HAVE_GPGME
@@ -349,7 +292,7 @@ lb_imap_server_info_free(struct handle_info *info)
 {
     g_assert(info != NULL);
 
-    imap_handle_force_disconnect(info->handle);
+    //imap_handle_force_disconnect(info->handle); -- FIXME unref'ing handle will disconnect?
     g_object_unref(info->handle);
     g_free(info);
 }
@@ -468,7 +411,7 @@ libbalsa_imap_server_new_from_config(void)
     LibBalsaImapServer *imap_server;
     LibBalsaServer *server;
     gboolean d, d1;
-    gint tls_mode, conn_limit;
+    gint conn_limit;
 
     tmp_server.host = libbalsa_conf_get_string("Server");
     if(strrchr(tmp_server.host, ':') == NULL) {
@@ -495,9 +438,7 @@ libbalsa_imap_server_new_from_config(void)
     }
     d1 = libbalsa_conf_get_bool_with_default("Anonymous", &d);
     if(!d) server->try_anonymous = !!d1;
-    server->use_ssl |= libbalsa_conf_get_bool("SSL=false");
-    tls_mode = libbalsa_conf_get_int_with_default("TLSMode", &d);
-    if(!d) server->tls_mode = tls_mode;
+    libbalsa_server_load_security_config(server);
     conn_limit = libbalsa_conf_get_int_with_default("ConnectionLimit", &d);
     if(!d) imap_server->max_connections = conn_limit;
     d1 = libbalsa_conf_get_bool_with_default("PersistentCache", &d);
@@ -662,8 +603,7 @@ libbalsa_imap_server_get_handle(LibBalsaImapServer *imap_server, GError **err)
         if(imap_mbox_is_disconnected(info->handle)) {
             ImapResult rc;
 
-            rc=imap_mbox_handle_connect(info->handle, server->host,
-                                        REQ_SSL(server));
+            rc=imap_mbox_handle_connect(info->handle, server->host);
             if(rc != IMAP_SUCCESS) {
                 handle_connection_error(rc, info, server, err);
                 g_mutex_unlock(&imap_server->lock);
@@ -760,8 +700,7 @@ libbalsa_imap_server_get_handle_with_user(LibBalsaImapServer *imap_server,
     if (imap_mbox_is_disconnected(info->handle)) {
         ImapResult rc;
 
-        rc=imap_mbox_handle_connect(info->handle, server->host,
-                                    REQ_SSL(server));
+        rc=imap_mbox_handle_connect(info->handle, server->host);
         if(rc != IMAP_SUCCESS) {
             handle_connection_error(rc, info, server, err);
             g_mutex_unlock(&imap_server->lock);
diff --git a/libbalsa/imap-server.h b/libbalsa/imap-server.h
index 03e285d9..220d02e1 100644
--- a/libbalsa/imap-server.h
+++ b/libbalsa/imap-server.h
@@ -80,5 +80,4 @@ void libbalsa_imap_server_set_use_idle(LibBalsaImapServer *server,
                                        gboolean use_idle);
 gboolean libbalsa_imap_server_get_use_idle(LibBalsaImapServer *server);
 
-extern gint ImapDebug;
 #endif /* __IMAP_SERVER_H__ */
diff --git a/libbalsa/imap/Makefile.am b/libbalsa/imap/Makefile.am
index f379389c..7f3a7c79 100644
--- a/libbalsa/imap/Makefile.am
+++ b/libbalsa/imap/Makefile.am
@@ -33,8 +33,7 @@ libimap_a_SOURCES = \
        libimap-marshal.c       \
        libimap-marshal.h       \
        libimap.h       \
-       siobuf.c        \
-       siobuf.h        \
+       siobuf-nc.h     \
        util.c          \
        util.h
 
@@ -44,6 +43,7 @@ EXTRA_DIST = \
 AM_CPPFLAGS = -I${top_builddir} -I${top_srcdir} -I${top_srcdir}/libbalsa \
        -I${top_srcdir}/libnetclient \
        -I${top_srcdir}/libbalsa/imap \
+       -DG_LOG_DOMAIN=\"imap\" \
        $(BALSA_CFLAGS)
 
 AM_CFLAGS   = $(LIBIMAP_CFLAGS) -ansi
diff --git a/libbalsa/imap/auth-cram.c b/libbalsa/imap/auth-cram.c
index c56e11a6..980662a6 100644
--- a/libbalsa/imap/auth-cram.c
+++ b/libbalsa/imap/auth-cram.c
@@ -21,37 +21,30 @@
 
 /* IMAP login/authentication code */
 
-#include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
-#include <glib.h>
 
 #include "imap-auth.h"
 #include "net-client-utils.h"
 
 #include "imap_private.h"
 
-#define LONG_STRING 1024
-
 /* imap_auth_cram_md5: AUTH=CRAM-MD5 support. */
 ImapResult
 imap_auth_cram(ImapMboxHandle* handle)
 {
-  char ibuf[LONG_STRING*2];
+  gchar *challenge;
   gchar *auth_buf;
   unsigned cmdno;
-  int rc, ok;
-  char *user = NULL, *pass = NULL;
+  int rc;
+  gchar **auth_data;
 
   if (!imap_mbox_handle_can_do(handle, IMCAP_ACRAM_MD5))
     return IMAP_AUTH_UNAVAIL;
 
-  ok = 0;
-  if(!ok && handle->user_cb)
-    handle->user_cb(IME_GET_USER_PASS, handle->user_arg, 
-                    "CRAM-MD5", &user, &pass, &ok);
-  if(!ok || user == NULL || pass == NULL) {
+  g_signal_emit_by_name(handle->sio, "auth", TRUE, &auth_data);
+  if((auth_data == NULL) || (auth_data[0] == NULL) || (auth_data[1] == NULL)) {
     imap_mbox_handle_set_msg(handle, "Authentication cancelled");
+       g_strfreev(auth_data);
     return IMAP_AUTH_CANCELLED;
   }
 
@@ -65,29 +58,29 @@ imap_auth_cram(ImapMboxHandle* handle)
    * primary host name of the server. The syntax of the unencoded form must
    * correspond to that of an RFC 822 'msg-id' [RFC822] as described in [POP3].
    */
-  imap_handle_flush(handle);
-  do
-    rc = imap_cmd_step(handle, cmdno);
-  while(rc == IMR_UNTAGGED);
+  rc = imap_cmd_process_untagged(handle, cmdno);
 
   if (rc != IMR_RESPOND) {
-    g_warning("cram-md5: unexpected response:\n");
+    g_warning("cram-md5: unexpected response: %d", rc);
     return IMAP_AUTH_FAILURE;
   }
-  imap_mbox_gets(handle, ibuf, sizeof(ibuf)); /* check error */
-  auth_buf = net_client_cram_calc(ibuf, G_CHECKSUM_MD5, user, pass);
-  g_free(user);
-  memset(pass, 0, strlen(pass));
-  g_free(pass);
+  challenge = net_client_siobuf_get_line(handle->sio, NULL);
+  if (challenge != NULL) {
+         auth_buf = net_client_cram_calc(challenge, G_CHECKSUM_MD5, auth_data[0], auth_data[1]);
+  } else {
+         auth_buf = NULL;
+  }
+  g_free(challenge);
+  net_client_free_authstr(auth_data[0]);
+  net_client_free_authstr(auth_data[1]);
+  g_free(auth_data);
+  if (auth_buf == NULL) {
+         return IMAP_AUTH_FAILURE;
+  }
 
-  imap_handle_write(handle, auth_buf, strlen(auth_buf));
-  imap_handle_write(handle, "\r\n", 2U);
-  imap_handle_flush(handle);
-  memset(auth_buf, 0, strlen(auth_buf));
-  g_free(auth_buf);
-  do
-    rc = imap_cmd_step (handle, cmdno);
-  while (rc == IMR_UNTAGGED);
+  net_client_write_line(NET_CLIENT(handle->sio), "%s", NULL, auth_buf);
+  net_client_free_authstr(auth_buf);
+  rc = imap_cmd_process_untagged(handle, cmdno);
 
   return rc == IMR_OK ? IMAP_SUCCESS : IMAP_AUTH_FAILURE;
 }
diff --git a/libbalsa/imap/auth-gssapi.c b/libbalsa/imap/auth-gssapi.c
index 480223cf..1c382d50 100644
--- a/libbalsa/imap/auth-gssapi.c
+++ b/libbalsa/imap/auth-gssapi.c
@@ -19,11 +19,6 @@
 /* IMAP login/authentication code, GSSAPI method, see RFC2222 and RFC2078 */
 
 #include "config.h"
-
-#define _XOPEN_SOURCE 500
-#include <stdio.h>
-#include <string.h>
-
 #include "imap-auth.h"
 
 #if defined(HAVE_GSSAPI)
@@ -34,304 +29,136 @@
 #endif
 
 #include "imap_private.h"
-#include "siobuf.h"
-#include "util.h"
-
-#define LONG_STRING 2048
+#include "siobuf-nc.h"
+#include "net-client-utils.h"
 
-enum {
-    GSSAPI_P_NONE      = 1 << 0,
-    GSSAPI_P_INTEGRITY = 1 << 1,
-    GSSAPI_P_PRIVACY   = 1 << 2
-};
 
-#define WAIT_FOR_PROMPT(rc,handle,cmdno, buf, len) \
-    do (rc) = imap_cmd_step((handle), (cmdno)); while((rc) == IMR_UNTAGGED);
-
-static gboolean ag_get_target(const char *host, gss_name_t *target_name);
-static OM_uint32 ag_get_token(gss_ctx_id_t *context, gss_name_t target,
-                              gss_buffer_t sec_token,
-                              char *client_token, ssize_t token_sz);
-static void ag_parse_request(ImapMboxHandle *handle, char *buf, ssize_t buf_sz,
-                             gss_buffer_desc *request);
-static gboolean ag_negotiate_parameters(ImapMboxHandle *handle,
-                                        const char *user, unsigned cmdno,
-                                        gss_ctx_id_t context, int *rc);
-
-/* imap_auth_gssapi: gssapi support. */
-ImapResult
-imap_auth_gssapi(ImapMboxHandle* handle)
+static gboolean
+imap_gss_auth_init(ImapMboxHandle* handle, NetClientGssCtx *gss_ctx, unsigned *cmdno, GError **error)
 {
-    static const char Gssapi_cmd[] = "AUTHENTICATE GSSAPI";
-    unsigned cmdno;
-    int rc, ok;
-    char *user = NULL;
-    OM_uint32 state, min_stat;
-    gss_ctx_id_t context;
-    gss_name_t target_name;
-    gss_buffer_t sec_token;
-    char client_token[LONG_STRING];
-    char request_buf[LONG_STRING];
-    gss_buffer_desc request;
-    int c;
-    gboolean sasl_ir;
-
-    if (!imap_mbox_handle_can_do(handle, IMCAP_AGSSAPI))
-        return IMAP_AUTH_UNAVAIL;
-    sasl_ir = imap_mbox_handle_can_do(handle, IMCAP_SASLIR);
+       gint state;
+       gchar *output_token;
+       ImapResponse rc;
+       gboolean result;
 
-    /* Acquire initial credentials. */
-    sec_token = GSS_C_NO_BUFFER;
-    context   = GSS_C_NO_CONTEXT;
-    
-    if( !ag_get_target(handle->host, &target_name)) {
-        imap_mbox_handle_set_msg(handle, "Could not get service name");
-        return IMAP_AUTH_UNAVAIL;
-    }
-
-    state = ag_get_token(&context, target_name, sec_token,
-                         client_token, sizeof(client_token));
-    if (state != GSS_S_COMPLETE && state != GSS_S_CONTINUE_NEEDED) {
-        imap_mbox_handle_set_msg(handle, "GSS ignored - no ticket.");
-        printf("GSSAPI: ignored - no ticket (%d).\n", state);
-        gss_release_name (&min_stat, &target_name);
-        return IMAP_AUTH_UNAVAIL;
-    }
-
-    /* get user name */
-    ok = 0;
-    if(!ok && handle->user_cb)
-        handle->user_cb(IME_GET_USER, handle->user_arg, 
-                        "GASSAPI", &user, &ok);
-    if(!ok || user == NULL) {
-        imap_mbox_handle_set_msg(handle, "Authentication cancelled");
-        return IMAP_AUTH_CANCELLED;
-    }
-    
-    /* start the negotiation */
-    if(sasl_ir) { /* save one RTT */
+       state = net_client_gss_auth_step(gss_ctx, NULL, &output_token, error);
+       if (state >= 0) {
         ImapCmdTag tag;
-        if(IMAP_MBOX_IS_DISCONNECTED(handle))
-            return IMAP_AUTH_UNAVAIL;
-        cmdno = imap_make_tag(tag);
-        sio_write(handle->sio, tag, strlen(tag));
-        sio_write(handle->sio, " ", 1);
-        sio_write(handle->sio, Gssapi_cmd, strlen(Gssapi_cmd));
-        sio_write(handle->sio, " ", 1);
-        sio_write(handle->sio, client_token, strlen(client_token));
-        sio_write(handle->sio, "\r\n", 2);
-    } else {
-        if(imap_cmd_start(handle, Gssapi_cmd, &cmdno) <0)
-            return IMAP_AUTH_FAILURE;
-        imap_handle_flush(handle);
-        
-        WAIT_FOR_PROMPT(rc,handle,cmdno, client_token,sizeof(client_token));
-        
-        if (rc != IMR_RESPOND) {
-            g_warning("gssapi: unexpected response.\n");
-            gss_release_name (&min_stat, &target_name);
-            return IMAP_AUTH_FAILURE;
-        }
-        while( (c=sio_getc((handle)->sio)) != EOF && c != '\n');
-        
-        /* now start the security context initialisation loop... */
-        sio_printf(handle->sio, "%s\r\n", client_token);
-    }
-    imap_handle_flush(handle);
-    
-    /* The negotiation loop as in  RFC2222 */
-    while(state == GSS_S_CONTINUE_NEEDED) {
-        WAIT_FOR_PROMPT(rc,handle,cmdno,client_token,sizeof(client_token));
-        if (rc != IMR_RESPOND) {
-            g_warning("gssapi: unexpected response in the loop.\n");
-            gss_release_name (&min_stat, &target_name);
-            return IMAP_AUTH_UNAVAIL;      
-        }
-
-        ag_parse_request(handle, request_buf, sizeof(request_buf), &request);
-        sec_token = &request;
-        
-        /* Respond to the challenge. */
-        state = ag_get_token(&context, target_name, sec_token,
-                             client_token, sizeof(client_token));
-        if (state != GSS_S_COMPLETE && state != GSS_S_CONTINUE_NEEDED) {
-            imap_mbox_handle_set_msg(handle,
-                                     "Error exchanging GSS credentials");
-            gss_release_name (&min_stat, &target_name);
-            goto negotiation_aborted;
-        }
-        sio_printf(handle->sio, "%s\r\n", client_token);
-        imap_handle_flush(handle);
-    }
-    
-    gss_release_name (&min_stat, &target_name);
-    
-    /* get security flags and buffer size */
-    WAIT_FOR_PROMPT(rc,handle,cmdno,client_token,sizeof(client_token));
-    if (rc != IMR_RESPOND) return IMAP_AUTH_UNAVAIL;
 
-    if(!ag_negotiate_parameters(handle, user, cmdno, context, &rc))
-        goto negotiation_aborted;
-
-    /* clean up. */
-    state = gss_delete_sec_context(&min_stat, &context, &request);
-    if (state != GSS_S_COMPLETE)
-        g_warning("gss_delete_sec_context() failed");
-    gss_release_buffer (&min_stat, &request);
-    return rc == IMR_OK ? IMAP_SUCCESS : IMAP_AUTH_UNAVAIL;
- negotiation_aborted:
-    sio_write(handle->sio, "*\r\n", 3); imap_handle_flush(handle);
-    WAIT_FOR_PROMPT(rc,handle,cmdno,client_token, sizeof(client_token));
-    return IMAP_AUTH_FAILURE;
+        *cmdno = imap_make_tag(tag);
+               if (imap_mbox_handle_can_do(handle, IMCAP_SASLIR)) {
+                       result = net_client_write_line(NET_CLIENT(handle->sio), "%s AUTHENTICATE GSSAPI %s", 
error, tag, output_token);
+               } else {
+                       result = net_client_write_line(NET_CLIENT(handle->sio), "%s AUTHENTICATE GSSAPI", 
error, tag);
+                       if (result) {
+                               rc = imap_cmd_process_untagged(handle, *cmdno);
+
+                               if (rc == IMR_RESPOND) {
+                                       net_client_siobuf_discard_line(handle->sio, NULL);
+                                       result = net_client_write_line(NET_CLIENT(handle->sio), "%s", error, 
output_token);
+                               } else {
+                                       result = FALSE;
+                               }
+                       }
+               }
+               g_free(output_token);
+       } else {
+               result = FALSE;
+       }
+
+       return result;
 }
 
-/* ag_get_target: get an IMAP service ticket name for the server */
 static gboolean
-ag_get_target(const char *host, gss_name_t *target_name)
+imap_gss_auth_loop(ImapMboxHandle* handle, NetClientGssCtx *gss_ctx, unsigned cmdno, GError **error)
 {
-    OM_uint32 maj_stat, min_stat;
-    gss_buffer_desc request;
-    char buf[LONG_STRING];
-    gss_OID mech_name;
-
-    snprintf (buf, sizeof (buf), "imap@%s", host);
-    request.value = buf;
-    request.length = strlen(buf) + 1;
-    maj_stat = gss_import_name(&min_stat, &request, GSS_C_NT_HOSTBASED_SERVICE,
-                               target_name);
-    if(maj_stat != GSS_S_COMPLETE)
-        return FALSE;
-    maj_stat = gss_display_name(&min_stat, *target_name, &request,
-                                &mech_name);
-    printf("GSSAPI: Using service name [%s]\n",(char*) request.value);
-    maj_stat = gss_release_buffer (&min_stat, &request);
-
-    return maj_stat == GSS_S_COMPLETE;
+    int rc;
+       gchar *input_token;
+       gint state = 0;
+       gboolean result;
+
+       do {
+               rc = imap_cmd_process_untagged(handle, cmdno);
+               result = FALSE;
+               if (rc == IMR_RESPOND) {
+                       input_token = net_client_siobuf_get_line(handle->sio, error);
+                       if (input_token != NULL) {
+                               result = TRUE;
+                       }
+               }
+
+               if (result) {
+                       gchar *output_token = NULL;
+
+                       if (state == 0) {
+                               state = net_client_gss_auth_step(gss_ctx, input_token, &output_token, error);
+                       } else {
+                               output_token = net_client_gss_auth_finish(gss_ctx, input_token, error);
+                               if (output_token == NULL) {
+                                       state = -1;
+                               } else {
+                                       state = 2;
+                               }
+                       }
+                       g_free(input_token);
+                       if (state >= 0) {
+                               result = net_client_write_line(NET_CLIENT(handle->sio), "%s", NULL, 
output_token);
+                       }
+                       g_free(output_token);
+               }
+       } while (result && (state != 2));
+
+       return result && (state == 2);
 }
 
-/* ag_get_token obtains next CLIENT_TOKEN as a response to SEC_TOKEN.
- */
-static OM_uint32
-ag_get_token(gss_ctx_id_t *context, gss_name_t target, gss_buffer_t sec_token,
-             char *client_token, ssize_t token_sz)
+/* imap_auth_gssapi: gssapi support. */
+ImapResult
+imap_auth_gssapi(ImapMboxHandle* handle)
 {
-    OM_uint32 state, min_stat;
-    gss_buffer_desc send_token;
-    unsigned cflags;
-    gint outlen;
-    gint b64state = 0;
-    gint b64save = 0;
+    NetClientGssCtx *gss_ctx;
+    GError *error = NULL;
+    ImapResult retval;
 
-    *client_token = '\0';
-    state = gss_init_sec_context
-        (&min_stat, GSS_C_NO_CREDENTIAL, context,
-         target, GSS_C_NO_OID, GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG, 0, 
-         GSS_C_NO_CHANNEL_BINDINGS, sec_token, NULL, &send_token,
-         &cflags, NULL);
-
-    if (state != GSS_S_COMPLETE && state != GSS_S_CONTINUE_NEEDED)
-        return state;
-
-    outlen = g_base64_encode_step(send_token.value, send_token.length, FALSE,
-                                  client_token, &b64state, &b64save);
-    outlen += g_base64_encode_close(FALSE, client_token + outlen, &b64state, &b64save);
-    gss_release_buffer(&min_stat, &send_token);
-    return state;
-}
-
-static void
-ag_parse_request(ImapMboxHandle *handle, char *buf, ssize_t buf_sz,
-                 gss_buffer_desc *request)
-{
-    char line[LONG_STRING];
-    gint b64state = 0;
-    guint b64save = 0;
+    if (!imap_mbox_handle_can_do(handle, IMCAP_AGSSAPI)) {
+        return IMAP_AUTH_UNAVAIL;
+    }
 
-    sio_gets(handle->sio, line, LONG_STRING); /* FIXME: error checking */
-    request->length =
-        g_base64_decode_step(line, strlen(line), (guchar *) buf, &b64state, &b64save);
-    request->value = buf;
-}
+    /* try to create the context */
+    gss_ctx = net_client_gss_ctx_new("imap", handle->host, "test", &error);
+    if (gss_ctx == NULL) {
+       retval = IMAP_AUTH_UNAVAIL;
+    } else {
+       gboolean result;
+        unsigned cmdno;
+        int rc;
+
+       result = imap_gss_auth_init(handle, gss_ctx, &cmdno, &error);
+       if (result) {
+               result = imap_gss_auth_loop(handle, gss_ctx, cmdno, &error);
+               if (!result) {
+                       /* cancel the auth process */
+                       (void) net_client_write_line(NET_CLIENT(handle->sio), "*", NULL);
+               }
+               rc = imap_cmd_process_untagged(handle, cmdno);
+       }
+
+               net_client_gss_ctx_free(gss_ctx);
+               retval = (result && (rc == IMR_OK)) ? IMAP_SUCCESS : IMAP_AUTH_UNAVAIL;
+    }
 
-/* ag_negotiate_parameters() implements the final phase, establishes
-   the security levels and attempts to set the user whose mailboxes
-   are to be accessed.
-*/
-static gboolean
-ag_negotiate_parameters(ImapMboxHandle *handle, const char * user,
-                        unsigned cmdno, gss_ctx_id_t context, int *rc)
-{
-    OM_uint32 state, min_stat;
-    gss_buffer_desc request_buf, send_token;
-    char buf[LONG_STRING];
-    gss_qop_t quality;
-    int cflags;
-    char server_conf_flags;
-    unsigned char *t;
-    unsigned long buf_size;
-    gint outlen;
-    gint b64state = 0;
-    gint b64save = 0;
+    if (error != NULL) {
+        gchar *err_msg;
 
-    ag_parse_request(handle, buf, sizeof(buf), &request_buf);
-    state = gss_unwrap(&min_stat, context, &request_buf, &send_token,
-                       &cflags, &quality);
-    if (state != GSS_S_COMPLETE) {
-        imap_mbox_handle_set_msg(handle,
-                                 "Could not unwrap security level data");
-        gss_release_buffer (&min_stat, &send_token);
-        return FALSE;
-    }
-    
-    /* first octet is security levels supported. We want NONE */
-    server_conf_flags = *((char*) send_token.value);
-    if ( !(server_conf_flags & GSSAPI_P_NONE) ) {
-        imap_mbox_handle_set_msg(handle,
-                                 "Server requires integrity or privacy");
-        gss_release_buffer (&min_stat, &send_token);
-        return FALSE;
+       g_message("%s: %s", __func__, error->message);
+       err_msg = g_strdup_printf("GSSAPI auth failed: %s", error->message);
+       imap_mbox_handle_set_msg(handle, err_msg);
+       g_free(err_msg);
+       g_error_free(error);
     }
-    
-    /* we don't care about buffer size if we don't wrap content. But
-     * here it is */
-    t = send_token.value;
-    buf_size = (t[1] << 16) | (t[2]<<8) | t[3];
-    gss_release_buffer (&min_stat, &send_token);
-    printf("GSSAPI: Security level flags: %c%c%c\n",
-           server_conf_flags & GSSAPI_P_NONE      ? 'N' : '-',
-           server_conf_flags & GSSAPI_P_INTEGRITY ? 'I' : '-',
-           server_conf_flags & GSSAPI_P_PRIVACY   ? 'P' : '-');
-    printf("GSSAPI: Maximum GSS token size is %lu\n", buf_size);
-    
-    /* Set P_NONE and accept the buf_size. */
-    buf[0] = GSSAPI_P_NONE;
-    buf[1] = (buf_size >> 16) & 0xff;
-    buf[2] = (buf_size >> 8)  & 0xff;
-    buf[3] = (buf_size)       & 0xff;
-    strncpy (buf + 4, user, sizeof(buf)-4);
-    request_buf.value = buf;
-    request_buf.length = 4 + strlen(user) + 1;
-    state = gss_wrap(&min_stat, context, 0, GSS_C_QOP_DEFAULT,
-                     &request_buf, &cflags, &send_token);
-    if (state != GSS_S_COMPLETE) {
-        imap_mbox_handle_set_msg(handle, "Error creating login request");
-        return FALSE;
-    }
-    
-    outlen = g_base64_encode_step(send_token.value,
-                                  MIN(send_token.length, ((sizeof buf - 1) / 4 - 1) * 3),
-                                  FALSE, buf, &b64state, &b64save);
-    outlen += g_base64_encode_close(FALSE, buf + outlen, &b64state, &b64save);
-    buf[outlen] = '\0';
-    sio_printf(handle->sio, "%s\r\n", buf); imap_handle_flush(handle);
-    WAIT_FOR_PROMPT(*rc,handle,cmdno,buf,sizeof(buf));
-    if (*rc == IMR_RESPOND)
-        return FALSE;
 
-    return TRUE; /* the negotiation was successful but if we got rc ==
-                    IMR_NO, the user was not allowed to access the
-                    mailbox. */
+    return retval;
 }
+
 #else /* defined(HAVE_GSSAPI) */
 
 ImapResult
diff --git a/libbalsa/imap/imap-auth.c b/libbalsa/imap/imap-auth.c
index adaa7d47..febc0859 100644
--- a/libbalsa/imap/imap-auth.c
+++ b/libbalsa/imap/imap-auth.c
@@ -27,10 +27,14 @@
 #include "imap-auth.h"
 #include "util.h"
 #include "imap_private.h"
-#include "siobuf.h"
+#include "siobuf-nc.h"
+#include "net-client-utils.h"
 
 static ImapResult imap_auth_anonymous(ImapMboxHandle* handle);
 static ImapResult imap_auth_plain(ImapMboxHandle* handle);
+static ImapResult imap_auth_login(ImapMboxHandle* handle);
+
+typedef ImapResult (*ImapAuthenticator)(ImapMboxHandle* handle);
 
 /* ordered from strongest to weakest. Auth anonymous does not really
  * belong here, does it? */
@@ -70,49 +74,59 @@ imap_authenticate(ImapMboxHandle* handle)
 /* =================================================================== */
 /*                           AUTHENTICATORS                            */
 /* =================================================================== */
-#define SHORT_STRING 64
 /* imap_auth_login: Plain LOGIN support */
-ImapResult
+static ImapResult
 imap_auth_login(ImapMboxHandle* handle)
 {
-  char q_user[SHORT_STRING], q_pass[SHORT_STRING];
-  char buf[2*SHORT_STRING+7];
-  char *user = NULL, *pass = NULL;
-  ImapResponse rc;
-  int ok;
+  gchar **auth_data;
+  ImapResult result;
   
   if (imap_mbox_handle_can_do(handle, IMCAP_LOGINDISABLED))
     return IMAP_AUTH_UNAVAIL;
   
-  ok = 0;
-  if(!ok && handle->user_cb)
-    handle->user_cb(IME_GET_USER_PASS, handle->user_arg,
-                    "LOGIN", &user, &pass, &ok);
-  if(!ok || user == NULL || pass == NULL) {
+  g_signal_emit_by_name(handle->sio, "auth", TRUE, &auth_data);
+  if((auth_data == NULL) || (auth_data[0] == NULL) || (auth_data[1] == NULL)) {
     imap_mbox_handle_set_msg(handle, "Authentication cancelled");
+       g_strfreev(auth_data);
     return IMAP_AUTH_CANCELLED;
   }
 
-  imap_quote_string(q_user, sizeof (q_user), user);
-  imap_quote_string(q_pass, sizeof (q_pass), pass);
-  g_free(user); g_free(pass); /* FIXME: clean passwd first */
-  g_snprintf (buf, sizeof (buf), "LOGIN %s %s", q_user, q_pass);
-  rc = imap_cmd_exec(handle, buf);
-  return  (rc== IMR_OK) ?  IMAP_SUCCESS : IMAP_AUTH_FAILURE;
+  /* RFC 6855, Sect. 5, explicitly forbids UTF-8 usernames or passwords */
+  if (!g_str_is_ascii(auth_data[0]) || !g_str_is_ascii(auth_data[1])) {
+         imap_mbox_handle_set_msg(handle, "Cannot LOGIN with UTF-8 username or password");
+         result = IMAP_AUTH_CANCELLED;
+  } else {
+         gchar *q_user;
+         gchar *q_pass;
+         gchar *buf;
+         ImapResponse rc;
+
+         q_user = imap_quote_string(auth_data[0]);
+         q_pass = imap_quote_string(auth_data[1]);
+         buf = g_strjoin(" ", "LOGIN", q_user, q_pass, NULL);
+         net_client_free_authstr(q_user);
+         net_client_free_authstr(q_pass);
+         rc = imap_cmd_exec(handle, buf);
+         net_client_free_authstr(buf);
+
+         result = (rc == IMR_OK) ? IMAP_SUCCESS : IMAP_AUTH_FAILURE;
+  }
+
+  net_client_free_authstr(auth_data[0]);
+  net_client_free_authstr(auth_data[1]);
+  g_free(auth_data);
+  return result;
 }
 
 /* =================================================================== */
 /* SASL PLAIN RFC-2595                                                 */
 /* =================================================================== */
-#define WAIT_FOR_PROMPT(rc,handle,cmdno) \
-    do (rc) = imap_cmd_step((handle), (cmdno)); while((rc) == IMR_UNTAGGED);
-
 static ImapResult
 imap_auth_sasl(ImapMboxHandle* handle, ImapCapability cap,
               const char *sasl_cmd,
               gboolean (*getmsg)(ImapMboxHandle *h, char **msg, int *msglen))
 {
-  char *msg = NULL, *msg64;
+  char *msg64;
   ImapResponse rc;
   int msglen;
   unsigned cmdno;
@@ -122,77 +136,56 @@ imap_auth_sasl(ImapMboxHandle* handle, ImapCapability cap,
     return IMAP_AUTH_UNAVAIL;
   sasl_ir = imap_mbox_handle_can_do(handle, IMCAP_SASLIR);
   
-  if(!getmsg(handle, &msg, &msglen)) {
+  if(!getmsg(handle, &msg64, &msglen)) {
     imap_mbox_handle_set_msg(handle, "Authentication cancelled");
     return IMAP_AUTH_CANCELLED;
   }
   
-  msg64 = g_base64_encode((const guchar *) msg, msglen);
-  g_free(msg);
-
   if(sasl_ir) { /* save one RTT */
     ImapCmdTag tag;
     if(IMAP_MBOX_IS_DISCONNECTED(handle))
       return IMAP_AUTH_UNAVAIL;
     cmdno = imap_make_tag(tag);
-    sio_write(handle->sio, tag, strlen(tag));
-    sio_write(handle->sio, " ", 1);
-    sio_write(handle->sio, sasl_cmd, strlen(sasl_cmd));
-    sio_write(handle->sio, " ", 1);
+    net_client_write_line(NET_CLIENT(handle->sio), "%s %s %s",
+       NULL, tag, sasl_cmd, msg64);
   } else {
-    int c;
     if(imap_cmd_start(handle, sasl_cmd, &cmdno) <0) {
-      g_free(msg64);
+      net_client_free_authstr(msg64);
       return IMAP_AUTH_FAILURE;
     }
-    imap_handle_flush(handle);
-    WAIT_FOR_PROMPT(rc,handle,cmdno);
+    rc = imap_cmd_process_untagged(handle, cmdno);
     
     if (rc != IMR_RESPOND) {
-      g_warning("imap %s: unexpected response.\n", sasl_cmd);
-      g_free(msg64);
-      return IMAP_AUTH_FAILURE;
-    }
-    while( (c=sio_getc((handle)->sio)) != EOF && c != '\n');
-    if(c == EOF) {
-      imap_handle_disconnect(handle);
-      g_free(msg64);
+      g_warning("imap %s: unexpected response.", sasl_cmd);
+      net_client_free_authstr(msg64);
       return IMAP_AUTH_FAILURE;
     }
+    net_client_siobuf_discard_line(handle->sio, NULL);
+    net_client_write_line(NET_CLIENT(handle->sio), "%s", NULL, msg64);
   }
-  sio_write(handle->sio, msg64, strlen(msg64));
-  sio_write(handle->sio, "\r\n", 2);
-  g_free(msg64);
-  imap_handle_flush(handle);
-  do
-    rc = imap_cmd_step (handle, cmdno);
-  while (rc == IMR_UNTAGGED);
+  net_client_free_authstr(msg64);
+  rc = imap_cmd_process_untagged(handle, cmdno);
   return  (rc== IMR_OK) ?  IMAP_SUCCESS : IMAP_AUTH_FAILURE;
 }
 
 static gboolean
 getmsg_plain(ImapMboxHandle *h, char **retmsg, int *retmsglen)
 {
-  char *user = NULL, *pass = NULL, *msg;
-  int ok, userlen, passlen, msglen;
-  ok = 0;
-  if(!ok && h->user_cb)
-    h->user_cb(IME_GET_USER_PASS, h->user_arg,
-                    "LOGIN", &user, &pass, &ok);
-  if(!ok || user == NULL || pass == NULL)
-    return 0;
-
-  userlen = strlen(user);
-  passlen = strlen(pass);
-  msglen  = 2*userlen + passlen + 2;
-  msg     = g_malloc(msglen+1);
-  strcpy(msg, user); 
-  strcpy(msg+userlen+1, user);
-  strcpy(msg+userlen*2+2, pass); 
-  g_free(user); g_free(pass);
-  *retmsg = msg;
-  *retmsglen = msglen;
-  return 1;
+       gchar **auth_data;
+       gboolean result;
+
+       g_signal_emit_by_name(h->sio, "auth", TRUE, &auth_data);
+       if ((auth_data == NULL) || (auth_data[0] == NULL) || (auth_data[1] == NULL)) {
+               result = FALSE;
+       } else {
+               *retmsg = net_client_auth_plain_calc(auth_data[0], auth_data[1]);
+               *retmsglen = strlen(*retmsg);
+               result = TRUE;
+       }
+       net_client_free_authstr(auth_data[0]);
+       net_client_free_authstr(auth_data[1]);
+       g_free(auth_data);
+       return result;
 }
 
 static ImapResult
@@ -209,14 +202,19 @@ imap_auth_plain(ImapMboxHandle* handle)
 static gboolean
 getmsg_anonymous(ImapMboxHandle *h, char **retmsg, int *retmsglen)
 {
-  int ok = 0;
-  if(!ok && h->user_cb)
-    h->user_cb(IME_GET_USER, h->user_arg,
-              "ANONYMOUS", retmsg, &ok);
-  if(!ok || *retmsg == NULL)
-    return 0;
-  *retmsglen = strlen(*retmsg);
-  return 1;
+       gchar **auth_data;
+       gboolean result;
+
+       g_signal_emit_by_name(h->sio, "auth", FALSE, &auth_data);
+       if((auth_data == NULL) || (auth_data[0] == NULL)) {
+               result = FALSE;
+       } else {
+               *retmsg = g_base64_encode((const guchar *) auth_data[0], strlen(auth_data[0]));
+               *retmsglen = strlen(*retmsg);
+               result = TRUE;
+       }
+       g_strfreev(auth_data);
+       return result;
 }
 
 static ImapResult
diff --git a/libbalsa/imap/imap-auth.h b/libbalsa/imap/imap-auth.h
index f8923a49..19bf2de4 100644
--- a/libbalsa/imap/imap-auth.h
+++ b/libbalsa/imap/imap-auth.h
@@ -20,10 +20,8 @@
 #include "libimap.h"
 #include "imap-handle.h"
 
-typedef ImapResult (*ImapAuthenticator)(ImapMboxHandle* handle);
 ImapResult imap_authenticate(ImapMboxHandle* handle);
 ImapResult imap_auth_cram(ImapMboxHandle* handle);
-ImapResult imap_auth_login(ImapMboxHandle* handle);
 ImapResult imap_auth_gssapi(ImapMboxHandle* handle);
 
 #endif
diff --git a/libbalsa/imap/imap-commands.c b/libbalsa/imap/imap-commands.c
index b5efb468..5a73defe 100644
--- a/libbalsa/imap/imap-commands.c
+++ b/libbalsa/imap/imap-commands.c
@@ -23,7 +23,7 @@
 #include "imap-handle.h"
 #include "imap-commands.h"
 #include "imap_private.h"
-#include "siobuf.h"
+#include "siobuf-nc.h"
 #include "util.h"
 
 #define ELEMENTS(x) (sizeof (x) / sizeof(x[0]))
@@ -122,7 +122,7 @@ imap_check_capability(ImapMboxHandle* handle)
 
   if (!(imap_mbox_handle_can_do(handle, IMCAP_IMAP4) ||
         imap_mbox_handle_can_do(handle, IMCAP_IMAP4REV1))) {
-    g_warning("IMAP4rev1 required but not provided.\n");
+    g_warning("IMAP4rev1 required but not provided.");
     return FALSE;
   }  
   return TRUE;
@@ -495,11 +495,8 @@ append_commit(ImapMboxHandle *handle, unsigned cmdno, ImapSequence *uid_seq)
     handle->uidplus.dst = uid_seq->ranges;
     handle->uidplus.store_response = 1;
   }
-  sio_write(handle->sio, "\r\n", 2);
-  sio_flush(handle->sio);
-  do {
-    rc = imap_cmd_step (handle, cmdno);
-  } while (rc == IMR_UNTAGGED);
+  net_client_siobuf_flush(handle->sio, NULL);
+  rc = imap_cmd_process_untagged(handle, cmdno);
 
   if(uid_seq) {
     if(uid_seq->uid_validity == 0) {
@@ -579,27 +576,21 @@ imap_mbox_append_multi_real(ImapMboxHandle *handle,
       /* MULTIAPPEND continuation */
       if(flags) {
        gchar *str = enum_flag_to_str(flags);
-       sio_printf(handle->sio, " (%s) {%lu%s}\r\n", str,
+       sio_printf(handle->sio, " (%s) {%lu%s}", str,
                   (unsigned long)msg_size, litstr);
        g_free(str);
       } else 
-       sio_printf(handle->sio, " {%lu%s}\r\n",
+       sio_printf(handle->sio, " {%lu%s}",
                   (unsigned long)msg_size, litstr);
     }
 
     if(use_literal)
       rc = IMR_RESPOND; /* we do it without flushing */
     else {
-      sio_flush(handle->sio);
-      do {
-       rc = imap_cmd_step (handle, cmdno);
-      } while (rc == IMR_UNTAGGED);
+       net_client_siobuf_flush(handle->sio, NULL);
+       rc = imap_cmd_process_untagged(handle, cmdno);
       if(rc != IMR_RESPOND) return rc;
-      EAT_LINE(handle, c);
-      if(c == -1) {
-       imap_handle_disconnect(handle);
-       return IMR_SEVERED;
-      }
+      net_client_siobuf_discard_line(handle->sio, NULL);
     }
 
     for(s=0; s<msg_size; s+= delta) {
@@ -940,12 +931,9 @@ imap_assure_needed_flags(ImapMboxHandle *h, ImapMsgFlag needed_flags)
     }
   }
   if(cmd) { /* was ever altered */
-    sio_flush(h->sio);
     for(i=0; i<issued_cmd; i++) {
       h->search_arg = &flag[i];
-      do {
-        rc = imap_cmd_step(h, cmdno[i]);
-      } while (rc == IMR_UNTAGGED);
+      rc = imap_cmd_process_untagged(h, cmdno[i]);
     }
     imap_handle_idle_enable(h, 30);
   }
@@ -1040,7 +1028,7 @@ set_avail_headers(ImapMboxHandle *h, const char *seq, ImapFetchType ift)
         }
       
       break;
-    default: g_warning("unexpected sequence %s\n", seq);
+    default: g_warning("unexpected sequence %s", seq);
     }
     if(*tmp==',') tmp++;
     s = tmp;
@@ -1681,11 +1669,8 @@ imap_mbox_thread(ImapMboxHandle *h, const char *how, ImapSearchKey *filter)
         return rc;
     }
 
-    sio_write(h->sio, "\r\n", 2);
-    imap_handle_flush(h);
-    do
-      rc = imap_cmd_step(h, cmdno);
-    while(rc == IMR_UNTAGGED);
+    net_client_siobuf_flush(h->sio, NULL);
+    rc = imap_cmd_process_untagged(h, cmdno);
     imap_handle_idle_enable(h, 30);
   }
  exit_cleanup:
@@ -1998,12 +1983,9 @@ imap_mbox_sort_filter(ImapMboxHandle *handle, ImapSortKey key, int ascending,
             != IMR_OK)
           return rc;
       }
-      sio_write(handle->sio, "\r\n", 2);
       imap_handle_idle_enable(handle, 30);
-      imap_handle_flush(handle);
-      do
-        rc = imap_cmd_step(handle, cmdno);
-      while(rc == IMR_UNTAGGED);
+      net_client_siobuf_flush(handle->sio, NULL);
+      rc = imap_cmd_process_untagged(handle, cmdno);
     } else {                                           /* CASE 2b */
       /* try client-side sorting... */
       if(handle->enable_client_sort) {
diff --git a/libbalsa/imap/imap-handle.c b/libbalsa/imap/imap-handle.c
index bbf6d76f..b9f6cbc3 100644
--- a/libbalsa/imap/imap-handle.c
+++ b/libbalsa/imap/imap-handle.c
@@ -20,9 +20,6 @@
 #define _XOPEN_SOURCE 500
 #define _DEFAULT_SOURCE     1
 
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
 #include <glib.h>
 #include <glib-object.h>
 #include <ctype.h>
@@ -34,25 +31,14 @@
 #include <unistd.h>
 #include <gmime/gmime-utils.h>
 
-#if defined(HAVE_RES_INIT)
-#include <netinet/in.h>
-#include <arpa/nameser.h>
-#include <resolv.h>
-#endif                          /* defined(HAVE_RES_INIT) */
-
-#include <openssl/ssl.h>
-#include <openssl/err.h>
-
 #include "libimap-marshal.h"
 #include "imap-auth.h"
 #include "imap-handle.h"
 #include "imap-commands.h"
 #include "imap_private.h"
-#include "siobuf.h"
+#include "siobuf-nc.h"
 #include "util.h"
 
-#define ASYNC_DEBUG 0
-
 #define LONG_STRING 512
 #define ELEMENTS(x) (sizeof (x) / sizeof(x[0]))
 
@@ -107,6 +93,10 @@ static ImapResponse ir_handle_response(ImapMboxHandle *h);
 static ImapAddress* imap_address_from_string(const gchar *string, gchar **n);
 static gchar*       imap_address_to_string(const ImapAddress *addr);
 
+static gboolean async_process(GSocket      *source,
+                                                         GIOCondition  condition,
+                                                         gpointer      data);
+
 static GType
 imap_mbox_handle_get_type()
 {
@@ -145,8 +135,7 @@ imap_mbox_handle_init(ImapMboxHandle *handle)
   handle->msg_cache = NULL;
   handle->flag_cache=  g_array_new(FALSE, TRUE, sizeof(ImapFlagCache));
   handle->doing_logout = FALSE;
-  handle->using_tls = 0;
-  handle->tls_mode = IMAP_TLS_ENABLED;
+  handle->tls_mode = NET_CLIENT_CRYPT_STARTTLS;
   handle->idle_state = IDLE_INACTIVE;
   handle->cmd_info = NULL;
   handle->status_resps = g_hash_table_new_full(g_str_hash, g_str_equal,
@@ -154,6 +143,9 @@ imap_mbox_handle_init(ImapMboxHandle *handle)
 
   handle->info_cb  = NULL;
   handle->info_arg = NULL;
+  handle->auth_cb = NULL;
+  handle->auth_arg = NULL;
+  handle->cert_cb = NULL;
   handle->op_cancelled = 0;
   handle->enable_anonymous = 0;
   handle->enable_client_sort = 0;
@@ -234,7 +226,7 @@ imap_handle_set_option(ImapMboxHandle *h, ImapOption opt, gboolean state)
   case IMAP_OPT_CLIENT_SORT: h->enable_client_sort = !!state; break;
   case IMAP_OPT_COMPRESS:    h->enable_compress    = !!state; break;
   case IMAP_OPT_IDLE:        h->enable_idle        = !!state; break;
-  default: g_warning("imap_set_option: invalid option\n");
+  default: g_warning("imap_set_option: invalid option");
   }
 }
 
@@ -246,17 +238,16 @@ imap_handle_set_infocb(ImapMboxHandle* h, ImapInfoCb cb, void *arg)
 }
 
 void
-imap_handle_set_usercb(ImapMboxHandle* h, ImapUserCb cb, void *arg)
+imap_handle_set_authcb(ImapMboxHandle* h, GCallback cb, void *arg)
 {
-  h->user_cb  = cb;
-  h->user_arg = arg;
+       h->auth_cb  = cb;
+       h->auth_arg = arg;
 }
 
 void
-imap_handle_set_monitorcb(ImapMboxHandle* h, ImapMonitorCb cb, void*arg)
+imap_handle_set_certcb(ImapMboxHandle* h, GCallback cb)
 {
-  h->monitor_cb  = cb;
-  h->monitor_arg = arg;
+       h->cert_cb  = cb;
 }
 
 void
@@ -329,63 +320,83 @@ imap_handle_set_timeout(ImapMboxHandle *h, int milliseconds)
   int old_timeout = h->timeout;
   h->timeout = milliseconds;
   if(h->sio)
-    sio_set_timeout(h->sio, milliseconds);
+    net_client_set_timeout(NET_CLIENT(h->sio), (milliseconds + 500) / 1000);
   return old_timeout;
 }
 
+/* Called with a locked handle. */
+static void
+socket_source_add(ImapMboxHandle *h)
+{
+       if (h->sock_source == NULL) {
+           h->sock_source = g_socket_create_source(net_client_get_socket(NET_CLIENT(h->sio)), 
G_IO_IN|G_IO_HUP, NULL);
+           g_source_set_callback(h->sock_source, (GSourceFunc) async_process, h, NULL);
+           g_source_attach(h->sock_source, NULL);
+           g_debug("async_process() registered");
+       }
+}
+
+/* Called with a locked handle. */
+static void
+socket_source_remove(ImapMboxHandle *h)
+{
+       if (h->sock_source != NULL) {
+               g_source_destroy(h->sock_source);
+               g_source_unref(h->sock_source);
+               h->sock_source = NULL;
+           g_debug("async_process() removed");
+       }
+}
+
+
 /** Called with a locked handle. */
 static gboolean
 async_process_real(ImapMboxHandle *h)
 {
-  ImapResponse rc = IMR_UNTAGGED;
-  unsigned async_cmd;
-  int retval;
-
-  async_cmd = cmdi_get_pending(h->cmd_info);
-  if(ASYNC_DEBUG) printf("async_process() enter loop\n");
-  while( (retval = sio_poll(h->sio, TRUE, FALSE, TRUE)) != -1 &&
-         (retval & SIO_READ) != 0) {
-    rc=imap_cmd_step(h, async_cmd);
-    if(h->idle_state == IDLE_RESPONSE_PENDING) {
-      int c;
-      if(rc != IMR_RESPOND) {
-       g_message("async_process_real() expected IMR_RESPOND but got %d\n", rc);
-       imap_handle_disconnect(h);
-       return FALSE;
-      }
-      EAT_LINE(h, c);
-      if (c == '\n') {
-       h->idle_state = IDLE_ACTIVE;
-       if (ASYNC_DEBUG) printf("IDLE is now ACTIVE\n");
-      }
-    } else if (rc == IMR_UNKNOWN ||
-       rc == IMR_SEVERED || rc == IMR_BYE || rc == IMR_PROTOCOL ||
-       rc  == IMR_BAD) {
-      printf("async_process() got unexpected response %i!\n"
-             "Last message was: \"%s\" - shutting down connection.\n",
-             rc, h->last_msg);
-      imap_handle_disconnect(h);
-      return FALSE;
-    }
-    async_cmd = cmdi_get_pending(h->cmd_info);
-    if(ASYNC_DEBUG)
-      printf("async_process() loop iteration finished, next async_cmd=%x\n",
-           async_cmd);
-  }
-  if(ASYNC_DEBUG) printf("async_process() loop left\n");
-  if(h->idle_state == IDLE_INACTIVE && async_cmd == 0) {
-    if(ASYNC_DEBUG) printf("Last async command completed.\n");
-    if(h->async_watch_id) {
-      g_source_remove(h->async_watch_id);
-      h->async_watch_id = 0;
-    }
-    imap_handle_idle_enable(h, IDLE_TIMEOUT);
-  }
-  if(ASYNC_DEBUG)
-    printf("async_process() sio: %d rc: %d returns %d (%d cmds in queue)\n",
-           retval, rc, h->idle_state == IDLE_INACTIVE && async_cmd == 0,
-           g_list_length(h->cmd_info));
-  return h->idle_state != IDLE_INACTIVE || async_cmd != 0;
+       ImapResponse rc = IMR_UNTAGGED;
+       unsigned async_cmd;
+
+       g_debug("%s: ENTER", __func__);
+       async_cmd = cmdi_get_pending(h->cmd_info);
+       g_debug("%s: enter loop, cmnd %u", __func__, async_cmd);
+       while (net_client_can_read(NET_CLIENT(h->sio))) {
+               rc = imap_cmd_step(h, async_cmd);
+               if (h->idle_state == IDLE_RESPONSE_PENDING) {
+                       int c;
+                       if(rc != IMR_RESPOND) {
+                               g_message("%s: expected IMR_RESPOND but got %d", __func__, rc);
+                               imap_handle_disconnect(h);
+                               return G_SOURCE_REMOVE;
+                       }
+                       EAT_LINE(h, c);
+                       if (c == '\n') {
+                               h->idle_state = IDLE_ACTIVE;
+                               g_debug("%s: IDLE is now ACTIVE", __func__);
+                       }
+               } else if (rc == IMR_UNKNOWN ||
+                       rc == IMR_SEVERED || rc == IMR_BYE || rc == IMR_PROTOCOL ||
+                       rc  == IMR_BAD) {
+                       g_debug("%s: got unexpected response %i! "
+                               "Last message was: \"%s\" - shutting down connection.",
+                               __func__, rc, h->last_msg);
+                       imap_handle_disconnect(h);
+                       return G_SOURCE_REMOVE;
+               }
+               async_cmd = cmdi_get_pending(h->cmd_info);
+               g_debug("%s: loop iteration finished, next async_cmd=%x", __func__,
+                       async_cmd);
+       }
+       g_debug("%s: loop left", __func__);
+       if (h->idle_state == IDLE_INACTIVE && async_cmd == 0) {
+               g_debug("%s: Last async command completed.", __func__);
+               socket_source_remove(h);
+               imap_handle_idle_enable(h, IDLE_TIMEOUT);
+       }
+       g_debug("%s: rc: %d returns %d (%d cmds in queue)", __func__,
+               rc, h->idle_state == IDLE_INACTIVE && async_cmd == 0,
+               g_list_length(h->cmd_info));
+       g_debug("%s: DONE", __func__);
+       return h->idle_state != IDLE_INACTIVE || async_cmd != 0;
 }
 
 /* imap_handle_idle_enable: enables calling IDLE command after seconds
@@ -402,31 +413,35 @@ async_process_real(ImapMboxHandle *h)
    by IDLE and STORE commands, for example. */
 
 static gboolean
-async_process(GIOChannel *source, GIOCondition condition, gpointer data)
-{
-  ImapMboxHandle *h = (ImapMboxHandle*)data;
-  gboolean retval_async;
-
-  g_return_val_if_fail(h, FALSE);
-
-  if(ASYNC_DEBUG) printf("async_process() ENTER\n");
-  if(!g_mutex_trylock(&h->mutex))
-    return FALSE;/* async data on already locked handle? Don't try again. */
-  if(ASYNC_DEBUG) printf("async_process() LOCKED\n");
-  if(h->state == IMHS_DISCONNECTED) {
-    if(ASYNC_DEBUG) printf("async_process() on disconnected\n");
-    g_mutex_unlock(&h->mutex);
-    return FALSE;
-  }
-  if( (condition & G_IO_HUP) == G_IO_HUP) {
-      imap_handle_disconnect(h);
-      g_mutex_unlock(&h->mutex);
-      return FALSE;
-  }
-  retval_async = async_process_real(h);
+async_process(GSocket      *source,
+                         GIOCondition  condition,
+                         gpointer      data)
+{
+       ImapMboxHandle *h = (ImapMboxHandle *) data;
+       gboolean retval_async;
+
+       g_return_val_if_fail(h, FALSE);
+
+       g_debug("%s: ENTER", __func__);
+       if (g_mutex_trylock(&h->mutex)) {
+               g_debug("%s: LOCKED", __func__);
+               if (h->state == IMHS_DISCONNECTED) {
+                       g_debug("%s: on disconnected", __func__);
+                       retval_async = G_SOURCE_REMOVE;
+               } else if ((condition & G_IO_HUP) == G_IO_HUP) {
+                       g_debug("%s: hangup", __func__);
+                       imap_handle_disconnect(h);
+                       retval_async = G_SOURCE_REMOVE;
+               } else {
+                       retval_async = async_process_real(h);
+               }
+               g_mutex_unlock(&h->mutex);
+       } else {
+               retval_async = G_SOURCE_REMOVE;         /* async data on already locked handle? Don't try 
again. */
+       }
 
-  g_mutex_unlock(&h->mutex);
-  return retval_async;
+       g_debug("%s: DONE (keep: %d)", __func__, retval_async);
+       return retval_async;
 }
 
 static gboolean
@@ -450,16 +465,10 @@ idle_start(gpointer data)
   IMAP_REQUIRED_STATE3(h, IMHS_CONNECTED, IMHS_AUTHENTICATED,
                        IMHS_SELECTED, FALSE);
 
-  asyncno = imap_make_tag(tag); sio_write(h->sio, tag, strlen(tag));
-  sio_write(h->sio, " IDLE\r\n", 7); sio_flush(h->sio);
+  asyncno = imap_make_tag(tag);
+  net_client_write_line(NET_CLIENT(h->sio), "%s IDLE", NULL, tag);
   cmdi_add_handler(&h->cmd_info, asyncno, cmdi_empty, NULL);
-  if(!h->iochannel) {
-    h->iochannel = g_io_channel_unix_new(h->sd);
-    g_io_channel_set_encoding(h->iochannel, NULL, NULL);
-  }
-  if(ASYNC_DEBUG) printf("async_process() registered\n");
-  h->async_watch_id = g_io_add_watch(h->iochannel, G_IO_IN|G_IO_HUP,
-                                    async_process, h);
+  socket_source_add(h);
   h->idle_state = IDLE_RESPONSE_PENDING;
 
   g_mutex_unlock(&h->mutex);
@@ -480,15 +489,10 @@ imap_cmd_issue(ImapMboxHandle* h, const char* cmd)
   if (imap_cmd_start(h, cmd, &async_cmd)<0)
     return IMR_SEVERED;  /* irrecoverable connection error. */
 
-  sio_flush(h->sio);
-  if(ASYNC_DEBUG) printf("command '%s' issued.\n", cmd);
+  g_debug("command '%s' issued.", cmd);
   cmdi_add_handler(&h->cmd_info, async_cmd, cmdi_empty, NULL);
-  if(!h->iochannel) {
-    h->iochannel = g_io_channel_unix_new(h->sd);
-    g_io_channel_set_encoding(h->iochannel, NULL, NULL);
-  }
-  h->async_watch_id = g_io_add_watch(h->iochannel, G_IO_IN|G_IO_HUP,
-                                     async_process, h);
+  socket_source_add(h);
+
   return IMR_OK /* async_cmd */;
 }
 
@@ -498,7 +502,7 @@ imap_handle_idle_enable(ImapMboxHandle *h, int seconds)
   if( !h->enable_idle || !imap_mbox_handle_can_do(h, IMCAP_IDLE))
     return FALSE;
   if(h->idle_state != IDLE_INACTIVE) {
-    fprintf(stderr, "IDLE already enabled\n");
+    g_warning("IDLE already enabled");
     return FALSE;
   }
   if(!h->idle_enable_id)
@@ -513,17 +517,14 @@ imap_handle_idle_disable(ImapMboxHandle *h)
     g_source_remove(h->idle_enable_id);
     h->idle_enable_id = 0;
   }
-  if(h->async_watch_id) {
-    g_source_remove(h->async_watch_id);
-    h->async_watch_id = 0;
+  if(h->sock_source != NULL) {
+       socket_source_remove(h);
     if(h->sio && h->idle_state == IDLE_RESPONSE_PENDING) {
       int c;
       ImapResponse rc;
       unsigned async_cmd = cmdi_get_pending(h->cmd_info);
 
-      do {
-       rc = imap_cmd_step(h, async_cmd);
-      } while (rc == IMR_UNTAGGED);
+      rc = imap_cmd_process_untagged(h, async_cmd);
       if(rc != IMR_RESPOND) {
        imap_handle_disconnect(h);
        return FALSE;
@@ -537,7 +538,7 @@ imap_handle_idle_disable(ImapMboxHandle *h)
     }
     if (h->sio &&  h->idle_state == IDLE_ACTIVE) {
       /* we might have been disconnected before */
-      sio_write(h->sio,"DONE\r\n",6); sio_flush(h->sio);
+      net_client_write_line(NET_CLIENT(h->sio), "DONE", NULL);
       h->idle_state = IDLE_INACTIVE;
     }
   }
@@ -554,22 +555,12 @@ imap_handle_op_cancelled(ImapMboxHandle *h)
 void
 imap_handle_disconnect(ImapMboxHandle *h)
 {
-  /* cppcheck-suppress unreadVariable */
-  gboolean still_connected __attribute__ ((__unused__));
-
-  still_connected = imap_handle_idle_disable(h);
+  gboolean G_GNUC_UNUSED dummy;
+  dummy = imap_handle_idle_disable(h);
   if(h->sio) {
-    sio_detach(h->sio); h->sio = NULL;
-    imap_compress_release(&h->compress);
-  }
-  if(h->iochannel) {
-    g_io_channel_unref(h->iochannel); h->iochannel = NULL;
+    g_object_unref(h->sio); h->sio = NULL;
   }
-  if(h->async_watch_id) {
-    g_source_remove(h->async_watch_id);
-    h->async_watch_id = 0;
-  }
-  close(h->sd);
+  socket_source_remove(h);
   h->state = IMHS_DISCONNECTED;
 }
 
@@ -583,14 +574,13 @@ int imap_mbox_is_selected     (ImapMboxHandle *h)
 { return IMAP_MBOX_IS_SELECTED(h); }
 
 ImapResult
-imap_mbox_handle_connect(ImapMboxHandle* ret, const char *host, int over_ssl)
+imap_mbox_handle_connect(ImapMboxHandle* ret, const char *host)
 {
   ImapResult rc;
 
   g_return_val_if_fail(imap_mbox_is_disconnected(ret), IMAP_CONNECT_FAILED);
 
   g_mutex_lock(&ret->mutex);
-  ret->over_ssl = over_ssl;
 
   g_free(ret->host);   ret->host   = g_strdup(host);
 
@@ -670,10 +660,10 @@ imap_handle_force_disconnect(ImapMboxHandle *h)
   g_mutex_unlock(&h->mutex);
 }
 
-ImapTlsMode
-imap_handle_set_tls_mode(ImapMboxHandle* r, ImapTlsMode state)
+NetClientCryptMode
+imap_handle_set_tls_mode(ImapMboxHandle* r, NetClientCryptMode state)
 {
-  ImapTlsMode res;
+  NetClientCryptMode res;
   g_return_val_if_fail(r,0);
   res = r->tls_mode;
   r->tls_mode = state;
@@ -689,60 +679,7 @@ struct ListData {
   void * cb_data;
 };
 
-int
-imap_socket_open(const char* host, const char *def_port)
-{
-  static const int USEIPV6 = 1;
-  int rc, fd = -1;
-  
-  /* --- IPv4/6 --- */
-  /* "65536\0" */
-  const char *port;
-  char *hostname;
-  struct addrinfo hints;
-  struct addrinfo* res;
-  struct addrinfo* cur;
-  
-  /* we accept v4 or v6 STREAM sockets */
-  memset (&hints, 0, sizeof (hints));
-
-  hints.ai_family = USEIPV6 ? AF_UNSPEC : AF_INET;
-  hints.ai_socktype = SOCK_STREAM;
-
-  port = strrchr(host, ':');
-  if (port) {
-    hostname = g_strndup(host, port-host);
-    port ++;
-  } else {
-    port = def_port;
-    hostname = g_strdup(host);
-  }
-  rc = getaddrinfo(hostname, port, &hints, &res);
-#if defined(HAVE_RES_INIT)
-  if (rc == EAI_AGAIN) {
-    res_init();
-    rc = getaddrinfo(hostname, port, &hints, &res);
-  }
-#endif                          /* defined(HAVE_RES_INIT) */
-  g_free(hostname);
-  if(rc)
-    return -1;
-  
-  for (cur = res; cur != NULL; cur = cur->ai_next) {
-    fd = socket (cur->ai_family, cur->ai_socktype, cur->ai_protocol);
-    if (fd >= 0) {
-      if ((rc=connect(fd, cur->ai_addr, cur->ai_addrlen)) == 0) {
-       break;
-      } else {
-       close (fd);
-        fd = -1;
-      }
-    }
-  }
-  freeaddrinfo (res);
-  return fd; /* FIXME: provide more info why the connection failed. */
-}
-
+#if 0
 static int
 imap_timeout_cb(void *arg)
 {
@@ -762,13 +699,13 @@ imap_timeout_cb(void *arg)
 
   return ok;
 }
+#endif
 
 static ImapResult
 imap_mbox_connect(ImapMboxHandle* handle)
 {
-  static const int SIO_BUFSZ=8192;
   ImapResponse resp;
-  const char *service = "imap";
+  GError *error = NULL;
 
   /* reset some handle status */
   handle->op_cancelled = FALSE;
@@ -776,72 +713,58 @@ imap_mbox_connect(ImapMboxHandle* handle)
   handle->can_fetch_body = TRUE;
   handle->idle_state = IDLE_INACTIVE;
   if(handle->sio) {
-    sio_detach(handle->sio); handle->sio = NULL;
-    imap_compress_release(&handle->compress);
+    g_object_unref(handle->sio); handle->sio = NULL;
   }
 
-  handle->using_tls = 0;
-  if(handle->over_ssl) service = "imaps";
-
-  handle->sd = imap_socket_open(handle->host, service);
-  if(handle->sd<0)
-    return IMAP_CONNECT_FAILED;
-  
-  /* Add buffering to the socket */
-  handle->sio = sio_attach(handle->sd, handle->sd, SIO_BUFSZ);
-  if (handle->sio == NULL) {
-    close(handle->sd);
-    return IMAP_NOMEM;
+  handle->sio = net_client_siobuf_new(handle->host,
+         handle->tls_mode == NET_CLIENT_CRYPT_ENCRYPTED ? 993 : 143);
+  g_signal_connect(G_OBJECT(handle->sio), "auth", handle->auth_cb, handle->auth_arg);
+  g_signal_connect(G_OBJECT(handle->sio), "cert-check", handle->cert_cb, handle->sio);
+  if (!net_client_connect(NET_CLIENT(handle->sio), &error)) {
+       imap_mbox_handle_set_msg(handle, error->message);
+       g_clear_error(&error);
+       return IMAP_CONNECT_FAILED;
   }
-  imap_compress_init(&handle->compress);
+  
+#if 0
   if(handle->timeout>0) {
     sio_set_timeout(handle->sio, handle->timeout);
     sio_set_timeoutcb(handle->sio, imap_timeout_cb, handle);
   }
-  if(handle->over_ssl) {
-    SSL *ssl = imap_create_ssl();
-    if(!ssl) {
-      imap_mbox_handle_set_msg(handle,"SSL context could not be created");
-      return IMAP_UNSECURE;
-    }
-    if(imap_setup_ssl(handle->sio, handle->host, ssl,
-                      handle->user_cb, handle->user_arg)) 
-      handle->using_tls = 1;
-    else {
-      imap_mbox_handle_set_msg(handle,"SSL negotiation failed");
-      imap_handle_disconnect(handle);
+#endif
+  if (handle->tls_mode == NET_CLIENT_CRYPT_ENCRYPTED) {
+    if (!net_client_start_tls(NET_CLIENT(handle->sio), &error)) {
+      imap_mbox_handle_set_msg(handle, error->message);
+         g_clear_error(&error);
       return IMAP_UNSECURE;
     }
   }
-  if(handle->monitor_cb) 
-    sio_set_monitorcb(handle->sio, handle->monitor_cb, handle->monitor_arg);
 
   handle->state = IMHS_CONNECTED;
   if ( (resp=imap_cmd_step(handle, 0)) != IMR_UNTAGGED) {
-    g_message("imap_mbox_connect:unexpected initial response(%d):\n%s\n",
+    g_message("imap_mbox_connect:unexpected initial response(%d): %s",
              resp, handle->last_msg);
     imap_handle_disconnect(handle);
     return IMAP_PROTOCOL_ERROR;
   }
   handle->can_fetch_body = 
     (strncmp(handle->last_msg, "Microsoft Exchange", 18) != 0);
-  if(handle->over_ssl)
-    resp = IMR_OK; /* secured already with SSL */
-  else if(handle->tls_mode != IMAP_TLS_DISABLED &&
-          imap_mbox_handle_can_do(handle, IMCAP_STARTTLS)) {
+  if((handle->tls_mode == NET_CLIENT_CRYPT_ENCRYPTED) ||
+        (handle->tls_mode == NET_CLIENT_CRYPT_NONE)) {
+    resp = IMAP_SUCCESS; /* secured already with SSL, or no encryption requested */
+  } else if(imap_mbox_handle_can_do(handle, IMCAP_STARTTLS)) {
     if( imap_handle_starttls(handle) != IMR_OK) {
       imap_mbox_handle_set_msg(handle,"TLS negotiation failed");
-      return IMAP_UNSECURE; /* TLS negotiation error */
+      resp = IMAP_UNSECURE; /* TLS negotiation error */
+    } else {
+      resp = IMAP_SUCCESS; /* secured with TLS */
     }
-    resp = IMR_OK; /* secured with TLS */
-  } else
-    resp = IMR_NO; /* not over SSL and TLS unavailable */
-  if(handle->tls_mode == IMAP_TLS_REQUIRED && resp != IMR_OK) {
-    imap_mbox_handle_set_msg(handle,"TLS required but not available");
-    return IMAP_UNSECURE;
+  } else {
+       imap_mbox_handle_set_msg(handle,"TLS required but not available");
+    resp = IMR_NO; /* TLS unavailable */
   }
 
-  return IMAP_SUCCESS;
+  return resp;
 }
 
 unsigned
@@ -853,7 +776,7 @@ imap_make_tag(ImapCmdTag tag)
 }
 
 static int
-imap_get_atom(struct siobuf *sio, char* atom, size_t len)
+imap_get_atom(NetClientSioBuf *sio, char* atom, size_t len)
 {
   unsigned i;
   int c = 0;
@@ -866,7 +789,7 @@ imap_get_atom(struct siobuf *sio, char* atom, size_t len)
 
 #define IS_FLAG_CHAR(c) (strchr("(){ %*\"]",(c))==NULL&&(c)>0x1f&&(c)!=0x7f)
 static int
-imap_get_flag(struct siobuf *sio, char* flag, size_t len)
+imap_get_flag(NetClientSioBuf *sio, char* flag, size_t len)
 {
   unsigned i;
   int c = 0;
@@ -886,7 +809,7 @@ imap_get_flag(struct siobuf *sio, char* flag, size_t len)
 */
 #define IS_TAG_CHAR(c) (strchr("(){ %\"\\]",(c))==NULL&&(c)>0x1f&&(c)!=0x7f)
 static int
-imap_cmd_get_tag(struct siobuf *sio, char* tag, size_t len)
+imap_cmd_get_tag(NetClientSioBuf *sio, char* tag, size_t len)
 {
   unsigned i;
   int c = 0;
@@ -1092,80 +1015,6 @@ imap_mbox_handle_get_msg(ImapMboxHandle* h, unsigned seqno)
   return h->msg_cache[seqno-1];
 }
 
-ImapMessage*
-imap_mbox_handle_get_msg_v(ImapMboxHandle* h, unsigned no)
-{
-  g_return_val_if_fail(h, 0);
-  g_return_val_if_fail(no-1<h->exists, NULL);
-  if(mbox_view_is_active(&h->mbox_view))
-    no = mbox_view_get_msg_no(&h->mbox_view, no);
-  return h->msg_cache[no-1];
-}
-unsigned
-imap_mbox_get_msg_no(ImapMboxHandle* h, unsigned no)
-{
-  g_return_val_if_fail(h, 0);
-  if(!mbox_view_is_active(&h->mbox_view))
-    return no;
-  else
-    return mbox_view_get_msg_no(&h->mbox_view, no);
-}
-
-unsigned
-imap_mbox_get_rev_no(ImapMboxHandle* h, unsigned seqno)
-{
-  if(!mbox_view_is_active(&h->mbox_view))
-    return seqno;
-  else
-    return mbox_view_get_rev_no(&h->mbox_view, seqno);
-}
-
-
-static void
-set_view_cb(ImapMboxHandle* handle, unsigned seqno, void*arg)
-{
-  mbox_view_append_no(&handle->mbox_view, seqno);
-}
-
-unsigned
-imap_mbox_set_view(ImapMboxHandle *h, ImapMsgFlag fl, gboolean state)
-{
-  char *flag;
-  gchar * cmd;
-  const gchar *cmd_prefix;
-  void *arg;
-  ImapSearchCb cb;
-  ImapResponse rc;
-
-  mbox_view_dispose(&h->mbox_view);
-  if(fl==0)
-    return 1;
-
-  if(imap_mbox_handle_can_do(h, IMCAP_ESEARCH))
-    cmd_prefix = "SEARCH RETURN (ALL) ";
-  else
-    cmd_prefix = "SEARCH ALL ";
-
-  switch(fl) {
-  case IMSGF_SEEN:     flag = "SEEN"; break;
-  case IMSGF_ANSWERED: flag = "ANSWERED"; break;
-  case IMSGF_FLAGGED:  flag = "FLAGGED"; break;
-  case IMSGF_DELETED:  flag = "DELETED"; break;
-  case IMSGF_DRAFT:    flag = "DRAFT"; break;
-  case IMSGF_RECENT:   flag = "RECENT"; break;
-  default: return 1;
-  }
-  cb  = h->search_cb;  h->search_cb  = (ImapSearchCb)set_view_cb;
-  arg = h->search_arg; h->search_arg = NULL;
-  g_free(h->mbox_view.filter_str);
-  h->mbox_view.filter_str = g_strconcat(state ? "" : "UN", flag, NULL);
-  cmd = g_strconcat(cmd_prefix, h->mbox_view.filter_str, NULL);
-  rc = imap_cmd_exec(h, cmd);
-  g_free(cmd);
-  h->search_cb = cb; h->search_arg = arg;
-  return rc == IMR_OK;
-}
-
 const char*
 imap_mbox_get_filter(ImapMboxHandle *h)
 {
@@ -1549,7 +1398,7 @@ imap_sequence_nth(ImapSequence *i_seq, unsigned nth)
       return r->lo + nth;
     nth -= range_length;
   }
-  g_warning("imap_sequence_nth: too large parameter; returning bogus data\n");
+  g_warning("imap_sequence_nth: too large parameter; returning bogus data");
   return 0;
 }
 
@@ -1966,10 +1815,7 @@ imap_cmd_start(ImapMboxHandle* handle, const char* cmd, unsigned *cmdno)
     return -1;
 
   *cmdno = imap_make_tag(tag);
-  sio_write(handle->sio, tag, strlen(tag));
-  sio_write(handle->sio, " ", 1);
-  sio_write(handle->sio, cmd, strlen(cmd));
-  sio_write(handle->sio, "\r\n", 2);
+  net_client_write_line(NET_CLIENT(handle->sio), "%s %s", NULL, tag, cmd);
   return 1;
 }
 
@@ -1990,18 +1836,11 @@ imap_cmd_step(ImapMboxHandle* handle, unsigned lastcmd)
   g_return_val_if_fail(handle, IMR_BAD);
   g_return_val_if_fail(handle->state != IMHS_DISCONNECTED, IMR_BAD);
 
-  if(ERR_peek_error()) {
-    fprintf(stderr, "OpenSSL error in %s():\n", __FUNCTION__);
-    ERR_print_errors_fp(stderr);
-    fprintf(stderr, "\nEnd of print_errors - severing the connection...\n");
-    imap_handle_disconnect(handle);
-    return IMR_SEVERED;
-  }
   ci = cmdi_find_by_no(handle->cmd_info, lastcmd);
   if(ci && ci->completed) {
     /* The response to this command has been encountered earlier,
        send it. */
-    printf("Sending stored response to %x and removing info.\n",  lastcmd);
+    g_debug("Sending stored response to %x and removing info.",  lastcmd);
     rc = ci->rc;
     handle->cmd_info = g_list_remove(handle->cmd_info, ci);
     g_free(ci);
@@ -2009,7 +1848,7 @@ imap_cmd_step(ImapMboxHandle* handle, unsigned lastcmd)
   }
 
   if( imap_cmd_get_tag(handle->sio, tag, sizeof(tag))<0) {
-    printf("IMAP connection to %s severed.\n", handle->host);
+    g_debug("IMAP connection to %s severed.", handle->host);
     imap_handle_disconnect(handle);
     return IMR_SEVERED;
   }
@@ -2029,7 +1868,7 @@ imap_cmd_step(ImapMboxHandle* handle, unsigned lastcmd)
   /* tagged completion code is the only alternative. */
   /* our command tags are hexadecimal numbers, at most 7 chars */
   if(sscanf(tag, "%7x", &cmdno) != 1) {
-    printf("scanning '%s' for tag number failed. Cannot recover.\n", tag);
+    g_warning("scanning '%s' for tag number failed. Cannot recover.", tag);
     imap_handle_disconnect(handle);
     return IMR_BAD;
   }
@@ -2042,17 +1881,17 @@ imap_cmd_step(ImapMboxHandle* handle, unsigned lastcmd)
   ci = cmdi_find_by_no(handle->cmd_info, cmdno);
 #ifdef DEBUG
   if(lastcmd != cmdno)
-    printf("Looking for %x and encountered response to %x (%p)\n",
+    g_debug("Looking for %x and encountered response to %x (%p)",
            lastcmd, cmdno, ci);
 #endif
   if(ci) {
     if(ci->complete_cb && !ci->complete_cb(handle, ci->cb_data)) {
       ci->rc = rc;
       ci->completed = 1;
-      printf("Cmd %x marked as completed with rc=%d\n", cmdno, rc);
+      g_debug("Cmd %x marked as completed with rc=%d", cmdno, rc);
     } else {
 #ifdef DEBUG
-      printf("CmdInfo for cmd %x removed\n", cmdno);
+      g_debug("CmdInfo for cmd %x removed", cmdno);
 #endif
       handle->cmd_info = g_list_remove(handle->cmd_info, ci);
       g_free(ci);
@@ -2064,6 +1903,17 @@ imap_cmd_step(ImapMboxHandle* handle, unsigned lastcmd)
     return lastcmd == cmdno ? rc : IMR_UNTAGGED;
 }
 
+ImapResponse
+imap_cmd_process_untagged(ImapMboxHandle* handle, unsigned cmdno)
+{
+       ImapResponse rc;
+
+       do {
+               rc = imap_cmd_step(handle, cmdno);
+       } while (rc == IMR_UNTAGGED);
+       return rc;
+}
+
 /**executes a command, and wait for the response from the server.
  * Also, handle untagged responses.
  * Returns ImapResponse.
@@ -2088,13 +1938,10 @@ imap_cmd_exec_cmdno(ImapMboxHandle* handle, const char* cmd,
 
   if(ret_cmdno) *ret_cmdno = cmdno;
   g_return_val_if_fail(handle->state != IMHS_DISCONNECTED && 1, IMR_BAD);
-  sio_flush(handle->sio);
   if(handle->state == IMHS_DISCONNECTED)
     return IMR_SEVERED;
 
-  do {
-    rc = imap_cmd_step (handle, cmdno);
-  } while (rc == IMR_UNTAGGED);
+  rc = imap_cmd_process_untagged(handle, cmdno);
 
   imap_handle_idle_enable(handle, IDLE_TIMEOUT);
 
@@ -2135,14 +1982,11 @@ imap_cmd_exec_cmds(ImapMboxHandle* handle, const char** cmds,
   }
   if (rc == IMR_OK) {
     g_return_val_if_fail(handle->state != IMHS_DISCONNECTED && 1, IMR_BAD);
-    sio_flush(handle->sio);
     if(handle->state == IMHS_DISCONNECTED)
       rc = IMR_SEVERED;
     else {
       for (cmd_count=0; cmds[cmd_count]; ++cmd_count) {
-       do {
-         rc = imap_cmd_step (handle, cmdnos[cmd_count]);
-       } while (rc == IMR_UNTAGGED);
+         rc = imap_cmd_process_untagged(handle, cmdnos[cmd_count]);
 
        if ( !(rc == IMR_OK || rc == IMR_NO || rc == IMR_BAD) ) {
          ret_rc = rc;
@@ -2162,57 +2006,8 @@ imap_cmd_exec_cmds(ImapMboxHandle* handle, const char** cmds,
   return ret_rc;
 }
 
-int
-imap_handle_write(ImapMboxHandle *conn, const char *buf, size_t len)
-{
-  g_return_val_if_fail(conn, -1);
-  g_return_val_if_fail(conn->sio, -1);
-
-  sio_write(conn->sio, buf, len); /* why it is void? */
-  return 0;
-}
-
-void
-imap_handle_flush(ImapMboxHandle *handle)
-{
-  g_return_if_fail(handle);
-  g_return_if_fail(handle->sio);
-  sio_flush(handle->sio);
-}
-
-char*
-imap_mbox_gets(ImapMboxHandle *h, char* buf, size_t sz)
-{
-  char* rc;
-  g_return_val_if_fail(h, NULL);
-  g_return_val_if_fail(h->sio, NULL);
-
-  rc = sio_gets(h->sio, buf, sz);
-  if(rc == NULL)
-      imap_handle_disconnect(h);
-  return rc;
-}
-
-const char*
-lbi_strerror(ImapResult rc)
-{
-  switch(rc) {
-   
-  case IMAP_SUCCESS:        return "action succeeded";
-  case IMAP_NOMEM:          return "not enough memory";
-  case IMAP_CONNECT_FAILED: return "transport level connect failed";
-  case IMAP_PROTOCOL_ERROR: return "unexpected server response";
-  case IMAP_AUTH_FAILURE:   return "authentication failure";
-  case IMAP_AUTH_UNAVAIL:   return "no supported authentication method available ";
-  case IMAP_UNSECURE:       return "secure connection requested but "
-                              "could not be established.";
-  case IMAP_SELECT_FAILED: return "SELECT command failed";
-  default: return "Unknown error";
-  }
-}
-
 static GString*
-imap_get_string_with_lookahead(struct siobuf* sio, int c)
+imap_get_string_with_lookahead(NetClientSioBuf *sio, int c)
 { /* string */  
   GString *res = NULL;
   if(c=='"') { /* quoted */
@@ -2236,8 +2031,8 @@ imap_get_string_with_lookahead(struct siobuf* sio, int c)
     if(len==0 || buf[len-1] != '}') return NULL;
     buf[len-1] = '\0';
     len = strtol(buf, NULL, 10);
-    if( c != 0x0d) { printf("lit1:%d\n",c); return NULL;}
-    if( (c=sio_getc(sio)) != 0x0a) { printf("lit1:%d\n",c); return NULL;}
+    if( c != 0x0d) { g_debug("lit1:%d",c); return NULL;}
+    if( (c=sio_getc(sio)) != 0x0a) { g_debug("lit1:%d",c); return NULL;}
     res = g_string_sized_new(len+1);
     if(len>0) sio_read(sio, res->str, len);
     res->len = len;
@@ -2248,14 +2043,14 @@ imap_get_string_with_lookahead(struct siobuf* sio, int c)
 
 /* see the spec for the definition of string */
 static char*
-imap_get_string(struct siobuf* sio)
+imap_get_string(NetClientSioBuf *sio)
 {
   GString * s = imap_get_string_with_lookahead(sio, sio_getc(sio));
   return s ? g_string_free(s, FALSE) : NULL;
 }
 
 static gboolean
-imap_is_nil (struct siobuf *sio, int c)
+imap_is_nil (NetClientSioBuf *sio, int c)
 {
   return g_ascii_toupper (c) == 'N' && g_ascii_toupper (sio_getc (sio)) == 'I'
     && g_ascii_toupper (sio_getc (sio)) == 'L';
@@ -2263,7 +2058,7 @@ imap_is_nil (struct siobuf *sio, int c)
 
 /* see the spec for the definition of nstring */
 static char*
-imap_get_nstring(struct siobuf* sio)
+imap_get_nstring(NetClientSioBuf *sio)
 {
   int c = sio_getc(sio);
   if(toupper(c)=='N') { /* nil */
@@ -2278,7 +2073,7 @@ imap_get_nstring(struct siobuf* sio)
 /* see the spec for the definition of astring */
 #define IS_ASTRING_CHAR(c) (strchr("(){ %*\"\\", (c))==0&&(c)>0x1F&&(c)!=0x7F)
 static char*
-imap_get_astring(struct siobuf *sio, int* lookahead)
+imap_get_astring(NetClientSioBuf *sio, int* lookahead)
 {
   char* res;
   int c = sio_getc(sio);
@@ -2300,7 +2095,7 @@ imap_get_astring(struct siobuf *sio, int* lookahead)
 
 /* nstring / literal8 as in the BINARY extension */
 static GString*
-imap_get_binary_string(struct siobuf *sio)
+imap_get_binary_string(NetClientSioBuf *sio)
 {
   int c = sio_getc(sio);
   if(toupper(c)=='N') { /* nil */
@@ -2322,14 +2117,14 @@ imap_get_binary_string(struct siobuf *sio)
 #include "imap-handle.h"
 
 static int
-ignore_bad_charset(struct siobuf *sio, int c)
+ignore_bad_charset(NetClientSioBuf *sio, int c)
 {
   while(c==' ') {
     gchar * astring = imap_get_astring(sio, &c); 
     g_free(astring);
   }
   if(c != ')')
-    fprintf(stderr,"ignore_bad_charset: expected ')' got '%c'\n", c);
+    g_warning("ignore_bad_charset: expected ')' got '%c'", c);
   else c = sio_getc(sio);
   return c;
 }
@@ -2459,7 +2254,7 @@ ir_get_append_copy_uids(ImapMboxHandle *h, gboolean append_only)
     if( (rc = imap_get_sequence(h, NULL, NULL)) != IMR_OK)
       return rc;
     if( (c=sio_getc(h->sio)) != ' ') {
-      printf("Expected ' ' found '%c'\n", c);
+      g_debug("Expected ' ' found '%c'", c);
       return IMR_PROTOCOL;
     }
   }
@@ -2519,7 +2314,7 @@ ir_resp_text_code(ImapMboxHandle *h)
   default: while( c != ']' && (c=sio_getc(h->sio)) != EOF) ; break;
   }
   if(c != ']')
-    printf("ir_resp_text_code, on exit c=%c\n", c);
+    g_debug("ir_resp_text_code, on exit c=%c", c);
   return c == ']' ? rc : IMR_PROTOCOL;
 }
 
@@ -2551,7 +2346,7 @@ ir_ok(ImapMboxHandle *h)
     if(h->info_cb)
       h->info_cb(h, rc, line, h->info_arg);
     else
-      printf("INFO : '%s'\n", line);
+      g_debug("INFO : '%s'", line);
     rc = IMR_OK; /* in case it was IMR_ALERT */
   }
   return rc;
@@ -2569,7 +2364,7 @@ ir_no(ImapMboxHandle *h)
     if(h->info_cb)
       h->info_cb(h, IMR_NO, line, h->info_arg);
     else
-      printf("WARN : '%s'\n", line);
+      g_debug("WARN : '%s'", line);
   }
   return IMR_NO;
 }
@@ -2585,7 +2380,7 @@ ir_bad(ImapMboxHandle *h)
     if(h->info_cb)
       h->info_cb(h, IMR_BAD, line, h->info_arg);
     else
-      printf("ERROR: %s\n", line);
+      g_debug("ERROR: %s", line);
   }
   return IMR_BAD;
 }
@@ -2612,10 +2407,8 @@ ir_bye(ImapMboxHandle *h)
     imap_mbox_handle_set_state(h, IMHS_DISCONNECTED);
     /* we close the connection here unless we are doing logout. */
     if(h->sio) {
-      sio_detach(h->sio); h->sio = NULL; 
-      imap_compress_release(&h->compress);
+      g_object_unref(h->sio); h->sio = NULL;
     }
-    close(h->sd);
   }
   return IMR_BYE;
 }
@@ -2624,11 +2417,11 @@ static ImapResponse
 ir_check_crlf(ImapMboxHandle *h, int c)
 {
   if( c != 0x0d) {
-    printf("CR:%d\n",c);
+    g_debug("CR:%d",c);
     return IMR_PROTOCOL;
   }
   if( (c=sio_getc(h->sio)) != 0x0a) {
-    printf("LF:%d\n",c);
+    g_debug("LF:%d",c);
     return IMR_PROTOCOL;
   }
   return IMR_OK;
@@ -2766,7 +2559,7 @@ ir_esearch(ImapMboxHandle *h)
     c = imap_get_atom(h->sio, atom, sizeof(atom));
     if(c == EOF) return IMR_SEVERED;
     if(g_ascii_strcasecmp(atom, "TAG")) { /* TAG is the only acceptable response here! */
-      printf("ESearch expected TAG encountered %s\n", atom);
+      g_debug("ESearch expected TAG encountered %s", atom);
       return IMR_PROTOCOL; 
     }
     if(c != ' ')
@@ -2843,7 +2636,7 @@ static ImapResponse
 ir_flags(ImapMboxHandle *h)
 {
   /* FIXME: implement! */
-  int c; EAT_LINE(h, c);
+  net_client_siobuf_discard_line(h->sio, NULL);
   return IMR_OK;
 }
 
@@ -2946,7 +2739,7 @@ ir_quotaroot(ImapMboxHandle *h)
   mbox = imap_get_astring(h->sio, &eol);
   if (mbox) {
     if (strcmp(mbox, mbx7))
-      fprintf(stderr, "expected QUOTAROOT for %s, not for %s\n", mbx7, mbox);
+      g_debug("expected QUOTAROOT for %s, not for %s", mbx7, mbox);
     else {
       if (eol == ' ')
         h->quota_root = imap_get_astring(h->sio, &eol);
@@ -2973,7 +2766,7 @@ ir_quota(ImapMboxHandle *h)
   h->quota_max_k = h->quota_used_k = 0;
   if (root) {
     if (strcmp(root, h->quota_root))
-      fprintf(stderr, "expected QUOTA for %s, not for %s\n", h->quota_root,
+      g_debug("expected QUOTA for %s, not for %s", h->quota_root,
               root);
     else {
       while ((c = sio_getc(h->sio)) != -1 && c == ' ');
@@ -2997,7 +2790,7 @@ ir_quota(ImapMboxHandle *h)
               h->quota_used_k = strtoul(usage, &endptr1, 10);
               h->quota_max_k = strtoul(limit, &endptr2, 10);
               if (*endptr1 != '\0' || *endptr2 != '\0') {
-                fprintf(stderr, "bad QUOTA '%s %s %s'\n", resource, usage,
+                g_debug("bad QUOTA '%s %s %s'", resource, usage,
                         limit);
                 h->quota_max_k = h->quota_used_k = 0;
                 c = ')';
@@ -3071,7 +2864,7 @@ ir_myrights(ImapMboxHandle *h)
   mbox = imap_get_astring(h->sio, &eol);
   if (mbox && eol == ' ') {
     if (strcmp(mbox, mbx7))
-      fprintf(stderr, "expected MYRIGHTS for %s, not for %s\n", mbx7, mbox);
+      g_debug("expected MYRIGHTS for %s, not for %s", mbx7, mbox);
     else {
       retval = extract_acl(h, "\n", &h->rights, NULL);
       h->has_rights = 1;
@@ -3110,7 +2903,7 @@ ir_getacl(ImapMboxHandle *h)
 
   mbx7 = imap_utf8_to_mailbox(h->mbox);
   if (strcmp(mbox, mbx7)) {
-    fprintf(stderr, "expected ACL for %s, not for %s\n", mbx7, mbox);
+    g_debug("expected ACL for %s, not for %s", mbx7, mbox);
     retval = IMR_NO;
   } else if (eol == '\n') {
     retval = IMR_OK;
@@ -3215,7 +3008,7 @@ imap_address_to_string(const ImapAddress *addr)
    (eg., when end of list is found instead).
 */
 static ImapAddress*
-imap_get_address(struct siobuf* sio)
+imap_get_address(NetClientSioBuf *sio)
 {
   char *addr[4], *p;
   ImapAddress *res = NULL;
@@ -3275,7 +3068,7 @@ imap_get_address(struct siobuf* sio)
 }
 
 static ImapResponse
-imap_get_addr_list (struct siobuf *sio, ImapAddress ** list)
+imap_get_addr_list (NetClientSioBuf *sio, ImapAddress ** list)
 {
   int c;
   ImapAddress *res;
@@ -3304,7 +3097,7 @@ imap_get_addr_list (struct siobuf *sio, ImapAddress ** list)
 }
 
 static ImapResponse
-ir_envelope(struct siobuf *sio, ImapEnvelope *env)
+ir_envelope(NetClientSioBuf *sio, ImapEnvelope *env)
 {
   int c;
   char *date, *str;
@@ -3315,14 +3108,14 @@ ir_envelope(struct siobuf *sio, ImapEnvelope *env)
 #if GMAIL_BUG_20100725 == 1
   /* GMAIL returns sometimes NIL instead of the envelope. */
   if (c == 'N') {
-      printf("GMail message/rfc822 bug detected.\n");      
+      g_debug("GMail message/rfc822 bug detected.");
       env = NULL;
       if (sio_getc(sio) == 'I' &&
           sio_getc(sio) == 'L') return IMR_PARSE;
   }
 #endif /* GMAIL_BUG_20100725 */
   if( c != '(') {
-      printf("envelope's ( expected but got '%c'\n", c);
+      g_debug("envelope's ( expected but got '%c'", c);
       return IMR_PROTOCOL;
   }
 
@@ -3355,10 +3148,10 @@ ir_envelope(struct siobuf *sio, ImapEnvelope *env)
   if( (c=sio_getc(sio)) != ' ') return IMR_PROTOCOL;
   str = imap_get_nstring(sio);
   if(env) env->in_reply_to = str; else g_free(str);
-  if( (c=sio_getc(sio)) != ' ') { printf("c=%c\n",c); return IMR_PROTOCOL;}
+  if( (c=sio_getc(sio)) != ' ') { g_debug("c=%c",c); return IMR_PROTOCOL;}
   str = imap_get_nstring(sio);
   if(env) env->message_id = str; else g_free(str);
-  if( (c=sio_getc(sio)) != ')') { printf("c=%d\n",c);return IMR_PROTOCOL;}
+  if( (c=sio_getc(sio)) != ')') { g_debug("c=%d",c);return IMR_PROTOCOL;}
   return IMR_OK;
 }
 
@@ -3420,7 +3213,7 @@ ir_msg_att_rfc822_size(ImapMboxHandle *h, int c, unsigned seqno)
 }
 
 static ImapResponse
-ir_media(struct siobuf* sio, ImapMediaBasic *imb, ImapBody *body)
+ir_media(NetClientSioBuf *sio, ImapMediaBasic *imb, ImapBody *body)
 {
   gchar *type, *subtype;
 
@@ -3455,7 +3248,7 @@ ir_media(struct siobuf* sio, ImapMediaBasic *imb, ImapBody *body)
 }
 
 static ImapResponse
-ir_body_fld_param_hash(struct siobuf* sio, GHashTable * params)
+ir_body_fld_param_hash(NetClientSioBuf *sio, GHashTable * params)
 {
   int c;
   gchar *key, *val;
@@ -3478,13 +3271,13 @@ ir_body_fld_param_hash(struct siobuf* sio, GHashTable * params)
 }
 
 static ImapResponse
-ir_body_fld_param(struct siobuf* sio, ImapBody *body)
+ir_body_fld_param(NetClientSioBuf *sio, ImapBody *body)
 {
   return ir_body_fld_param_hash(sio, body ? body->params : NULL);
 }
 
 static ImapResponse
-ir_body_fld_id(struct siobuf* sio, ImapBody *body)
+ir_body_fld_id(NetClientSioBuf *sio, ImapBody *body)
 {
   gchar* id = imap_get_nstring(sio);
 
@@ -3496,7 +3289,7 @@ ir_body_fld_id(struct siobuf* sio, ImapBody *body)
 }
 
 static ImapResponse
-ir_body_fld_desc(struct siobuf* sio, ImapBody *body)
+ir_body_fld_desc(NetClientSioBuf *sio, ImapBody *body)
 {
   gchar* desc = imap_get_nstring(sio);
   if(body)
@@ -3507,7 +3300,7 @@ ir_body_fld_desc(struct siobuf* sio, ImapBody *body)
 }
 
 static ImapResponse
-ir_body_fld_enc(struct siobuf* sio, ImapBody *body)
+ir_body_fld_enc(NetClientSioBuf *sio, ImapBody *body)
 {
   gchar* str = imap_get_string(sio);
   ImapBodyEncoding enc;
@@ -3527,7 +3320,7 @@ ir_body_fld_enc(struct siobuf* sio, ImapBody *body)
 }
 
 static ImapResponse
-ir_body_fld_octets(struct siobuf* sio, ImapBody *body)
+ir_body_fld_octets(NetClientSioBuf *sio, ImapBody *body)
 {
   char buf[12];
   int c = imap_get_atom(sio, buf, sizeof(buf));
@@ -3539,7 +3332,7 @@ ir_body_fld_octets(struct siobuf* sio, ImapBody *body)
 }
 
 static ImapResponse
-ir_body_fields(struct siobuf* sio, ImapBody *body)
+ir_body_fields(NetClientSioBuf *sio, ImapBody *body)
 {
   ImapResponse rc;
   int c;
@@ -3547,7 +3340,7 @@ ir_body_fields(struct siobuf* sio, ImapBody *body)
   if( (rc=ir_body_fld_param (sio, body))!=IMR_OK) return rc;
   if(sio_getc(sio) != ' ') return IMR_PROTOCOL;
   if( (rc=ir_body_fld_id    (sio, body))!=IMR_OK) return rc;
-  if((c=sio_getc(sio)) != ' ') { printf("err=%c\n", c); return IMR_PROTOCOL; }
+  if((c=sio_getc(sio)) != ' ') { g_debug("err=%c", c); return IMR_PROTOCOL; }
   if( (rc=ir_body_fld_desc  (sio, body))!=IMR_OK) return rc;
   if(sio_getc(sio) != ' ') return IMR_PROTOCOL;
   if( (rc=ir_body_fld_enc   (sio, body))!=IMR_OK) return rc;
@@ -3558,7 +3351,7 @@ ir_body_fields(struct siobuf* sio, ImapBody *body)
 }
 
 static ImapResponse
-ir_body_fld_lines(struct siobuf* sio, ImapBody* body)
+ir_body_fld_lines(NetClientSioBuf *sio, ImapBody* body)
 {
   char buf[12];
   int c = imap_get_atom(sio, buf, sizeof(buf));
@@ -3571,7 +3364,7 @@ ir_body_fld_lines(struct siobuf* sio, ImapBody* body)
 
 /* body_fld_dsp = "(" string SP body_fld_param ")" / nil */
 static ImapResponse
-ir_body_fld_dsp (struct siobuf *sio, ImapBody * body)
+ir_body_fld_dsp (NetClientSioBuf *sio, ImapBody * body)
 {
   ImapResponse rc;
   int c;
@@ -3625,7 +3418,7 @@ ir_body_fld_dsp (struct siobuf *sio, ImapBody * body)
 
 /* body-fld-lang = nstring / "(" string *(SP string) ")" */
 static ImapResponse
-ir_body_fld_lang (struct siobuf *sio, ImapBody * body)
+ir_body_fld_lang (NetClientSioBuf *sio, ImapBody * body)
 {
   int c;
 
@@ -3667,7 +3460,7 @@ ir_body_fld_lang (struct siobuf *sio, ImapBody * body)
  *                  "(" body-extension *(SP body-extension) ")"
  */
 static ImapResponse
-ir_body_extension (struct siobuf *sio, ImapBody * body)
+ir_body_extension (NetClientSioBuf *sio, ImapBody * body)
 {
   int c;
 
@@ -3716,7 +3509,7 @@ typedef enum _ImapBodyExtensibility ImapBodyExtensibility;
  */
 
 static ImapResponse
-ir_body_ext_mpart (struct siobuf *sio, ImapBody * body,
+ir_body_ext_mpart (NetClientSioBuf *sio, ImapBody * body,
                   ImapBodyExtensibility type)
 {
   ImapResponse rc;
@@ -3795,7 +3588,7 @@ ir_body_ext_mpart (struct siobuf *sio, ImapBody * body,
  *                   ; "BODY" fetch
  */
 static ImapResponse
-ir_body_ext_1part (struct siobuf *sio, ImapBody * body,
+ir_body_ext_1part (NetClientSioBuf *sio, ImapBody * body,
                   ImapBodyExtensibility type)
 {
   ImapResponse rc;
@@ -3812,8 +3605,8 @@ ir_body_ext_1part (struct siobuf *sio, ImapBody * body,
     sio_ungetc(sio);
     if(isdigit(c)) { 
       char buf[20];
-      printf("Incorrect GMail number-of-lines entry detected. "
-            "Working around.\n");
+      g_debug("Incorrect GMail number-of-lines entry detected. "
+            "Working around.");
       c = imap_get_atom(sio, buf, sizeof(buf));
       if(c != ' ')
        return IMR_PROTOCOL;
@@ -3883,10 +3676,10 @@ ir_body_ext_1part (struct siobuf *sio, ImapBody * body,
 /* body-type-mpart = 1*body SP media-subtype
  *                   [SP body-ext-mpart]
  */
-static ImapResponse ir_body (struct siobuf *sio, int c, ImapBody * body,
+static ImapResponse ir_body (NetClientSioBuf *sio, int c, ImapBody * body,
                             ImapBodyExtensibility type);
 static ImapResponse
-ir_body_type_mpart (struct siobuf *sio, ImapBody * body,
+ir_body_type_mpart (NetClientSioBuf *sio, ImapBody * body,
                    ImapBodyExtensibility type)
 {
   ImapResponse rc;
@@ -3942,7 +3735,7 @@ ir_body_type_mpart (struct siobuf *sio, ImapBody * body,
  *                   [SP body-ext-1part]
  */
 static ImapResponse
-ir_body_type_1part (struct siobuf *sio, ImapBody * body,
+ir_body_type_1part (NetClientSioBuf *sio, ImapBody * body,
                    ImapBodyExtensibility type)
 {
   ImapResponse rc;
@@ -4045,7 +3838,7 @@ ir_body_type_1part (struct siobuf *sio, ImapBody * body,
 
 /* body = "(" (body-type-1part / body-type-mpart) ")" */
 static ImapResponse
-ir_body (struct siobuf *sio, int c, ImapBody * body,
+ir_body (NetClientSioBuf *sio, int c, ImapBody * body,
         ImapBodyExtensibility type)
 {
   ImapResponse rc;
@@ -4070,7 +3863,7 @@ ir_body (struct siobuf *sio, int c, ImapBody * body,
 
 /* read [section] and following string. FIXME: other kinds of body. */ 
 static ImapResponse
-ir_body_section(struct siobuf *sio, unsigned seqno,
+ir_body_section(NetClientSioBuf *sio, unsigned seqno,
                ImapFetchBodyType body_type,
                ImapFetchBodyInternalCb body_cb, void *arg)
 {
diff --git a/libbalsa/imap/imap-handle.h b/libbalsa/imap/imap-handle.h
index 875cdb22..55373baa 100644
--- a/libbalsa/imap/imap-handle.h
+++ b/libbalsa/imap/imap-handle.h
@@ -19,6 +19,7 @@
 
 #include <glib.h>
 
+#include "net-client.h"
 #include "libimap.h"
 
 typedef enum {
@@ -120,22 +121,21 @@ typedef void(*ImapListCb)(ImapMboxHandle*handle, int delim,
 
 ImapMboxHandle *imap_mbox_handle_new(void);
 void imap_handle_set_option(ImapMboxHandle *h, ImapOption opt, gboolean state);
-void imap_handle_set_monitorcb(ImapMboxHandle* h, ImapMonitorCb cb, void*);
 void imap_handle_set_infocb(ImapMboxHandle* h, ImapInfoCb cb, void*);
-void imap_handle_set_usercb(ImapMboxHandle* h, ImapUserCb cb, void*);
 void imap_handle_set_flagscb(ImapMboxHandle* h, ImapFlagsCb cb, void*);
+void imap_handle_set_authcb(ImapMboxHandle* h, GCallback cb, void *arg);
+void imap_handle_set_certcb(ImapMboxHandle* h, GCallback cb);
 int imap_handle_set_timeout(ImapMboxHandle *, int milliseconds);
 gboolean imap_handle_idle_enable(ImapMboxHandle *, int seconds);
 gboolean imap_handle_idle_disable(ImapMboxHandle *)
     __attribute__ ((warn_unused_result));
 gboolean imap_handle_op_cancelled(ImapMboxHandle *h);
-ImapResult imap_mbox_handle_connect(ImapMboxHandle* r, const char *hst, 
-                                    int over_ssl);
+ImapResult imap_mbox_handle_connect(ImapMboxHandle* r, const char *hst);
 ImapResult imap_mbox_handle_reconnect(ImapMboxHandle* r,
                                       gboolean *readonly);
 void imap_handle_force_disconnect(ImapMboxHandle *h);
 
-ImapTlsMode imap_handle_set_tls_mode(ImapMboxHandle *h, ImapTlsMode option);
+NetClientCryptMode imap_handle_set_tls_mode(ImapMboxHandle *h, NetClientCryptMode option);
 
 /* int below is a boolean */
 int      imap_mbox_handle_can_do(ImapMboxHandle* handle, ImapCapability cap);
@@ -159,17 +159,11 @@ ImapResponse imap_mbox_handle_fetch_env(ImapMboxHandle* handle,
                                         const gchar *seq);
 
 ImapMessage* imap_mbox_handle_get_msg(ImapMboxHandle* handle, unsigned seqno);
-ImapMessage* imap_mbox_handle_get_msg_v(ImapMboxHandle* handle, unsigned no);
-unsigned imap_mbox_get_msg_no(ImapMboxHandle* h, unsigned no);
-unsigned imap_mbox_get_rev_no(ImapMboxHandle* h, unsigned seqno);
 
 unsigned imap_mbox_handle_first_unseen(ImapMboxHandle* handle);
-unsigned imap_mbox_find_next(ImapMboxHandle* handle, unsigned start, 
-                             const char *search_str);
 ImapResponse imap_mbox_find_all(ImapMboxHandle *h, const char *search_str,
                                 unsigned *msgcnt, unsigned**msgs);
 
-unsigned imap_mbox_set_view(ImapMboxHandle *h, ImapMsgFlag f, gboolean state);
 unsigned imap_mbox_set_sort(ImapMboxHandle *h, ImapSortKey isr, 
                             int ascending);
 const char *imap_mbox_get_filter(ImapMboxHandle *h);
diff --git a/libbalsa/imap/imap-tls.c b/libbalsa/imap/imap-tls.c
index 4376080c..d07275b7 100644
--- a/libbalsa/imap/imap-tls.c
+++ b/libbalsa/imap/imap-tls.c
@@ -41,347 +41,28 @@
  */
 
 #include "config.h"
-
-#include <string.h>
-#include <openssl/ssl.h>
-#include <openssl/x509v3.h>
-#include <openssl/err.h>
-
-/* Support for SSLv3 should *not* be enabled as it is unsafe (see
- * <http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-3566> and
- * <http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-8730>.
- *
- * Uncomment the following line if you *really* want to enable SSLv3 support.
- * Otherwise, only the "safe" protocols TLS 1.0, TLS 1.1 and TLS 1.2 are used
- * (note that TLS 1.1 and TLS 1.2 support depends upon the OpenSSL version) */
-/* #define ENABLE_SSL3 1 */
-
-#include "siobuf.h"
+#include "siobuf-nc.h"
 #include "imap_private.h"
 
-static SSL_CTX *global_ssl_context = NULL;
-static GMutex global_tls_lock;
-
-  /* Setting callbacks is not required any more with 1.1.0-pre4 and newer */
-#if OPENSSL_VERSION_NUMBER < 0x010100004L
-/* OpenSSL static locks */
-static GMutex *mutexes = NULL;
-
-static void
-locking_function(int mode, int n, const char *file, int line)
-{
-  if(mode & CRYPTO_LOCK)
-         g_mutex_lock(&mutexes[n]);
-  else
-         g_mutex_unlock(&mutexes[n]);
-}
-
-static unsigned long
-id_function(void)
-{
-  return (unsigned long) g_thread_self();
-}
-
-/* OpenSSL dynamic locks */
-struct CRYPTO_dynlock_value {
-  GMutex mutex;
-};
-
-static struct CRYPTO_dynlock_value*
-dyn_create_function(const char *file, int line)
-{
-  struct CRYPTO_dynlock_value *value =
-    (struct CRYPTO_dynlock_value*)malloc(sizeof(struct CRYPTO_dynlock_value));
-
-  if(!value)
-    return NULL;
-  g_mutex_init(&value->mutex);
-  return value;
-}
-
-static void
-dyn_lock_function(int mode, struct CRYPTO_dynlock_value *l,
-                  const char *file, int line)
-{
-  if(mode & CRYPTO_LOCK)
-         g_mutex_lock(&l->mutex);
-  else
-         g_mutex_unlock(&l->mutex);
-}
-
-static void
-dyn_destroy_function(struct CRYPTO_dynlock_value *l,
-                     const char *file, int line)
-{
-       g_mutex_clear(&l->mutex);
-  free(l);
-}
-
-static int
-imaptls_thread_setup(void)
-{
-  int i, mutex_cnt = CRYPTO_num_locks();
-
-  mutexes = (GMutex*)malloc(mutex_cnt*sizeof(GMutex));
-  if(!mutexes)
-    return 0;
-  for(i=0; i<mutex_cnt; i++)
-         g_mutex_init(&mutexes[i]);
-  CRYPTO_set_id_callback(id_function);
-  CRYPTO_set_locking_callback(locking_function);
-  
-  /* dynamic locking for future releases of OpenSSL */
-  CRYPTO_set_dynlock_create_callback (dyn_create_function);
-  CRYPTO_set_dynlock_lock_callback   (dyn_lock_function);
-  CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function);
-  return 1;
-}
-
-#if defined(DO_PROPER_OPENSSL_CLEANUP)
-static int
-imaptls_thread_cleanup(void)
-{
-  int i, mutex_cnt = CRYPTO_num_locks();
-  if(!mutexes)
-    return 0;
-  CRYPTO_set_id_callback(NULL);
-  CRYPTO_set_locking_callback(NULL);
-  CRYPTO_set_dynlock_create_callback(NULL);
-  CRYPTO_set_dynlock_lock_callback(NULL);
-  CRYPTO_set_dynlock_destroy_callback(NULL);
-  for(i=0; i<mutex_cnt; i++)
-         g_mutex_clear(&mutexes[i]);
-  free(mutexes); mutexes = NULL;
-  return 1;
-}
-#endif /* DO_PROPER_OPENSSL_CLEANUP */
-#else
-static int imaptls_thread_setup() { return 0; }
-#endif /* OPENSSL_VERSION_NUMBER < OPENSSL_VER(1,1,0,0,4) */
-
-SSL*
-imap_create_ssl(void)
-{
-  SSL *ssl;
-
-  g_mutex_lock(&global_tls_lock);
-  if(!global_ssl_context) {
-    /* Initialize OpenSSL library, follow "Network Security with
-       OpenSSL", ISBN 0-596-00270-X, guidelines. Example 4-2. */
-    imaptls_thread_setup();
-    SSL_library_init();
-    SSL_load_error_strings();
-#if 0
-    global_ssl_context = SSL_CTX_new (TLSv1_client_method ());
-#else
-    /* Note: SSLv23_client_method() actually enables *all* protocols, including
-     * SSLv(2|3) and TLSv1.(0|1|2), so we must switch all unsafe ones off */
-    global_ssl_context = SSL_CTX_new (SSLv23_client_method ());
-    if(!global_ssl_context) {
-        fprintf(stderr, "Could not initialize SSL Context.\n");
-        ERR_print_errors_fp(stderr);
-        fprintf(stderr, "\nEnd of print_errors\n");
-        g_mutex_unlock(&global_tls_lock);
-        return NULL;
-    }
-
-#ifdef ENABLE_SSL3
-    SSL_CTX_set_options(global_ssl_context, SSL_OP_ALL|SSL_OP_NO_SSLv2);
-#else
-    SSL_CTX_set_options(global_ssl_context, SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3);
-#endif
-#endif
-    /* no client certificate password support yet
-     * SSL_CTX_set_default_passwd_cb (ctx, ctx_password_cb);
-     * SSL_CTX_set_default_passwd_cb_userdata (ctx, ctx_password_cb_arg); 
-     */
-
-    /* Load the trusted CAs here. We just trust the system CA for the
-       moment but we could try to be compatible with libESMTP in this
-       respect.
-    */
-   SSL_CTX_set_default_verify_paths (global_ssl_context);
-  }
-  g_mutex_unlock(&global_tls_lock);
-
-  ssl = SSL_new(global_ssl_context);
-
-  /* setup client certificates here */
-  return ssl;
-}
-
-/* check_server_identity() follows example 5-8 in the OpenSSL book. */
-static int
-host_matches_domain(const char* host, const char*domain, int host_len)
-{ 
-  if(!domain || !host)
-    return 0;
-  if(domain[0] == '*') { /* RFC2595, section 2.4 */
-    int domain_len = strlen(domain);
-    if(domain_len<2 || domain[1] != '.') /* wrong wildcard format! */
-      return 0;
-    if(host_len - domain_len + 2<= 0) /* host much shorter than wildcard */
-      return 0;
-    return g_ascii_strcasecmp(host + host_len - domain_len+2, 
-                              domain+2) == 0;
-  } else 
-    return g_ascii_strncasecmp(host, domain, host_len) == 0;
-}
-
-static int
-imap_check_server_identity(SSL *ssl, const char *host,
-                           ImapUserCb user_cb, void *user_arg)
-{
-  long vfy_result;
-  X509 *cert;
-  X509_NAME *subj;
-  int ok, host_len;
-  gchar *colon;
-  int has_extension_with_dns_name = 0;
-  STACK_OF(GENERAL_NAME) *altnames;
-
-  if(!host)
-    return 0;
-  /* Check whether the certificate matches the server. */
-  cert = SSL_get_peer_certificate(ssl);
-  if(!cert)
-    return 0;
-
-  colon = strchr(host, ':');
-  host_len = colon ? colon - host : (int)strlen(host);
-  ok = 0;
-
-  altnames = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
-
-  if (altnames) {
-    int i;
-
-    for (i=0; i< sk_GENERAL_NAME_num(altnames); i++) {
-      const GENERAL_NAME *current_name = sk_GENERAL_NAME_value(altnames, i);
-
-      /* We handle only GEN_DNS. GEN_IP (certificates for IP numbers)
-         are too weird to be real in IMAP case. */
-      if (current_name->type == GEN_DNS) {
-        const ASN1_IA5STRING *ia5 = current_name->d.ia5;
-        const char *name = (const char*)ia5->data;
-        has_extension_with_dns_name = 1;
-
-        if (strlen(name) == (size_t)ia5->length &&
-            host_matches_domain(host, name, host_len)) {
-          /* printf("verified name using extension\n"); */
-          ok = 1;
-          break;
-        }
-      }
-    }
-    sk_GENERAL_NAME_pop_free(altnames, GENERAL_NAME_free);
-  }
-
-  if (!has_extension_with_dns_name) {
-    char data[256];
-    size_t name_len;
-    if( (subj = X509_get_subject_name(cert)) &&
-        (name_len = 
-         X509_NAME_get_text_by_NID(subj, NID_commonName,
-                                   data, sizeof(data)))){
-      data[sizeof(data)-1] = 0;
-
-      /* Remember to check whether there was no truncation or NUL
-         characters embedded in the text. */
-      if(name_len == strlen(data) &&
-         host_matches_domain(host, data, host_len)) {
-        ok =1;
-        /* printf("verified name using common name\n"); */
-      }
-    }
-  }
-
-  X509_free(cert);
-  if(ok)
-    vfy_result = SSL_get_verify_result(ssl);
-  else
-    vfy_result = X509_V_ERR_APPLICATION_VERIFICATION;
-
-  if(vfy_result == X509_V_OK)
-    return 1;
-  /* There was a problem with the verification, one has to leave it up
-   * to the application what to do with this.
-   */
-  ok = 0;
-  if(user_cb)
-    user_cb(IME_TLS_VERIFY_ERROR, user_arg, &ok, 
-            vfy_result, ssl);
-  return ok;
-}
-
-static int
-check_cipher_strength(SSL *ssl, ImapUserCb user_cb, void *user_arg)
-{
-  int ok, bits = SSL_get_cipher_bits(ssl, NULL);
-
-  if (bits > 40) 
-    return 1;
-  ok = 0;
-  if (user_cb != NULL)
-    user_cb(IME_TLS_WEAK_CIPHER, user_arg,
-                    bits, &ok);
-  return ok;
-}
-
-int
-imap_setup_ssl(struct siobuf *sio, const char* host, SSL *ssl,
-               ImapUserCb user_cb, void *user_arg)
-{
-  if(ERR_peek_error()) {
-    fprintf(stderr, "OpenSSL error in %s():\n", __FUNCTION__);
-    ERR_print_errors_fp(stderr);
-    fprintf(stderr, "\nEnd of print_errors\n");
-  }
-  if(sio_set_tlsclient_ssl (sio, ssl)) {
-    if(!imap_check_server_identity(ssl, host, user_cb, user_arg)) {
-      printf("Server identity not confirmed\n");
-      return 0;
-    }
-    if(!check_cipher_strength(ssl, user_cb, user_arg)) {
-      printf("Cipher too weak\n");
-      return 0;
-    }
-    return 1;
-  } else {
-    printf("set_tlsclient failed for %s\n", host);
-    return 0;
-  }
-}
-
 ImapResponse
 imap_handle_starttls(ImapMboxHandle *handle)
 {
-  ImapResponse rc;
-  SSL *ssl;
-
-  IMAP_REQUIRED_STATE1(handle, IMHS_CONNECTED, IMR_BAD);
-  if(!imap_mbox_handle_can_do(handle, IMCAP_STARTTLS)) 
-    return IMR_NO;
-
-
-  ssl = imap_create_ssl();
-  if(!ssl) { 
-    printf("ssl=%p ctx=%p\n", ssl, global_ssl_context);
-    return IMR_NO;
-  }
-
-  if( (rc=imap_cmd_exec(handle, "StartTLS")) != IMR_OK) {
-    SSL_free(ssl);
-    return rc;
-  }
-  if(imap_setup_ssl(handle->sio, handle->host, ssl,
-                    handle->user_cb, handle->user_arg)) {
-    handle->using_tls = 1;
-    handle->has_capabilities = 0;
-    return IMR_OK;
-  } else {
-    /* ssl is owned now by sio, no need to free it SSL_free(ssl); */
-    imap_handle_disconnect(handle);
-    return IMR_NO;
-  }
+       ImapResponse rc;
+
+       IMAP_REQUIRED_STATE1(handle, IMHS_CONNECTED, IMR_BAD);
+       if (!imap_mbox_handle_can_do(handle, IMCAP_STARTTLS))
+               return IMR_NO;
+
+       rc = imap_cmd_exec(handle, "StartTLS");
+       if (rc != IMR_OK) {
+               return rc;
+       }
+       if (net_client_start_tls(NET_CLIENT(handle->sio), NULL)) {
+               handle->has_capabilities = 0;
+               return IMR_OK;
+       } else {
+               /* ssl is owned now by sio, no need to free it SSL_free(ssl); */
+               imap_handle_disconnect(handle);
+               return IMR_NO;
+       }
 }
diff --git a/libbalsa/imap/imap_compress.c b/libbalsa/imap/imap_compress.c
index a974b6d2..0010ab97 100644
--- a/libbalsa/imap/imap_compress.c
+++ b/libbalsa/imap/imap_compress.c
@@ -15,169 +15,26 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <zlib.h>
-#include "siobuf.h"
+#include "siobuf-nc.h"
 #include "imap-handle.h"
 #include "imap_private.h"
 
-/** Arbitrary. Current choice is as good as any other. */
-static const unsigned IMAP_COMPRESS_BUFFER_SIZE = 8192;
-
-static int
-imap_compress_cb(char **dstbuf, int *dstlen,
-                 const char *srcbuf, int srclen, void *arg)
-{
-  struct ImapCompressContext *icb = &((ImapMboxHandle*)arg)->compress;
-  int err;
-
-  *dstbuf = icb->out_buffer;
-
-  if (*dstlen == 0) { /* first call */
-    icb->out_stream.next_in  = (Bytef*)srcbuf;
-    icb->out_stream.avail_in = srclen;
-    icb->out_uncompressed += srclen;
-  }
-
-  icb->out_stream.next_out = (Byte*)*dstbuf;
-  icb->out_stream.avail_out = IMAP_COMPRESS_BUFFER_SIZE;
-
-  err = deflate(&icb->out_stream, srclen ? Z_NO_FLUSH : Z_SYNC_FLUSH);
-  if ( !(err == Z_OK || err == Z_STREAM_END || err == Z_BUF_ERROR) ) {
-    fprintf(stderr, "deflate error1 %d\n", err);
-    *dstlen = -1;
-  } else {
-    *dstlen = IMAP_COMPRESS_BUFFER_SIZE - icb->out_stream.avail_out;
-    /* printf("imap_compress_cb %d bytes to %d\n", srclen, *dstlen); */
-    icb->out_compressed += *dstlen;
-  }
-
-  return *dstlen;
-}
-
-static int
-imap_decompress_cb(char **dstbuf, int *dstlen,
-                   const char *srcbuf, int srclen, void *arg)
-{
-  struct ImapCompressContext *icb = &((ImapMboxHandle*)arg)->compress;
-  int err;
-
-  *dstbuf = icb->in_buffer;
-
-  if (srclen) {
-    icb->in_stream.next_in  = (Bytef*)srcbuf;
-    icb->in_stream.avail_in = srclen;
-    icb->in_compressed += srclen;
-  }
-
-  icb->in_stream.next_out = (Byte*)*dstbuf;
-  icb->in_stream.avail_out =  IMAP_COMPRESS_BUFFER_SIZE;
-  err = inflate(&icb->in_stream, Z_SYNC_FLUSH);
-  
-  if (!(err == Z_OK || err == Z_BUF_ERROR || err == Z_STREAM_END)) {
-    fprintf(stderr, "inflate error %d\n", err);
-    *dstlen = -1;
-  } else {
-    *dstlen = IMAP_COMPRESS_BUFFER_SIZE - icb->in_stream.avail_out;
-    /* printf("imap_decompress_cb %d bytes to %d\n", srclen, *dstlen); */
-    icb->in_uncompressed += *dstlen;
-  }
-  return *dstlen;
-}
-
 /** Enables COMPRESS extension if available. Assumes that the handle
     is already locked. */
 ImapResponse
 imap_compress(ImapMboxHandle *handle)
 {
-  struct ImapCompressContext *icb;
-  int err;
-
-  if (!handle->enable_compress ||
-      !imap_mbox_handle_can_do(handle, IMCAP_COMPRESS_DEFLATE))
-    return IMR_NO;
-
-  if (imap_cmd_exec(handle, "COMPRESS DEFLATE") != IMR_OK)
-    return IMR_NO;
-
-  icb = &handle->compress;
-  icb->in_buffer = malloc(IMAP_COMPRESS_BUFFER_SIZE);
-  icb->out_buffer = malloc(IMAP_COMPRESS_BUFFER_SIZE);
-
-  if (!icb->in_buffer || !icb->out_buffer)
-    return IMR_NO;
-
-  /* Compression enabled. Everything that we send and receive now must
-     go through compression/decompression routines enabled in sio. */
-
-  icb->out_stream.zalloc = Z_NULL;
-  icb->out_stream.zfree = Z_NULL;
-  icb->out_stream.opaque = (voidpf)0;
-
-  /* amazingly enough, deflateInit() won't do */
-  err = deflateInit2(&icb->out_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
-                     -15, 8, Z_DEFAULT_STRATEGY);
-  if (err != Z_OK) {
-    fprintf(stderr, "deflateInit error: %d\n", err);
-    return IMR_NO;
-  }
-
-  icb->in_stream.next_in = Z_NULL;
-  icb->in_stream.avail_in = 0;
-  icb->in_stream.zalloc = Z_NULL;
-  icb->in_stream.zfree = Z_NULL;
-  icb->in_stream.opaque = (voidpf)0;
-
-  /* amazingly enough, inflateInit() won't do */
-  err = inflateInit2(&icb->in_stream, -15);
-  if (err != Z_OK) {
-    fprintf(stderr, "inflateInit error: %d\n", err);
-    return IMR_NO;
-  }
-
-  if (handle->sio) {
-    sio_set_securitycb(handle->sio, imap_compress_cb, imap_decompress_cb,
-                       handle);
-    return IMR_OK;
-  } else {
-    fprintf(stderr, "SIO not set!\n");
-    return IMR_NO;
-  }
-}
-
-void
-imap_compress_init(struct ImapCompressContext *buf)
-{
-  memset(buf, 0, sizeof(struct ImapCompressContext));
+       if (!handle->enable_compress ||
+               !imap_mbox_handle_can_do(handle, IMCAP_COMPRESS_DEFLATE))
+               return IMR_NO;
+
+       if (imap_cmd_exec(handle, "COMPRESS DEFLATE") != IMR_OK)
+               return IMR_NO;
+
+       if (net_client_start_compression(NET_CLIENT(handle->sio), NULL)) {
+               return IMR_OK;
+       } else {
+               g_warning("%s: SIO not set!", __func__);
+               return IMR_NO;
+       }
 }
-
-/** releases any data that might have been allocated by compression routines. */
-
-void
-imap_compress_release(struct ImapCompressContext *buf)
-{
-
-  if (buf->in_buffer) {
-    inflateEnd(&buf->in_stream);
-    free(buf->in_buffer);
-  }
-
-  if (buf->out_buffer) {
-    deflateEnd(&buf->out_stream);
-    free(buf->out_buffer);
-  }
-  if (buf->in_uncompressed) {
-    printf("IMAP server compression %lu -> %lu sent %5.1f %% over wire\n",
-           buf->in_compressed, buf->in_uncompressed,  
-           100.0*(buf->in_compressed/(float)buf->in_uncompressed));
-  }
-  if (buf->in_uncompressed) {
-    printf("IMAP client compression %lu -> %lu sent %5.1f %% over wire\n",
-           buf->out_uncompressed, buf->out_compressed,  
-           100.0*(buf->out_compressed/(float)buf->out_uncompressed));
-  }
-}
-
-
diff --git a/libbalsa/imap/imap_compress.h b/libbalsa/imap/imap_compress.h
index 85f5c720..ac5e5977 100644
--- a/libbalsa/imap/imap_compress.h
+++ b/libbalsa/imap/imap_compress.h
@@ -17,22 +17,8 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <zlib.h>
-
 #include "imap-handle.h"
 
-struct ImapCompressContext {
-  z_stream out_stream;
-  z_stream in_stream;
-  char *in_buffer;
-  char *out_buffer;
-  unsigned long in_uncompressed, in_compressed;
-  unsigned long out_uncompressed, out_compressed;
-};
-
 ImapResponse imap_compress(ImapMboxHandle* h);
 
-void imap_compress_init(struct ImapCompressContext *buf);
-void imap_compress_release(struct ImapCompressContext *buf);
-
 #endif /* __IMAP_COMPRESS_H__ */
diff --git a/libbalsa/imap/imap_private.h b/libbalsa/imap/imap_private.h
index 7f7dcc86..e9821ead 100644
--- a/libbalsa/imap/imap_private.h
+++ b/libbalsa/imap/imap_private.h
@@ -19,10 +19,11 @@
 
 #include <glib.h>
 #include <glib-object.h>
-#include <openssl/ssl.h>
 
 #include "config.h"
 
+#include "net-client-siobuf.h"
+
 #include "imap-commands.h"
 #include "imap_compress.h"
 
@@ -54,8 +55,8 @@ typedef struct {
 struct _ImapMboxHandle {
   GObject object;
 
-  int sd; /* socket descriptor */
-  struct siobuf * sio;
+  NetClientSioBuf *sio;
+
   char *host;
   char* mbox; /* currently selected mailbox, if any */
   int timeout; /* timeout in milliseconds */
@@ -82,9 +83,6 @@ struct _ImapMboxHandle {
                           * processing of current line is finished. */
   GNode *thread_root; /* deprecated! */
 
-  /** Compression data */
-  struct ImapCompressContext compress;
-
   struct {
     GList* src; /**< returned by COPY */
     GList* dst; /**< returned by APPEND and COPY */
@@ -96,28 +94,27 @@ struct _ImapMboxHandle {
   gboolean doing_logout;
   ImapInfoCb info_cb;
   void *info_arg;
-  ImapUserCb user_cb; /* for user interaction, if really necessary */
-  void *user_arg;
+
+  GCallback auth_cb;   /* authentication callback ("auth" signal) */
+  void *auth_arg;
+
+  GCallback cert_cb;   /* untrusted certificate callback ("cert-check" signal) */
 
   ImapFlagsCb flags_cb;
   void *flags_arg;
   ImapFetchBodyInternalCb body_cb;
   void *body_arg;
 
-  ImapMonitorCb monitor_cb;
-  void *monitor_arg;
-
   ImapSearchCb search_cb;
   void *search_arg;
 
   GHashTable *status_resps; /* A hash of STATUS responses that we wait for */
 
-  GIOChannel *iochannel; /* IO channel used for monitoring the connection */
+  GSource *sock_source;
   GMutex mutex;
   guint idle_enable_id; /* callback to issue IDLE after a period of
                            inactivity */
-  guint async_watch_id;  /* callback to process incoming data */
-  ImapTlsMode tls_mode; /* disabled, enabled, required */
+  NetClientCryptMode tls_mode; /* disabled, enabled, required */
   enum { IDLE_INACTIVE, IDLE_RESPONSE_PENDING, IDLE_ACTIVE }
     idle_state; /*  IDLE State? */
   unsigned op_cancelled:1; /* last op timed out and was cancelled by user */
@@ -138,10 +135,6 @@ struct _ImapMboxHandle {
   gulong quota_max_k;         /**< max. available quota in kByte */
   gulong quota_used_k;        /**< used quota in kByte */
   gchar *quota_root;
-
-  unsigned over_ssl:1; /* transmission is to be made over SSL-protected
-                        * connection, usually to imaps port. */
-  unsigned using_tls:1;
 };
 
 #define IMAP_MBOX_IS_DISCONNECTED(h)  ((h)->state == IMHS_DISCONNECTED)
@@ -170,7 +163,7 @@ struct _ImapMboxHandle {
 
 #define IS_ATOM_CHAR(c) (strchr("(){ %*\"\\]",(c))==NULL&&(c)>0x1f&&(c)!=0x7f)
 
-#define EAT_LINE(h, c) while( (c=sio_getc(h->sio)) != -1 && c != '\n')
+#define EAT_LINE(h, c) c = net_client_siobuf_discard_line(h->sio, NULL)
 
 extern const char* imap_msg_flags[6];
 
@@ -189,7 +182,6 @@ ImapResponse imap_cmd_exec_cmds(ImapMboxHandle* handle, const char** cmds,
                                unsigned rc_to_return);
 
 ImapResponse imap_cmd_issue(ImapMboxHandle* handle, const char* cmd);
-char* imap_mbox_gets(ImapMboxHandle *h, char* buf, size_t sz);
 
 ImapResponse imap_write_key(ImapMboxHandle *handle, ImapSearchKey *s,
                             unsigned cmdno, int use_literal);
@@ -199,10 +191,6 @@ ImapResponse imap_search_exec_unlocked(ImapMboxHandle *h, gboolean uid,
 ImapResponse imap_assure_needed_flags(ImapMboxHandle *h,
                                       ImapMsgFlag needed_flags);
 
-SSL* imap_create_ssl(void);
-int imap_setup_ssl(struct siobuf *sio, const char* host, SSL *ssl,
-                   ImapUserCb user_cb, void *user_arg);
-
 void imap_handle_disconnect(ImapMboxHandle *h);
 ImapConnectionState imap_mbox_handle_get_state(ImapMboxHandle *h);
 void imap_mbox_handle_set_state(ImapMboxHandle *h,
@@ -219,12 +207,9 @@ gchar *imap_coalesce_set(int cnt, unsigned *seqnos);
 /* even more private functions */
 int imap_cmd_start(ImapMboxHandle* handle, const char* cmd, unsigned* cmdno);
 ImapResponse imap_cmd_step(ImapMboxHandle* handle, unsigned cmdno);
-int      imap_handle_write(ImapMboxHandle *conn, const char *buf, size_t len);
-void     imap_handle_flush(ImapMboxHandle *handle);
+ImapResponse imap_cmd_process_untagged(ImapMboxHandle* handle, unsigned cmdno);
 unsigned imap_make_tag(ImapCmdTag tag);
 void mbox_view_append_no(MboxView *mv, unsigned seqno);
 
-int imap_socket_open(const char* host, const char *def_port);
-
 extern const char* imap_status_item_names[5];
 #endif /* __IMAP_PRIVATE_H__ */
diff --git a/libbalsa/imap/imap_search.c b/libbalsa/imap/imap_search.c
index 354e7433..025c1822 100644
--- a/libbalsa/imap/imap_search.c
+++ b/libbalsa/imap/imap_search.c
@@ -22,7 +22,7 @@
 #include <glib.h>
 #include <time.h>
 
-#include "siobuf.h"
+#include "siobuf-nc.h"
 #include "imap_search.h"
 #include "imap_private.h"
 
@@ -258,7 +258,7 @@ imap_search_checks(const ImapSearchKey *s, ImapSearchKeyType s_type)
 void
 imap_search_key_set_next(ImapSearchKey *list, ImapSearchKey *next)
 {
-  if(list->next) g_warning("I may be loosing my tail now!\n");
+  if(list->next) g_warning("I may be loosing my tail now!");
   list->next = next;
 }
 static void
@@ -319,13 +319,11 @@ imap_write_key_string(ImapMboxHandle *handle, ImapSearchKey *k,
       int c;
       ImapResponse rc;
       unsigned len = strlen(k->d.string.s);
-      sio_printf(handle->sio, "{%u}\r\n", len);
-      imap_handle_flush(handle);
-      do
-        rc = imap_cmd_step(handle, cmdno);
-      while(rc == IMR_UNTAGGED);
+      sio_printf(handle->sio, "{%u}", len);
+      net_client_siobuf_flush(handle->sio, NULL);
+      rc = imap_cmd_process_untagged(handle, cmdno);
       if (rc != IMR_RESPOND) {
-        fprintf(stderr, "%s(): unexpected response:\n", __FUNCTION__);
+        g_debug("%s(): unexpected response", __FUNCTION__);
         return rc;
       }
       /* consume to the end of line */
@@ -518,22 +516,16 @@ imap_search_exec_unlocked(ImapMboxHandle *h, gboolean uid,
       sio_printf(h->sio, "%s%s %s %u:%u ", tag, uid ? " UID" : "", cmd_string,
                lo, hi);
       if( (ir=imap_write_key(h, s, cmdno, can_do_literals)) == IMR_OK) {
-       sio_write(h->sio, "\r\n", 2);
-       imap_handle_flush(h);
-       do {
-         ir = imap_cmd_step(h, cmdno);
-       } while(ir == IMR_UNTAGGED);
+       net_client_siobuf_flush(h->sio, NULL);
+       ir = imap_cmd_process_untagged(h, cmdno);
       } else break;
     }
   } else { /* no split */
     cmdno = imap_make_tag(tag);
     sio_printf(h->sio, "%s%s %s ", tag, uid ? " UID" : "", cmd_string);
     if( (ir=imap_write_key(h, s, cmdno, can_do_literals)) == IMR_OK) {
-      sio_write(h->sio, "\r\n", 2);
-      imap_handle_flush(h);
-      do {
-         ir = imap_cmd_step(h, cmdno);
-      } while(ir == IMR_UNTAGGED);
+      net_client_siobuf_flush(h->sio, NULL);
+      ir = imap_cmd_process_untagged(h, cmdno);
     }
   }
   h->search_cb  = ocb;
diff --git a/libbalsa/imap/imap_tst.c b/libbalsa/imap/imap_tst.c
index f51e9622..7b14c8f9 100644
--- a/libbalsa/imap/imap_tst.c
+++ b/libbalsa/imap/imap_tst.c
@@ -38,36 +38,23 @@
 struct {
   char *user;
   char *password;
-  ImapTlsMode tls_mode;
-  gboolean over_ssl;
-  gboolean monitor;
+  NetClientCryptMode tls_mode;
   gboolean anonymous;
   gboolean compress;
-} TestContext = { NULL, NULL, IMAP_TLS_ENABLED, FALSE, FALSE, FALSE, FALSE };
-
-static void
-monitor_cb(const char *buffer, int length, int direction, void *arg)
-{
-  int i;
-  printf("IMAP %c: ", direction ? 'C' : 'S');
-  for (i = 0; i < length; i++)
-    putchar(buffer[i]);
-
-  fflush(NULL);
-}
+} TestContext = { NULL, NULL, NET_CLIENT_CRYPT_STARTTLS_OPT, FALSE, FALSE };
 
 
 static gchar*
-get_user(const char* method) {
+get_user() {
 
   if(TestContext.user) {
-    printf("Login with method %s as user: %s\n", method, TestContext.user);
+    printf("Login as user: %s\n", TestContext.user);
     return g_strdup(TestContext.user);
   } else {
     char buf[256];
     size_t len;
 
-    fprintf(stderr, "Login with method %s as user: ", method);
+    fprintf(stderr, "Login as user: ");
     fflush(stderr);
     if(!fgets(buf, sizeof(buf), stdin))
       return NULL;
@@ -110,54 +97,24 @@ get_password()
   }
 }
 
-static void
-user_cb(ImapUserEventType ue, void *arg, ...)
+static gchar **
+auth_cb(NetClient *client, gboolean need_passwd, gpointer user_data)
 {
-    va_list alist;
-    va_start(alist, arg);
-    switch(ue) {
-        int *ok;
-    case IME_GET_USER_PASS: {
-        gchar *method = va_arg(alist, gchar*);
-        gchar **user = va_arg(alist, gchar**);
-        gchar **pass = va_arg(alist, gchar**);
-        ok = va_arg(alist, int*);
-       g_free(*user); *user = get_user(method);
-       g_free(*pass); *pass = get_password();
-        *ok = 1; printf("Logging in with %s\n", method);
-        break;
-    }
-    case IME_GET_USER:  { /* for eg kerberos */
-        gchar **user;
-        gchar *method;
-        method = va_arg(alist, gchar*);
-        user = va_arg(alist, gchar**);
-        ok = va_arg(alist, int*);
-        *ok = 1; /* consider popping up a dialog window here */
-        g_free(*user); *user = get_user(method);
-        break;
-    }
-    case IME_TLS_VERIFY_ERROR:
-        ok = va_arg(alist, int*);
-       *ok = 1;
-        break;
-    case IME_TLS_NO_PEER_CERT: {
-        ok = va_arg(alist, int*); *ok = 0;
-        printf("IMAP:TLS: Server presented no cert!\n");
-        break;
-    }
-    case IME_TLS_WEAK_CIPHER: {
-        ok = va_arg(alist, int*); *ok = 1;
-        printf("IMAP:TLS: Weak cipher accepted.\n");
-        break;
-    }
-    case IME_TIMEOUT: {
-        ok = va_arg(alist, int*); *ok = 1;
-        break;
-    }
-    default: g_warning("unhandled imap event type! Fix the code."); break;
+    gchar **result = NULL;
+
+    result = g_new0(gchar *, 3U);
+    result[0] = get_user();
+    if (need_passwd) {
+       result[1] = get_password();
     }
-    va_end(alist);
+    return result;
+}
+
+static gboolean
+cert_cb(NetClient *client, GTlsCertificate *peer_cert, GTlsCertificateFlags errors, gpointer user_data)
+{
+       printf("cert error 0x%x, accepted...\n", errors);
+       return TRUE;
 }
 
 static ImapMboxHandle*
@@ -171,11 +128,11 @@ get_handle(const char *host)
 
   if(TestContext.compress)
     imap_handle_set_option(h, IMAP_OPT_COMPRESS, TRUE);
-  if(TestContext.monitor)
-    imap_handle_set_monitorcb(h, monitor_cb, NULL);
 
-  imap_handle_set_usercb(h, user_cb, NULL);
-  if(imap_mbox_handle_connect(h, host, TestContext.over_ssl) != IMAP_SUCCESS) {
+  imap_handle_set_authcb(h, G_CALLBACK(auth_cb), NULL);
+  imap_handle_set_certcb(h, G_CALLBACK(cert_cb));
+
+  if(imap_mbox_handle_connect(h, host) != IMAP_SUCCESS) {
     g_object_unref(h);
     return NULL;
   }
@@ -629,14 +586,10 @@ process_options(int argc, char *argv[])
       TestContext.anonymous = TRUE;
     } else if( strcmp(argv[first_arg], "-c") == 0) {
       TestContext.compress = TRUE;
-    } else if( strcmp(argv[first_arg], "-m") == 0) {
-      TestContext.monitor = TRUE;
-    } else if( strcmp(argv[first_arg], "-s") == 0) {
-      TestContext.over_ssl = TRUE;
     } else if( strcmp(argv[first_arg], "-T") == 0) {
-      TestContext.tls_mode = IMAP_TLS_REQUIRED;
+      TestContext.tls_mode = NET_CLIENT_CRYPT_STARTTLS;
     } else if( strcmp(argv[first_arg], "-t") == 0) {
-      TestContext.tls_mode = IMAP_TLS_DISABLED;
+      TestContext.tls_mode = NET_CLIENT_CRYPT_NONE;
     } else {
       break; /* break the loop - non-option encountered. */
     }
diff --git a/libbalsa/imap/libimap.h b/libbalsa/imap/libimap.h
index e44938f6..616989a5 100644
--- a/libbalsa/imap/libimap.h
+++ b/libbalsa/imap/libimap.h
@@ -42,12 +42,6 @@ typedef enum {
   IMAP_SELECT_FAILED /* SELECT command failed */
 } ImapResult;
 
-typedef enum {
-  IMAP_TLS_DISABLED,
-  IMAP_TLS_ENABLED,
-  IMAP_TLS_REQUIRED
-} ImapTlsMode;
-
 typedef enum { 
   IMLIST_MARKED = 0,
   IMLIST_UNMARKED,
@@ -273,8 +267,6 @@ void*        imap_message_serialize(ImapMessage *);
 ImapMessage* imap_message_deserialize(void *data);
 size_t imap_serialized_message_size(void *data);
 
-const char *lbi_strerror(ImapResult rc);
-
 /* RFC 4314: IMAP ACL's */
 typedef enum {
   IMAP_ACL_NONE = 0,
diff --git a/libbalsa/imap/util.c b/libbalsa/imap/util.c
index c9bd0893..6860ab3d 100644
--- a/libbalsa/imap/util.c
+++ b/libbalsa/imap/util.c
@@ -27,71 +27,28 @@
 
 #define SKIPWS(c) while (*(c) && isspace ((unsigned char) *(c))) c++;
 
-void
-imap_quote_string(char *dest, size_t dlen, const char *src)
+gchar *
+imap_quote_string(const gchar *src)
 {
-  char quote[] = "\"\\", *pt;
-  const char *s;
+       g_return_val_if_fail(src != NULL, NULL);
 
-  pt = dest;
-  s  = src;
+       if ((strchr(src, '"') == NULL) && (strchr(src, '\\') == NULL)) {
+               /* no need to quote... */
+               return g_strdup(src);
+       } else {
+               GString *buf;
 
-  *pt++ = '"';
-  /* save room for trailing quote-char */
-  dlen -= 2;
-  
-  for (; *s && dlen; s++)
-  {
-    if (strchr (quote, *s))
-    {
-      dlen -= 2;
-      if (!dlen)
-       break;
-      *pt++ = '\\';
-      *pt++ = *s;
-    }
-    else
-    {
-      *pt++ = *s;
-      dlen--;
-    }
-  }
-  *pt++ = '"';
-  *pt = 0;
-}
-
-/* imap_unquote_string: 
- *  modify the argument removing quote characters 
- */
-void
-imap_unquote_string (char *s)
-{
-  char *d = s;
-
-  if (*s == '\"')
-    s++;
-  else
-    return;
-
-  while (*s)
-  {
-    if (*s == '\"')
-    {
-      *d = '\0';
-      return;
-    }
-    if (*s == '\\')
-    {
-      s++;
-    }
-    if (*s)
-    {
-      *d = *s;
-      d++;
-      s++;
-    }
-  }
-  *d = '\0';
+               buf = g_string_sized_new(strlen(src + 3U));
+               g_string_append_c(buf, '"');
+               for (; *src != '\0'; src++) {
+                       if ((*src == '"') || (*src == '\\')) {
+                               g_string_append_c(buf, '\\');
+                       }
+                       g_string_append_c(buf, *src);
+               }
+               g_string_append_c(buf, '"');
+               return g_string_free(buf, FALSE);
+       }
 }
 
 /* imap_skip_atom: return index into string where next IMAP atom begins.
diff --git a/libbalsa/imap/util.h b/libbalsa/imap/util.h
index 583399d3..a01477f1 100644
--- a/libbalsa/imap/util.h
+++ b/libbalsa/imap/util.h
@@ -17,8 +17,10 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-void imap_quote_string(char *dest, size_t dlen, const char *src);
-void imap_unquote_string(char *s);
+#include <glib.h>
+
+gchar *imap_quote_string(const gchar *src)
+       G_GNUC_WARN_UNUSED_RESULT;
 char* imap_next_word(char *s);
 char* imap_skip_atom(char *s);
 
diff --git a/libbalsa/libbalsa.c b/libbalsa/libbalsa.c
index 9cac38cd..0c7190bc 100644
--- a/libbalsa/libbalsa.c
+++ b/libbalsa/libbalsa.c
@@ -30,9 +30,6 @@
 #include <sys/stat.h>
 #include <stdarg.h>
 #include <unistd.h>
-#include <openssl/ssl.h>
-#include <openssl/x509.h>
-#include <openssl/err.h>
 
 #ifdef HAVE_NOTIFY
 #include <libnotify/notify.h>
@@ -53,6 +50,8 @@
 #if HAVE_GCR
 #define GCR_API_SUBJECT_TO_CHANGE
 #include <gcr/gcr.h>
+#else
+#include <gnutls/x509.h>
 #endif
 
 #include "misc.h"
@@ -347,145 +346,87 @@ libbalsa_ask(gboolean (*cb)(void *arg), void *arg)
 }
 
 
-static int libbalsa_ask_for_cert_acceptance(X509 *cert,
-                                           const char *explanation);
-
-#ifndef HAVE_GCR
-
-static char*
-asn1time_to_string(ASN1_UTCTIME *tm)
-{
-    char buf[64];
-    BIO *bio  = BIO_new(BIO_s_mem());
-    strncpy(buf, _("Invalid date"), sizeof(buf)); buf[sizeof(buf)-1]='\0';
-
-    if(ASN1_TIME_print(bio, tm)) {
-        int cnt;
-        cnt = BIO_read(bio, buf, sizeof(buf)-1);
-        buf[cnt] = '\0';
-    }
-    BIO_free(bio);
-    return g_strdup(buf);
-}
-
-static char*
-x509_get_part (char *line, const char *ndx)
-{
-    static char ret[256];
-    char *c;
-
-    strncpy (ret, _("Unknown"), sizeof (ret)); ret[sizeof(ret)-1]='\0';
-
-    c = strstr(line, ndx);
-    if (c) {
-        char *c2;
-
-        c += strlen (ndx);
-        c2 = strchr (c, '/');
-        if (c2)
-            *c2 = '\0';
-        strncpy (ret, c, sizeof (ret));
-        if (c2)
-            *c2 = '/';
-    }
+static int libbalsa_ask_for_cert_acceptance(GTlsCertificate      *cert,
+                                                                                       GTlsCertificateFlags  
errors);
 
-    return ret;
-}
-static void
-x509_fingerprint (char *s, unsigned len, X509 * cert)
-{
-    unsigned j, i, n, c;
-    unsigned char md[EVP_MAX_MD_SIZE];
-
-
-    X509_digest(cert, EVP_md5(), md, &n);
-    if(len<3*n) n = len/3;
-    for (j=i=0; j<n; j++) {
-        c = (md[j] >>4) & 0xF; s[i++] = c<10 ? c + '0' : c+'A'-10;
-        c = md[j] & 0xF;       s[i++] = c<10 ? c + '0' : c+'A'-10;
-        if(j<n-1) s[i++] = ':';
-    }
-    s[i] = '\0';
-}
-
-#endif  /* HAVE_GCR */
-
-static GList *accepted_certs = NULL; /* certs accepted for this session */
+static GList *accepted_certs = NULL; /* GTlsCertificate items accepted for this session */
 static GMutex certificate_lock;
 
 void
 libbalsa_certs_destroy(void)
 {
        g_mutex_lock(&certificate_lock);
-    g_list_foreach(accepted_certs, (GFunc)X509_free, NULL);
-    g_list_free(accepted_certs);
+    g_list_free_full(accepted_certs, g_object_unref);
     accepted_certs = NULL;
     g_mutex_unlock(&certificate_lock);
 }
 
-/* compare Example 10-7 in the OpenSSL book */
+
+#define CERT_ACCEPT_NO                 0
+#define CERT_ACCEPT_SESSION            1
+#define CERT_ACCEPT_PERMANENT  2
+
+
 gboolean
-libbalsa_is_cert_known(X509* cert, long vfy_result)
+libbalsa_is_cert_known(GTlsCertificate      *cert,
+                                          GTlsCertificateFlags  errors)
 {
-    X509 *tmpcert = NULL;
-    FILE *fp;
-    gchar *cert_name;
-    gboolean res = FALSE;
-    GList *lst;
-
-    g_mutex_lock(&certificate_lock);
-    for(lst = accepted_certs; lst; lst = lst->next) {
-        int X509_res = X509_cmp(cert, lst->data);
-        if(X509_res == 0) {
-               g_mutex_unlock(&certificate_lock);
-            return TRUE;
-       }
-    }
-    
-    cert_name = g_strconcat(g_get_home_dir(), "/.balsa/certificates", NULL);
-
-    fp = fopen(cert_name, "rt");
-    g_free(cert_name);
-    if(fp) {
-        /* 
-        printf("Looking for cert: %s\n", 
-               X509_NAME_oneline(X509_get_subject_name (cert),
-                                 buf, sizeof (buf)));
-        */
-        res = FALSE;
-        while ((tmpcert = PEM_read_X509(fp, NULL, NULL, NULL)) != NULL) {
-            res = X509_cmp(cert, tmpcert)==0;
-            X509_free(tmpcert);
-            if(res) break;
-        }
-        ERR_clear_error();
-        fclose(fp);
-    }
-    g_mutex_unlock(&certificate_lock);
-    
-    if(!res) {
-       const char *reason = X509_verify_cert_error_string(vfy_result);
-       res = libbalsa_ask_for_cert_acceptance(cert, reason);
+       gchar *cert_file;
+       GList *cert_db;
+       gboolean cert_ok;
+       GList *lst;
+
+       /* check the list of accepted certificates for this session */
        g_mutex_lock(&certificate_lock);
-       if(res == 2) {
-           cert_name = g_strconcat(g_get_home_dir(),
-                                   "/.balsa/certificates", NULL);
-            libbalsa_assure_balsa_dir();
-           fp = fopen(cert_name, "a");
-           if (fp) {
-               if(PEM_write_X509 (fp, cert))
-                   res = TRUE;
-               fclose(fp);
-           }
-           g_free(cert_name);
+       for (lst = accepted_certs; lst; lst = lst->next) {
+               if (g_tls_certificate_is_same(cert, G_TLS_CERTIFICATE(lst->data))) {
+                       g_mutex_unlock(&certificate_lock);
+                       return TRUE;
+               }
        }
-       if(res == 1)
-           accepted_certs = 
-               g_list_prepend(accepted_certs, X509_dup(cert));
+
+       /* check the database of accepted certificates */
+       cert_file = g_build_filename(g_get_home_dir(), ".balsa", "certificates", NULL);
+       cert_db = g_tls_certificate_list_new_from_file(cert_file, NULL);
        g_mutex_unlock(&certificate_lock);
-    }
 
-    return res;
+       cert_ok = FALSE;
+       for (lst = cert_db; !cert_ok && (lst != NULL); lst = g_list_next(lst)) {
+               if (g_tls_certificate_is_same(cert, G_TLS_CERTIFICATE(lst->data))) {
+                       cert_ok = TRUE;
+               }
+       }
+       g_list_free_full(cert_db, g_object_unref);
+
+       /* ask the user if the certificate is not in the data base */
+       if (!cert_ok) {
+               int accepted;
+
+               accepted = libbalsa_ask_for_cert_acceptance(cert, errors);
+               g_mutex_lock(&certificate_lock);
+               if (accepted == CERT_ACCEPT_SESSION) {
+                       accepted_certs = g_list_prepend(accepted_certs, g_object_ref(cert));
+                       cert_ok = TRUE;
+               } else if (accepted == CERT_ACCEPT_PERMANENT) {
+                       gchar *pem_data;
+                       FILE *fd;
+
+                       g_object_get(G_OBJECT(cert), "certificate-pem", &pem_data, NULL);
+                       fd = fopen(cert_file, "a");
+                       if (fd != NULL) {
+                               fputs(pem_data, fd);
+                               fclose(fd);
+                       }
+                       g_free(pem_data);
+                       cert_ok = TRUE;
+               } else {
+                       /* nothing to do */
+               }
+               g_mutex_unlock(&certificate_lock);
+       }
+       g_free(cert_file);
+
+       return cert_ok;
 }
 
 /* libbalsa_ask_for_cert_acceptance():
@@ -497,7 +438,7 @@ libbalsa_is_cert_known(X509* cert, long vfy_result)
 
 */
 struct AskCertData {
-    X509 *certificate;
+    GTlsCertificate *certificate;
     const char *explanation;
 };
 
@@ -511,8 +452,7 @@ ask_cert_real(void *data)
     GtkWidget *cert_widget;
     GString *str;
     unsigned i;
-    unsigned char *der_buf = NULL;
-    int der_len;
+    GByteArray *cert_der;
     GcrCertificate *gcr_cert;
     GtkWidget *label;
 
@@ -525,9 +465,9 @@ ask_cert_real(void *data)
                                          _("_Reject"), GTK_RESPONSE_CANCEL,
                                          NULL);
     gtk_window_set_role(GTK_WINDOW(dialog), "tls_cert_dialog");
-    der_len = i2d_X509(acd->certificate, &der_buf);
-    gcr_cert = gcr_simple_certificate_new(der_buf, der_len);
-    OPENSSL_free(der_buf);
+    g_object_get(G_OBJECT(acd->certificate), "certificate", &cert_der, NULL);
+    gcr_cert = gcr_simple_certificate_new(cert_der->data, cert_der->len);
+    g_byte_array_unref(cert_der);
     cert_widget = GTK_WIDGET(gcr_certificate_widget_new(gcr_cert));
     g_object_unref(G_OBJECT(gcr_cert));
 
@@ -548,14 +488,14 @@ ask_cert_real(void *data)
 
     switch(gtk_dialog_run(GTK_DIALOG(dialog))) {
     case 0:
-       i = 1;
+       i = CERT_ACCEPT_SESSION;
        break;
     case 1:
-       i = 2;
+       i = CERT_ACCEPT_PERMANENT;
        break;
     case GTK_RESPONSE_CANCEL:
     default:
-       i = 0;
+       i = CERT_ACCEPT_NO;
        break;
     }
     gtk_widget_destroy(dialog);
@@ -564,52 +504,115 @@ ask_cert_real(void *data)
 
 #else
 
+static gnutls_x509_crt_t G_GNUC_WARN_UNUSED_RESULT
+get_gnutls_cert(GTlsCertificate *cert)
+{
+       gnutls_x509_crt_t res_crt;
+    int gnutls_res;
+
+    gnutls_res = gnutls_x509_crt_init(&res_crt);
+    if (gnutls_res == GNUTLS_E_SUCCESS) {
+       GByteArray *cert_der;
+
+       g_object_get(G_OBJECT(cert), "certificate", &cert_der, NULL);
+       if (cert_der != NULL) {
+               gnutls_datum_t data;
+
+               data.data = cert_der->data;
+               data.size = cert_der->len;
+               gnutls_res = gnutls_x509_crt_import(res_crt, &data, GNUTLS_X509_FMT_DER);
+               if (gnutls_res != GNUTLS_E_SUCCESS) {
+                       gnutls_x509_crt_deinit(res_crt);
+                       res_crt = NULL;
+               }
+               g_byte_array_unref(cert_der);
+       }
+    } else {
+       res_crt = NULL;
+    }
+    return res_crt;
+}
+
+static gchar * G_GNUC_WARN_UNUSED_RESULT
+gnutls_get_dn(gnutls_x509_crt_t cert, int (*load_fn)(gnutls_x509_crt_t cert, char *buf, size_t *buf_size))
+{
+    size_t buf_size;
+    gchar *str_buf;
+
+    buf_size = 0U;
+    (void) load_fn(cert, NULL, &buf_size);
+    str_buf = g_malloc0(buf_size + 1U);
+    if (load_fn(cert, str_buf, &buf_size) != GNUTLS_E_SUCCESS) {
+       g_free(str_buf);
+       str_buf = NULL;
+    } else {
+       libbalsa_utf8_sanitize(&str_buf, TRUE, NULL);
+    }
+    return str_buf;
+}
+
+static gchar * G_GNUC_WARN_UNUSED_RESULT
+x509_fingerprint(gnutls_x509_crt_t cert)
+{
+    size_t buf_size;
+    guint8 sha1_buf[20];
+    gchar *str_buf;
+    gint n;
+
+    buf_size = 20U;
+    g_message("%d", gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, sha1_buf, &buf_size));
+    str_buf = g_malloc0(60U);
+    for (n = 0; n < 20; n++) {
+       sprintf(&str_buf[3 * n], "%02x:", sha1_buf[n]);
+    }
+    str_buf[59] = '\0';
+    return str_buf;
+}
+
 static int
 ask_cert_real(void *data)
 {
-    static const char *part[] =
-        {"/CN=", "/Email=", "/O=", "/OU=", "/L=", "/ST=", "/C="};
-
     struct AskCertData *acd = (struct AskCertData*)data;
-    X509 *cert = acd->certificate;
-    char buf[256]; /* fingerprint requires EVP_MAX_MD_SIZE*3 */
-    char *name = NULL, *c, *valid_from, *valid_until;
+    gnutls_x509_crt_t cert;
+    gchar *name, *c, *valid_from, *valid_until;
     GtkWidget* dialog, *label;
     unsigned i;
+    GString* str;
 
-    GString* str = g_string_new("");
+    cert = get_gnutls_cert(acd->certificate);
+    if (cert == NULL) {
+       g_warning("%s: unable to create gnutls cert", __func__);
+       return CERT_ACCEPT_NO;
+    }
 
+    str = g_string_new("");
     g_string_printf(str, _("Authenticity of this certificate "
                            "could not be verified.\n"
                            "<b>Reason:</b> %s\n"
                            "<b>This certificate belongs to:</b>\n"),
                     acd->explanation);
 
-    name = X509_NAME_oneline(X509_get_subject_name (cert), buf, sizeof (buf));
-    for (i = 0; i < ELEMENTS(part); i++) {
-        g_string_append(str, x509_get_part (name, part[i]));
-        g_string_append_c(str, '\n');
-    }
+    name = gnutls_get_dn(cert, gnutls_x509_crt_get_dn);
+    g_string_append(str, name);
+    g_free(name);
 
     g_string_append(str, _("\n<b>This certificate was issued by:</b>\n"));
-    name = X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof (buf));
-    for (i = 0; i < ELEMENTS(part); i++) {
-        g_string_append(str, x509_get_part (name, part[i]));
-        g_string_append_c(str, '\n');
-    }
-
-    buf[0] = '\0';
-    x509_fingerprint (buf, sizeof (buf), cert);
-    valid_from  = asn1time_to_string(X509_get_notBefore(cert));
-    valid_until = asn1time_to_string(X509_get_notAfter(cert)),
-    c = g_strdup_printf(_("<b>This certificate is valid</b>\n"
-                          "from %s\n"
-                          "to %s\n"
-                          "<b>Fingerprint:</b> %s"),
-                        valid_from, valid_until,
-                        buf);
-    g_string_append(str, c); g_free(c);
-    g_free(valid_from); g_free(valid_until);
+    name = gnutls_get_dn(cert, gnutls_x509_crt_get_issuer_dn);
+    g_string_append_printf(str, "%s\n", name);
+    g_free(name);
+
+    name = x509_fingerprint(cert);
+    valid_from  = libbalsa_date_to_utf8(gnutls_x509_crt_get_activation_time(cert), "%x %X");
+    valid_until = libbalsa_date_to_utf8(gnutls_x509_crt_get_expiration_time(cert), "%x %X");
+    g_string_append_printf(str, _("<b>This certificate is valid</b>\n"
+                                                         "from %s\n"
+                                                         "to %s\n"
+                                         "<b>Fingerprint:</b> %s"),
+                               valid_from, valid_until, name);
+    g_free(name);
+    g_free(valid_from);
+    g_free(valid_until);
+    gnutls_x509_crt_deinit(cert);
 
     /* This string uses markup, so we must replace "&" with "&amp;" */
     c = str->str;
@@ -639,10 +642,10 @@ ask_cert_real(void *data)
     gtk_widget_show(label);
 
     switch(gtk_dialog_run(GTK_DIALOG(dialog))) {
-    case 0: i = 1; break;
-    case 1: i = 2; break;
+    case 0: i = CERT_ACCEPT_SESSION; break;
+    case 1: i = CERT_ACCEPT_PERMANENT; break;
     case GTK_RESPONSE_CANCEL:
-    default: i=0; break;
+    default: i=CERT_ACCEPT_NO; break;
     }
     gtk_widget_destroy(dialog);
     /* Process some events to let the window disappear:
@@ -656,54 +659,27 @@ ask_cert_real(void *data)
 #endif /* HAVE_GCR */
 
 static int
-libbalsa_ask_for_cert_acceptance(X509 *cert, const char *explanation)
+libbalsa_ask_for_cert_acceptance(GTlsCertificate      *cert,
+                                                                GTlsCertificateFlags  errors)
 {
     struct AskCertData acd;
     acd.certificate = cert;
-    acd.explanation = explanation;
-    return libbalsa_ask(ask_cert_real, &acd);
-}
-
-
-static int
-ask_timeout_real(void *data)
-{
-    const char *host = (const char*)data;
-    GtkWidget* dialog;
-    int i;
-
-    dialog = gtk_message_dialog_new(NULL, /* FIXME: NULL parent */
-                                    GTK_DIALOG_MODAL,
-                                    GTK_MESSAGE_INFO,
-                                    GTK_BUTTONS_YES_NO,
-                                    _("Connection to %s timed out. Abort?"),
-                                    host);
-    gtk_window_set_role(GTK_WINDOW(dialog), "timeout_dialog");
-    switch(gtk_dialog_run(GTK_DIALOG(dialog))) {
-    case GTK_RESPONSE_YES: i = 1; break;
-    case GTK_RESPONSE_NO: i = 0; break;
-    default: printf("Unknown response. Defaulting to 'yes'.\n");
-        i = 1;
+    if ((errors & G_TLS_CERTIFICATE_UNKNOWN_CA) == G_TLS_CERTIFICATE_UNKNOWN_CA) {
+       acd.explanation = _("the signing certificate authority is not known");
+    } else if ((errors & G_TLS_CERTIFICATE_BAD_IDENTITY) == G_TLS_CERTIFICATE_BAD_IDENTITY) {
+       acd.explanation = _("the certificate does not match the expected identity of the site that it was 
retrieved from");
+    } else if ((errors & G_TLS_CERTIFICATE_NOT_ACTIVATED) == G_TLS_CERTIFICATE_NOT_ACTIVATED) {
+       acd.explanation = _("the certificate's activation time is still in the future");
+    } else if ((errors & G_TLS_CERTIFICATE_EXPIRED) == G_TLS_CERTIFICATE_EXPIRED) {
+       acd.explanation = _("the certificate has expired");
+    } else if ((errors & G_TLS_CERTIFICATE_REVOKED) == G_TLS_CERTIFICATE_REVOKED) {
+       acd.explanation = _("the certificate has been revoked ");
+    } else if ((errors & G_TLS_CERTIFICATE_INSECURE) == G_TLS_CERTIFICATE_INSECURE) {
+       acd.explanation = _("the certificate's algorithm is considered insecure");
+    } else {
+       acd.explanation = _("an error occurred validating the certificate");
     }
-    gtk_widget_destroy(dialog);
-    /* Process some events to let the window disappear:
-     * not really necessary but helps with debugging. */
-   while(gtk_events_pending()) 
-        gtk_main_iteration_do(FALSE);
-    printf("%s returns %d\n", __FUNCTION__, i);
-    return i;
-}
-
-gboolean
-libbalsa_abort_on_timeout(const char *host)
-{  /* It appears not to be entirely thread safe... Some locks do not
-      get released as they should be. */
-    char *hostname;
-
-    hostname = g_alloca (strlen (host) + 1);
-    strcpy (hostname, host);
-    
-    return libbalsa_ask(ask_timeout_real, hostname) != 0; 
+    return libbalsa_ask(ask_cert_real, &acd);
 }
 
 
diff --git a/libbalsa/libbalsa.h b/libbalsa/libbalsa.h
index d1b2de9a..75f299e8 100644
--- a/libbalsa/libbalsa.h
+++ b/libbalsa/libbalsa.h
@@ -38,7 +38,6 @@ typedef struct _LibBalsaSmtpServer LibBalsaSmtpServer;
 typedef struct _LibbalsaVfs LibbalsaVfs;
 
 
-#include <openssl/ssl.h>
 #include "message.h"
 #include "body.h"
 #include "files.h"
@@ -136,11 +135,10 @@ gchar *libbalsa_guess_imap_inbox(void);
 gchar* libbalsa_date_to_utf8(time_t date, const gchar *date_string);
 LibBalsaMessageStatus libbalsa_get_icon_from_flags(LibBalsaMessageFlag flags);
 
-gboolean libbalsa_is_cert_known(X509* cert, long vfy_result);
+gboolean libbalsa_is_cert_known(GTlsCertificate      *cert,
+                                                               GTlsCertificateFlags  errors);
 void libbalsa_certs_destroy(void);
 
-gboolean libbalsa_abort_on_timeout(const char *host);
-
 GThread *libbalsa_get_main_thread(void);
 gboolean libbalsa_am_i_subthread(void);
 void libbalsa_message(const char *fmt, ...)
diff --git a/libbalsa/misc.c b/libbalsa/misc.c
index e1356c4b..e9332405 100644
--- a/libbalsa/misc.c
+++ b/libbalsa/misc.c
@@ -985,8 +985,8 @@ libbalsa_create_size_group(GtkWidget * chooser)
 void
 libbalsa_assure_balsa_dir(void)
 {
-    gchar* dir = g_strconcat(g_get_home_dir(), "/.balsa", NULL);
-    mkdir(dir, S_IRUSR|S_IWUSR|S_IXUSR);
+    gchar* dir = g_build_filename(g_get_home_dir(), ".balsa", NULL);
+    g_mkdir_with_parents(dir, S_IRUSR|S_IWUSR|S_IXUSR);
     g_free(dir);
 }
 
diff --git a/libbalsa/send.c b/libbalsa/send.c
index 75eca44a..ae170890 100644
--- a/libbalsa/send.c
+++ b/libbalsa/send.c
@@ -27,7 +27,7 @@
 #include "send.h"
 
 #include <math.h>
-
+#include <stdlib.h>
 #include <string.h>
 
 #include "libbalsa.h"
diff --git a/libbalsa/server.c b/libbalsa/server.c
index 7b62f25e..5f7af731 100644
--- a/libbalsa/server.c
+++ b/libbalsa/server.c
@@ -30,12 +30,11 @@
 #include <libsecret/secret.h>
 #endif                          /* defined(HAVE_LIBSECRET) */
 
-#include <openssl/err.h>
-
 #include "libbalsa.h"
 #include "libbalsa_private.h"
 #include "libbalsa-marshal.h"
 #include "libbalsa-conf.h"
+#include "net-client-utils.h"
 #include <glib/gi18n.h>
 
 #if defined(HAVE_LIBSECRET)
@@ -58,9 +57,9 @@ static void libbalsa_server_finalize(GObject * object);
 
 static void libbalsa_server_real_set_username(LibBalsaServer * server,
                                              const gchar * username);
-static void libbalsa_server_real_set_host(LibBalsaServer * server,
-                                         const gchar * host,
-                                          gboolean use_ssl);
+static void libbalsa_server_real_set_host(LibBalsaServer     *server,
+                                                                                 const gchar        *host,
+                                                                                 NetClientCryptMode  
security);
 /* static gchar* libbalsa_server_real_get_password(LibBalsaServer *server); */
 
 enum {
@@ -166,8 +165,6 @@ libbalsa_server_init(LibBalsaServer * server)
     server->user = NULL;
     server->passwd = NULL;
     server->remember_passwd = TRUE;
-    server->use_ssl         = FALSE;
-    server->tls_mode        = LIBBALSA_TLS_ENABLED;
     server->security           = NET_CLIENT_CRYPT_STARTTLS;
 }
 
@@ -190,10 +187,7 @@ libbalsa_server_finalize(GObject * object)
 
     g_free(server->cert_file);
     server->cert_file = NULL;
-    if (server->cert_passphrase != NULL) {
-       memset(server->cert_passphrase, 0, strlen(server->cert_passphrase));
-    }
-    g_free(server->cert_passphrase);
+    net_client_free_authstr(server->cert_passphrase);
     server->cert_passphrase = NULL;
 
     G_OBJECT_CLASS(parent_class)->finalize(object);
@@ -234,13 +228,13 @@ libbalsa_server_set_password(LibBalsaServer * server,
 
 void
 libbalsa_server_set_host(LibBalsaServer * server, const gchar * host,
-                         gboolean use_ssl)
+                         NetClientCryptMode security)
 {
     g_return_if_fail(server != NULL);
     g_return_if_fail(LIBBALSA_IS_SERVER(server));
 
     g_signal_emit(G_OBJECT(server), libbalsa_server_signals[SET_HOST],
-                 0, host, use_ssl);
+                 0, host, security);
 
 }
 
@@ -280,13 +274,13 @@ libbalsa_server_real_set_username(LibBalsaServer * server,
 
 static void
 libbalsa_server_real_set_host(LibBalsaServer * server, const gchar * host,
-                              gboolean use_ssl)
+       NetClientCryptMode  security)
 {
     g_return_if_fail(LIBBALSA_IS_SERVER(server));
 
     g_free(server->host);
     server->host = g_strdup(host);
-    server->use_ssl = use_ssl;
+    server->security = security;
 }
 
 
@@ -300,10 +294,47 @@ libbalsa_server_real_get_password(LibBalsaServer * server)
 }
 #endif
 
+void
+libbalsa_server_load_security_config(LibBalsaServer *server)
+{
+       gboolean not_found;
+
+    g_return_if_fail(LIBBALSA_IS_SERVER(server));
+
+    server->security = libbalsa_conf_get_int_with_default("Security", &not_found);
+    if (not_found) {
+       gboolean want_ssl;
+
+       g_debug("server %s@%s: no security config, try to read old settings", server->protocol, server->host);
+       want_ssl = libbalsa_conf_get_bool_with_default("SSL", &not_found);
+       if (want_ssl && !not_found) {
+               server->security = NET_CLIENT_CRYPT_ENCRYPTED;
+       } else {
+               int want_tls;
+
+               want_tls = libbalsa_conf_get_int_with_default("TLSMode", &not_found);
+               if (not_found) {
+                       server->security = NET_CLIENT_CRYPT_STARTTLS;
+               } else {
+                       switch (want_tls) {
+                       case 0:
+                               server->security = NET_CLIENT_CRYPT_NONE;
+                               break;
+                       case 1:
+                               server->security = NET_CLIENT_CRYPT_STARTTLS_OPT;
+                               break;
+                       default:
+                               server->security = NET_CLIENT_CRYPT_STARTTLS;
+                       }
+               }
+       }
+    }
+
+}
 
 /* libbalsa_server_load_config:
    load the server configuration using gnome-config.
-   Try to use sensible defaults. 
+   Try to use sensible defaults.
    FIXME: Port field is kept here only for compatibility, drop after 1.4.x
    release.
 */
@@ -320,16 +351,8 @@ libbalsa_server_load_config(LibBalsaServer * server)
             g_free(server->host);
             server->host = newhost;
         }
-    }       
-    server->use_ssl = libbalsa_conf_get_bool("SSL=false");
-    d = FALSE;
-    server->tls_mode = libbalsa_conf_get_int_with_default("TLSMode", &d);
-    if(d) server->tls_mode = LIBBALSA_TLS_ENABLED;
-    d = FALSE;
-    server->security = libbalsa_conf_get_int_with_default("Security", &d);
-    if (d) {
-       server->security = NET_CLIENT_CRYPT_STARTTLS;
     }
+    libbalsa_server_load_security_config(server);
     server->user = libbalsa_conf_private_get_string("Username");
     if (!server->user)
        server->user = g_strdup(getenv("USER"));
@@ -454,88 +477,9 @@ libbalsa_server_save_config(LibBalsaServer * server)
         g_free(tmp);
     }
 
-    libbalsa_conf_set_bool("SSL", server->use_ssl);
-    libbalsa_conf_set_int("TLSMode", server->tls_mode);
     libbalsa_conf_set_int("Security", server->security);
 }
 
-void
-libbalsa_server_user_cb(ImapUserEventType ue, void *arg, ...)
-{
-    va_list alist;
-    int *ok;
-    LibBalsaServer *is = LIBBALSA_SERVER(arg);
-
-    va_start(alist, arg);
-    switch(ue) {
-    case IME_GET_USER_PASS: {
-        gchar *method = va_arg(alist, gchar*);
-        gchar **user = va_arg(alist, gchar**);
-        gchar **pass = va_arg(alist, gchar**);
-        ok = va_arg(alist, int*);
-        if(!is->passwd) {
-            is->passwd = libbalsa_server_get_password(is, NULL);
-        }
-        *ok = is->passwd != NULL;
-        if(*ok) {
-            g_free(*user); *user = g_strdup(is->user);
-            g_free(*pass); *pass = g_strdup(is->passwd);
-            libbalsa_information(LIBBALSA_INFORMATION_DEBUG,
-                                 /* host, authentication method */
-                                 _("Logging in to %s using %s"), 
-                                   is->host, method);
-        }
-        break;
-    }
-    case IME_GET_USER:  { /* for eg kerberos */
-        gchar **user;
-        va_arg(alist, gchar*); /* Ignore the method */
-        user = va_arg(alist, gchar**);
-        ok = va_arg(alist, int*);
-        *ok = 1; /* consider popping up a dialog window here */
-        g_free(*user); *user = g_strdup(is->user);
-        break;
-    }
-    case IME_TLS_VERIFY_ERROR:  {
-        long vfy_result;
-        SSL *ssl;
-        X509 *cert;
-        ok = va_arg(alist, int*);
-        vfy_result = va_arg(alist, long);
-        X509_verify_cert_error_string(vfy_result);
-#if 0
-        printf("IMAP:TLS: failed cert verification: %ld : %s.\n",
-               vfy_result, reason);
-#endif
-        ssl = va_arg(alist, SSL*);
-        cert = SSL_get_peer_certificate(ssl);
-       if(cert) {
-           *ok = libbalsa_is_cert_known(cert, vfy_result);
-           X509_free(cert);
-       }
-        break;
-    }
-    case IME_TLS_NO_PEER_CERT: {
-        ok = va_arg(alist, int*); *ok = 0;
-        printf("IMAP:TLS: Server presented no cert!\n");
-        break;
-    }
-    case IME_TLS_WEAK_CIPHER: {
-        ok = va_arg(alist, int*); *ok = 1;
-        printf("IMAP:TLS: Weak cipher accepted.\n");
-        break;
-    }
-    case IME_TIMEOUT: {
-        ok = va_arg(alist, int*); *ok = 1;
-        /* *ok = libbalsa_abort_on_timeout(is->host); */
-        /* For now, always timeout. The UI needs some work. */
-        break;
-    }
-    default: g_warning("unhandled imap event type! Fix the code."); break;
-    }
-    va_end(alist);
-}
-
 /* Connect the server's "get-password" signal to the callback; if the
  * ask-password callback is connected more than once, the dialog is
  * popped up the corresponding number of times, so we'll ignore the
@@ -561,7 +505,7 @@ libbalsa_server_get_auth(NetClient *client,
 
     g_debug("%s: %p %p: encrypted = %d", __func__, client, user_data,
             net_client_is_encrypted(client));
-    if (server->try_anonymous == 0U) {
+    if ((server->try_anonymous == 0U) || (strcmp(server->protocol, "imap") == 0)) {
         result = g_new0(gchar *, 3U);
         result[0] = g_strdup(server->user);
         if (need_passwd) {
@@ -582,50 +526,7 @@ libbalsa_server_check_cert(NetClient           *client,
                                                   GTlsCertificateFlags errors,
                                                   gpointer             user_data)
 {
-    GByteArray *cert_der = NULL;
-    gboolean result = FALSE;
-
-    /* FIXME - this a hack, simulating the (OpenSSL based) input for libbalsa_is_cert_known().
-        If we switch completely to
-     * (GnuTLS based) GTlsCertificate/GTlsClientConnection, we can omit this... */
-    g_debug("%s: %p %p %u %p", __func__, client, peer_cert, errors, user_data);
-
-    /* create a OpenSSL X509 object from the certificate's DER data */
-    g_object_get(G_OBJECT(peer_cert), "certificate", &cert_der, NULL);
-    if (cert_der != NULL) {
-        X509 *ossl_cert;
-        const unsigned char *der_p;
-
-        der_p = (const unsigned char *) cert_der->data;
-        ossl_cert = d2i_X509(NULL, &der_p, cert_der->len);
-        g_byte_array_unref(cert_der);
-
-        if (ossl_cert != NULL) {
-            long vfy_result;
-
-            /* convert the GIO error flags into OpenSSL error flags */
-            if ((errors & G_TLS_CERTIFICATE_UNKNOWN_CA) == G_TLS_CERTIFICATE_UNKNOWN_CA) {
-                vfy_result = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT;
-            } else if ((errors & G_TLS_CERTIFICATE_BAD_IDENTITY) ==
-                       G_TLS_CERTIFICATE_BAD_IDENTITY) {
-                vfy_result = X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
-            } else if ((errors & G_TLS_CERTIFICATE_NOT_ACTIVATED) ==
-                       G_TLS_CERTIFICATE_NOT_ACTIVATED) {
-                vfy_result = X509_V_ERR_CERT_NOT_YET_VALID;
-            } else if ((errors & G_TLS_CERTIFICATE_EXPIRED) == G_TLS_CERTIFICATE_EXPIRED) {
-                vfy_result = X509_V_ERR_CERT_HAS_EXPIRED;
-            } else if ((errors & G_TLS_CERTIFICATE_REVOKED) == G_TLS_CERTIFICATE_REVOKED) {
-                vfy_result = X509_V_ERR_CERT_REVOKED;
-            } else {
-                vfy_result = X509_V_ERR_APPLICATION_VERIFICATION;
-            }
-
-            result = libbalsa_is_cert_known(ossl_cert, vfy_result);
-            X509_free(ossl_cert);
-        }
-    }
-
-    return result;
+       return libbalsa_is_cert_known(peer_cert, errors);
 }
 
 
diff --git a/libbalsa/server.h b/libbalsa/server.h
index 2f47088c..4082a4ed 100644
--- a/libbalsa/server.h
+++ b/libbalsa/server.h
@@ -53,11 +53,13 @@ GType libbalsa_server_get_type(void);
 
 typedef struct _LibBalsaServerClass LibBalsaServerClass;
 
+#if 0
 typedef enum {
     LIBBALSA_TLS_DISABLED,
     LIBBALSA_TLS_ENABLED,
     LIBBALSA_TLS_REQUIRED
 } LibBalsaTlsMode;
+#endif
 
 struct _LibBalsaServer {
     GObject object;
@@ -73,8 +75,8 @@ struct _LibBalsaServer {
     /* We include SSL support in UI unconditionally to preserve config
      * between SSL and non-SSL builds. We just fail if SSL is requested
      * in non-SSL build. */
-    LibBalsaTlsMode tls_mode;
-    unsigned use_ssl:1;
+    //LibBalsaTlsMode tls_mode;
+    //unsigned use_ssl:1;
     unsigned remember_passwd:1;
     unsigned try_anonymous:1; /* user wants anonymous access */
 };
@@ -84,7 +86,7 @@ struct _LibBalsaServerClass {
 
     void (*set_username) (LibBalsaServer * server, const gchar * name);
     void (*set_host) (LibBalsaServer * server,
-                     const gchar * host, gboolean use_ssl);
+                     const gchar * host, NetClientCryptMode  security);
     void (*config_changed) (LibBalsaServer * server);
     gchar *(*get_password) (LibBalsaServer * server);
 };
@@ -95,18 +97,18 @@ void libbalsa_server_set_username(LibBalsaServer * server,
                                  const gchar * username);
 void libbalsa_server_set_password(LibBalsaServer * server,
                                  const gchar * passwd);
-void libbalsa_server_set_host(LibBalsaServer * server, const gchar * host,
-                              gboolean use_ssl);
+void libbalsa_server_set_host(LibBalsaServer     *server,
+                                                         const gchar        *host,
+                                                         NetClientCryptMode  security);
 gchar *libbalsa_server_get_password(LibBalsaServer * server,
                                    LibBalsaMailbox * mbox);
 
 void libbalsa_server_config_changed(LibBalsaServer * server);
 void libbalsa_server_load_config(LibBalsaServer * server);
+void libbalsa_server_load_security_config(LibBalsaServer * server);
 void libbalsa_server_save_config(LibBalsaServer * server);
 
 
-void libbalsa_server_user_cb(ImapUserEventType ue, void *arg, ...);
-
 /* NetClient related signal handlers */
 gchar **libbalsa_server_get_auth(NetClient *client,
                                                                 gboolean   need_passwd,
diff --git a/libbalsa/smtp-server.c b/libbalsa/smtp-server.c
index d7433638..67ffec44 100644
--- a/libbalsa/smtp-server.c
+++ b/libbalsa/smtp-server.c
@@ -334,9 +334,10 @@ smtp_server_response(GtkDialog * dialog, gint response,
         libbalsa_smtp_server_set_name(sdi->smtp_server,
                                       gtk_entry_get_text(GTK_ENTRY
                                                          (sdi->name)));
+        server->security = (NetClientCryptMode) (gtk_combo_box_get_active(GTK_COMBO_BOX(sdi->tlsm)) + 1);
         libbalsa_server_set_host(server,
                                  gtk_entry_get_text(GTK_ENTRY(sdi->host)),
-                                 FALSE);
+                                                                server->security);
         server->try_anonymous = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sdi->auth_button)) ? 0U : 1U;
         libbalsa_server_set_username(server,
                                      gtk_entry_get_text(GTK_ENTRY
@@ -344,7 +345,6 @@ smtp_server_response(GtkDialog * dialog, gint response,
         libbalsa_server_set_password(server,
                                      gtk_entry_get_text(GTK_ENTRY
                                                         (sdi->pass)));
-        server->security = (NetClientCryptMode) (gtk_combo_box_get_active(GTK_COMBO_BOX(sdi->tlsm)) + 1);
         server->client_cert = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sdi->cert_button));
         g_free(server->cert_file);
         server->cert_file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(sdi->cert_file));
diff --git a/libinit_balsa/assistant_page_user.c b/libinit_balsa/assistant_page_user.c
index 6e444205..de6b7ed0 100644
--- a/libinit_balsa/assistant_page_user.c
+++ b/libinit_balsa/assistant_page_user.c
@@ -203,7 +203,7 @@ create_pop3_mbx(const gchar *name, const gchar* host, gint security,
 
     libbalsa_server_set_username(server, login);
     libbalsa_server_set_password(server, passwd);
-    libbalsa_server_set_host(server, host, FALSE);
+    libbalsa_server_set_host(server, host, security);
     server->security        = security;
     server->remember_passwd = remember;
     mbx->name               = g_strdup(name && *name ? name : host);
@@ -217,7 +217,7 @@ create_pop3_mbx(const gchar *name, const gchar* host, gint security,
 }
 
 static void
-create_imap_mbx(const gchar *name, const gchar* host, gint security,
+create_imap_mbx(const gchar *name, const gchar* host, NetClientCryptMode security,
                 const gchar *login, const gchar *passwd,
                 gboolean remember)
 {
@@ -226,17 +226,7 @@ create_imap_mbx(const gchar *name, const gchar* host, gint security,
         LIBBALSA_SERVER(libbalsa_imap_server_new(login, host));
     libbalsa_server_set_username(server, login);
     libbalsa_server_set_password(server, passwd);
-    libbalsa_server_set_host(server, host, security == NET_CLIENT_CRYPT_ENCRYPTED);
-    switch (security) {
-    case NET_CLIENT_CRYPT_STARTTLS:
-       server->tls_mode   = LIBBALSA_TLS_REQUIRED;
-       break;
-    case NET_CLIENT_CRYPT_STARTTLS_OPT:
-       server->tls_mode   = LIBBALSA_TLS_ENABLED;
-       break;
-    default:
-       server->tls_mode   = LIBBALSA_TLS_DISABLED;
-    }
+    libbalsa_server_set_host(server, host, security);
     server->remember_passwd = remember;
     mbnode = balsa_mailbox_node_new_imap_folder(server, NULL);
     mbnode->name = g_strdup(name && *name ? name : host);
@@ -268,7 +258,7 @@ balsa_druid_page_user_next(GtkAssistant * druid, GtkWidget * page,
         LibBalsaMailbox *mbx = NULL;
         const gchar *login = gtk_entry_get_text(GTK_ENTRY(user->login));
         const gchar *passwd = gtk_entry_get_text(GTK_ENTRY(user->passwd));
-        gint security = balsa_option_get_active(user->security) + NET_CLIENT_CRYPT_ENCRYPTED;
+        NetClientCryptMode security = balsa_option_get_active(user->security) + NET_CLIENT_CRYPT_ENCRYPTED;
         gboolean remember = 
             balsa_option_get_active(user->remember_passwd) == 0;
         switch(balsa_option_get_active(user->incoming_type)) {
@@ -313,7 +303,7 @@ balsa_druid_page_user_next(GtkAssistant * druid, GtkWidget * page,
     }
     libbalsa_server_set_host(LIBBALSA_SERVER(smtp_server),
                              gtk_entry_get_text(GTK_ENTRY(user->smtp)),
-                             FALSE);
+                             FALSE);   // FIXME!!
 
     g_free(balsa_app.local_mail_directory);
     balsa_app.local_mail_directory =
diff --git a/libnetclient/Makefile.am b/libnetclient/Makefile.am
index 926f8162..52f7b998 100644
--- a/libnetclient/Makefile.am
+++ b/libnetclient/Makefile.am
@@ -6,6 +6,8 @@ libnetclient_a_SOURCES =        \
        net-client.h                    \
        net-client-pop.c                \
        net-client-pop.h                \
+       net-client-siobuf.c             \
+       net-client-siobuf.h             \
        net-client-smtp.c               \
        net-client-smtp.h               \
        net-client-utils.c              \
diff --git a/libnetclient/meson.build b/libnetclient/meson.build
index 59134812..1fd5011b 100644
--- a/libnetclient/meson.build
+++ b/libnetclient/meson.build
@@ -7,6 +7,8 @@ libnetclient_a_sources = [
   'net-client-pop.h',
   'net-client-smtp.c',
   'net-client-smtp.h',
+  'net-client-siobuf.c',
+  'net-client-siobuf.h',
   'net-client-utils.c',
   'net-client-utils.h'
   ]
diff --git a/libnetclient/net-client-pop.c b/libnetclient/net-client-pop.c
index 3b3b07b0..43700b78 100644
--- a/libnetclient/net-client-pop.c
+++ b/libnetclient/net-client-pop.c
@@ -175,12 +175,10 @@ net_client_pop_connect(NetClientPop *client, gchar **greeting, GError **error)
                g_signal_emit_by_name(client, "auth", need_pwd, &auth_data);
                if ((auth_data != NULL) && (auth_data[0] != NULL)) {
                        result = net_client_pop_auth(client, auth_data[0], auth_data[1], auth_supported, 
error);
-                       memset(auth_data[0], 0, strlen(auth_data[0]));
-                       if (auth_data[1] != NULL) {
-                               memset(auth_data[1], 0, strlen(auth_data[1]));
-                       }
+                       net_client_free_authstr(auth_data[0]);
+                       net_client_free_authstr(auth_data[1]);
                }
-               g_strfreev(auth_data);
+               g_free(auth_data);
        }
 
        return result;
@@ -527,8 +525,7 @@ net_client_pop_auth_plain(NetClientPop *client, const gchar *user, const gchar *
                if (result) {
                        result = net_client_pop_execute(client, "%s", NULL, error, base64_buf);
                }
-               memset(base64_buf, 0, strlen(base64_buf));
-               g_free(base64_buf);
+               net_client_free_authstr(base64_buf);
        } else {
                result = FALSE;
        }
@@ -548,13 +545,11 @@ net_client_pop_auth_login(NetClientPop *client, const gchar *user, const gchar *
 
                base64_buf = g_base64_encode((const guchar *) user, strlen(user));
                result = net_client_pop_execute_sasl(client, "%s", NULL, error, base64_buf);
-               memset(base64_buf, 0, strlen(base64_buf));
-               g_free(base64_buf);
+               net_client_free_authstr(base64_buf);
                if (result) {
                        base64_buf = g_base64_encode((const guchar *) passwd, strlen(passwd));
                        result = net_client_pop_execute(client, "%s", NULL, error, base64_buf);
-                       memset(base64_buf, 0, strlen(base64_buf));
-                       g_free(base64_buf);
+                       net_client_free_authstr(base64_buf);
                }
        }
 
@@ -585,11 +580,9 @@ net_client_pop_auth_apop(NetClientPop *client, const gchar *user, const gchar *p
 
        auth_buf = g_strconcat(client->priv->apop_banner, passwd, NULL);
        md5_buf = g_compute_checksum_for_string(G_CHECKSUM_MD5, auth_buf, -1);
-       memset(auth_buf, 0, strlen(auth_buf));
-       g_free(auth_buf);
+       net_client_free_authstr(auth_buf);
        result = net_client_pop_execute(client, "APOP %s %s", NULL, error, user, md5_buf);
-       memset(md5_buf, 0, strlen(md5_buf));
-       g_free(md5_buf);
+       net_client_free_authstr(md5_buf);
 
        return result;
 }
@@ -607,8 +600,7 @@ net_client_pop_auth_cram(NetClientPop *client, GChecksumType chksum_type, const
                auth_buf = net_client_cram_calc(challenge, chksum_type, user, passwd);
                if (auth_buf != NULL) {
                        result = net_client_pop_execute(client, "%s", NULL, error, auth_buf);
-                       memset(auth_buf, 0, strlen(auth_buf));
-                       g_free(auth_buf);
+                       net_client_free_authstr(auth_buf);
                } else {
                        result = FALSE;
                }
diff --git a/libnetclient/net-client-smtp.c b/libnetclient/net-client-smtp.c
index 7a014897..e094a684 100644
--- a/libnetclient/net-client-smtp.c
+++ b/libnetclient/net-client-smtp.c
@@ -161,12 +161,10 @@ net_client_smtp_connect(NetClientSmtp *client, gchar **greeting, GError **error)
                g_signal_emit_by_name(client, "auth", need_pwd, &auth_data);
                if ((auth_data != NULL) && (auth_data[0] != NULL)) {
                        result = net_client_smtp_auth(client, auth_data[0], auth_data[1], auth_supported, 
error);
-                       memset(auth_data[0], 0, strlen(auth_data[0]));
-                       if (auth_data[1] != NULL) {
-                               memset(auth_data[1], 0, strlen(auth_data[1]));
-                       }
+                       net_client_free_authstr(auth_data[0]);
+                       net_client_free_authstr(auth_data[1]);
                }
-               g_strfreev(auth_data);
+               g_free(auth_data);
        }
 
        return result;
@@ -427,8 +425,7 @@ net_client_smtp_auth_plain(NetClientSmtp *client, const gchar *user, const gchar
        base64_buf = net_client_auth_plain_calc(user, passwd);
        if (base64_buf != NULL) {
                result = net_client_smtp_execute(client, "AUTH PLAIN %s", NULL, error, base64_buf);
-               memset(base64_buf, 0, strlen(base64_buf));
-               g_free(base64_buf);
+               net_client_free_authstr(base64_buf);
        } else {
                result = FALSE;
        }
@@ -445,13 +442,11 @@ net_client_smtp_auth_login(NetClientSmtp *client, const gchar *user, const gchar
 
        base64_buf = g_base64_encode((const guchar *) user, strlen(user));
        result = net_client_smtp_execute(client, "AUTH LOGIN %s", NULL, error, base64_buf);
-       memset(base64_buf, 0, strlen(base64_buf));
-       g_free(base64_buf);
+       net_client_free_authstr(base64_buf);
        if (result) {
                base64_buf = g_base64_encode((const guchar *) passwd, strlen(passwd));
                result = net_client_smtp_execute(client, "%s", NULL, error, base64_buf);
-               memset(base64_buf, 0, strlen(base64_buf));
-               g_free(base64_buf);
+               net_client_free_authstr(base64_buf);
        }
 
        return result;
@@ -471,8 +466,7 @@ net_client_smtp_auth_cram(NetClientSmtp *client, GChecksumType chksum_type, cons
                auth_buf = net_client_cram_calc(challenge, chksum_type, user, passwd);
                if (auth_buf != NULL) {
                        result = net_client_smtp_execute(client, "%s", NULL, error, auth_buf);
-                       memset(auth_buf, 0, strlen(auth_buf));
-                       g_free(auth_buf);
+                       net_client_free_authstr(auth_buf);
                } else {
                        result = FALSE;
                }
diff --git a/libnetclient/net-client-utils.c b/libnetclient/net-client-utils.c
index bcc4e808..83c9641a 100644
--- a/libnetclient/net-client-utils.c
+++ b/libnetclient/net-client-utils.c
@@ -12,7 +12,6 @@
  * <http://www.gnu.org/licenses/>.
  */
 
-#include <string.h>
 #include <stdio.h>
 #include <glib/gi18n.h>
 #include "net-client.h"
@@ -56,16 +55,13 @@ net_client_cram_calc(const gchar *base64_challenge, GChecksumType chksum_type, c
 
        chal_plain = g_base64_decode(base64_challenge, &plain_len);
        digest = g_compute_hmac_for_data(chksum_type, (const guchar *) passwd, strlen(passwd), chal_plain, 
plain_len);
-       memset(chal_plain, 0, plain_len);
-       g_free(chal_plain);
+       net_client_free_authstr((gchar *) chal_plain);
 
        auth_buf = g_strdup_printf("%s %s", user, digest);
-       memset(digest, 0, strlen(digest));
-       g_free(digest);
+       net_client_free_authstr(digest);
 
        base64_buf = g_base64_encode((const guchar *) auth_buf, strlen(auth_buf));
-       memset(auth_buf, 0, strlen(auth_buf));
-       g_free(auth_buf);
+       net_client_free_authstr(auth_buf);
 
        return base64_buf;
 }
@@ -107,6 +103,7 @@ net_client_auth_plain_calc(const gchar *user, const gchar *passwd)
        strcpy(&plain_buf[user_len + 1U], user);
        strcpy(&plain_buf[(2U * user_len) + 2U], passwd);
        base64_buf = g_base64_encode((const guchar *) plain_buf, (2U * user_len) + passwd_len + 2U);
+       /* contains \0 chars, cannot use net_client_free_authstr */
        memset(plain_buf, 0, (2U * user_len) + passwd_len + 2U);
        g_free(plain_buf);
 
@@ -114,6 +111,20 @@ net_client_auth_plain_calc(const gchar *user, const gchar *passwd)
 }
 
 
+void
+net_client_free_authstr(gchar *str)
+{
+       if (str != NULL) {
+               guint n;
+
+               for (n = 0; str[n] != '\0'; n++) {
+                       str[n] = g_random_int_range(32, 128);
+               }
+               g_free(str);
+       }
+}
+
+
 #if defined(HAVE_GSSAPI)
 
 NetClientGssCtx *
diff --git a/libnetclient/net-client-utils.h b/libnetclient/net-client-utils.h
index f4c0a8fc..ab90dfea 100644
--- a/libnetclient/net-client-utils.h
+++ b/libnetclient/net-client-utils.h
@@ -71,6 +71,16 @@ gchar *net_client_auth_plain_calc(const gchar *user, const gchar *passwd)
        G_GNUC_MALLOC;
 
 
+/** @brief Safely free an authentication string
+ *
+ * @param str string
+ *
+ * This function can be used to safely free an authentication string.  It overwrites the passed string with 
random characters, and
+ * then frees it.
+ */
+void net_client_free_authstr(gchar *str);
+
+
 #if defined(HAVE_GSSAPI)
 
 /** @brief Create a GSSAPI authentication context
diff --git a/libnetclient/net-client.c b/libnetclient/net-client.c
index 724dbdac..b7d77be3 100644
--- a/libnetclient/net-client.c
+++ b/libnetclient/net-client.c
@@ -16,9 +16,25 @@
 #include <stdio.h>
 #include <glib/gi18n.h>
 #include <gnutls/x509.h>
+#include "net-client-utils.h"
 #include "net-client.h"
 
 
+/*
+ * Stacking of the streams:
+ * Input channel:
+ *   GSocketClient *sock
+ *      GSocketConnection *plain_conn
+ *         GIOStream *tls_conn -- optional
+ *            GInputStream *comp_istream -- optional
+ *               GDataInputStream *istream
+ *
+ * Output channel:
+ *   GSocketClient *sock
+ *      GSocketConnection *plain_conn
+ *         GIOStream *tls_conn -- optional
+ *            GOutputStream *ostream -- optionally compressed
+ */
 struct _NetClientPrivate {
        gchar *host_and_port;
        guint16 default_port;
@@ -30,6 +46,10 @@ struct _NetClientPrivate {
        GDataInputStream *istream;
        GOutputStream *ostream;
        GTlsCertificate *certificate;
+
+       GZlibCompressor *comp;
+       GZlibDecompressor *decomp;
+       GInputStream *comp_istream;
 };
 
 
@@ -133,7 +153,27 @@ void
 net_client_shutdown(const NetClient *client)
 {
        if (NET_IS_CLIENT(client)) {
-               /* note: we must unref the GDataInputStream, but *not* the GOutputStream! */
+               /* Note: we must unref the GDataInputStream, but the GOutputStream only if compression is 
active! */
+               if (client->priv->comp != NULL) {
+                       /* Note: for some strange reason, GIO decides to send a 0x03 0x00 sequence when 
closing a compressed connection, before
+                        * sending the usual FIN, ACK TCP reply packet.  As the remote server does not expect 
the former (the connection has
+                        * already been closed on its side), it replies with with a RST TCP packet.  
Unref'ing client->priv->ostream and
+                        * client->priv->comp /after/ all other components of the connection fixes the issue 
for unencrypted connections, but
+                        * throws a critical error for TLS.  Observed with gio 2.48.2 and 2.50.3, no idea how 
it can be fixed.
+                        * See also https://bugzilla.gnome.org/show_bug.cgi?id=795985. */
+                       if (client->priv->ostream != NULL) {
+                               g_object_unref(G_OBJECT(client->priv->ostream));
+                       }
+                       g_object_unref(G_OBJECT(client->priv->comp));
+               }
+               if (client->priv->decomp != NULL) {
+                       g_object_unref(G_OBJECT(client->priv->decomp));
+                       client->priv->decomp = NULL;
+               }
+               if (client->priv->comp_istream!= NULL) {
+                       g_object_unref(G_OBJECT(client->priv->comp_istream));
+                       client->priv->comp_istream = NULL;
+               }
                if (client->priv->istream != NULL) {
                        g_object_unref(G_OBJECT(client->priv->istream));
                        client->priv->istream = NULL;
@@ -374,8 +414,7 @@ net_client_set_cert_from_pem(NetClient *client, const gchar *pem_data, GError **
                                                g_byte_array_unref(cert_der);
                                                if (key_pass != NULL) {
                                                        res = gnutls_x509_privkey_import2(key, &data, 
GNUTLS_X509_FMT_PEM, key_pass, 0);
-                                                       memset(key_pass, 0, strlen(key_pass));
-                                                       g_free(key_pass);
+                                                       net_client_free_authstr(key_pass);
                                                }
                                        }
                                }
@@ -475,6 +514,45 @@ net_client_start_tls(NetClient *client, GError **error)
 }
 
 
+gboolean
+net_client_start_compression(NetClient *client, GError **error)
+{
+       gboolean result = FALSE;
+
+       g_return_val_if_fail(NET_IS_CLIENT(client), FALSE);
+
+       if (client->priv->plain_conn == NULL) {
+               g_set_error(error, NET_CLIENT_ERROR_QUARK, (gint) NET_CLIENT_ERROR_NOT_CONNECTED, _("not 
connected"));
+       } else if (client->priv->comp != NULL) {
+               g_set_error(error, NET_CLIENT_ERROR_QUARK, (gint) NET_CLIENT_ERROR_COMP_ACTIVE, _("connection 
is already compressed"));
+       } else {
+               client->priv->comp = g_zlib_compressor_new(G_ZLIB_COMPRESSOR_FORMAT_RAW, -1);
+               client->priv->decomp = g_zlib_decompressor_new(G_ZLIB_COMPRESSOR_FORMAT_RAW);
+
+               g_filter_input_stream_set_close_base_stream(G_FILTER_INPUT_STREAM(client->priv->istream), 
FALSE);
+               g_object_unref(client->priv->istream);
+
+               if (client->priv->tls_conn != NULL) {
+                       client->priv->comp_istream =
+                               
g_converter_input_stream_new(g_io_stream_get_input_stream(G_IO_STREAM(client->priv->tls_conn)),
+                                       G_CONVERTER(client->priv->decomp));
+               } else {
+                       client->priv->comp_istream =
+                               
g_converter_input_stream_new(g_io_stream_get_input_stream(G_IO_STREAM(client->priv->plain_conn)),
+                                       G_CONVERTER(client->priv->decomp));
+               }
+               client->priv->istream = g_data_input_stream_new(client->priv->comp_istream);
+               g_data_input_stream_set_newline_type(client->priv->istream, G_DATA_STREAM_NEWLINE_TYPE_CR_LF);
+
+               client->priv->ostream = g_converter_output_stream_new(client->priv->ostream, 
G_CONVERTER(client->priv->comp));
+               result = TRUE;
+               g_debug("connection is compressed");
+       }
+
+       return result;
+}
+
+
 gboolean
 net_client_set_timeout(NetClient *client, guint timeout_secs)
 {
@@ -485,6 +563,25 @@ net_client_set_timeout(NetClient *client, guint timeout_secs)
 }
 
 
+GSocket *
+net_client_get_socket(NetClient *client)
+{
+       g_return_val_if_fail(NET_IS_CLIENT(client) && (client->priv->plain_conn != NULL), NULL);
+
+       return g_socket_connection_get_socket(client->priv->plain_conn);
+}
+
+
+gboolean
+net_client_can_read(NetClient *client)
+{
+       g_return_val_if_fail(NET_IS_CLIENT(client) && (client->priv->plain_conn != NULL) && 
(client->priv->istream != NULL), FALSE);
+
+       return (g_socket_condition_check(g_socket_connection_get_socket(client->priv->plain_conn), G_IO_IN) 
!= 0) ||
+               (g_buffered_input_stream_get_available(G_BUFFERED_INPUT_STREAM(client->priv->istream)) > 0U);
+}
+
+
 /* == local functions 
=========================================================================================================== */
 
 static void
diff --git a/libnetclient/net-client.h b/libnetclient/net-client.h
index e92f9b8e..cd57be4e 100644
--- a/libnetclient/net-client.h
+++ b/libnetclient/net-client.h
@@ -67,6 +67,7 @@ enum _NetClientError {
        NET_CLIENT_ERROR_NOT_CONNECTED,                 /**< The client is not connected. */
        NET_CLIENT_ERROR_CONNECTION_LOST,               /**< The connection is lost. */
        NET_CLIENT_ERROR_TLS_ACTIVE,                    /**< TLS is already active for the connection. */
+       NET_CLIENT_ERROR_COMP_ACTIVE,                   /**< Compression is already active for the 
connection. */
        NET_CLIENT_ERROR_LINE_TOO_LONG,                 /**< The line is too long. */
        NET_CLIENT_ERROR_GNUTLS,                                /**< A GnuTLS error occurred. */
        NET_CLIENT_ERROR_GSSAPI                                 /**< A GSSAPI error occurred. */
@@ -194,6 +195,17 @@ gboolean net_client_set_cert_from_file(NetClient *client, const gchar *pem_path,
 gboolean net_client_start_tls(NetClient *client, GError **error);
 
 
+/** @brief Start compression
+ *
+ * @param client network client
+ * @param error filled with error information on error
+ * @return TRUE if the connection is now compressed, FALSE on error
+ *
+ * Enable deflate compression of the connection, as defined by e. g. RFC 4978 <em>The IMAP COMPRESS 
Extension</em>.
+ */
+gboolean net_client_start_compression(NetClient *client, GError **error);
+
+
 /** @brief Read a CRLF-terminated line from a network client
  *
  * @param client network client
@@ -279,6 +291,26 @@ gboolean net_client_execute(NetClient *client, gchar **response, const gchar *re
 gboolean net_client_set_timeout(NetClient *client, guint timeout_secs);
 
 
+/** @brief Get the socket
+ *
+ * @param client network client
+ * @return the network client's socket on success, or NULL on error
+ *
+ * Gets the underlying GSocket object of the network client connection, e. g. for monitoring it via a 
GSource.
+ */
+GSocket *net_client_get_socket(NetClient *client);
+
+
+/** @brief Check for pending input data
+ *
+ * @param client network client
+ * @return TRUE if data is available for reading
+ *
+ * Returns if data is ready for reading, because either the socket is ready, or there is still data in the 
buffering input stream.
+ */
+gboolean net_client_can_read(NetClient *client);
+
+
 /** 
  * @mainpage
  *
@@ -287,6 +319,8 @@ gboolean net_client_set_timeout(NetClient *client, guint timeout_secs);
  * client classes (see files net-client-smtp.h and net-client-pop.h, respectively).  The file 
net-client-utils.h contains some
  * helper functions for authentication.
  *
+ * The module net-client-siobuf.h implements some functions for replacing the @em siobuf in Balsa's 
libbalsa/imap module.
+ *
  * \author Written by Albrecht Dreß mailto:albrecht dress arcor de
  * \copyright Copyright &copy; Albrecht Dreß 2017<br/>
  * This library is free software: you can redistribute it and/or modify it under the terms of the GNU 
General Public License as
diff --git a/libnetclient/test/Makefile.am b/libnetclient/test/Makefile.am
index a04d45e0..b900c744 100644
--- a/libnetclient/test/Makefile.am
+++ b/libnetclient/test/Makefile.am
@@ -2,7 +2,8 @@
 
 # Note: the following hack is needed so lcov recognises the paths of the sources...
 libsrcdir = $(shell echo $(abs_srcdir) | sed -e 's;/test$$;;')
-test_src = $(libsrcdir)/net-client.c $(libsrcdir)/net-client-pop.c $(libsrcdir)/net-client-smtp.c 
$(libsrcdir)/net-client-utils.c
+test_src = $(libsrcdir)/net-client.c $(libsrcdir)/net-client-pop.c $(libsrcdir)/net-client-siobuf.c \
+       $(libsrcdir)/net-client-smtp.c $(libsrcdir)/net-client-utils.c
 
 EXTRA_DIST =           \
        tests.c                 \
@@ -25,7 +26,7 @@ clean-local:
        -rm -rf gcov
 
 tests: tests.c
-       $(CC) $(LIBNETCLIENT_CFLAGS) $(CPPFLAGS) $(TESTFLAGS) -I. -I.. -I../.. $< $(test_src) -o $@ 
$(LIBNETCLIENT_LIBS)
+       $(CC) $(LIBNETCLIENT_CFLAGS) $(CPPFLAGS) $(TESTFLAGS) -DG_LOG_DOMAIN=\"libnetclient\" -I. -I.. 
-I../.. $< $(test_src) -o $@ $(LIBNETCLIENT_LIBS)
        $(VALGRIND) $(VALGRFLAGS) ./$@
        $(LCOV) $(LCOVFLGS) -c -b $(libsrcdir) -d $(abs_srcdir) --no-external -o $@.covi
        $(LCOV) $(LCOVFLGS) -r $@.covi $< -o $@.covi
diff --git a/libnetclient/test/echoserver.py b/libnetclient/test/echoserver.py
index ab827304..2905f8b0 100644
--- a/libnetclient/test/echoserver.py
+++ b/libnetclient/test/echoserver.py
@@ -5,6 +5,8 @@
 # Echo server listening at port 65000, with the following non-standard
 # features:
 # - any 'x' in the received string is replaced by 'ThisIsLong'
+# - 'COMPRESS' in the received string causes the connection to be switched
+#   to deflate compression
 # - 'DISCONNECT' in the received string causes the connection to be closed
 # 
 # Copyright (C) Albrecht Dreß <mailto:albrecht dress arcor de> 2017
@@ -24,6 +26,7 @@
 
 import sys
 import socket
+import zlib
 
 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 server_address = ('localhost', 65000)
@@ -34,9 +37,11 @@ while True:
     connection, client_address = sock.accept()
     try:
         comp = False
+        comp_ctx = zlib.compressobj(-1, zlib.DEFLATED, -15)
+        decomp_ctx = zlib.decompressobj(-15)
         while True:
             if comp:
-                data = zlib.decompress(connection.recv(2048))
+                data = decomp_ctx.decompress(connection.recv(2048))
             else:
                 data = connection.recv(2048)
             if data:
@@ -45,9 +50,12 @@ while True:
                     break
                 data = data.replace('x', 'ThisIsLong')
                 if comp:
-                    connection.sendall(zlib.compress(data))
+                    connection.sendall(comp_ctx.compress(data) + comp_ctx.flush(zlib.Z_FULL_FLUSH))
                 else:
                     connection.sendall(data)
+                if data.startswith('COMPRESS'):
+                    print "compression enabled"
+                    comp = True
             else:
                 break
     finally:
diff --git a/libnetclient/test/start-test-env.sh.in b/libnetclient/test/start-test-env.sh.in
index e1f10fd6..37e99211 100644
--- a/libnetclient/test/start-test-env.sh.in
+++ b/libnetclient/test/start-test-env.sh.in
@@ -23,5 +23,5 @@ EOF
 
 echo "shut down echo and GnuTLS servers..."
 @SCREEN@ -S e_echo -X quit
-@SCREEN@ -S s_server1 -X quit
-@SCREEN@ -S s_server2 -X quit
+@SCREEN@ -S s_server1 -X stuff $'\003'
+@SCREEN@ -S s_server2 -X stuff $'\003'
diff --git a/libnetclient/test/tests.c b/libnetclient/test/tests.c
index 12ecbb34..eb20401a 100644
--- a/libnetclient/test/tests.c
+++ b/libnetclient/test/tests.c
@@ -13,19 +13,25 @@
  */
 
 #include <sys/types.h>
+#include <poll.h>
 #include <signal.h>
 #include <string.h>
 #include <sput.h>
 #include "net-client.h"
 #include "net-client-smtp.h"
 #include "net-client-pop.h"
+#include "net-client-siobuf.h"
 #include "net-client-utils.h"
 
 
+#define SUPPRESS_CRITICALS             1
+
+
 static void test_basic(void);
 static void test_basic_crypt(void);
 static void test_smtp(void);
 static void test_pop3(void);
+static void test_siobuf(void);
 static void test_utils(void);
 
 
@@ -35,10 +41,11 @@ log_dummy(const gchar G_GNUC_UNUSED *log_domain, GLogLevelFlags G_GNUC_UNUSED lo
 {
 }
 
+
 int
 main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv)
 {
-       g_log_set_default_handler(log_dummy, NULL);
+       g_log_set_handler("libnetclient", G_LOG_LEVEL_MASK, log_dummy, NULL);
 
        sput_start_testing();
 
@@ -54,6 +61,9 @@ main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv)
        sput_enter_suite("test POP3");
        sput_run_test(test_pop3);
 
+       sput_enter_suite("test SIOBUF (libbalsa/imap compatibility layer)");
+       sput_run_test(test_siobuf);
+
        sput_enter_suite("test utility functions");
        sput_run_test(test_utils);
 
@@ -70,13 +80,21 @@ test_basic(void)
        GError *error = NULL;
        gboolean op_res;
        gchar *read_res;
+       struct pollfd fds[1];
 
        sput_fail_unless(net_client_new(NULL, 65000, 42) == NULL, "missing host");
 
        sput_fail_unless((basic = net_client_new("localhost", 64999, 42)) != NULL, "localhost; port 64999");
        sput_fail_unless(net_client_get_host(NULL) == NULL, "get host w/o client");
+       sput_fail_unless(net_client_get_socket(NULL) == NULL, "get host w/o client");
        sput_fail_unless(strcmp(net_client_get_host(basic), "localhost") == 0, "read host ok");
+       sput_fail_unless(net_client_get_socket(basic) == NULL, "get socket w/o connection");
+       sput_fail_unless(net_client_can_read(NULL) == FALSE, "check can read w/o client");
+       sput_fail_unless(net_client_can_read(basic) == FALSE, "check can read w/o connection");
        sput_fail_unless(net_client_connect(basic, NULL) == FALSE, "connect failed");
+       op_res = net_client_start_compression(basic, &error);
+       sput_fail_unless((op_res == FALSE) && (error->code == NET_CLIENT_ERROR_NOT_CONNECTED), "start 
compression: not connected");
+       g_clear_error(&error);
        g_object_unref(basic);
 
        sput_fail_unless((basic = net_client_new("www.google.com", 80, 1)) != NULL, "www.google.com:80; port 
0");
@@ -101,6 +119,7 @@ test_basic(void)
        op_res = net_client_configure(basic, "localhost", 65000, 42, &error);
        sput_fail_unless((op_res == FALSE) && (error->code == NET_CLIENT_ERROR_CONNECTED), "cannot configure 
already connected");
        g_clear_error(&error);
+       sput_fail_unless(net_client_get_socket(basic) != NULL, "get socket ok");
 
        sput_fail_unless(net_client_write_buffer(NULL, "xxx", 3U, NULL) == FALSE, "write buffer w/o client");
        sput_fail_unless(net_client_write_buffer(basic, NULL, 3U, NULL) == FALSE, "write buffer w/o buffer");
@@ -137,8 +156,54 @@ test_basic(void)
        sput_fail_unless((op_res == FALSE) && (error->code == NET_CLIENT_ERROR_LINE_TOO_LONG), "read line too 
long");
        g_clear_error(&error);
 
-       sput_fail_unless(net_client_write_buffer(basic, "DISCONNECT\r\n", 12U, NULL) == TRUE, "disconnect");
+       sput_fail_unless(net_client_can_read(basic) == FALSE, "no data");
+       sput_fail_unless(net_client_write_buffer(basic, "line1\r\nline2\r\n", 14U, NULL) == TRUE, "write 
lines");
+       sput_fail_unless(net_client_can_read(basic) == TRUE, "data ready");
+       op_res = net_client_read_line(basic, &read_res, NULL);
+       sput_fail_unless((op_res == TRUE) && (strcmp("line1", read_res) == 0), "read line 1 ok");
+       g_free(read_res);
+       sput_fail_unless(net_client_can_read(basic) == TRUE, "data ready");
+       op_res = net_client_read_line(basic, &read_res, NULL);
+       sput_fail_unless((op_res == TRUE) && (strcmp("line2", read_res) == 0), "read line 2 ok");
+       g_free(read_res);
+       sput_fail_unless(net_client_can_read(basic) == FALSE, "no data");
+
+       sput_fail_unless(net_client_start_compression(NULL, NULL) == FALSE, "start compression w/o client");
+       op_res = net_client_execute(basic, &read_res, "COMPRESS", NULL);
+       sput_fail_unless((op_res == TRUE) && (strcmp("COMPRESS", read_res) == 0), "execute 'COMPRESS' ok");
+       g_free(read_res);
+       sput_fail_unless(net_client_start_compression(basic, NULL) == TRUE, "start compression");
+       op_res = net_client_start_compression(basic, &error);
+       sput_fail_unless((op_res == FALSE) && (error->code == NET_CLIENT_ERROR_COMP_ACTIVE), "compression 
already enabled");
+       g_clear_error(&error);
+
+       sput_fail_unless(net_client_can_read(basic) == FALSE, "no data");
+       sput_fail_unless(net_client_write_buffer(basic, "line1\r\nline2\r\n", 14U, NULL) == TRUE, "write 
lines");
+       sput_fail_unless(net_client_can_read(basic) == TRUE, "data ready");
+       op_res = net_client_read_line(basic, &read_res, NULL);
+       sput_fail_unless((op_res == TRUE) && (strcmp("line1", read_res) == 0), "read line 1 ok");
+       g_free(read_res);
+       sput_fail_unless(net_client_can_read(basic) == TRUE, "data ready");
+       op_res = net_client_read_line(basic, &read_res, NULL);
+       sput_fail_unless((op_res == TRUE) && (strcmp("line2", read_res) == 0), "read line 2 ok");
+       g_free(read_res);
+       sput_fail_unless(net_client_can_read(basic) == FALSE, "no data");
+
+       fds[0].fd = g_socket_get_fd(net_client_get_socket(basic));
+       fds[0].events = POLLIN;
+       poll(fds, 1, 0);
+       sput_fail_unless((fds[0].revents & POLLIN) == 0, "no data for reading");
+
+       sput_fail_unless(net_client_write_line(basic, "Hi There", NULL) == TRUE, "send data");
+
+       poll(fds, 1, 1000);
+       sput_fail_unless((fds[0].revents & POLLIN) == POLLIN, "data ready for reading");
 
+       op_res = net_client_read_line(basic, &read_res, NULL);
+       sput_fail_unless((op_res == TRUE) && (strcmp("Hi There", read_res) == 0), "receive data ok");
+       g_free(read_res);
+
+       sput_fail_unless(net_client_write_buffer(basic, "DISCONNECT\r\n", 12U, NULL) == TRUE, "disconnect");
        op_res = net_client_read_line(basic, NULL, &error);
        sput_fail_unless((op_res == FALSE) && (error->code = NET_CLIENT_ERROR_CONNECTION_LOST), "read line, 
client lost");
        g_clear_error(&error);
@@ -175,7 +240,9 @@ test_basic_crypt(void)
 {
        NetClient *basic;
        gboolean op_res;
+       gchar *read_res;
        GError *error = NULL;
+       struct pollfd fds[1];
 
        /* tests without client cert check */
        sput_fail_unless((basic = net_client_new("localhost", 65001, 42)) != NULL, "localhost; port 65001");
@@ -200,6 +267,36 @@ test_basic_crypt(void)
        op_res = net_client_start_tls(basic, &error);
        sput_fail_unless((op_res == FALSE) && (error->code == NET_CLIENT_ERROR_TLS_ACTIVE), "start tls: 
already started");
        g_clear_error(&error);
+
+       fds[0].fd = g_socket_get_fd(net_client_get_socket(basic));
+       fds[0].events = POLLIN;
+       poll(fds, 1, 0);
+       sput_fail_unless((fds[0].revents & POLLIN) == 0, "no data for reading");
+
+       sput_fail_unless(net_client_write_line(basic, "Hi There", NULL) == TRUE, "send data");
+
+       poll(fds, 1, 1000);
+       sput_fail_unless((fds[0].revents & POLLIN) == POLLIN, "data ready for reading");
+
+       op_res = net_client_read_line(basic, &read_res, NULL);
+       sput_fail_unless((op_res == TRUE) && (strcmp("Hi There", read_res) == 0), "read data ok");
+       g_free(read_res);
+
+       sput_fail_unless(net_client_can_read(basic) == FALSE, "no data");
+       sput_fail_unless(net_client_write_buffer(basic, "line1\r\nline2\r\n", 14U, NULL) == TRUE, "write 
lines");
+       sput_fail_unless(net_client_can_read(basic) == TRUE, "data ready");
+       op_res = net_client_read_line(basic, &read_res, NULL);
+       sput_fail_unless((op_res == TRUE) && (strcmp("line1", read_res) == 0), "read line 1 ok");
+       g_free(read_res);
+       sput_fail_unless(net_client_can_read(basic) == TRUE, "data ready");
+       op_res = net_client_read_line(basic, &read_res, NULL);
+       sput_fail_unless((op_res == TRUE) && (strcmp("line2", read_res) == 0), "read line 2 ok");
+       g_free(read_res);
+       sput_fail_unless(net_client_can_read(basic) == FALSE, "no data");
+
+       /* compression on top of tls */
+       sput_fail_unless(net_client_start_compression(basic, NULL) == TRUE, "start compression");
+       // TODO - how can we check exchanging compressed data over tls?
        g_object_unref(basic);
 
        /* tests with client cert check */
@@ -690,6 +787,98 @@ test_pop3(void)
 }
 
 
+static void
+test_siobuf(void)
+{
+       NetClientSioBuf *siobuf;
+       gchar buffer[64];
+       GError *error = NULL;
+       gint read_res;
+       gboolean op_res;
+       gchar *recv_data;
+
+       sput_fail_unless(net_client_siobuf_new(NULL, 65000) == NULL, "missing host");
+       sput_fail_unless((siobuf = net_client_siobuf_new("localhost", 65000)) != NULL, "localhost; port 
65000");
+
+       sput_fail_unless(net_client_siobuf_getc(NULL, NULL)  == -1, "getc w/o client");
+       sput_fail_unless(net_client_siobuf_getc(siobuf, NULL) == -1, "getc fails, not connected");
+
+       sput_fail_unless(net_client_siobuf_gets(NULL, buffer, 1024U, NULL) == NULL, "gets w/o client");
+       sput_fail_unless(net_client_siobuf_gets(siobuf, NULL, 1024U, NULL) == NULL, "gets w/o buffer");
+       sput_fail_unless(net_client_siobuf_gets(siobuf, buffer, 0U, NULL) == NULL, "gets w/o buffer size");
+       sput_fail_unless(net_client_siobuf_gets(siobuf, buffer, 32U, NULL) == NULL, "gets fails, not 
connected");
+
+       sput_fail_unless(net_client_siobuf_read(NULL, buffer, 1024U, NULL) == -1, "read w/o client");
+       sput_fail_unless(net_client_siobuf_read(siobuf, NULL, 1024U, NULL) == -1, "read w/o buffer");
+       sput_fail_unless(net_client_siobuf_read(siobuf, buffer, 0U, NULL) == -1, "read w/o buffer size");
+       sput_fail_unless(net_client_siobuf_read(siobuf, buffer, 32U, NULL) == -1, "read fails, not 
connected");
+
+       sput_fail_unless(net_client_siobuf_ungetc(NULL) == -1, "ungetc w/o client");
+       sput_fail_unless(net_client_siobuf_ungetc(siobuf) == -1, "ungetc at beginning of buffer");
+
+       sput_fail_unless(net_client_set_timeout(NET_CLIENT(siobuf), 10) == TRUE, "set timeout");
+       sput_fail_unless(net_client_connect(NET_CLIENT(siobuf), NULL) == TRUE, "connect");
+       sput_fail_unless(net_client_write_buffer(NET_CLIENT(siobuf), "line1\r\nLINE2\r\nABCD3\r\n", 21U, 
NULL) == TRUE, "write data");
+
+       sput_fail_unless(net_client_siobuf_getc(siobuf, NULL) == 'l', "getc ok");
+       sput_fail_unless(net_client_siobuf_getc(siobuf, NULL) == 'i', "getc ok");
+       sput_fail_unless(net_client_siobuf_ungetc(siobuf) == 0, "ungetc ok");
+       sput_fail_unless(net_client_siobuf_ungetc(siobuf) == 0, "ungetc ok");
+       sput_fail_unless(net_client_siobuf_ungetc(siobuf) == -1, "ungetc at beginning of buffer");
+
+       sput_fail_unless((net_client_siobuf_gets(siobuf, buffer, 3U, NULL) == buffer) && (strcmp(buffer, 
"li") == 0), "gets ok");
+       sput_fail_unless((net_client_siobuf_gets(siobuf, buffer, 32U, NULL) == buffer) && (strcmp(buffer, 
"ne1\r\n") == 0), "gets ok");
+
+       memset(buffer, 0, sizeof(buffer));
+       sput_fail_unless((net_client_siobuf_read(siobuf, buffer, 10U, NULL) == 10) && (strcmp(buffer, 
"LINE2\r\nABC") == 0), "read ok");
+       memset(buffer, 0, sizeof(buffer));
+       read_res = net_client_siobuf_read(siobuf, buffer, 10U, &error);
+       sput_fail_unless((read_res == 4) && (strcmp(buffer, "D3\r\n") == 0) && (error->code == 
G_IO_ERROR_TIMED_OUT), "short read ok");
+       g_clear_error(&error);
+
+       net_client_siobuf_write(NULL, "abcd", 4U);
+       net_client_siobuf_write(siobuf, NULL, 4U);
+       net_client_siobuf_write(siobuf, "abcd", 0U);
+       net_client_siobuf_write(siobuf, "abcd", 4U);
+
+       net_client_siobuf_printf(NULL, "%d", 4711);
+       net_client_siobuf_printf(siobuf, NULL);
+       net_client_siobuf_printf(siobuf, "%d", 4711);
+
+       sput_fail_unless(net_client_siobuf_flush(NULL, NULL) == FALSE, "flush write w/o client");
+       sput_fail_unless(net_client_siobuf_flush(siobuf, NULL) == TRUE, "flush successful");
+       sput_fail_unless(net_client_siobuf_flush(siobuf, NULL) == FALSE, "flush write w/o data");
+
+       op_res = net_client_read_line(NET_CLIENT(siobuf), &recv_data, &error);
+       sput_fail_unless(op_res && (strcmp(recv_data, "abcd4711") == 0), "buffered write: read back ok");
+       g_free(recv_data);
+       sput_fail_unless(net_client_can_read(NET_CLIENT(siobuf)) == FALSE, "no data left");
+
+       net_client_siobuf_write(siobuf, "abcd\r\n1234\r\nqrst\r\n9876", 22U);
+       sput_fail_unless(net_client_siobuf_flush(siobuf, NULL) == TRUE, "flush successful");
+
+       sput_fail_unless(net_client_siobuf_get_line(NULL, NULL) == NULL, "get line w/o client");
+       sput_fail_unless(net_client_siobuf_getc(siobuf, NULL) == 'a', "getc ok");
+       recv_data = net_client_siobuf_get_line(siobuf, NULL);
+       sput_fail_unless(strcmp(recv_data, "bcd") == 0, "get line #1 ok");
+       g_free(recv_data);
+       recv_data = net_client_siobuf_get_line(siobuf, NULL);
+       sput_fail_unless(strcmp(recv_data, "1234") == 0, "get line #2 ok");
+       g_free(recv_data);
+       sput_fail_unless((net_client_siobuf_gets(siobuf, buffer, 5U, NULL) == buffer) && (strcmp(buffer, 
"qrst") == 0), "gets ok");
+       recv_data = net_client_siobuf_get_line(siobuf, NULL);
+       sput_fail_unless(strcmp(recv_data, "") == 0, "get line #3 ok");
+       g_free(recv_data);
+
+       sput_fail_unless(net_client_siobuf_getc(siobuf, NULL) == '9', "getc ok");
+       sput_fail_unless(net_client_siobuf_discard_line(NULL, NULL) == -1, "discard line w/o client");
+       sput_fail_unless(net_client_siobuf_discard_line(siobuf, NULL) == '\n', "discard line ok");
+       sput_fail_unless(net_client_siobuf_discard_line(siobuf, NULL) == -1, "discard line w/o data");
+       sput_fail_unless(net_client_siobuf_get_line(siobuf, NULL) == NULL, "get line w/o data");
+
+       g_object_unref(siobuf);
+}
+
 static void
 test_utils(void)
 {
diff --git a/meson.build b/meson.build
index 33998aa6..89a92faa 100644
--- a/meson.build
+++ b/meson.build
@@ -349,39 +349,6 @@ if osmo
     description : 'If defined, enable Osmo address book support.')
 endif # osmo
 
-# OpenSSL configuration.
-#
-ssl_dep = dependency('openssl')
-if not ssl_dep.found()
-  if not compiler.has_header('openssl/ssl.h')
-    error('OpenSSL headers not found')
-  endif
-
-  # Look for SSL_library_init
-  code = '''
-  /* Override any GCC internal prototype to avoid an error.
-     Use char because int might match the return type of a GCC
-     builtin and then its argument prototype would still apply.  */
-  char SSL_library_init ();
-  int
-  main ()
-  {
-    return SSL_library_init ();
-  }
-  '''
-  ssl_link_args = ['-lssl', '-lcrypto']
-  result = compiler.links(code,
-                          args : ssl_link_args,
-                          name : 'OpenSSL test')
-  if result
-    ssl_dep = declare_dependency(linkargs : ssl_link_args)
-  else
-    error('libssl not found')
-  endif
-endif # not ssl_dep.found()
-balsa_deps += ssl_dep
-balsa_ab_deps += ssl_dep
-
 # KRB5/GSSAPI configuration.
 #
 if gss
@@ -556,10 +523,6 @@ if compiler.has_function('ctime_r')
     description : 'Define to 1 if you have the ‘ctime_r’ function.')
 endif
 
-if not compiler.has_header('zlib.h')
-  error('zlib library required')
-endif
-
 if compiler.has_header('locale.h')
   conf.set('HAVE_LOCALE_H', 1,
     description : 'Define to 1 if you have the <locale.h> header')
diff --git a/src/ab-window.c b/src/ab-window.c
index b1a75275..85228e1c 100644
--- a/src/ab-window.c
+++ b/src/ab-window.c
@@ -23,6 +23,7 @@
 #include "ab-window.h"
 
 #include <string.h>
+#include <stdlib.h>
 #include <glib/gi18n.h>
 #include "address-view.h"
 #include "balsa-app.h"
diff --git a/src/folder-conf.c b/src/folder-conf.c
index d609a1bf..167c417b 100644
--- a/src/folder-conf.c
+++ b/src/folder-conf.c
@@ -58,7 +58,6 @@ struct _FolderDialogData {
     BalsaServerConf bsc;
     GtkWidget *folder_name, *port, *username, *anonymous, *remember,
         *password, *subscribed, *list_inbox, *prefix;
-    GtkWidget *use_ssl, *tls_mode;
     GtkWidget *connection_limit, *enable_persistent,
         *use_idle, *has_bugs, *use_status;
 };
@@ -154,10 +153,25 @@ static void
 validate_folder(GtkWidget *w, FolderDialogData * fcw)
 {
     gboolean sensitive = TRUE;
-    if (!*gtk_entry_get_text(GTK_ENTRY(fcw->folder_name)))
-       sensitive = FALSE;
-    else if (!*gtk_entry_get_text(GTK_ENTRY(fcw->bsc.server)))
-       sensitive = FALSE;
+
+    if (!*gtk_entry_get_text(GTK_ENTRY(fcw->folder_name))) {
+       sensitive = FALSE;
+    } else if (!*gtk_entry_get_text(GTK_ENTRY(fcw->bsc.server))) {
+       sensitive = FALSE;
+    }
+
+    /* encryption w/ client cert requires cert file */
+    if (sensitive &&
+       ((gtk_combo_box_get_active(GTK_COMBO_BOX(fcw->bsc.security)) + 1) != NET_CLIENT_CRYPT_NONE) &&
+               gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fcw->bsc.need_client_cert))) {
+       gchar *cert_file;
+
+       cert_file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fcw->bsc.client_cert_file));
+       if ((cert_file == NULL) || (cert_file[0] == '\0')) {
+               sensitive = FALSE;
+       }
+       g_free(cert_file);
+    }
 
     gtk_dialog_set_response_sensitive(fcw->dialog, GTK_RESPONSE_OK, sensitive);
 }
@@ -176,6 +190,19 @@ remember_cb(GtkToggleButton * button, FolderDialogData * fcw)
                              gtk_toggle_button_get_active(button));
 }
 
+static void
+security_cb(GtkComboBox *combo, FolderDialogData *fcw)
+{
+       gboolean sensitive;
+
+       sensitive = (gtk_combo_box_get_active(combo) + 1) != NET_CLIENT_CRYPT_NONE;
+       gtk_widget_set_sensitive(fcw->bsc.need_client_cert, sensitive);
+       sensitive = sensitive & gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fcw->bsc.need_client_cert));
+       gtk_widget_set_sensitive(fcw->bsc.client_cert_file, sensitive);
+       gtk_widget_set_sensitive(fcw->bsc.client_cert_passwd, sensitive);
+       validate_folder(GTK_WIDGET(combo), fcw);
+}
+
 static gboolean
 folder_conf_clicked_ok(FolderDialogData * fcw)
 {
@@ -197,7 +224,7 @@ folder_conf_clicked_ok(FolderDialogData * fcw)
                          G_CALLBACK(ask_password), NULL);
     }
 
-    s->tls_mode = balsa_server_conf_get_tls_mode(&fcw->bsc);
+    s->security = balsa_server_conf_get_security(&fcw->bsc);
     libbalsa_imap_server_set_max_connections
         (LIBBALSA_IMAP_SERVER(s),
          gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON
@@ -243,8 +270,7 @@ folder_conf_clicked_ok(FolderDialogData * fcw)
     fcw->mbnode->list_inbox =
         gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fcw->list_inbox));
 
-    libbalsa_server_set_host(s, host, 
-                             balsa_server_conf_get_use_ssl(&fcw->bsc));
+    libbalsa_server_set_host(s, host, s->security);
     libbalsa_server_config_changed(s); /* trigger config save */
 
     if (insert) {
@@ -331,7 +357,7 @@ folder_conf_imap_node(BalsaMailboxNode *mn)
     gtk_container_set_border_width(GTK_CONTAINER(grid), 12);
     gtk_notebook_append_page(GTK_NOTEBOOK(notebook), grid,
                              gtk_label_new_with_mnemonic(_("_Basic")));
-    advanced = balsa_server_conf_get_advanced_widget(&fcw->bsc, s, 3);
+    advanced = balsa_server_conf_get_advanced_widget(&fcw->bsc);
     /* Limit number of connections */
     fcw->connection_limit = 
         balsa_server_conf_add_spinner
@@ -383,9 +409,20 @@ folder_conf_imap_node(BalsaMailboxNode *mn)
         libbalsa_create_grid_entry(grid, G_CALLBACK(validate_folder),
                                    fcw, r++, s ? s->host : default_server,
                                    label);
-    fcw->bsc.default_ports = IMAP_DEFAULT_PORTS;
     g_free(default_server);
 
+    label = libbalsa_create_grid_label(_("Se_curity:"), grid, r);
+    fcw->bsc.security = gtk_combo_box_text_new();
+    gtk_widget_set_hexpand(fcw->bsc.security, TRUE);
+    gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(fcw->bsc.security), _("IMAP over SSL (IMAPS)"));
+    gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(fcw->bsc.security), _("TLS required"));
+    gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(fcw->bsc.security), _("TLS if possible (not 
recommended)"));
+    gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(fcw->bsc.security), _("None (not recommended)"));
+    gtk_grid_attach(GTK_GRID(grid), fcw->bsc.security, 1, r++, 1, 1);
+    gtk_combo_box_set_active(GTK_COMBO_BOX(fcw->bsc.security), s ? s->security - 1 : 
NET_CLIENT_CRYPT_STARTTLS - 1);
+    g_signal_connect(fcw->bsc.security, "changed", G_CALLBACK(security_cb), fcw);
+    gtk_label_set_mnemonic_widget(GTK_LABEL(label), fcw->bsc.security);
+
     label= libbalsa_create_grid_label(_("Use_r name:"), grid, r);
     fcw->username =
         libbalsa_create_grid_entry(grid, G_CALLBACK(validate_folder),
diff --git a/src/mailbox-conf.c b/src/mailbox-conf.c
index 6cb3a878..28932bd0 100644
--- a/src/mailbox-conf.c
+++ b/src/mailbox-conf.c
@@ -98,7 +98,6 @@ struct _MailboxConfWindow {
 
        /* for pop3 mailboxes */
        struct {
-               GtkWidget *security;
            GtkWidget *username;
            GtkWidget *password;
            GtkWidget *check;
@@ -178,76 +177,8 @@ mailbox_conf_combo_box_make(GtkComboBoxText * combo_box, unsigned cnt,
 }
 
 
-static void
-bsc_ssl_toggled_cb(GtkWidget * widget, BalsaServerConf * bsc)
-{
-    const gchar *host, *colon;
-    gboolean newstate =
-        !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
-
-    gtk_widget_set_sensitive(bsc->tls_option, newstate);
-
-    host = gtk_entry_get_text(GTK_ENTRY(bsc->server));
-    if ((colon = strchr(host, ':')) != NULL) {
-       /* A port was specified... */
-       gchar *port = g_ascii_strdown(colon + 1, -1);
-        if (strstr(bsc->default_ports, port) != NULL)
-           /* and it is one of the default ports, so strip it. */
-           gtk_editable_delete_text(GTK_EDITABLE(bsc->server),
-                                     colon - host, -1);
-       g_free(port);
-    }
-}
-
 GtkWidget*
-balsa_server_conf_get_advanced_widget(BalsaServerConf *bsc, LibBalsaServer *s,
-                                      int extra_rows)
-{
-    static const struct menu_data tls_menu[] = {
-        { N_("Never"),       LIBBALSA_TLS_DISABLED },
-        { N_("If Possible"), LIBBALSA_TLS_ENABLED  },
-        { N_("Required"),    LIBBALSA_TLS_REQUIRED }
-    };
-    GtkWidget *label;
-    GtkWidget *box;
-    gboolean use_ssl = s && s->use_ssl;
-
-    box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
-
-    bsc->grid = GTK_GRID(libbalsa_create_grid());
-    gtk_container_set_border_width(GTK_CONTAINER(bsc->grid), 12);
-    gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(bsc->grid),
-                       FALSE, FALSE, 0);
-
-    bsc->used_rows = 0;
-
-    bsc->use_ssl = balsa_server_conf_add_checkbox(bsc, _("Use _SSL"));
-    if(use_ssl)
-       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bsc->use_ssl), TRUE);
-
-    label =
-        libbalsa_create_grid_label(_("Use _TLS:"), GTK_WIDGET(bsc->grid), 1);
-
-    bsc->tls_option = gtk_combo_box_text_new();
-    gtk_widget_set_hexpand(bsc->tls_option, TRUE);
-    mailbox_conf_combo_box_make(GTK_COMBO_BOX_TEXT(bsc->tls_option),
-                                ELEMENTS(tls_menu), tls_menu);
-    gtk_combo_box_set_active(GTK_COMBO_BOX(bsc->tls_option),
-                             s ? s->tls_mode : LIBBALSA_TLS_ENABLED);
-    gtk_grid_attach(bsc->grid, bsc->tls_option, 1, 1, 1, 1);
-    gtk_label_set_mnemonic_widget(GTK_LABEL(label), bsc->tls_option);
-
-    g_signal_connect(G_OBJECT (bsc->use_ssl), "toggled",
-                     G_CALLBACK (bsc_ssl_toggled_cb), bsc);
-    gtk_widget_show_all(GTK_WIDGET(bsc->grid));
-    bsc->used_rows = 2;
-    gtk_widget_set_sensitive(bsc->tls_option, !use_ssl);
-
-    return box;
-}
-
-static GtkWidget*
-balsa_server_conf_get_advanced_widget_new(BalsaServerConf *bsc)
+balsa_server_conf_get_advanced_widget(BalsaServerConf *bsc)
 {
     GtkWidget *box;
     GtkWidget *label;
@@ -304,35 +235,10 @@ balsa_server_conf_add_spinner(BalsaServerConf *bsc,
     return spin_button;
 }
 
-void
-balsa_server_conf_set_values(BalsaServerConf *bsc, LibBalsaServer *server)
-{
-    g_return_if_fail(server);
-
-    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bsc->use_ssl), 
-                                 server->use_ssl);
-    gtk_combo_box_set_active(GTK_COMBO_BOX(bsc->tls_option),
-                             server->tls_mode);
-    gtk_widget_set_sensitive(bsc->tls_option, !server->use_ssl);
-}
-
-
-gboolean
-balsa_server_conf_get_use_ssl(BalsaServerConf *bsc)
-{
-    return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(bsc->use_ssl));
-}
-
-LibBalsaTlsMode
-balsa_server_conf_get_tls_mode(BalsaServerConf *bsc)
+NetClientCryptMode
+balsa_server_conf_get_security(BalsaServerConf *bsc)
 {
-    struct mailbox_conf_combo_box_info *info =
-        g_object_get_data(G_OBJECT(bsc->tls_option),
-                          BALSA_MC_COMBO_BOX_INFO);
-    gint active = gtk_combo_box_get_active(GTK_COMBO_BOX(bsc->tls_option));
-
-    return (LibBalsaTlsMode)
-        GPOINTER_TO_INT(g_slist_nth_data(info->tags, active));
+       return gtk_combo_box_get_active(GTK_COMBO_BOX(bsc->security)) + 1;
 }
 
 /* END BalsaServerConf ===================================== */
@@ -351,10 +257,16 @@ static void
 client_cert_changed(GtkToggleButton *button, MailboxConfWindow *mcw)
 {
        gboolean sensitive;
+       BalsaServerConf *bsc;
 
+       if (g_type_is_a(mcw->mailbox_type, LIBBALSA_TYPE_MAILBOX_POP3)) {
+               bsc = &mcw->mb_data.pop3.bsc;
+       } else {
+               bsc = &mcw->mb_data.imap.bsc;
+       }
        sensitive = gtk_toggle_button_get_active(button);
-       gtk_widget_set_sensitive(mcw->mb_data.pop3.bsc.client_cert_file, sensitive);
-       gtk_widget_set_sensitive(mcw->mb_data.pop3.bsc.client_cert_passwd, sensitive);
+       gtk_widget_set_sensitive(bsc->client_cert_file, sensitive);
+       gtk_widget_set_sensitive(bsc->client_cert_passwd, sensitive);
     check_for_blank_fields(NULL, mcw);
 }
 
@@ -362,12 +274,18 @@ static void
 security_changed(GtkComboBox *combo, MailboxConfWindow *mcw)
 {
        gboolean sensitive;
+       BalsaServerConf *bsc;
 
+       if (g_type_is_a(mcw->mailbox_type, LIBBALSA_TYPE_MAILBOX_POP3)) {
+               bsc = &mcw->mb_data.pop3.bsc;
+       } else {
+               bsc = &mcw->mb_data.imap.bsc;
+       }
        sensitive = (gtk_combo_box_get_active(combo) + 1) != NET_CLIENT_CRYPT_NONE;
-       gtk_widget_set_sensitive(mcw->mb_data.pop3.bsc.need_client_cert, sensitive);
-       sensitive = sensitive & 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mcw->mb_data.pop3.bsc.need_client_cert));
-       gtk_widget_set_sensitive(mcw->mb_data.pop3.bsc.client_cert_file, sensitive);
-       gtk_widget_set_sensitive(mcw->mb_data.pop3.bsc.client_cert_passwd, sensitive);
+       gtk_widget_set_sensitive(bsc->need_client_cert, sensitive);
+       sensitive = sensitive & gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(bsc->need_client_cert));
+       gtk_widget_set_sensitive(bsc->client_cert_file, sensitive);
+       gtk_widget_set_sensitive(bsc->client_cert_passwd, sensitive);
     check_for_blank_fields(NULL, mcw);
 }
 
@@ -688,7 +606,7 @@ mailbox_conf_set_values_pop3(LibBalsaMailbox   *mailbox,
        if (server->host != NULL) {
                gtk_entry_set_text(GTK_ENTRY(mcw->mb_data.pop3.bsc.server), server->host);
        }
-       gtk_combo_box_set_active(GTK_COMBO_BOX(mcw->mb_data.pop3.security), server->security - 1);
+       gtk_combo_box_set_active(GTK_COMBO_BOX(mcw->mb_data.pop3.bsc.security), server->security - 1);
 
        if (server->user != NULL) {
                gtk_entry_set_text(GTK_ENTRY(mcw->mb_data.pop3.username), server->user);
@@ -779,7 +697,6 @@ mailbox_conf_set_values(MailboxConfWindow *mcw)
                if (path)
                        gtk_entry_set_text(GTK_ENTRY(mcw->mb_data.imap.folderpath),
                                path);
-               balsa_server_conf_set_values(&mcw->mb_data.imap.bsc, server);
                if(libbalsa_imap_server_has_persistent_cache
                        (LIBBALSA_IMAP_SERVER(server)))
                        gtk_toggle_button_set_active
@@ -810,50 +727,56 @@ static void
 check_for_blank_fields(GtkWidget G_GNUC_UNUSED *widget, MailboxConfWindow *mcw)
 {
     gboolean sensitive;
+    BalsaServerConf *bsc = NULL;
 
     if (mcw == NULL || mcw->window == NULL)
         return;
 
     sensitive = TRUE;
 
-    if (mcw->mailbox_name &&!*gtk_entry_get_text(GTK_ENTRY(mcw->mailbox_name)))
-       sensitive = FALSE;
-    else if (g_type_is_a(mcw->mailbox_type, LIBBALSA_TYPE_MAILBOX_LOCAL) ) {
-        gchar *filename =
-            gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(mcw->window));
-       if (filename)
-           g_free(filename);
-       else
-           sensitive = FALSE;
+    if (mcw->mailbox_name &&!*gtk_entry_get_text(GTK_ENTRY(mcw->mailbox_name))) {
+       sensitive = FALSE;
+    } else if (g_type_is_a(mcw->mailbox_type, LIBBALSA_TYPE_MAILBOX_LOCAL) ) {
+       gchar *filename =
+               gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(mcw->window));
+       if (filename) {
+               g_free(filename);
+       } else {
+               sensitive = FALSE;
+       }
     } else if (g_type_is_a(mcw->mailbox_type, LIBBALSA_TYPE_MAILBOX_IMAP ) ) {
-       if (!*gtk_entry_get_text(GTK_ENTRY(mcw->mb_data.imap.folderpath))
-            || !*gtk_entry_get_text(GTK_ENTRY(mcw->mb_data.imap.bsc.server))
-            || !*gtk_entry_get_text(GTK_ENTRY(mcw->mb_data.imap.username)))
-           sensitive = FALSE;
+       bsc = &mcw->mb_data.imap.bsc;
+       if (!*gtk_entry_get_text(GTK_ENTRY(mcw->mb_data.imap.folderpath))
+               || !*gtk_entry_get_text(GTK_ENTRY(bsc->server))
+                       || !*gtk_entry_get_text(GTK_ENTRY(mcw->mb_data.imap.username))) {
+               sensitive = FALSE;
+       }
     } else if (g_type_is_a(mcw->mailbox_type, LIBBALSA_TYPE_MAILBOX_POP3) ) {
        /* POP3: require user name and server */
+       bsc = &mcw->mb_data.pop3.bsc;
        if ((gtk_entry_get_text(GTK_ENTRY(mcw->mb_data.pop3.username))[0] == '\0') ||
-            (gtk_entry_get_text(GTK_ENTRY(mcw->mb_data.pop3.bsc.server))[0] == '\0')) {
+               (gtk_entry_get_text(GTK_ENTRY(bsc->server))[0] == '\0')) {
                sensitive = FALSE;
        }
        /* procmail filtering requires command */
        if (sensitive &&
                gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mcw->mb_data.pop3.filter)) &&
-               (gtk_entry_get_text(GTK_ENTRY(mcw->mb_data.pop3.filter_cmd))[0] == '\0')) {
+                       (gtk_entry_get_text(GTK_ENTRY(mcw->mb_data.pop3.filter_cmd))[0] == '\0')) {
                sensitive = FALSE;
        }
-       /* encryption w/ client cert requires cert file */
-       if (sensitive &&
-               ((gtk_combo_box_get_active(GTK_COMBO_BOX(mcw->mb_data.pop3.security)) + 1) != 
NET_CLIENT_CRYPT_NONE) &&
-               gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mcw->mb_data.pop3.bsc.need_client_cert))) {
-               gchar *cert_file;
-
-               cert_file = 
gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(mcw->mb_data.pop3.bsc.client_cert_file));
-               if ((cert_file == NULL) || (cert_file[0] == '\0')) {
-                       sensitive = FALSE;
-               }
-               g_free(cert_file);
+    }
+
+    /* encryption w/ client cert requires cert file */
+    if (sensitive && (bsc != NULL) &&
+       ((gtk_combo_box_get_active(GTK_COMBO_BOX(bsc->security)) + 1) != NET_CLIENT_CRYPT_NONE) &&
+               gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(bsc->need_client_cert))) {
+       gchar *cert_file;
+
+       cert_file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(bsc->client_cert_file));
+       if ((cert_file == NULL) || (cert_file[0] == '\0')) {
+               sensitive = FALSE;
        }
+       g_free(cert_file);
     }
 
     gtk_dialog_set_response_sensitive(mcw->window, MCW_RESPONSE, sensitive);
@@ -900,8 +823,8 @@ update_pop_mailbox(MailboxConfWindow *mcw)
        g_free(LIBBALSA_MAILBOX(mailbox)->name);
        LIBBALSA_MAILBOX(mailbox)->name = g_strdup(gtk_entry_get_text(GTK_ENTRY(mcw->mailbox_name)));
 
-       libbalsa_server_set_host(server, gtk_entry_get_text(GTK_ENTRY(mcw->mb_data.pop3.bsc.server)), FALSE);
-       server->security = gtk_combo_box_get_active(GTK_COMBO_BOX(mcw->mb_data.pop3.security)) + 1;
+       server->security = balsa_server_conf_get_security(&mcw->mb_data.pop3.bsc);
+       libbalsa_server_set_host(server, gtk_entry_get_text(GTK_ENTRY(mcw->mb_data.pop3.bsc.server)), 
server->security);
 
        libbalsa_server_set_username(server, gtk_entry_get_text(GTK_ENTRY(mcw->mb_data.pop3.username)));
        libbalsa_server_set_password(server, gtk_entry_get_text(GTK_ENTRY(mcw->mb_data.pop3.password)));
@@ -954,7 +877,7 @@ update_imap_mailbox(MailboxConfWindow *mcw)
     server->remember_passwd = 
         gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mcw->
                                                        mb_data.imap.remember));
-    server->tls_mode = balsa_server_conf_get_tls_mode(&mcw->mb_data.imap.bsc);
+       server->security = balsa_server_conf_get_security(&mcw->mb_data.imap.bsc);
     libbalsa_server_set_password(server,
                                 gtk_entry_get_text(GTK_ENTRY
                                                    (mcw->mb_data.imap.password)));
@@ -971,8 +894,7 @@ update_imap_mailbox(MailboxConfWindow *mcw)
     libbalsa_server_set_host(server,
                             gtk_entry_get_text(GTK_ENTRY
                                                (mcw->mb_data.imap.bsc.server)),
-                             balsa_server_conf_get_use_ssl
-                             (&mcw->mb_data.imap.bsc));
+                                               server->security);
     libbalsa_server_config_changed(server);
     g_signal_connect(G_OBJECT(server), "get-password",
                      G_CALLBACK(ask_password), mailbox);
@@ -1264,6 +1186,29 @@ create_generic_dialog(MailboxConfWindow * mcw)
     return dialog;
 }
 
+static GtkWidget *
+create_security_entry(GtkWidget *grid, gint *row, MailboxConfWindow *mcw)
+{
+    GtkWidget *label;
+    GtkWidget *security;
+
+    label = libbalsa_create_grid_label(_("Se_curity:"), grid, *row);
+    security = gtk_combo_box_text_new();
+    gtk_widget_set_hexpand(security, TRUE);
+    if (g_type_is_a(mcw->mailbox_type, LIBBALSA_TYPE_MAILBOX_POP3)) {
+       gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(security), _("POP3 over SSL (POP3S)"));
+    } else {
+       gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(security), _("IMAP over SSL (IMAPS)"));
+    }
+    gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(security), _("TLS required"));
+    gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(security), _("TLS if possible (not recommended)"));
+    gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(security), _("None (not recommended)"));
+    gtk_grid_attach(GTK_GRID(grid), security, 1, (*row)++, 1, 1);
+    g_signal_connect(security, "changed", G_CALLBACK(security_changed), mcw);
+    gtk_label_set_mnemonic_widget(GTK_LABEL(label), security);
+    return security;
+}
+
 static GtkWidget *
 create_pop_mailbox_dialog(MailboxConfWindow *mcw)
 {
@@ -1287,17 +1232,7 @@ create_pop_mailbox_dialog(MailboxConfWindow *mcw)
        libbalsa_create_grid_entry(grid, G_CALLBACK(check_for_blank_fields), mcw, row++, "localhost", label);
 
     /* security */
-    label = libbalsa_create_grid_label(_("Se_curity:"), grid, row);
-    mcw->mb_data.pop3.security = gtk_combo_box_text_new();
-    gtk_widget_set_hexpand(mcw->mb_data.pop3.security, TRUE);
-    mcw->mb_data.pop3.security = gtk_combo_box_text_new();
-    gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(mcw->mb_data.pop3.security), _("POP3 over SSL 
(POP3S)"));
-    gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(mcw->mb_data.pop3.security), _("TLS required"));
-    gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(mcw->mb_data.pop3.security), _("TLS if possible (not 
recommended)"));
-    gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(mcw->mb_data.pop3.security), _("None (not 
recommended)"));
-    gtk_grid_attach(GTK_GRID(grid), mcw->mb_data.pop3.security, 1, row++, 1, 1);
-    g_signal_connect(mcw->mb_data.pop3.security, "changed", G_CALLBACK(security_changed), mcw);
-    gtk_label_set_mnemonic_widget(GTK_LABEL(label), mcw->mb_data.pop3.security);
+    mcw->mb_data.pop3.bsc.security = create_security_entry(grid, &row, mcw);
 
     /* username  */
     label= libbalsa_create_grid_label(_("Use_r name:"), grid, row);
@@ -1325,7 +1260,7 @@ create_pop_mailbox_dialog(MailboxConfWindow *mcw)
     mcw->mb_data.pop3.filter_cmd =
        libbalsa_create_grid_entry(grid, G_CALLBACK(check_for_blank_fields), mcw, row++, "procmail -f -", 
label);
 
-    advanced = balsa_server_conf_get_advanced_widget_new(&mcw->mb_data.pop3.bsc);
+    advanced = balsa_server_conf_get_advanced_widget(&mcw->mb_data.pop3.bsc);
     gtk_notebook_append_page(GTK_NOTEBOOK(notebook), advanced, gtk_label_new_with_mnemonic(_("_Advanced")));
        g_signal_connect(mcw->mb_data.pop3.bsc.need_client_cert, "toggled", G_CALLBACK(client_cert_changed), 
mcw);
        g_signal_connect(mcw->mb_data.pop3.bsc.client_cert_file, "file-set", 
G_CALLBACK(check_for_blank_fields), mcw);
@@ -1397,8 +1332,10 @@ create_imap_mailbox_dialog(MailboxConfWindow *mcw)
     label = libbalsa_create_grid_label(_("_Server:"), grid, ++row);
     mcw->mb_data.imap.bsc.server =
        libbalsa_create_grid_entry(grid, G_CALLBACK(check_for_blank_fields),
-                                   mcw, row, "localhost", label);
-    mcw->mb_data.imap.bsc.default_ports = IMAP_DEFAULT_PORTS;
+                                   mcw, row++, "localhost", label);
+
+    /* security */
+    mcw->mb_data.imap.bsc.security = create_security_entry(grid, &row, mcw);
 
     /* username  */
     label = libbalsa_create_grid_label(_("_Username:"), grid, ++row);
@@ -1441,8 +1378,7 @@ create_imap_mailbox_dialog(MailboxConfWindow *mcw)
     gtk_grid_attach(GTK_GRID(grid), entry, 1, row, 1, 1);
 
     advanced =
-        balsa_server_conf_get_advanced_widget(&mcw->mb_data.imap.bsc,
-                                              NULL, 1);
+        balsa_server_conf_get_advanced_widget(&mcw->mb_data.imap.bsc);
     mcw->mb_data.imap.enable_persistent = 
         balsa_server_conf_add_checkbox(&mcw->mb_data.imap.bsc,
                                        _("Enable _persistent cache"));
diff --git a/src/mailbox-conf.h b/src/mailbox-conf.h
index 8a32d1f6..a548c4b6 100644
--- a/src/mailbox-conf.h
+++ b/src/mailbox-conf.h
@@ -48,22 +48,17 @@ void mailbox_conf_view_check(BalsaMailboxConfView * mcc,
 
 
 typedef struct {
-    GtkWidget *use_ssl;
-    GtkWidget *tls_mode;
+    GtkWidget *security;
     GtkGrid   *grid;       /* internal */
-    GtkWidget *tls_option; /* internal */
     GtkWidget *server;     /* internal */
     GtkWidget *need_client_cert;
     GtkWidget *client_cert_file;
     GtkWidget *client_cert_passwd;
-    const gchar *default_ports;
     unsigned   used_rows;  /* internal */
 } BalsaServerConf;
-#define IMAP_DEFAULT_PORTS "143 993 imap imaps"
 
-GtkWidget* balsa_server_conf_get_advanced_widget(BalsaServerConf *bsc,
-                                                 LibBalsaServer *s,
-                                                 int extra_rows);
+
+GtkWidget*      balsa_server_conf_get_advanced_widget(BalsaServerConf *bsc);
 GtkWidget*      balsa_server_conf_add_checkbox(BalsaServerConf *bsc,
                                                const char *label);
 GtkWidget*      balsa_server_conf_add_spinner(BalsaServerConf *bsc,
@@ -72,7 +67,6 @@ GtkWidget*      balsa_server_conf_add_spinner(BalsaServerConf *bsc,
                                               gint initial_value);
 void            balsa_server_conf_set_values(BalsaServerConf *bsc,
                                              LibBalsaServer *server);
-gboolean        balsa_server_conf_get_use_ssl(BalsaServerConf *bsc);
-LibBalsaTlsMode balsa_server_conf_get_tls_mode(BalsaServerConf *bsc);
+NetClientCryptMode balsa_server_conf_get_security(BalsaServerConf *bsc);
 
 #endif                         /* __MAILBOX_CONF_H__ */
diff --git a/src/mailbox-node.c b/src/mailbox-node.c
index c6a746b8..e946d75f 100644
--- a/src/mailbox-node.c
+++ b/src/mailbox-node.c
@@ -605,9 +605,8 @@ balsa_mailbox_node_new_from_config(const gchar* group)
 
     folder->server = LIBBALSA_SERVER(libbalsa_imap_server_new_from_config());
 
-    if(balsa_app.debug)
-       printf("Server loaded, host: %s, %s.\n", folder->server->host,
-              folder->server->use_ssl ? "SSL" : "no SSL");
+       g_debug("Server loaded, host: %s, security %d.", folder->server->host,
+               folder->server->security);
     g_signal_connect_swapped(G_OBJECT(folder->server), "config-changed", 
                              G_CALLBACK(config_folder_update), folder);
     g_signal_connect(G_OBJECT(folder), "show-prop-dialog", 
diff --git a/src/main.c b/src/main.c
index 77746dd0..7e682997 100644
--- a/src/main.c
+++ b/src/main.c
@@ -611,8 +611,6 @@ parse_options(int                       argc,
         {"get-stats", 's', 0, G_OPTION_ARG_NONE,
          &(cmd_get_stats),
          N_("Prints number unread and unsent messages"), NULL},
-        {"debug-imap", 'D', 0, G_OPTION_ARG_NONE, &ImapDebug,
-         N_("Debug IMAP connection"), NULL},
         {"help", 'h', 0, G_OPTION_ARG_NONE, &help, N_("Show help options"), NULL},
         {"version", 'v', 0, G_OPTION_ARG_NONE, &version, N_("Show version"), NULL},
         /* last but not least a special option that collects filenames */
diff --git a/src/save-restore.c b/src/save-restore.c
index 48fbf192..f6bd4d5d 100644
--- a/src/save-restore.c
+++ b/src/save-restore.c
@@ -934,9 +934,6 @@ config_global_load(void)
            g_free(passphrase_rot);
         }
 
-        /* default set to "Use TLS if possible" */
-       server->tls_mode = libbalsa_conf_get_int("ESMTPTLSMode=1");
-
        passphrase =
            libbalsa_conf_private_get_string("ESMTPCertificatePassphrase");
        if (passphrase) {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]