From 9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf Mon Sep 17 00:00:00 2001 From: zautrix Date: Fri, 18 Mar 2005 20:17:03 +0000 Subject: Initial revision --- (limited to 'libetpan/src/low-level/smtp') 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 +#include +#include +#include +#include + + +/* + 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 [] + ETRN + STARTTLS + AUTH + */ + 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 +#include +#include +#include + + +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 +#include +#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 +#include + +#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 + +#include + +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 +#include + +#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 + +#include + +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 -- cgit v0.9.0.2