0.8.6claws75
[claws.git] / src / smtp.c
index bf7eda42ad2d3c46018ab2a0f633730efebb9590..82a0cbaa0f7ab70c566cd40bc0ccbac991f4071e 100644 (file)
 #include "md5.h"
 #include "base64.h"
 #include "utils.h"
+#include "log.h"
 
 static gint verbose = 1;
 
-static gint smtp_starttls(SockInfo *sock);
-static gint smtp_auth_cram_md5(SockInfo *sock, gchar *buf, gint len);
-static gint smtp_auth_login(SockInfo *sock, gchar *buf, gint len);
+#define UI_UPDATE(session, phase) \
+{ \
+       if (SESSION(session)->ui_func) \
+               SESSION(session)->ui_func(SESSION(session), phase); \
+}
+
+static gint smtp_starttls(SMTPSession *session);
+static gint smtp_auth_cram_md5(SMTPSession *session, gchar *buf, gint len);
+static gint smtp_auth_login(SMTPSession *session, gchar *buf, gint len);
+
 static gint smtp_ok(SockInfo *sock, gchar *buf, gint len);
 
-#if USE_SSL
-Session *smtp_session_new(const gchar *server, gushort port,
-                         const gchar *domain,
-                         const gchar *user, const gchar *pass,
-                         SSLType ssl_type)
+Session *smtp_session_new(void)
+{
+       SMTPSession *session;
+
+       session = g_new0(SMTPSession, 1);
+       SESSION(session)->type             = SESSION_SMTP;
+       SESSION(session)->server           = NULL;
+       SESSION(session)->sock             = NULL;
+       SESSION(session)->connected        = FALSE;
+       SESSION(session)->phase            = SESSION_READY;
+       SESSION(session)->last_access_time = 0;
+       SESSION(session)->data             = NULL;
+
+       SESSION(session)->destroy          = smtp_session_destroy;
+       SESSION(session)->ui_func          = NULL;
+
+       session->avail_auth_type           = 0;
+       session->user                      = NULL;
+       session->pass                      = NULL;
+
+       return SESSION(session);
+}
+
+void smtp_session_destroy(Session *session)
+{
+       sock_close(session->sock);
+       session->sock = NULL;
+
+       g_free(SMTP_SESSION(session)->user);
+       g_free(SMTP_SESSION(session)->pass);
+}
+
+#if USE_OPENSSL
+gint smtp_connect(SMTPSession *session, const gchar *server, gushort port,
+                 const gchar *domain, const gchar *user, const gchar *pass,
+                 SSLType ssl_type)
 #else
