summaryrefslogtreecommitdiffabout
path: root/libetpan/src/low-level/smtp
Side-by-side diff
Diffstat (limited to 'libetpan/src/low-level/smtp') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/low-level/smtp/TODO1
-rw-r--r--libetpan/src/low-level/smtp/mailsmtp.c984
-rw-r--r--libetpan/src/low-level/smtp/mailsmtp.h94
-rw-r--r--libetpan/src/low-level/smtp/mailsmtp_helper.c228
-rw-r--r--libetpan/src/low-level/smtp/mailsmtp_helper.h74
-rw-r--r--libetpan/src/low-level/smtp/mailsmtp_socket.c99
-rw-r--r--libetpan/src/low-level/smtp/mailsmtp_socket.h56
-rw-r--r--libetpan/src/low-level/smtp/mailsmtp_ssl.c74
-rw-r--r--libetpan/src/low-level/smtp/mailsmtp_ssl.h55
-rw-r--r--libetpan/src/low-level/smtp/mailsmtp_types.h126
10 files changed, 1791 insertions, 0 deletions
diff --git a/libetpan/src/low-level/smtp/TODO b/libetpan/src/low-level/smtp/TODO
new file mode 100644
index 0000000..96f44c6
--- a/dev/null
+++ b/libetpan/src/low-level/smtp/TODO
@@ -0,0 +1 @@
+- STARTTLS
diff --git a/libetpan/src/low-level/smtp/mailsmtp.c b/libetpan/src/low-level/smtp/mailsmtp.c
new file mode 100644
index 0000000..85659e9
--- a/dev/null
+++ b/libetpan/src/low-level/smtp/mailsmtp.c
@@ -0,0 +1,984 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa,
+ * All rights reserved.
+ *
+ * SMTP AUTH support by Juergen Graf
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "mailsmtp.h"
+#include "connect.h"
+#include "md5.h"
+#include "base64.h"
+#include "mail.h"
+
+#include <netinet/in.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+
+
+/*
+ RFC 2821 : SMTP
+ RFC 1891 : SMTP Service Extension for Delivery Status Notifications
+
+ RFC 1428 : Transition of Internet Mail from Just-Send-8 to 8bit-SMTP/MIME
+ RFC 1652 : SMTP Service Extension for 8bit-MIMEtransport
+ RFC 1845 : SMTP Service Extension for Checkpoint/Restart
+ RFC 1846 : SMTP 521 Reply Code
+ RFC 1870 : SMTP Service Extension for Message Size Declaration
+ RFC 1985 : SMTP Service Extension for Remote Message Queue Starting
+ RFC 2034 : SMTP Service Extension for Returning Enhanced Error Codes
+ RFC 2442 : The Batch SMTP Media Type
+ RFC 2487 : SMTP Service Extension for Secure SMTP over TLS
+ RFC 2505 : Anti-Spam Recommendations for SMTP MTAs
+ RFC 2554 : SMTP Service Extension for Authentication
+ RFC 2645 : ON-DEMAND MAIL RELAY (ODMR) SMTP with Dynamic IP Addresses
+ RFC 2852 : Deliver By SMTP Service Extension
+ RFC 2920 : SMTP Service Extension for Command Pipelining
+ RFC 3030 : SMTP Service Extensions for Transmission of Large and Binary MIME
+ Messages
+*/
+
+#define SMTP_STATUS_CONTINUE 0x1000
+
+mailsmtp * mailsmtp_new(size_t progr_rate,
+ progress_function * progr_fun)
+{
+ mailsmtp * session;
+
+ session = malloc(sizeof(* session));
+ if (session == NULL)
+ goto err;
+
+ session->stream = NULL;
+
+ session->progr_rate = progr_rate;
+ session->progr_fun = progr_fun;
+
+ session->response = NULL;
+
+ session->line_buffer = mmap_string_new("");
+ if (session->line_buffer == NULL)
+ goto free_session;
+
+ session->response_buffer = mmap_string_new("");
+ if (session->response_buffer == NULL)
+ goto free_line_buffer;
+
+ session->esmtp = 0;
+ session->auth = MAILSMTP_AUTH_NOT_CHECKED;
+
+ return session;
+
+ free_line_buffer:
+ mmap_string_free(session->line_buffer);
+ free_session:
+ free(session);
+ err:
+ return NULL;
+}
+
+void mailsmtp_free(mailsmtp * session)
+{
+ if (session->stream)
+ mailsmtp_quit(session);
+
+ mmap_string_free(session->line_buffer);
+ mmap_string_free(session->response_buffer);
+ free(session);
+}
+
+static int send_command(mailsmtp * f, char * command);
+
+static int read_response(mailsmtp * session);
+
+/* smtp operations */
+
+int mailsmtp_connect(mailsmtp * session, mailstream * s)
+{
+ int code;
+
+ session->stream = s;
+
+ code = read_response(session);
+
+ switch (code) {
+ case 220:
+ return MAILSMTP_NO_ERROR;
+
+ case 554:
+ session->stream = NULL;
+ mailstream_close(s);
+ return MAILSMTP_ERROR_SERVICE_NOT_AVAILABLE;
+
+ default:
+ session->stream = NULL;
+ mailstream_close(s);
+ return MAILSMTP_ERROR_UNEXPECTED_CODE;
+ }
+}
+
+
+#define SMTP_STRING_SIZE 513
+
+int mailsmtp_quit(mailsmtp * session)
+{
+ char command[SMTP_STRING_SIZE];
+ int r;
+
+ snprintf(command, SMTP_STRING_SIZE, "QUIT\r\n");
+ r = send_command(session, command);
+ if (r == -1)
+ return MAILSMTP_ERROR_STREAM;
+ r = read_response(session);
+ if (r == 0)
+ return MAILSMTP_ERROR_STREAM;
+ mailstream_close(session->stream);
+ session->stream = NULL;
+
+ return MAILSMTP_NO_ERROR;
+}
+
+
+
+#define HOSTNAME_SIZE 256
+
+int mailsmtp_helo(mailsmtp * session)
+{
+ int r;
+ char hostname[HOSTNAME_SIZE];
+ char command[SMTP_STRING_SIZE];
+
+ r = gethostname(hostname, HOSTNAME_SIZE);
+ if (r < 0)
+ return MAILSMTP_ERROR_HOSTNAME;
+
+ snprintf(command, SMTP_STRING_SIZE, "HELO %s\r\n", hostname);
+ r = send_command(session, command);
+ if (r == -1)
+ return MAILSMTP_ERROR_STREAM;
+ r = read_response(session);
+
+ switch (r) {
+ case 250:
+ session->esmtp = 0;
+ session->auth = MAILSMTP_AUTH_NOT_CHECKED;
+ return MAILSMTP_NO_ERROR;
+
+ case 504:
+ return MAILSMTP_ERROR_NOT_IMPLEMENTED;
+
+ case 550:
+ return MAILSMTP_ERROR_ACTION_NOT_TAKEN;
+
+ case 0:
+ return MAILSMTP_ERROR_STREAM;
+
+ default:
+ return MAILSMTP_ERROR_UNEXPECTED_CODE;
+ }
+}
+
+int mailsmtp_mail(mailsmtp * session, const char * from)
+{
+ int r;
+ char command[SMTP_STRING_SIZE];
+
+ snprintf(command, SMTP_STRING_SIZE, "MAIL FROM:<%s>\r\n", from);
+ r = send_command(session, command);
+ if (r == -1)
+ return MAILSMTP_ERROR_STREAM;
+ r = read_response(session);
+
+ switch (r) {
+ case 250:
+ return MAILSMTP_NO_ERROR;
+
+ case 552:
+ return MAILSMTP_ERROR_EXCEED_STORAGE_ALLOCATION;
+
+ case 451:
+ return MAILSMTP_ERROR_IN_PROCESSING;
+
+ case 452:
+ return MAILSMTP_ERROR_INSUFFICIENT_SYSTEM_STORAGE;
+
+ case 550:
+ return MAILSMTP_ERROR_MAILBOX_UNAVAILABLE;
+
+ case 553:
+ return MAILSMTP_ERROR_MAILBOX_NAME_NOT_ALLOWED;
+
+ case 503:
+ return MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND;
+
+ case 0:
+ return MAILSMTP_ERROR_STREAM;
+
+ default:
+ return MAILSMTP_ERROR_UNEXPECTED_CODE;
+ }
+}
+
+int mailsmtp_rcpt(mailsmtp * session, const char * to)
+{
+ return mailesmtp_rcpt(session, to, 0, NULL);
+}
+
+int mailsmtp_data(mailsmtp * session)
+{
+ int r;
+ char command[SMTP_STRING_SIZE];
+
+ snprintf(command, SMTP_STRING_SIZE, "DATA\r\n");
+ r = send_command(session, command);
+ if (r == -1)
+ return MAILSMTP_ERROR_STREAM;
+ r = read_response(session);
+
+ switch (r) {
+ case 354:
+ return MAILSMTP_NO_ERROR;
+
+ case 451:
+ return MAILSMTP_ERROR_IN_PROCESSING;
+
+ case 554:
+ return MAILSMTP_ERROR_TRANSACTION_FAILED;
+
+ case 503:
+ return MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND;
+
+ default:
+ return MAILSMTP_ERROR_UNEXPECTED_CODE;
+ }
+}
+
+static int send_data(mailsmtp * session, const char * message, size_t size);
+
+int mailsmtp_data_message(mailsmtp * session,
+ const char * message,
+ size_t size)
+{
+ int r;
+
+ r = send_data(session, message, size);
+ if (r == -1)
+ return MAILSMTP_ERROR_STREAM;
+
+ r = read_response(session);
+
+ switch(r) {
+ case 250:
+ return MAILSMTP_NO_ERROR;
+
+ case 552:
+ return MAILSMTP_ERROR_EXCEED_STORAGE_ALLOCATION;
+
+ case 554:
+ return MAILSMTP_ERROR_TRANSACTION_FAILED;
+
+ case 451:
+ return MAILSMTP_ERROR_IN_PROCESSING;
+
+ case 452:
+ return MAILSMTP_ERROR_INSUFFICIENT_SYSTEM_STORAGE;
+
+ case 0:
+ return MAILSMTP_ERROR_STREAM;
+
+ default:
+ return MAILSMTP_ERROR_UNEXPECTED_CODE;
+ }
+}
+
+/* esmtp operations */
+
+
+/**
+ * called during mailesmtp_ehlo
+ * checks EHLO answer for server extensions and sets flags
+ * in session->esmtp
+ * checks AUTH methods in session->response and sets flags
+ * in session->auth
+ */
+#define isdelim(x) ((x) == ' ' || (x) == '\r' || (x) == '\n' || (x) == '\0')
+
+int mailesmtp_parse_ehlo(mailsmtp * session)
+{
+ char * response;
+
+ /* restore data */
+ session->esmtp = MAILSMTP_ESMTP;
+ session->auth = MAILSMTP_AUTH_CHECKED;
+
+ response = session->response;
+
+ /* ESMTP supported extensions :
+ DSN
+ EXPN
+ 8BITMIME
+ SIZE [<n>]
+ ETRN
+ STARTTLS
+ AUTH <mechanisms...>
+ */
+ while (response != NULL) {
+ if (!strncasecmp(response, "EXPN", 4) && isdelim(response[4]))
+ session->esmtp |= MAILSMTP_ESMTP_EXPN;
+ else if (!strncasecmp(response, "ETRN", 4) && isdelim(response[4]))
+ session->esmtp |= MAILSMTP_ESMTP_ETRN;
+ else if (!strncasecmp(response, "DSN", 3) && isdelim(response[3]))
+ session->esmtp |= MAILSMTP_ESMTP_DSN;
+ else if (!strncasecmp(response, "8BITMIME", 8) && isdelim(response[8]))
+ session->esmtp |= MAILSMTP_ESMTP_8BITMIME;
+ else if (!strncasecmp(response, "STARTTLS", 8) && isdelim(response[8]))
+ session->esmtp |= MAILSMTP_ESMTP_STARTTLS;
+ else if (!strncasecmp(response, "SIZE", 4) && isdelim(response[4])) {
+ session->esmtp |= MAILSMTP_ESMTP_SIZE;
+ /* TODO: grab optionnal max size */
+ } else if (!strncasecmp(response, "AUTH ", 5)) {
+ response += 5; /* remove "AUTH " */
+ while (response[0] != '\n' && response[0] != '\0') {
+ while (response[0] == ' ') response++;
+ if (strncasecmp(response, "LOGIN", 5) == 0) {
+ session->auth |= MAILSMTP_AUTH_LOGIN;
+ response += 5;
+ } else if (strncasecmp(response, "CRAM-MD5", 8) == 0) {
+ session->auth |= MAILSMTP_AUTH_CRAM_MD5;
+ response += 8;
+ } else if (strncasecmp(response, "PLAIN", 5) == 0) {
+ session->auth |= MAILSMTP_AUTH_PLAIN;
+ response += 5;
+ } else {
+ /* unknown auth method - jump to next word or eol */
+ while (!isdelim(response[0]) || response[0] == '\r')
+ response++;
+ }
+ }
+ }
+ response = strpbrk(response, "\n");
+ if (response != NULL)
+ response++;
+ }
+
+ return MAILSMTP_NO_ERROR;
+}
+
+
+int mailesmtp_ehlo(mailsmtp * session)
+{
+ int r;
+ char hostname[HOSTNAME_SIZE];
+ char command[SMTP_STRING_SIZE];
+
+ r = gethostname(hostname, HOSTNAME_SIZE);
+ if (r != 0)
+ return MAILSMTP_ERROR_HOSTNAME;
+
+ snprintf(command, SMTP_STRING_SIZE, "EHLO %s\r\n", hostname);
+ r = send_command(session, command);
+ if (r == -1)
+ return MAILSMTP_ERROR_STREAM;
+ r = read_response(session);
+
+ switch (r) {
+ case 250:
+ return mailesmtp_parse_ehlo(session);
+
+ case 504:
+ return MAILSMTP_ERROR_NOT_IMPLEMENTED;
+
+ case 550:
+ return MAILSMTP_ERROR_ACTION_NOT_TAKEN;
+
+ case 0:
+ return MAILSMTP_ERROR_STREAM;
+
+ default:
+ return MAILSMTP_ERROR_UNEXPECTED_CODE;
+ }
+}
+
+/*
+ if return_full is TRUE, the entire message is returned on error
+ envid can be NULL
+*/
+
+
+int mailesmtp_mail(mailsmtp * session,
+ const char * from,
+ int return_full,
+ const char * envid)
+{
+ int r;
+ char command[SMTP_STRING_SIZE];
+ char *body = "";
+
+#if notyet
+ /* TODO: figure out a way for the user to explicity enable this or not */
+ if (session->esmtp & MAILSMTP_ESMTP_8BITMIME)
+ body = " BODY=8BITMIME";
+#endif
+
+ if (session->esmtp & MAILSMTP_ESMTP_DSN) {
+ if (envid)
+ snprintf(command, SMTP_STRING_SIZE, "MAIL FROM:<%s> RET=%s ENVID=%s%s\r\n",
+ from, return_full ? "FULL" : "HDRS", envid, body);
+ else
+ snprintf(command, SMTP_STRING_SIZE, "MAIL FROM:<%s> RET=%s%s\r\n",
+ from, return_full ? "FULL" : "HDRS", body);
+ } else
+ snprintf(command, SMTP_STRING_SIZE, "MAIL FROM:<%s>%s\r\n",
+ from, body);
+
+ r = send_command(session, command);
+ if (r == -1)
+ return MAILSMTP_ERROR_STREAM;
+ r = read_response(session);
+
+ switch (r) {
+ case 250:
+ return MAILSMTP_NO_ERROR;
+
+ case 552:
+ return MAILSMTP_ERROR_EXCEED_STORAGE_ALLOCATION;
+
+ case 451:
+ return MAILSMTP_ERROR_IN_PROCESSING;
+
+ case 452:
+ return MAILSMTP_ERROR_INSUFFICIENT_SYSTEM_STORAGE;
+
+ case 550:
+ return MAILSMTP_ERROR_MAILBOX_UNAVAILABLE;
+
+ case 553:
+ return MAILSMTP_ERROR_MAILBOX_NAME_NOT_ALLOWED;
+
+ case 503:
+ return MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND;
+
+ case 0:
+ return MAILSMTP_ERROR_STREAM;
+
+ default:
+ return MAILSMTP_ERROR_UNEXPECTED_CODE;
+ }
+}
+
+int mailesmtp_rcpt(mailsmtp * session,
+ const char * to,
+ int notify,
+ const char * orcpt)
+{
+ int r;
+ char command[SMTP_STRING_SIZE];
+ char notify_str[30] = "";
+ char notify_info_str[30] = "";
+
+ if (notify != 0 && session->esmtp & MAILSMTP_ESMTP_DSN) {
+ if (notify & MAILSMTP_DSN_NOTIFY_SUCCESS)
+ strcat(notify_info_str, ",SUCCESS");
+ if (notify & MAILSMTP_DSN_NOTIFY_FAILURE)
+ strcat(notify_info_str, ",FAILURE");
+ if (notify & MAILSMTP_DSN_NOTIFY_DELAY)
+ strcat(notify_info_str, ",DELAY");
+
+ if (notify & MAILSMTP_DSN_NOTIFY_NEVER)
+ strcpy(notify_info_str, ",NEVER");
+
+ notify_info_str[0] = '=';
+
+ strcpy(notify_str, " NOTIFY");
+ strcat(notify_str, notify_info_str);
+ }
+
+ if (orcpt && session->esmtp & MAILSMTP_ESMTP_DSN)
+ snprintf(command, SMTP_STRING_SIZE, "RCPT TO:<%s>%s ORCPT=%s\r\n",
+ to, notify_str, orcpt);
+ else
+ snprintf(command, SMTP_STRING_SIZE, "RCPT TO:<%s>%s\r\n", to, notify_str);
+
+ r = send_command(session, command);
+ if (r == -1)
+ return MAILSMTP_ERROR_STREAM;
+ r = read_response(session);
+
+ switch (r) {
+ case 250:
+ return MAILSMTP_NO_ERROR;
+
+ case 251: /* not local user, will be forwarded */
+ return MAILSMTP_NO_ERROR;
+
+ case 550:
+ case 450:
+ return MAILSMTP_ERROR_MAILBOX_UNAVAILABLE;
+
+ case 551:
+ return MAILSMTP_ERROR_USER_NOT_LOCAL;
+
+ case 552:
+ return MAILSMTP_ERROR_EXCEED_STORAGE_ALLOCATION;
+
+ case 553:
+ return MAILSMTP_ERROR_MAILBOX_NAME_NOT_ALLOWED;
+
+ case 451:
+ return MAILSMTP_ERROR_IN_PROCESSING;
+
+ case 452:
+ return MAILSMTP_ERROR_INSUFFICIENT_SYSTEM_STORAGE;
+
+ case 503:
+ return MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND;
+
+ case 0:
+ return MAILSMTP_ERROR_STREAM;
+
+ default:
+ return MAILSMTP_ERROR_UNEXPECTED_CODE;
+ }
+}
+
+int auth_map_errors(int err)
+{
+ switch (err) {
+ case 235:
+ return MAILSMTP_NO_ERROR; /* AUTH successfull */
+ case 334:
+ return MAILSMTP_NO_ERROR; /* AUTH in progress */
+ case 432:
+ return MAILSMTP_ERROR_AUTH_TRANSITION_NEEDED;
+ case 454:
+ return MAILSMTP_ERROR_AUTH_TEMPORARY_FAILTURE;
+ case 504:
+ return MAILSMTP_ERROR_AUTH_NOT_SUPPORTED;
+ case 530:
+ return MAILSMTP_ERROR_AUTH_REQUIRED;
+ case 534:
+ return MAILSMTP_ERROR_AUTH_TOO_WEAK;
+ case 538:
+ return MAILSMTP_ERROR_AUTH_ENCRYPTION_REQUIRED;
+ default:
+ /* opportunistic approach ;) */
+ return MAILSMTP_NO_ERROR;
+ }
+}
+
+static int mailsmtp_auth_login(mailsmtp * session,
+ const char * user, const char * pass)
+{
+ int err;
+ char command[SMTP_STRING_SIZE];
+ char * user64, * pass64;
+
+ user64 = NULL;
+ pass64 = NULL;
+
+ user64 = encode_base64(user, strlen(user));
+ if (user64 == NULL) {
+ err = MAILSMTP_ERROR_MEMORY;
+ goto err_free;
+ }
+
+ pass64 = encode_base64(pass, strlen(pass));
+ if (pass64 == NULL) {
+ err = MAILSMTP_ERROR_MEMORY;
+ goto err_free;
+ }
+
+ snprintf(command, SMTP_STRING_SIZE, "%s\r\n", user64);
+ err = send_command(session, command);
+ if (err == -1) {
+ err = MAILSMTP_ERROR_STREAM;
+ goto err_free;
+ }
+ err = read_response(session);
+ err = auth_map_errors(err);
+ if (err != MAILSMTP_NO_ERROR)
+ goto err_free;
+
+ snprintf(command, SMTP_STRING_SIZE, "%s\r\n", pass64);
+ err = send_command(session, command);
+ if (err == -1) {
+ err = MAILSMTP_ERROR_STREAM;
+ goto err_free;
+ }
+ err = read_response(session);
+ err = auth_map_errors(err);
+
+ err_free:
+ free(user64);
+ free(pass64);
+
+ return err;
+}
+
+static int mailsmtp_auth_plain(mailsmtp * session,
+ const char * user, const char * pass)
+{
+ int err, len;
+ char command[SMTP_STRING_SIZE];
+ char * plain, * plain64;
+
+ len = strlen(user) + strlen(pass) + 3;
+ plain = (char *) malloc(len);
+ if (plain == NULL) {
+ err = MAILSMTP_ERROR_MEMORY;
+ goto err;
+ }
+
+ snprintf(plain, len, "%c%s%c%s", '\0', user, '\0', pass);
+ plain64 = encode_base64(plain, len - 1);
+
+ snprintf(command, SMTP_STRING_SIZE, "%s\r\n", plain64);
+ err = send_command(session, command);
+ if (err == -1) {
+ err = MAILSMTP_ERROR_STREAM;
+ goto err_free;
+ }
+
+ err = read_response(session);
+ err = auth_map_errors(err);
+
+err_free:
+ free(plain64);
+ free(plain);
+
+ err:
+ return err;
+}
+
+static char * convert_hex(unsigned char *in, int len)
+{
+ static char hex[] = "0123456789abcdef";
+ char * out;
+ int i;
+
+ out = (char *) malloc(len * 2 + 1);
+ if (out == NULL)
+ return NULL;
+
+ for (i = 0; i < len; i++) {
+ out[i * 2] = hex[in[i] >> 4];
+ out[i * 2 + 1] = hex[in[i] & 15];
+ }
+
+ out[i*2] = 0;
+
+ return out;
+}
+
+static char * hash_md5(const char * sec_key, const char * data, int len)
+{
+ char key[65], digest[24];
+ char * hash_hex;
+
+ int sec_len, i;
+
+ sec_len = strlen(sec_key);
+
+ if (sec_len < 64) {
+ memcpy(key, sec_key, sec_len);
+ for (i = sec_len; i < 64; i++) {
+ key[i] = 0;
+ }
+ } else {
+ memcpy(key, sec_key, 64);
+ }
+
+ hmac_md5(data, len, key, 64, digest);
+ hash_hex = convert_hex(digest, 16);
+
+ return hash_hex;
+}
+
+static int mailsmtp_auth_cram_md5(mailsmtp * session,
+ const char * user, const char * pass)
+{
+ int err;
+ char command[SMTP_STRING_SIZE];
+ char *response, *auth_hex, *auth;
+
+ response = decode_base64(session->response, strlen(session->response));
+ if (response == NULL) return MAILSMTP_ERROR_MEMORY;
+
+ auth_hex = hash_md5(pass, response, strlen(response));
+ if (auth_hex == NULL) {
+ err = MAILSMTP_ERROR_MEMORY;
+ goto err_free_response;
+ }
+
+ snprintf(command, SMTP_STRING_SIZE, "%s %s", user, auth_hex);
+
+ auth = encode_base64(command, strlen(command));
+ if (auth == NULL) {
+ err = MAILSMTP_ERROR_MEMORY;
+ goto err_free_auth_hex;
+ }
+
+ snprintf(command, SMTP_STRING_SIZE, "%s\r\n", auth);
+ err = send_command(session, command);
+ if (err == -1) {
+ err = MAILSMTP_ERROR_STREAM;
+ goto err_free;
+ }
+
+ err = read_response(session);
+ err = auth_map_errors(err);
+
+err_free:
+ free(auth);
+err_free_auth_hex:
+ free(auth_hex);
+err_free_response:
+ free(response);
+ return err;
+}
+
+int mailsmtp_auth_type(mailsmtp * session,
+ const char * user, const char * pass, int type)
+{
+ int err;
+ char command[SMTP_STRING_SIZE];
+
+ if (session->auth == MAILSMTP_AUTH_NOT_CHECKED)
+ return MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND;
+
+ if ( !(session->auth & type) ) return MAILSMTP_ERROR_AUTH_NOT_SUPPORTED;
+
+ switch (type) {
+ case MAILSMTP_AUTH_LOGIN:
+ snprintf(command, SMTP_STRING_SIZE, "AUTH LOGIN\r\n");
+ break;
+ case MAILSMTP_AUTH_PLAIN:
+ snprintf(command, SMTP_STRING_SIZE, "AUTH PLAIN\r\n");
+ break;
+ case MAILSMTP_AUTH_CRAM_MD5:
+ snprintf(command, SMTP_STRING_SIZE, "AUTH CRAM-MD5\r\n");
+ break;
+ default:
+ return MAILSMTP_ERROR_NOT_IMPLEMENTED;
+ }
+
+ err = send_command(session, command);
+ if (err == -1) return MAILSMTP_ERROR_STREAM;
+
+ err = read_response(session);
+ err = auth_map_errors(err);
+ if (err != MAILSMTP_NO_ERROR) return err;
+
+ switch (type) {
+ case MAILSMTP_AUTH_LOGIN:
+ return mailsmtp_auth_login(session, user, pass);
+ case MAILSMTP_AUTH_PLAIN:
+ return mailsmtp_auth_plain(session, user, pass);
+ case MAILSMTP_AUTH_CRAM_MD5:
+ return mailsmtp_auth_cram_md5(session, user, pass);
+ default:
+ return MAILSMTP_ERROR_NOT_IMPLEMENTED;
+ }
+}
+
+
+int mailsmtp_auth(mailsmtp * session, const char * user, const char * pass)
+{
+ if (session->auth == MAILSMTP_AUTH_NOT_CHECKED)
+ return MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND;
+
+ if (session->auth & MAILSMTP_AUTH_CRAM_MD5) {
+ return mailsmtp_auth_type(session, user, pass, MAILSMTP_AUTH_CRAM_MD5);
+ } else if (session->auth & MAILSMTP_AUTH_PLAIN) {
+ return mailsmtp_auth_type(session, user, pass, MAILSMTP_AUTH_PLAIN);
+ } else if (session->auth & MAILSMTP_AUTH_LOGIN) {
+ return mailsmtp_auth_type(session, user, pass, MAILSMTP_AUTH_LOGIN);
+ } else {
+ return MAILSMTP_ERROR_AUTH_NOT_SUPPORTED;
+ }
+}
+
+/* TODO: add mailesmtp_etrn, mailssmtp_expn */
+
+int mailesmtp_starttls(mailsmtp * session) {
+ int r;
+
+ if (!(session->esmtp & MAILSMTP_ESMTP_STARTTLS))
+ return MAILSMTP_ERROR_STARTTLS_NOT_SUPPORTED;
+
+ r = send_command(session, "STARTTLS\r\n");
+ if (r == -1)
+ return MAILSMTP_ERROR_STREAM;
+ r = read_response(session);
+
+ switch (r) {
+ case 220:
+ return MAILSMTP_NO_ERROR;
+
+ case 454:
+ return MAILSMTP_ERROR_STARTTLS_TEMPORARY_FAILURE;
+
+ default:
+ return MAILSMTP_ERROR_UNEXPECTED_CODE;
+ }
+}
+
+static int parse_response(mailsmtp * session,
+ char * response)
+{
+ char * message;
+ int code;
+ int cont = 0;
+
+ code = strtol(response, &message, 10);
+ if (* message == ' ')
+ mmap_string_append(session->response_buffer, message + 1);
+ else if (* message == '-') {
+ cont = SMTP_STATUS_CONTINUE;
+ mmap_string_append(session->response_buffer, message + 1);
+ }
+ else
+ mmap_string_append(session->response_buffer, message);
+
+ return code | cont;
+}
+
+static char * read_line(mailsmtp * session)
+{
+ return mailstream_read_line_remove_eol(session->stream,
+ session->line_buffer);
+}
+
+static int read_response(mailsmtp * session)
+{
+ char * line;
+ int code;
+
+ mmap_string_assign(session->response_buffer, "");
+
+ do {
+ line = read_line(session);
+
+ if (line != NULL) {
+ code = parse_response(session, line);
+ mmap_string_append_c(session->response_buffer, '\n');
+ }
+ else
+ code = 0;
+ }
+ while ((code & SMTP_STATUS_CONTINUE) != 0);
+
+ session->response = session->response_buffer->str;
+
+ return code;
+}
+
+
+
+
+
+static int send_command(mailsmtp * f, char * command)
+{
+ ssize_t r;
+
+ r = mailstream_write(f->stream, command, strlen(command));
+ if (r == -1)
+ return -1;
+
+ r = mailstream_flush(f->stream);
+ if (r == -1)
+ return -1;
+
+ return 0;
+}
+
+static int send_data(mailsmtp * session, const char * message, size_t size)
+{
+ if (mailstream_send_data(session->stream, message, size,
+ session->progr_rate, session->progr_fun) == -1)
+ return -1;
+
+ if (mailstream_flush(session->stream) == -1)
+ return -1;
+
+ return 0;
+}
+
+
+const char * mailsmtp_strerror(int errnum)
+{
+ switch (errnum) {
+ case MAILSMTP_NO_ERROR:
+ return "No error";
+ case MAILSMTP_ERROR_UNEXPECTED_CODE:
+ return "Unexpected error code";
+ case MAILSMTP_ERROR_SERVICE_NOT_AVAILABLE:
+ return "Service not available";
+ case MAILSMTP_ERROR_STREAM:
+ return "Stream error";
+ case MAILSMTP_ERROR_HOSTNAME:
+ return "gethostname() failed";
+ case MAILSMTP_ERROR_NOT_IMPLEMENTED:
+ return "Not implemented";
+ case MAILSMTP_ERROR_ACTION_NOT_TAKEN:
+ return "Error, action not taken";
+ case MAILSMTP_ERROR_EXCEED_STORAGE_ALLOCATION:
+ return "Data exceeds storage allocation";
+ case MAILSMTP_ERROR_IN_PROCESSING:
+ return "Error in processing";
+ case MAILSMTP_ERROR_INSUFFICIENT_SYSTEM_STORAGE:
+ return "Insufficient system storage";
+ case MAILSMTP_ERROR_MAILBOX_UNAVAILABLE:
+ return "Mailbox unavailable";
+ case MAILSMTP_ERROR_MAILBOX_NAME_NOT_ALLOWED:
+ return "Mailbox name not allowed";
+ case MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND:
+ return "Bad command sequence";
+ case MAILSMTP_ERROR_USER_NOT_LOCAL:
+ return "User not local";
+ case MAILSMTP_ERROR_TRANSACTION_FAILED:
+ return "Transaction failed";
+ case MAILSMTP_ERROR_MEMORY:
+ return "Memory error";
+ case MAILSMTP_ERROR_CONNECTION_REFUSED:
+ return "Connection refused";
+ case MAILSMTP_ERROR_STARTTLS_TEMPORARY_FAILURE:
+ return "TLS not available on server for temporary reason";
+ case MAILSMTP_ERROR_STARTTLS_NOT_SUPPORTED:
+ return "TLS not supported by server";
+ default:
+ return "Unknown error code";
+ }
+}
diff --git a/libetpan/src/low-level/smtp/mailsmtp.h b/libetpan/src/low-level/smtp/mailsmtp.h
new file mode 100644
index 0000000..72e1786
--- a/dev/null
+++ b/libetpan/src/low-level/smtp/mailsmtp.h
@@ -0,0 +1,94 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef MAILSMTP_H
+
+#define MAILSMTP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libetpan/mailsmtp_types.h>
+#include <libetpan/mailsmtp_helper.h>
+#include <libetpan/mailsmtp_socket.h>
+#include <libetpan/mailsmtp_ssl.h>
+
+
+mailsmtp * mailsmtp_new(size_t progr_rate,
+ progress_function * progr_fun);
+void mailsmtp_free(mailsmtp * session);
+
+int mailsmtp_connect(mailsmtp * session, mailstream * s);
+int mailsmtp_quit(mailsmtp * session);
+
+/**
+ * Tries AUTH with detected method - "better" method first:
+ * CRAM-MD5 -> PLAIN -> LOGIN
+ */
+int mailsmtp_auth(mailsmtp * session, const char * user, const char * pass);
+
+/**
+ * tries to autenticate with the server using given auth-type
+ * returns MAILSMTP_NO_ERROR on success
+ */
+int mailsmtp_auth_type(mailsmtp * session,
+ const char * user, const char * pass, int type);
+
+int mailsmtp_helo(mailsmtp * session);
+int mailsmtp_mail(mailsmtp * session, const char * from);
+int mailsmtp_rcpt(mailsmtp * session, const char * to);
+int mailsmtp_data(mailsmtp * session);
+int mailsmtp_data_message(mailsmtp * session,
+ const char * message,
+ size_t size);
+int mailesmtp_ehlo(mailsmtp * session);
+int mailesmtp_mail(mailsmtp * session,
+ const char * from,
+ int return_full,
+ const char * envid);
+int mailesmtp_rcpt(mailsmtp * session,
+ const char * to,
+ int notify,
+ const char * orcpt);
+int mailesmtp_starttls(mailsmtp * session);
+
+const char * mailsmtp_strerror(int errnum);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/smtp/mailsmtp_helper.c b/libetpan/src/low-level/smtp/mailsmtp_helper.c
new file mode 100644
index 0000000..69b73cc
--- a/dev/null
+++ b/libetpan/src/low-level/smtp/mailsmtp_helper.c
@@ -0,0 +1,228 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "mailsmtp.h"
+#include <string.h>
+#include <stdlib.h>
+#include "mail.h"
+
+int mailsmtp_init(mailsmtp * session)
+{
+ int r;
+
+ r = mailesmtp_ehlo(session);
+
+ if (r == MAILSMTP_NO_ERROR)
+ return MAILSMTP_NO_ERROR;
+
+ r = mailsmtp_helo(session);
+ if (r == MAILSMTP_NO_ERROR)
+ return MAILSMTP_NO_ERROR;
+
+ return r;
+}
+
+
+
+int mailesmtp_send(mailsmtp * session,
+ const char * from,
+ int return_full,
+ const char * envid,
+ clist * addresses,
+ const char * message, size_t size)
+{
+ int r;
+ clistiter * l;
+
+ if (!session->esmtp)
+ return mailsmtp_send(session, from, addresses, message, size);
+
+ r = mailesmtp_mail(session, from, return_full, envid);
+ if (r != MAILSMTP_NO_ERROR)
+ return r;
+
+ for(l = clist_begin(addresses) ; l != NULL; l = clist_next(l)) {
+ struct esmtp_address * addr;
+
+ addr = clist_content(l);
+
+ r = mailesmtp_rcpt(session, addr->address, addr->notify, addr->orcpt);
+ if (r != MAILSMTP_NO_ERROR)
+ return r;
+ }
+
+ r = mailsmtp_data(session);
+ if (r != MAILSMTP_NO_ERROR)
+ return r;
+
+ r = mailsmtp_data_message(session, message, size);
+ if (r != MAILSMTP_NO_ERROR)
+ return r;
+
+ return MAILSMTP_NO_ERROR;
+}
+
+int mailsmtp_send(mailsmtp * session,
+ const char * from,
+ clist * addresses,
+ const char * message, size_t size)
+{
+ int r;
+ clistiter * l;
+
+ r = mailsmtp_mail(session, from);
+ if (r != MAILSMTP_NO_ERROR)
+ return r;
+
+ for(l = clist_begin(addresses) ; l != NULL; l = clist_next(l)) {
+ struct esmtp_address * addr;
+
+ addr = clist_content(l);
+
+ r = mailsmtp_rcpt(session, addr->address);
+ if (r != MAILSMTP_NO_ERROR)
+ return r;
+ }
+
+ r = mailsmtp_data(session);
+ if (r != MAILSMTP_NO_ERROR)
+ return r;
+
+ r = mailsmtp_data_message(session, message, size);
+ if (r != MAILSMTP_NO_ERROR)
+ return r;
+
+ return MAILSMTP_NO_ERROR;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* esmtp addresses and smtp addresses */
+
+static struct esmtp_address * esmtp_address_new(char * addr,
+ int notify, char * orcpt)
+{
+ struct esmtp_address * esmtpa;
+
+ esmtpa = malloc(sizeof(* esmtpa));
+ if (esmtpa == NULL)
+ return NULL;
+
+ esmtpa->address = strdup(addr);
+ if (esmtpa->address == NULL) {
+ free(esmtpa);
+ return NULL;
+ }
+
+ if (orcpt != NULL) {
+ esmtpa->orcpt = strdup(orcpt);
+ if (esmtpa->orcpt == NULL) {
+ free(esmtpa->address);
+ free(esmtpa);
+ return NULL;
+ }
+ }
+ else
+ esmtpa->orcpt = NULL;
+
+ esmtpa->notify = notify;
+
+ return esmtpa;
+}
+
+static void esmtp_address_free(struct esmtp_address * addr)
+{
+ if (addr->orcpt)
+ free(addr->orcpt);
+ if (addr->address)
+ free(addr->address);
+
+ free(addr);
+}
+
+clist * esmtp_address_list_new()
+{
+ return clist_new();
+}
+
+void esmtp_address_list_free(clist * l)
+{
+ clist_foreach(l, (clist_func) esmtp_address_free, NULL);
+ clist_free(l);
+}
+
+int esmtp_address_list_add(clist * list, char * address,
+ int notify, char * orcpt)
+{
+ struct esmtp_address * esmtpa;
+ int r;
+
+ esmtpa = esmtp_address_new(address, notify, orcpt);
+ if (esmtpa == NULL)
+ return -1;
+
+ r = clist_append(list, esmtpa);
+ if (r < 0) {
+ esmtp_address_free(esmtpa);
+ return -1;
+ }
+
+ return 0;
+}
+
+clist * smtp_address_list_new()
+{
+ return esmtp_address_list_new();
+}
+
+int smtp_address_list_add(clist * list, char * address)
+{
+ return esmtp_address_list_add(list, address, 0, NULL);
+}
+
+void smtp_address_list_free(clist * l)
+{
+ esmtp_address_list_free(l);
+}
diff --git a/libetpan/src/low-level/smtp/mailsmtp_helper.h b/libetpan/src/low-level/smtp/mailsmtp_helper.h
new file mode 100644
index 0000000..2178d50
--- a/dev/null
+++ b/libetpan/src/low-level/smtp/mailsmtp_helper.h
@@ -0,0 +1,74 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef MAILSMTP_HELPER_H
+
+#define MAILSMTP_HELPER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mailsmtp_types.h"
+#include "clist.h"
+
+int mailsmtp_init(mailsmtp * session);
+
+int mailesmtp_send(mailsmtp * session,
+ const char * from,
+ int return_full,
+ const char * envid,
+ clist * addresses,
+ const char * message, size_t size);
+
+int mailsmtp_send(mailsmtp * session,
+ const char * from,
+ clist * addresses,
+ const char * message, size_t size);
+
+clist * esmtp_address_list_new();
+int esmtp_address_list_add(clist * list, char * address,
+ int notify, char * orcpt);
+void esmtp_address_list_free(clist * l);
+
+clist * smtp_address_list_new();
+int smtp_address_list_add(clist * list, char * address);
+void smtp_address_list_free(clist * l);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/smtp/mailsmtp_socket.c b/libetpan/src/low-level/smtp/mailsmtp_socket.c
new file mode 100644
index 0000000..6b8d81a
--- a/dev/null
+++ b/libetpan/src/low-level/smtp/mailsmtp_socket.c
@@ -0,0 +1,99 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "mailsmtp_socket.h"
+
+#include "mailsmtp.h"
+
+#include "connect.h"
+#include <netinet/in.h>
+#include <unistd.h>
+
+#define DEFAULT_SMTP_PORT 25
+#define SERVICE_NAME_SMTP "smtp"
+#define SERVICE_TYPE_TCP "tcp"
+
+int mailsmtp_socket_connect(mailsmtp * session,
+ const char * server, uint16_t port)
+{
+ int s;
+ mailstream * stream;
+
+ if (port == 0) {
+ port = mail_get_service_port(SERVICE_NAME_SMTP, SERVICE_TYPE_TCP);
+ if (port == 0)
+ port = DEFAULT_SMTP_PORT;
+ port = ntohs(port);
+ }
+
+ /* Connection */
+
+ s = mail_tcp_connect(server, port);
+ if (s == -1)
+ return MAILSMTP_ERROR_CONNECTION_REFUSED;
+
+ stream = mailstream_socket_open(s);
+ if (stream == NULL) {
+ close(s);
+ return MAILSMTP_ERROR_MEMORY;
+ }
+
+ return mailsmtp_connect(session, stream);
+}
+
+int mailsmtp_socket_starttls(mailsmtp * session) {
+ int r;
+ int fd;
+ mailstream_low * low;
+ mailstream_low * new_low;
+
+ r = mailesmtp_starttls(session);
+ if (r != MAILSMTP_NO_ERROR)
+ return r;
+
+ low = mailstream_get_low(session->stream);
+ fd = mailstream_low_get_fd(low);
+ if (fd == -1)
+ return MAILSMTP_ERROR_STREAM;
+
+ new_low = mailstream_low_ssl_open(fd);
+ if (new_low == NULL)
+ return MAILSMTP_ERROR_STREAM;
+
+ mailstream_low_free(low);
+ mailstream_set_low(session->stream, new_low);
+
+ return MAILSMTP_NO_ERROR;
+}
diff --git a/libetpan/src/low-level/smtp/mailsmtp_socket.h b/libetpan/src/low-level/smtp/mailsmtp_socket.h
new file mode 100644
index 0000000..2726c1d
--- a/dev/null
+++ b/libetpan/src/low-level/smtp/mailsmtp_socket.h
@@ -0,0 +1,56 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef MAILSMTP_SOCKET_H
+
+#define MAILSMTP_SOCKET_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <inttypes.h>
+
+#include <libetpan/mailsmtp_types.h>
+
+int mailsmtp_socket_connect(mailsmtp * session,
+ const char * server, uint16_t port);
+int mailsmtp_socket_starttls(mailsmtp * session);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/smtp/mailsmtp_ssl.c b/libetpan/src/low-level/smtp/mailsmtp_ssl.c
new file mode 100644
index 0000000..4a42326
--- a/dev/null
+++ b/libetpan/src/low-level/smtp/mailsmtp_ssl.c
@@ -0,0 +1,74 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "mailsmtp_socket.h"
+
+#include "mailsmtp.h"
+
+#include "connect.h"
+#include <netinet/in.h>
+#include <unistd.h>
+
+#define DEFAULT_SMTPS_PORT 465
+#define SERVICE_NAME_SMTPS "smtps"
+#define SERVICE_TYPE_TCP "tcp"
+
+int mailsmtp_ssl_connect(mailsmtp * session,
+ const char * server, uint16_t port)
+{
+ int s;
+ mailstream * stream;
+
+ if (port == 0) {
+ port = mail_get_service_port(SERVICE_NAME_SMTPS, SERVICE_TYPE_TCP);
+ if (port == 0)
+ port = DEFAULT_SMTPS_PORT;
+ port = ntohs(port);
+ }
+
+ /* Connection */
+
+ s = mail_tcp_connect(server, port);
+ if (s == -1)
+ return MAILSMTP_ERROR_CONNECTION_REFUSED;
+
+ stream = mailstream_ssl_open(s);
+ if (stream == NULL) {
+ close(s);
+ return MAILSMTP_ERROR_CONNECTION_REFUSED;
+ }
+
+ return mailsmtp_connect(session, stream);
+}
diff --git a/libetpan/src/low-level/smtp/mailsmtp_ssl.h b/libetpan/src/low-level/smtp/mailsmtp_ssl.h
new file mode 100644
index 0000000..01f4683
--- a/dev/null
+++ b/libetpan/src/low-level/smtp/mailsmtp_ssl.h
@@ -0,0 +1,55 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef MAILSMTP_SSL_H
+
+#define MAILSMTP_SSL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <inttypes.h>
+
+#include <libetpan/mailsmtp_types.h>
+
+int mailsmtp_ssl_connect(mailsmtp * session,
+ const char * server, uint16_t port);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/smtp/mailsmtp_types.h b/libetpan/src/low-level/smtp/mailsmtp_types.h
new file mode 100644
index 0000000..0aa2617
--- a/dev/null
+++ b/libetpan/src/low-level/smtp/mailsmtp_types.h
@@ -0,0 +1,126 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef MAILSMTP_TYPES_H
+
+#define MAILSMTP_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mailstream.h"
+#include "mmapstring.h"
+
+enum {
+ MAILSMTP_NO_ERROR = 0,
+ MAILSMTP_ERROR_UNEXPECTED_CODE,
+ MAILSMTP_ERROR_SERVICE_NOT_AVAILABLE,
+ MAILSMTP_ERROR_STREAM,
+ MAILSMTP_ERROR_HOSTNAME,
+ MAILSMTP_ERROR_NOT_IMPLEMENTED,
+ MAILSMTP_ERROR_ACTION_NOT_TAKEN,
+ MAILSMTP_ERROR_EXCEED_STORAGE_ALLOCATION,
+ MAILSMTP_ERROR_IN_PROCESSING,
+ MAILSMTP_ERROR_INSUFFICIENT_SYSTEM_STORAGE,
+ MAILSMTP_ERROR_MAILBOX_UNAVAILABLE,
+ MAILSMTP_ERROR_MAILBOX_NAME_NOT_ALLOWED,
+ MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND,
+ MAILSMTP_ERROR_USER_NOT_LOCAL,
+ MAILSMTP_ERROR_TRANSACTION_FAILED,
+ MAILSMTP_ERROR_MEMORY,
+ MAILSMTP_ERROR_AUTH_NOT_SUPPORTED,
+ MAILSMTP_ERROR_AUTH_LOGIN,
+ MAILSMTP_ERROR_AUTH_REQUIRED,
+ MAILSMTP_ERROR_AUTH_TOO_WEAK,
+ MAILSMTP_ERROR_AUTH_TRANSITION_NEEDED,
+ MAILSMTP_ERROR_AUTH_TEMPORARY_FAILTURE,
+ MAILSMTP_ERROR_AUTH_ENCRYPTION_REQUIRED,
+ MAILSMTP_ERROR_STARTTLS_TEMPORARY_FAILURE,
+ MAILSMTP_ERROR_STARTTLS_NOT_SUPPORTED,
+ MAILSMTP_ERROR_CONNECTION_REFUSED
+};
+
+enum {
+ MAILSMTP_AUTH_NOT_CHECKED = 0,
+ MAILSMTP_AUTH_CHECKED = 1,
+ MAILSMTP_AUTH_CRAM_MD5 = 2,
+ MAILSMTP_AUTH_PLAIN = 4,
+ MAILSMTP_AUTH_LOGIN = 8
+};
+
+enum {
+ MAILSMTP_ESMTP = 1,
+ MAILSMTP_ESMTP_EXPN = 2,
+ MAILSMTP_ESMTP_8BITMIME = 4,
+ MAILSMTP_ESMTP_SIZE = 8,
+ MAILSMTP_ESMTP_ETRN = 16,
+ MAILSMTP_ESMTP_STARTTLS = 32,
+ MAILSMTP_ESMTP_DSN = 64,
+};
+
+struct mailsmtp {
+ mailstream * stream;
+
+ size_t progr_rate;
+ progress_function * progr_fun;
+
+ char * response;
+
+ MMAPString * line_buffer;
+ MMAPString * response_buffer;
+
+ int esmtp; // contains flags MAILSMTP_ESMTP_*
+ int auth; // contains flags MAILSMTP_AUTH_*
+};
+
+typedef struct mailsmtp mailsmtp;
+
+#define MAILSMTP_DSN_NOTIFY_SUCCESS 1
+#define MAILSMTP_DSN_NOTIFY_FAILURE 2
+#define MAILSMTP_DSN_NOTIFY_DELAY 4
+#define MAILSMTP_DSN_NOTIFY_NEVER 8
+
+struct esmtp_address {
+ char * address;
+ int notify;
+ char * orcpt;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif