[balsa] IMAP goes GIO
- From: Peter Bloomfield <peterb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [balsa] IMAP goes GIO
- Date: Wed, 6 Jun 2018 02:08:40 +0000 (UTC)
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 "&" */
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", ¬_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", ¬_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", ¬_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 © 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]