-Session *smtp_session_new(const gchar *server, gushort port,
-                         const gchar *domain,
-                         const gchar *user, const gchar *pass)
+gint smtp_connect(SMTPSession *session, const gchar *server, gushort port,
+                 const gchar *domain, const gchar *user, const gchar *pass)
 #endif
 {
-       SMTPSession *session;
        SockInfo *sock;
        gboolean use_esmtp;
        SMTPAuthType avail_auth_type = 0;
        gint val;
 
-       g_return_val_if_fail(server != NULL, NULL);
+       g_return_val_if_fail(session != NULL, SM_ERROR);
+       g_return_val_if_fail(server != NULL, SM_ERROR);
 
-#if USE_SSL
+#if USE_OPENSSL
        use_esmtp = user != NULL || ssl_type == SSL_STARTTLS;
 #else
        use_esmtp = user != NULL;
 #endif
 
+       SESSION(session)->server = g_strdup(server);
+       session->user = user ? g_strdup(user) : NULL;
+       session->pass = pass ? g_strdup(pass) : user ? g_strdup("") : NULL;
+
+       UI_UPDATE(session, SMTP_CONNECT);
+
        if ((sock = sock_connect(server, port)) == NULL) {
                log_warning(_("Can't connect to SMTP server: %s:%d\n"),
                            server, port);
-               return NULL;
+               return SM_ERROR;
        }
 
-#if USE_SSL
+#if USE_OPENSSL
        if (ssl_type == SSL_TUNNEL && !ssl_init_socket(sock)) {
                log_warning(_("SSL connection failed"));
                sock_close(sock);
-               return NULL;
+               return SM_ERROR;
        }
 #endif
 
@@ -82,80 +126,55 @@ Session *smtp_session_new(const gchar *server, gushort port,
                log_warning(_("Error occurred while connecting to %s:%d\n"),
                            server, port);
                sock_close(sock);
-               return NULL;
+               return SM_ERROR;
        }
 
+       SESSION(session)->sock = sock;
+       SESSION(session)->connected = TRUE;
+
        if (!domain)
                domain = get_domain_name();
 
        if (use_esmtp)
-               val = smtp_ehlo(sock, domain, &avail_auth_type);
+               val = smtp_ehlo(session, domain, &avail_auth_type);
        else
-               val = smtp_helo(sock, domain);
+               val = smtp_helo(session, domain);
        if (val != SM_OK) {
                log_warning(_("Error occurred while sending HELO\n"));
-               sock_close(sock);
-               return NULL;
+               return val;
        }
 
-#if USE_SSL
+#if USE_OPENSSL
        if (ssl_type == SSL_STARTTLS) {
-               val = smtp_starttls(sock);
+               val = smtp_starttls(session);
                if (val != SM_OK) {
                        log_warning(_("Error occurred while sending STARTTLS\n"));
-                       sock_close(sock);
-                       return NULL;
+                       return val;
                }
                if (!ssl_init_socket_with_method(sock, SSL_METHOD_TLSv1)) {
-                       sock_close(sock);
-                       return NULL;
+                       return SM_ERROR;
                }
-               val = smtp_ehlo(sock, domain, &avail_auth_type);
+               val = smtp_ehlo(session, domain, &avail_auth_type);
                if (val != SM_OK) {
                        log_warning(_("Error occurred while sending EHLO\n"));
-                       sock_close(sock);
-                       return NULL;
+                       return val;
                }
        }
 #endif
 
-       session = g_new(SMTPSession, 1);
-       SESSION(session)->type             = SESSION_SMTP;
-       SESSION(session)->server           = g_strdup(server);
-       SESSION(session)->sock             = sock;
-       SESSION(session)->connected        = TRUE;
-       SESSION(session)->phase            = SESSION_READY;
-       SESSION(session)->last_access_time = 0;
-       SESSION(session)->data             = NULL;
-       session->avail_auth_type           = avail_auth_type;
-       session->user                      = user ? g_strdup(user) : NULL;
-       session->pass                      = pass ? g_strdup(pass) :
-                                            user ? g_strdup("") : NULL;
+       session->avail_auth_type = avail_auth_type;
 
-       return SESSION(session);
+       return 0;
 }
 
