59#include <sasl/saslutil.h>
62#define smtp_success(x) (((x) / 100) == 2)
64#define SMTP_CONTINUE 354
66#define SMTP_ERR_READ -2
67#define SMTP_ERR_WRITE -3
68#define SMTP_ERR_CODE -4
73#define SMTP_AUTH_SUCCESS 0
74#define SMTP_AUTH_UNAVAIL 1
75#define SMTP_AUTH_FAIL -1
82#define SMTP_CAP_NO_FLAGS 0
83#define SMTP_CAP_STARTTLS (1 << 0)
84#define SMTP_CAP_AUTH (1 << 1)
85#define SMTP_CAP_DSN (1 << 2)
86#define SMTP_CAP_EIGHTBITMIME (1 << 3)
87#define SMTP_CAP_SMTPUTF8 (1 << 4)
88#define SMTP_CAP_ALL ((1 << 5) - 1)
140 char buf[1024] = { 0 };
150 const char *s = buf + 4;
179 }
while (buf[3] ==
'-');
210 char buf[1024] = { 0 };
213 snprintf(buf,
sizeof(buf),
"RCPT TO:<%s> NOTIFY=%s\r\n",
239 char buf[1024] = { 0 };
240 struct Progress *progress = NULL;
245 FILE *fp = fopen(msgfile,
"r");
248 mutt_error(
_(
"SMTP session failed: unable to open %s"), msgfile);
260 snprintf(buf,
sizeof(buf),
"DATA\r\n");
274 while (fgets(buf,
sizeof(buf) - 1, fp))
277 term = buflen && buf[buflen - 1] ==
'\n';
278 if (term && ((buflen == 1) || (buf[buflen - 2] !=
'\r')))
279 snprintf(buf + buflen - 1,
sizeof(buf) - buflen + 1,
"\r\n");
295 if (!term && buflen &&
338 const char *
const c_smtp_oauth_refresh_command =
cs_subset_string(adata->
sub,
"smtp_oauth_refresh_command");
339 return c_smtp_oauth_refresh_command;
385 static unsigned short SmtpPort = 0;
388 struct servent *service = getservbyname(
"smtp",
"tcp");
390 SmtpPort = ntohs(service->s_port);
395 cac->
port = SmtpPort;
423 if (c_ssl_force_tls || (c_ssl_starttls !=
MUTT_NO))
428 char buf[1024] = { 0 };
429 snprintf(buf,
sizeof(buf),
"%s %s\r\n", esmtp ?
"EHLO" :
"HELO", adata->
fqdn);
451static int smtp_code(
const char *str,
size_t len,
int *n)
463 if (!end || (*end !=
'\0'))
479static int smtp_get_auth_response(
struct Connection *conn,
struct Buffer *input_buf,
480 int *smtp_rc,
struct Buffer *response_buf)
495 const char *smtp_response =
buf_string(input_buf) + 3;
513static int smtp_auth_gsasl(
struct SmtpAccountData *adata,
const char *mechlist)
515 Gsasl_session *gsasl_session = NULL;
516 struct Buffer *input_buf = NULL, *output_buf = NULL, *smtp_response_buf = NULL;
541 buf_printf(output_buf,
"AUTH %s", chosen_mech);
548 char *gsasl_step_output = NULL;
549 gsasl_rc = gsasl_step64(gsasl_session,
"", &gsasl_step_output);
550 if (gsasl_rc != GSASL_NEEDS_MORE && gsasl_rc != GSASL_OK)
553 gsasl_strerror(gsasl_rc));
559 gsasl_free(gsasl_step_output);
569 if (smtp_get_auth_response(adata->
conn, input_buf, &smtp_rc, smtp_response_buf) < 0)
575 char *gsasl_step_output = NULL;
576 gsasl_rc = gsasl_step64(gsasl_session,
buf_string(smtp_response_buf), &gsasl_step_output);
577 if ((gsasl_rc == GSASL_NEEDS_MORE) || (gsasl_rc == GSASL_OK))
581 gsasl_free(gsasl_step_output);
586 gsasl_strerror(gsasl_rc));
588 }
while ((gsasl_rc == GSASL_NEEDS_MORE) || (gsasl_rc == GSASL_OK));
620static int smtp_auth_sasl(
struct SmtpAccountData *adata,
const char *mechlist)
622 sasl_conn_t *saslconn = NULL;
623 sasl_interact_t *interaction = NULL;
624 const char *mech = NULL;
625 const char *
data = NULL;
636 rc = sasl_client_start(saslconn, mechlist, &interaction, &
data, &len, &mech);
637 if (rc == SASL_INTERACT)
639 }
while (rc == SASL_INTERACT);
641 if ((rc != SASL_OK) && (rc != SASL_CONTINUE))
644 sasl_dispose(&saslconn);
654 bufsize =
MAX((len * 2), 1024);
657 snprintf(buf, bufsize,
"AUTH %s", mech);
683 if (sasl_decode64(buf + 4, strlen(buf + 4), buf, bufsize - 1, &len) != SASL_OK)
691 saslrc = sasl_client_step(saslconn, buf, len, &interaction, &
data, &len);
692 if (saslrc == SASL_INTERACT)
694 }
while (saslrc == SASL_INTERACT);
698 if ((len * 2) > bufsize)
703 if (sasl_encode64(
data, len, buf, bufsize, &len) != SASL_OK)
710 }
while (rc ==
SMTP_READY && saslrc != SASL_FAIL);
720 sasl_dispose(&saslconn);
737 if (!method && !c_smtp_oauth_refresh_command)
740 const char *authtype = xoauth2 ?
"XOAUTH2" :
"OAUTHBEARER";
798 char buf[1024] = { 0 };
814 if (snprintf(buf + len,
sizeof(buf) - len,
"\r\n") != 2)
845 char b64[1024] = { 0 };
846 char buf[1026] = { 0 };
869 size_t len = snprintf(buf,
sizeof(buf),
"%s", adata->
conn->
account.
user);
871 snprintf(buf,
sizeof(buf),
"%s\r\n", b64);
887 snprintf(buf,
sizeof(buf),
"%s\r\n", b64);
904 mutt_error(
_(
"%s authentication failed"),
"LOGIN");
918 { smtp_auth_sasl, NULL },
921 { smtp_auth_gsasl, NULL },
957 if (c_smtp_authenticators && (c_smtp_authenticators->
count > 0))
982#if defined(USE_SASL_CYRUS)
985#elif defined(USE_SASL_GNU)
987 r = smtp_auth_gsasl(adata, adata->
auth_mechs);
1008 mutt_error(
_(
"%s authentication failed"),
"SASL");
1033 esmtp |= force_auth;
1049 else if (c_ssl_force_tls)
1070 mutt_error(
_(
"Could not negotiate TLS connection"));
1085 mutt_error(
_(
"SMTP server does not support authentication"));
1108 const struct AddressList *cc,
const struct AddressList *bcc,
1109 const char *msgfile,
bool eightbit,
struct ConfigSubset *sub)
1113 const char *envfrom = NULL;
1114 char buf[1024] = { 0 };
1126 if (c_envelope_from_address)
1158 int len = snprintf(buf,
sizeof(buf),
"MAIL FROM:<%s>", envfrom);
1165 len += snprintf(buf + len,
sizeof(buf) - len,
" RET=%s", c_dsn_return);
1170 snprintf(buf + len,
sizeof(buf) - len,
" SMTPUTF8");
1205 mutt_error(
_(
"SMTP session failed: write error"));
bool mutt_addrlist_uses_unicode(const struct AddressList *al)
Do any of a list of addresses use Unicode characters.
bool mutt_addr_uses_unicode(const char *str)
Does this address use Unicode character.
const char * mutt_str_atoi(const char *str, int *dst)
Convert ASCII string to an integer.
size_t mutt_b64_encode(const char *in, size_t inlen, char *out, size_t outlen)
Convert raw bytes to null-terminated base64 string.
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
const struct Slist * cs_subset_slist(const struct ConfigSubset *sub, const char *name)
Get a string-list config item by name.
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Convenience wrapper for the config headers.
const struct Address * cs_subset_address(const struct ConfigSubset *sub, const char *name)
Get an Address config item by name.
int mutt_account_getpass(struct ConnAccount *cac)
Fetch password into ConnAccount, if necessary.
int mutt_account_getuser(struct ConnAccount *cac)
Retrieve username into ConnAccount, if necessary.
void mutt_account_unsetpass(struct ConnAccount *cac)
Unset ConnAccount's password.
char * mutt_account_getoauthbearer(struct ConnAccount *cac, bool xoauth2)
Get an OAUTHBEARER/XOAUTH2 token.
ConnAccountField
Login credentials.
@ MUTT_CA_OAUTH_CMD
OAuth refresh command.
@ MUTT_CA_LOGIN
Login name.
@ MUTT_CA_HOST
Server name.
#define MUTT_ACCT_SSL
Account uses SSL/TLS.
#define MUTT_ACCT_USER
User field has been set.
Convenience wrapper for the core headers.
Structs that make up an email.
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
char * ShortHostname
Short version of the hostname.
bool OptNoCurses
(pseudo) when sending in batch mode
int mutt_ssl_starttls(struct Connection *conn)
Negotiate TLS over an already opened connection.
#define mutt_message(...)
#define mutt_debug(LEVEL,...)
const char * mutt_gsasl_get_mech(const char *requested_mech, const char *server_mechlist)
Pick a connection mechanism.
int mutt_gsasl_client_new(struct Connection *conn, const char *mech, Gsasl_session **sctx)
Create a new GNU SASL client.
void mutt_gsasl_client_finish(Gsasl_session **sctx)
Free a GNU SASL client.
@ LL_DEBUG3
Log at debug level 3.
@ LL_DEBUG2
Log at debug level 2.
@ LL_DEBUG1
Log at debug level 1.
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
#define mutt_array_size(x)
Convenience wrapper for the library headers.
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
char * mutt_str_dup(const char *str)
Copy a string, safely.
int mutt_str_asprintf(char **strp, const char *fmt,...)
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
char * mutt_strn_cat(char *d, size_t l, const char *s, size_t sl)
Concatenate two strings.
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
char * mutt_str_cat(char *buf, size_t buflen, const char *s)
Concatenate two strings.
int mutt_account_fromurl(struct ConnAccount *cac, const struct Url *url)
Fill ConnAccount with information from url.
ConnAccount object used by POP and IMAP.
@ MUTT_ACCT_TYPE_SMTP
Smtp Account.
struct Connection * mutt_conn_find(const struct ConnAccount *cac)
Find a connection from a list.
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
@ MUTT_PROGRESS_NET
Progress tracks bytes, according to $net_inc
void progress_free(struct Progress **ptr)
Free a Progress Bar.
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
struct Progress * progress_new(const char *msg, enum ProgressType type, size_t size)
Create a new Progress Bar.
QuadOption
Possible values for a quad-option.
@ MUTT_ABORT
User aborted the question (with Ctrl-G)
@ MUTT_NO
User answered 'No', or assume 'No'.
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
enum QuadOption query_quadoption(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
#define TAILQ_FOREACH(var, head, field)
#define STAILQ_FOREACH(var, head, field)
#define TAILQ_FIRST(head)
#define TAILQ_EMPTY(head)
int mutt_sasl_interact(sasl_interact_t *interaction)
Perform an SASL interaction with the user.
int mutt_sasl_client_new(struct Connection *conn, sasl_conn_t **saslconn)
Wrapper for sasl_client_new()
void mutt_sasl_setup_conn(struct Connection *conn, sasl_conn_t *saslconn)
Set up an SASL connection.
size_t mutt_sasl_plain_msg(char *buf, size_t buflen, const char *cmd, const char *authz, const char *user, const char *pass)
Construct a base64 encoded SASL PLAIN message.
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Miscellaneous functions for sending an email.
static int smtp_get_resp(struct SmtpAccountData *adata)
Read a command response from the SMTP server.
#define SMTP_CAP_NO_FLAGS
No flags are set.
#define SMTP_CAP_STARTTLS
Server supports STARTTLS command.
uint8_t SmtpCapFlags
SMTP server capabilities.
static int smtp_authenticate(struct SmtpAccountData *adata)
Authenticate to an SMTP server.
bool smtp_auth_is_valid(const char *authenticator)
Check if string is a valid smtp authentication method.
static int smtp_auth_oauth_xoauth2(struct SmtpAccountData *adata, const char *method, bool xoauth2)
Authenticate an SMTP connection using OAUTHBEARER/XOAUTH2.
static const struct SmtpAuth SmtpAuthenticators[]
Accepted authentication methods.
static bool valid_smtp_code(char *buf, int *n)
Is the is a valid SMTP return code?
#define SMTP_AUTH_UNAVAIL
static int smtp_helo(struct SmtpAccountData *adata, bool esmtp)
Say hello to an SMTP Server.
#define SMTP_CAP_EIGHTBITMIME
Server supports 8-bit MIME content.
#define SMTP_CAP_AUTH
Server supports AUTH command.
static int smtp_data(struct SmtpAccountData *adata, const char *msgfile)
Send data to an SMTP server.
static int smtp_fill_account(struct SmtpAccountData *adata, struct ConnAccount *cac)
Create ConnAccount object from SMTP Url.
#define SMTP_AUTH_SUCCESS
static const char * smtp_get_field(enum ConnAccountField field, void *gf_data)
Get connection login credentials - Implements ConnAccount::get_field()
static int smtp_auth_xoauth2(struct SmtpAccountData *adata, const char *method)
Authenticate an SMTP connection using XOAUTH2.
#define SMTP_CAP_SMTPUTF8
Server accepts UTF-8 strings.
int mutt_smtp_send(const struct AddressList *from, const struct AddressList *to, const struct AddressList *cc, const struct AddressList *bcc, const char *msgfile, bool eightbit, struct ConfigSubset *sub)
Send a message using SMTP.
#define SMTP_CAP_DSN
Server supports Delivery Status Notification.
static int smtp_auth_login(struct SmtpAccountData *adata, const char *method)
Authenticate using plain text.
static int smtp_auth_plain(struct SmtpAccountData *adata, const char *method)
Authenticate using plain text.
static int smtp_auth_oauth(struct SmtpAccountData *adata, const char *method)
Authenticate an SMTP connection using OAUTHBEARER.
static int smtp_rcpt_to(struct SmtpAccountData *adata, const struct AddressList *al)
Set the recipient to an Address.
static int smtp_open(struct SmtpAccountData *adata, bool esmtp)
Open an SMTP Connection.
Send email to an SMTP server.
int mutt_socket_close(struct Connection *conn)
Close a socket.
void mutt_socket_empty(struct Connection *conn)
Clear out any queued data.
int mutt_socket_open(struct Connection *conn)
Simple wrapper.
int mutt_socket_readln_d(char *buf, size_t buflen, struct Connection *conn, int dbg)
Read a line from a socket.
#define MUTT_SOCK_LOG_FULL
#define mutt_socket_readln(buf, buflen, conn)
#define mutt_socket_send(conn, buf)
#define mutt_socket_buffer_readln(buf, conn)
#define mutt_socket_send_d(conn, buf, dbg)
struct Buffer * mailbox
Mailbox and host address.
String manipulation buffer.
char * data
Pointer to data.
A set of inherited config items.
Login details for a remote server.
const char * service
Name of the service, e.g. "imap".
const char *(* get_field)(enum ConnAccountField field, void *gf_data)
Function to get some login credentials.
unsigned char type
Connection type, e.g. MUTT_ACCT_TYPE_IMAP.
MuttAccountFlags flags
Which fields are initialised, e.g. MUTT_ACCT_USER.
void * gf_data
Private data to pass to get_field()
unsigned short port
Port to connect to.
unsigned int ssf
Security strength factor, in bits (see notes)
struct ConnAccount account
Account details: username, password, etc.
Container for Accounts, Notifications.
struct ConfigSubset * sub
Inherited config items.
struct ListHead head
List containing values.
size_t count
Number of values in list.
const char * fqdn
Fully-qualified domain name.
struct ConfigSubset * sub
Config scope.
struct Connection * conn
Server Connection.
const char * auth_mechs
Allowed authorisation mechanisms.
SmtpCapFlags capabilities
Server capabilities.
SMTP authentication multiplexor.
int(* authenticate)(struct SmtpAccountData *adata, const char *method)
Authenticate an SMTP connection.
const char * method
Name of authentication method supported, NULL means variable.
A parsed URL proto://user:password@host:port/path?a=1&b=2
enum UrlScheme scheme
Scheme, e.g. U_SMTPS.
struct Url * url_parse(const char *src)
Fill in Url.
void url_free(struct Url **ptr)
Free the contents of a URL.
@ U_SMTPS
Url is smtps://.