-void smtp_session_destroy(SMTPSession *session)
-{
-       sock_close(SESSION(session)->sock);
-       SESSION(session)->sock = NULL;
-
-       g_free(session->user);
-       g_free(session->pass);
-}
-
-gint smtp_from(SMTPSession *session, const gchar *from,
-              SMTPAuthType forced_auth_type)
+gint smtp_from(SMTPSession *session, const gchar *from)
 {
        gchar buf[MSGBUFSIZE];
 
        g_return_val_if_fail(session != NULL, SM_ERROR);
        g_return_val_if_fail(from != NULL, SM_ERROR);
 
-       if (session->user) {
-               if (smtp_auth(session, forced_auth_type) != SM_OK)
-                       return SM_AUTHFAIL;
-       }
+       UI_UPDATE(session, SMTP_FROM);
 
        if (strchr(from, '<'))
                g_snprintf(buf, sizeof(buf), "MAIL FROM: %s", from);
@@ -181,17 +200,19 @@ gint smtp_auth(SMTPSession *session, SMTPAuthType forced_auth_type)
        g_return_val_if_fail(session != NULL, SM_ERROR);
        g_return_val_if_fail(session->user != NULL, SM_ERROR);
 
+       UI_UPDATE(session, SMTP_AUTH);
+
        sock = SESSION(session)->sock;
 
        if ((forced_auth_type == SMTPAUTH_CRAM_MD5 ||
             (forced_auth_type == 0 &&
              (session->avail_auth_type & SMTPAUTH_CRAM_MD5) != 0)) &&
-           smtp_auth_cram_md5(sock, buf, sizeof(buf)) == SM_OK)
+           smtp_auth_cram_md5(session, buf, sizeof(buf)) == SM_OK)
                authtype = SMTPAUTH_CRAM_MD5;
        else if ((forced_auth_type == SMTPAUTH_LOGIN ||
                  (forced_auth_type == 0 &&
                   (session->avail_auth_type & SMTPAUTH_LOGIN) != 0)) &&
-                smtp_auth_login(sock, buf, sizeof(buf)) == SM_OK)
+                smtp_auth_login(session, buf, sizeof(buf)) == SM_OK)
                authtype = SMTPAUTH_LOGIN;
        else {
                log_warning(_("SMTP AUTH not available\n"));
@@ -201,7 +222,7 @@ gint smtp_auth(SMTPSession *session, SMTPAuthType forced_auth_type)
        switch (authtype) {
        case SMTPAUTH_LOGIN:
                if (!strncmp(buf, "334 ", 4))
-                       to64frombits(buf, session->user, strlen(session->user));
+                       base64_encode(buf, session->user, strlen(session->user));
                else
                        /* Server rejects AUTH */
                        g_snprintf(buf, sizeof(buf), "*");
@@ -212,7 +233,7 @@ gint smtp_auth(SMTPSession *session, SMTPAuthType forced_auth_type)
                smtp_ok(sock, buf, sizeof(buf));
 
                if (!strncmp(buf, "334 ", 4))
-                       to64frombits(buf, session->pass, strlen(session->pass));
+                       base64_encode(buf, session->pass, strlen(session->pass));
                else
                        /* Server rejects AUTH */
                        g_snprintf(buf, sizeof(buf), "*");
@@ -223,7 +244,7 @@ gint smtp_auth(SMTPSession *session, SMTPAuthType forced_auth_type)
        case SMTPAUTH_CRAM_MD5:
                if (!strncmp(buf, "334 ", 4)) {
                        challenge = g_malloc(strlen(buf + 4) + 1);
-                       challengelen = from64tobits(challenge, buf + 4);
+                       challengelen = base64_decode(challenge, buf + 4, -1);
                        challenge[challengelen] = '\0';
                        if (verbose)
                                log_print("ESMTP< [Decoded: %s]\n", challenge);
@@ -239,7 +260,7 @@ gint smtp_auth(SMTPSession *session, SMTPAuthType forced_auth_type)
                                log_print("ESMTP> [Encoded: %s]\n", response);
 
                        response64 = g_malloc((strlen(response) + 3) * 2 + 1);
-                       to64frombits(response64, response, strlen(response));
+                       base64_encode(response64, response, strlen(response));
                        g_free(response);
 
                        sock_printf(sock, "%s\r\n", response64);
@@ -265,11 +286,16 @@ gint smtp_auth(SMTPSession *session, SMTPAuthType forced_auth_type)
        return smtp_ok(sock, NULL, 0);
 }
 
-gint smtp_ehlo(SockInfo *sock, const gchar *hostname,
+gint smtp_ehlo(SMTPSession *session, const gchar *hostname,
               SMTPAuthType *avail_auth_type)
 {
+       SockInfo *sock;
        gchar buf[MSGBUFSIZE];
 
+       UI_UPDATE(session, SMTP_EHLO);
+
+       sock = SESSION(session)->sock;
+
        *avail_auth_type = 0;
 
        sock_printf(sock, "EHLO %s\r\n", hostname);
@@ -309,8 +335,14 @@ gint smtp_ehlo(SockInfo *sock, const gchar *hostname,
        return SM_UNRECOVERABLE;
 }
 
-static gint smtp_starttls(SockInfo *sock)
+static gint smtp_starttls(SMTPSession *session)
 {
+       SockInfo *sock;
+
+       UI_UPDATE(session, SMTP_STARTTLS);
+
+       sock = SESSION(session)->sock;
+
        sock_printf(sock, "STARTTLS\r\n");
        if (verbose)
                log_print("ESMTP> STARTTLS\n");
@@ -318,8 +350,14 @@ static gint smtp_starttls(SockInfo *sock)
        return smtp_ok(sock, NULL, 0);
 }
 
-static gint smtp_auth_cram_md5(SockInfo *sock, gchar *buf, gint len)
+static gint smtp_auth_cram_md5(SMTPSession *session, gchar *buf, gint len)
 {
+       SockInfo *sock;
+
+       UI_UPDATE(session, SMTP_AUTH);
+
+       sock = SESSION(session)->sock;
+
        sock_printf(sock, "AUTH CRAM-MD5\r\n");
        if (verbose)
                log_print("ESMTP> AUTH CRAM-MD5\n");
@@ -327,8 +365,14 @@ static gint smtp_auth_cram_md5(SockInfo *sock, gchar *buf, gint len)
        return smtp_ok(sock, buf, len);
 }
 
-static gint smtp_auth_login(SockInfo *sock, gchar *buf, gint len)
+static gint smtp_auth_login(SMTPSession *session, gchar *buf, gint len)
 {
+       SockInfo *sock;
+
+       UI_UPDATE(session, SMTP_AUTH);
+
+       sock = SESSION(session)->sock;
+
        sock_printf(sock, "AUTH LOGIN\r\n");
        if (verbose)
                log_print("ESMTP> AUTH LOGIN\n");
@@ -336,8 +380,14 @@ static gint smtp_auth_login(SockInfo *sock, gchar *buf, gint len)
        return smtp_ok(sock, buf, len);
 }
 
-gint smtp_helo(SockInfo *sock, const gchar *hostname)
+gint smtp_helo(SMTPSession *session, const gchar *hostname)
 {
+       SockInfo *sock;
+
+       UI_UPDATE(session, SMTP_HELO);
+
+       sock = SESSION(session)->sock;
+
        sock_printf(sock, "HELO %s\r\n", hostname);
        if (verbose)
                log_print("SMTP> HELO %s\n", hostname);
@@ -345,10 +395,15 @@ gint smtp_helo(SockInfo *sock, const gchar *hostname)
        return smtp_ok(sock, NULL, 0);
 }
 
-gint smtp_rcpt(SockInfo *sock, const gchar *to)
+gint smtp_rcpt(SMTPSession *session, const gchar *to)
 {
+       SockInfo *sock;
        gchar buf[MSGBUFSIZE];
 
+       UI_UPDATE(session, SMTP_RCPT);
+
+       sock = SESSION(session)->sock;
+
        if (strchr(to, '<'))
                g_snprintf(buf, sizeof(buf), "RCPT TO: %s", to);
        else
@@ -361,8 +416,14 @@ gint smtp_rcpt(SockInfo *sock, const gchar *to)
        return smtp_ok(sock, NULL, 0);
 }
 
-gint smtp_data(SockInfo *sock)
+gint smtp_data(SMTPSession *session)
 {
+       SockInfo *sock;
+
+       UI_UPDATE(session, SMTP_DATA);
+
+       sock = SESSION(session)->sock;
+
        sock_printf(sock, "DATA\r\n");
        if (verbose)
                log_print("SMTP> DATA\n");
@@ -370,8 +431,14 @@ gint smtp_data(SockInfo *sock)
        return smtp_ok(sock, NULL, 0);
 }
 
-gint smtp_rset(SockInfo *sock)
+gint smtp_rset(SMTPSession *session)
 {
+       SockInfo *sock;
+
+       UI_UPDATE(session, SMTP_RSET);
+
+       sock = SESSION(session)->sock;
+
        sock_printf(sock, "RSET\r\n");
        if (verbose)
                log_print("SMTP> RSET\n");
@@ -379,8 +446,14 @@ gint smtp_rset(SockInfo *sock)
        return smtp_ok(sock, NULL, 0);
 }
 
-gint smtp_quit(SockInfo *sock)
+gint smtp_quit(SMTPSession *session)
 {
+       SockInfo *sock;
+
+       UI_UPDATE(session, SMTP_QUIT);
+
+       sock = SESSION(session)->sock;
+
        sock_printf(sock, "QUIT\r\n");
        if (verbose)
                log_print("SMTP> QUIT\n");
@@ -388,8 +461,14 @@ gint smtp_quit(SockInfo *sock)
        return smtp_ok(sock, NULL, 0);
 }
 
-gint smtp_eom(SockInfo *sock)
+gint smtp_eom(SMTPSession *session)
 {
+       SockInfo *sock;
+
+       UI_UPDATE(session, SMTP_EOM);
+
+       sock = SESSION(session)->sock;
+
        sock_printf(sock, ".\r\n");
        if (verbose)
                log_print("SMTP> . (EOM)\n");