NeoMutt  2025-12-11-980-ge38c27
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
smtp.c
Go to the documentation of this file.
1
28
34
35/* This file contains code for direct SMTP delivery of email messages. */
36
37#include "config.h"
38#include <arpa/inet.h>
39#include <netdb.h>
40#include <stdbool.h>
41#include <stdint.h>
42#include <stdio.h>
43#include <unistd.h>
44#include "mutt/lib.h"
45#include "address/lib.h"
46#include "config/lib.h"
47#include "email/lib.h"
48#include "core/lib.h"
49#include "conn/lib.h"
50#include "smtp.h"
51#include "progress/lib.h"
52#include "question/lib.h"
53#include "globals.h"
54#include "mutt_socket.h"
55#include "muttlib.h"
56#include "sendlib.h"
57#ifdef USE_SASL_GNU
58#include <gsasl.h>
59#endif
60#ifdef USE_SASL_CYRUS
61#include <sasl/sasl.h>
62#endif
63
65#define smtp_success(x) (((x) / 100) == 2)
66#define SMTP_READY 334
67#define SMTP_CONTINUE 354
68
69#define SMTP_ERR_READ -2
70#define SMTP_ERR_WRITE -3
71#define SMTP_ERR_CODE -4
72
73#define SMTP_PORT 25
74#define SMTPS_PORT 465
75
76#define SMTP_AUTH_SUCCESS 0
77#define SMTP_AUTH_UNAVAIL 1
78#define SMTP_AUTH_FAIL -1
79
84{
85 // clang-format off
88 SMTP_CAP_AUTH = 1U << 1,
89 SMTP_CAP_DSN = 1U << 2,
92 // clang-format on
93};
94typedef uint8_t SmtpCapFlags;
95
96#define SMTP_CAP_ALL ((1U << 5) - 1)
97
102{
103 const char *auth_mechs;
105 struct Connection *conn;
107 const char *fqdn;
108};
109
114{
123 int (*authenticate)(struct SmtpAccountData *adata, const char *method);
124
125 const char *method;
127};
128
135static bool valid_smtp_code(char *buf, int *n)
136{
137 return (mutt_str_atoi(buf, n) - buf) <= 3;
138}
139
146static int smtp_get_resp(struct SmtpAccountData *adata)
147{
148 int n = 0;
149 char buf[1024] = { 0 };
150
151 do
152 {
153 n = mutt_socket_readln(buf, sizeof(buf), adata->conn);
154 if (n < 4)
155 {
156 /* read error, or no response code */
157 return SMTP_ERR_READ;
158 }
159 const char *s = buf + 4; /* Skip the response code and the space/dash */
160 size_t plen;
161
162 if (mutt_istr_startswith(s, "8BITMIME"))
163 {
165 }
166 else if ((plen = mutt_istr_startswith(s, "AUTH ")))
167 {
168 adata->capabilities |= SMTP_CAP_AUTH;
169 FREE(&adata->auth_mechs);
170 adata->auth_mechs = mutt_str_dup(s + plen);
171 }
172 else if (mutt_istr_startswith(s, "DSN"))
173 {
174 adata->capabilities |= SMTP_CAP_DSN;
175 }
176 else if (mutt_istr_startswith(s, "STARTTLS"))
177 {
179 }
180 else if (mutt_istr_startswith(s, "SMTPUTF8"))
181 {
183 }
184
185 if (!valid_smtp_code(buf, &n))
186 return SMTP_ERR_CODE;
187
188 } while (buf[3] == '-');
189
190 if (smtp_success(n) || (n == SMTP_CONTINUE))
191 return 0;
192
193 mutt_error(_("SMTP session failed: %s"), buf);
194 return -1;
195}
196
204static int smtp_rcpt_to(struct SmtpAccountData *adata, const struct AddressList *al)
205{
206 if (!al)
207 return 0;
208
209 const char *const c_dsn_notify = cs_subset_string(adata->sub, "dsn_notify");
210
211 struct Address *a = NULL;
212 TAILQ_FOREACH(a, al, entries)
213 {
214 /* weed out group mailboxes, since those are for display only */
215 if (!a->mailbox || a->group)
216 {
217 continue;
218 }
219 char buf[1024] = { 0 };
220 if ((adata->capabilities & SMTP_CAP_DSN) && c_dsn_notify)
221 {
222 snprintf(buf, sizeof(buf), "RCPT TO:<%s> NOTIFY=%s\r\n",
223 buf_string(a->mailbox), c_dsn_notify);
224 }
225 else
226 {
227 snprintf(buf, sizeof(buf), "RCPT TO:<%s>\r\n", buf_string(a->mailbox));
228 }
229 if (mutt_socket_send(adata->conn, buf) == -1)
230 return SMTP_ERR_WRITE;
231 int rc = smtp_get_resp(adata);
232 if (rc != 0)
233 {
234 mutt_sleep(2);
235 mutt_error(_("SMTP session failed: cannot add recipient <%s>"),
236 buf_string(a->mailbox));
237 return rc;
238 }
239 }
240
241 return 0;
242}
243
251static int smtp_data(struct SmtpAccountData *adata, const char *msgfile)
252{
253 char buf[1024] = { 0 };
254 struct Progress *progress = NULL;
255 int rc = SMTP_ERR_WRITE;
256 int term = 0;
257 size_t buflen = 0;
258
259 FILE *fp = mutt_file_fopen(msgfile, "r");
260 if (!fp)
261 {
262 mutt_error(_("SMTP session failed: unable to open %s"), msgfile);
263 return -1;
264 }
265 const long size = mutt_file_get_size_fp(fp);
266 if (size == 0)
267 {
268 mutt_file_fclose(&fp);
269 return -1;
270 }
271 unlink(msgfile);
272 progress = progress_new(MUTT_PROGRESS_NET, size);
273 progress_set_message(progress, _("Sending message..."));
274
275 snprintf(buf, sizeof(buf), "DATA\r\n");
276 if (mutt_socket_send(adata->conn, buf) == -1)
277 {
278 mutt_file_fclose(&fp);
279 goto done;
280 }
281 rc = smtp_get_resp(adata);
282 if (rc != 0)
283 {
284 mutt_file_fclose(&fp);
285 goto done;
286 }
287
288 rc = SMTP_ERR_WRITE;
289 while (fgets(buf, sizeof(buf) - 1, fp))
290 {
291 buflen = mutt_str_len(buf);
292 term = buflen && buf[buflen - 1] == '\n';
293 if (term && ((buflen == 1) || (buf[buflen - 2] != '\r')))
294 snprintf(buf + buflen - 1, sizeof(buf) - buflen + 1, "\r\n");
295 if (buf[0] == '.')
296 {
297 if (mutt_socket_send_d(adata->conn, ".", MUTT_SOCK_LOG_FULL) == -1)
298 {
299 mutt_file_fclose(&fp);
300 goto done;
301 }
302 }
303 if (mutt_socket_send_d(adata->conn, buf, MUTT_SOCK_LOG_FULL) == -1)
304 {
305 mutt_file_fclose(&fp);
306 goto done;
307 }
308 progress_update(progress, MAX(0, ftell(fp)), -1);
309 }
310 if (!term && buflen &&
311 (mutt_socket_send_d(adata->conn, "\r\n", MUTT_SOCK_LOG_FULL) == -1))
312 {
313 mutt_file_fclose(&fp);
314 goto done;
315 }
316 mutt_file_fclose(&fp);
317
318 /* terminate the message body */
319 if (mutt_socket_send(adata->conn, ".\r\n") == -1)
320 goto done;
321
322 rc = smtp_get_resp(adata);
323
324done:
325 progress_free(&progress);
326 return rc;
327}
328
332static const char *smtp_get_field(enum ConnAccountField field, void *gf_data)
333{
334 struct SmtpAccountData *adata = gf_data;
335 if (!adata)
336 return NULL;
337
338 switch (field)
339 {
340 case MUTT_CA_LOGIN:
341 case MUTT_CA_USER:
342 {
343 const char *const c_smtp_user = cs_subset_string(adata->sub, "smtp_user");
344 return c_smtp_user;
345 }
346 case MUTT_CA_PASS:
347 {
348 const char *const c_smtp_pass = cs_subset_string(adata->sub, "smtp_pass");
349 return c_smtp_pass;
350 }
352 {
353 const char *const c_smtp_oauth_refresh_command = cs_subset_string(adata->sub, "smtp_oauth_refresh_command");
354 return c_smtp_oauth_refresh_command;
355 }
356 case MUTT_CA_HOST:
357 default:
358 return NULL;
359 }
360}
361
369static int smtp_fill_account(struct SmtpAccountData *adata, struct ConnAccount *cac)
370{
371 cac->flags = 0;
372 cac->port = 0;
374 cac->service = "smtp";
376 cac->gf_data = adata;
377
378 const char *const c_smtp_url = cs_subset_string(adata->sub, "smtp_url");
379
380 struct Url *url = url_parse(c_smtp_url);
381 if (!url || ((url->scheme != U_SMTP) && (url->scheme != U_SMTPS)) ||
382 !url->host || (account_from_url(cac, url) < 0))
383 {
384 url_free(&url);
385 mutt_error(_("Invalid SMTP URL: %s"), c_smtp_url);
386 return -1;
387 }
388
389 if (url->scheme == U_SMTPS)
390 cac->flags |= MUTT_ACCT_SSL;
391
392 if (cac->port == 0)
393 {
394 if (cac->flags & MUTT_ACCT_SSL)
395 {
396 cac->port = SMTPS_PORT;
397 }
398 else
399 {
400 static unsigned short SmtpPort = 0;
401 if (SmtpPort == 0)
402 {
403 struct servent *service = getservbyname("smtp", "tcp");
404 if (service)
405 SmtpPort = ntohs(service->s_port);
406 else
407 SmtpPort = SMTP_PORT;
408 mutt_debug(LL_DEBUG3, "Using default SMTP port %d\n", SmtpPort);
409 }
410 cac->port = SmtpPort;
411 }
412 }
413
414 url_free(&url);
415 return 0;
416}
417
425static int smtp_helo(struct SmtpAccountData *adata, bool esmtp)
426{
428
429 if (!esmtp)
430 {
431 /* if TLS or AUTH are requested, use EHLO */
432 if (adata->conn->account.flags & MUTT_ACCT_USER)
433 esmtp = true;
434#ifdef USE_SSL
435 const bool c_ssl_force_tls = cs_subset_bool(adata->sub, "ssl_force_tls");
436 const enum QuadOption c_ssl_starttls = cs_subset_quad(adata->sub, "ssl_starttls");
437
438 if (c_ssl_force_tls || (c_ssl_starttls != MUTT_NO))
439 esmtp = true;
440#endif
441 }
442
443 char buf[1024] = { 0 };
444 snprintf(buf, sizeof(buf), "%s %s\r\n", esmtp ? "EHLO" : "HELO", adata->fqdn);
445 /* XXX there should probably be a wrapper in mutt_socket.c that
446 * repeatedly calls adata->conn->write until all data is sent. This
447 * currently doesn't check for a short write. */
448 if (mutt_socket_send(adata->conn, buf) == -1)
449 return SMTP_ERR_WRITE;
450 return smtp_get_resp(adata);
451}
452
453#if defined(USE_SASL_CYRUS) || defined(USE_SASL_GNU)
460static int smtp_code(const struct Buffer *buf, int *n)
461{
462 if (buf_len(buf) < 3)
463 return false;
464
465 char code[4] = { 0 };
466 const char *str = buf_string(buf);
467
468 code[0] = str[0];
469 code[1] = str[1];
470 code[2] = str[2];
471 code[3] = 0;
472
473 const char *end = mutt_str_atoi(code, n);
474 if (!end || (*end != '\0'))
475 return false;
476 return true;
477}
478
490static int smtp_get_auth_response(struct Connection *conn, struct Buffer *input_buf,
491 int *smtp_rc, struct Buffer *response_buf)
492{
493 buf_reset(response_buf);
494 do
495 {
496 if (mutt_socket_buffer_readln(input_buf, conn) < 0)
497 return -1;
498 if (!smtp_code(input_buf, smtp_rc))
499 {
500 return -1;
501 }
502
503 if (*smtp_rc != SMTP_READY)
504 break;
505
506 const char *smtp_response = input_buf->data + 3;
507 if (*smtp_response)
508 {
509 smtp_response++;
510 buf_addstr(response_buf, smtp_response);
511 }
512 } while (buf_at(input_buf, 3) == '-');
513
514 return 0;
515}
516#endif
517
518#ifdef USE_SASL_GNU
526static int smtp_auth_gsasl(struct SmtpAccountData *adata, const char *mechlist)
527{
528 Gsasl_session *gsasl_session = NULL;
529 struct Buffer *input_buf = NULL;
530 struct Buffer *output_buf = NULL;
531 struct Buffer *smtp_response_buf = NULL;
532 int rc = SMTP_AUTH_FAIL;
533 int gsasl_rc = GSASL_OK;
534 int smtp_rc = 0;
535 bool first_response = true;
536
537 const char *chosen_mech = mutt_gsasl_get_mech(mechlist, adata->auth_mechs);
538 if (!chosen_mech)
539 {
540 mutt_debug(LL_DEBUG2, "returned no usable mech\n");
541 return SMTP_AUTH_UNAVAIL;
542 }
543
544 mutt_debug(LL_DEBUG2, "using mech %s\n", chosen_mech);
545
546 if (mutt_gsasl_client_new(adata->conn, chosen_mech, &gsasl_session) < 0)
547 {
548 mutt_debug(LL_DEBUG1, "Error allocating GSASL connection\n");
549 return SMTP_AUTH_UNAVAIL;
550 }
551
552 if (OptGui)
553 mutt_message(_("Authenticating (%s)..."), chosen_mech);
554
555 input_buf = buf_pool_get();
556 output_buf = buf_pool_get();
557 smtp_response_buf = buf_pool_get();
558
559 buf_printf(output_buf, "AUTH %s", chosen_mech);
560
561 /* Work around broken SMTP servers. See Debian #1010658.
562 * The msmtp source also forces IR for PLAIN because the author
563 * encountered difficulties with a server requiring it. */
564 if (mutt_str_equal(chosen_mech, "PLAIN"))
565 {
566 first_response = false;
567 char *gsasl_step_output = NULL;
568 gsasl_rc = gsasl_step64(gsasl_session, "", &gsasl_step_output);
569 if (gsasl_rc != GSASL_NEEDS_MORE && gsasl_rc != GSASL_OK)
570 {
571 mutt_debug(LL_DEBUG1, "gsasl_step64() failed (%d): %s\n", gsasl_rc,
572 gsasl_strerror(gsasl_rc));
573 goto fail;
574 }
575
576 buf_addch(output_buf, ' ');
577 buf_addstr(output_buf, gsasl_step_output);
578 gsasl_free(gsasl_step_output);
579 }
580
581 buf_addstr(output_buf, "\r\n");
582
583 do
584 {
585 if (mutt_socket_send(adata->conn, buf_string(output_buf)) < 0)
586 goto fail;
587
588 if (smtp_get_auth_response(adata->conn, input_buf, &smtp_rc, smtp_response_buf) < 0)
589 goto fail;
590
591 if (smtp_rc != SMTP_READY)
592 break;
593
594 /* Another workaround for broken SMTP servers. Instead of an
595 * empty challenge, some MS servers return a meaningless
596 * non-BASE64 encoded response in the initial reply, e.g. "334
597 * GSSAPI supported".
598 */
599 if (first_response)
600 {
601 first_response = false;
602 /* Use input_buf as a temp buffer. We've already processed the input */
603 if (mutt_b64_buffer_decode(input_buf, buf_string(smtp_response_buf)) < 0)
604 buf_reset(smtp_response_buf);
605 }
606
607 char *gsasl_step_output = NULL;
608 gsasl_rc = gsasl_step64(gsasl_session, buf_string(smtp_response_buf), &gsasl_step_output);
609 if ((gsasl_rc == GSASL_NEEDS_MORE) || (gsasl_rc == GSASL_OK))
610 {
611 buf_strcpy(output_buf, gsasl_step_output);
612 buf_addstr(output_buf, "\r\n");
613 gsasl_free(gsasl_step_output);
614 }
615 else
616 {
617 mutt_debug(LL_DEBUG1, "gsasl_step64() failed (%d): %s\n", gsasl_rc,
618 gsasl_strerror(gsasl_rc));
619 }
620 } while ((gsasl_rc == GSASL_NEEDS_MORE) || (gsasl_rc == GSASL_OK));
621
622 if (smtp_rc == SMTP_READY)
623 {
624 mutt_socket_send(adata->conn, "*\r\n");
625 goto fail;
626 }
627
628 if (smtp_success(smtp_rc) && (gsasl_rc == GSASL_OK))
630
631fail:
632 buf_pool_release(&input_buf);
633 buf_pool_release(&output_buf);
634 buf_pool_release(&smtp_response_buf);
635 mutt_gsasl_client_finish(&gsasl_session);
636
637 if (rc == SMTP_AUTH_FAIL)
638 mutt_debug(LL_DEBUG2, "%s failed\n", chosen_mech);
639
640 return rc;
641}
642#endif
643
644#ifdef USE_SASL_CYRUS
652static int smtp_auth_sasl(struct SmtpAccountData *adata, const char *mechlist)
653{
654 sasl_conn_t *saslconn = NULL;
655 sasl_interact_t *interaction = NULL;
656 const char *mech = NULL;
657 const char *data = NULL;
658 unsigned int data_len = 0;
659 struct Buffer *temp_buf = NULL;
660 struct Buffer *output_buf = NULL;
661 struct Buffer *smtp_response_buf = NULL;
662 int rc = SMTP_AUTH_FAIL;
663 int rc_sasl;
664 int rc_smtp;
665
666 if (mutt_sasl_client_new(adata->conn, &saslconn) < 0)
667 return SMTP_AUTH_FAIL;
668
669 /* Perform SASL client handshake: start negotiation with the server,
670 * handling any interactive prompts from the SASL library */
671 do
672 {
673 rc_sasl = sasl_client_start(saslconn, mechlist, &interaction, &data, &data_len, &mech);
674 if (rc_sasl == SASL_INTERACT)
675 mutt_sasl_interact(interaction);
676 } while (rc_sasl == SASL_INTERACT);
677
678 if ((rc_sasl != SASL_OK) && (rc_sasl != SASL_CONTINUE))
679 {
680 mutt_debug(LL_DEBUG2, "%s unavailable\n", NONULL(mech));
681 sasl_dispose(&saslconn);
682 return SMTP_AUTH_UNAVAIL;
683 }
684
685 if (OptGui)
686 {
687 // L10N: (%s) is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
688 mutt_message(_("Authenticating (%s)..."), mech);
689 }
690
691 /* Build the initial AUTH command, optionally including the first
692 * base64-encoded SASL response as part of the AUTH line */
693 temp_buf = buf_pool_get();
694 output_buf = buf_pool_get();
695 smtp_response_buf = buf_pool_get();
696
697 buf_printf(output_buf, "AUTH %s", mech);
698 if (data_len > 0)
699 {
700 buf_addch(output_buf, ' ');
701 mutt_b64_buffer_encode(temp_buf, data, data_len);
702 buf_addstr(output_buf, buf_string(temp_buf));
703 }
704 buf_addstr(output_buf, "\r\n");
705
706 /* Main SASL challenge/response loop: send base64-encoded data to the
707 * server, decode its response, and pass it to sasl_client_step() */
708 do
709 {
710 if (mutt_socket_send(adata->conn, buf_string(output_buf)) < 0)
711 goto fail;
712
713 if (smtp_get_auth_response(adata->conn, temp_buf, &rc_smtp, smtp_response_buf) < 0)
714 goto fail;
715
716 if (rc_smtp != SMTP_READY)
717 break;
718
719 if (mutt_b64_buffer_decode(temp_buf, buf_string(smtp_response_buf)) < 0)
720 {
721 mutt_debug(LL_DEBUG1, "error base64-decoding server response\n");
722 goto fail;
723 }
724
725 do
726 {
727 rc_sasl = sasl_client_step(saslconn, buf_string(temp_buf), buf_len(temp_buf),
728 &interaction, &data, &data_len);
729 if (rc_sasl == SASL_INTERACT)
730 mutt_sasl_interact(interaction);
731 } while (rc_sasl == SASL_INTERACT);
732
733 if (data_len > 0)
734 mutt_b64_buffer_encode(output_buf, data, data_len);
735 else
736 buf_reset(output_buf);
737
738 buf_addstr(output_buf, "\r\n");
739 } while (rc_sasl != SASL_FAIL);
740
741 /* Check final SMTP result and set up SASL security layer on success */
742 if (smtp_success(rc_smtp))
743 {
744 mutt_sasl_setup_conn(adata->conn, saslconn);
746 }
747 else
748 {
749 if (rc_smtp == SMTP_READY)
750 mutt_socket_send(adata->conn, "*\r\n");
751 sasl_dispose(&saslconn);
752 }
753
754fail:
755 buf_pool_release(&temp_buf);
756 buf_pool_release(&output_buf);
757 buf_pool_release(&smtp_response_buf);
758 return rc;
759}
760#endif
761
769static int smtp_auth_oauth_xoauth2(struct SmtpAccountData *adata, const char *method, bool xoauth2)
770{
771 /* If they did not explicitly request or configure oauth then fail quietly */
772 const char *const c_smtp_oauth_refresh_command = cs_subset_string(NeoMutt->sub, "smtp_oauth_refresh_command");
773 if (!method && !c_smtp_oauth_refresh_command)
774 return SMTP_AUTH_UNAVAIL;
775
776 const char *authtype = xoauth2 ? "XOAUTH2" : "OAUTHBEARER";
777
778 // L10N: (%s) is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
779 mutt_message(_("Authenticating (%s)..."), authtype);
780
781 /* We get the access token from the smtp_oauth_refresh_command */
782 char *oauthbearer = mutt_account_getoauthbearer(&adata->conn->account, xoauth2);
783 if (!oauthbearer)
784 return SMTP_AUTH_FAIL;
785
786 char *ibuf = NULL;
787 mutt_str_asprintf(&ibuf, "AUTH %s %s\r\n", authtype, oauthbearer);
788
789 int rc = mutt_socket_send(adata->conn, ibuf);
790 FREE(&oauthbearer);
791 FREE(&ibuf);
792
793 if (rc == -1)
794 return SMTP_AUTH_FAIL;
795 if (smtp_get_resp(adata) != 0)
796 return SMTP_AUTH_FAIL;
797
798 return SMTP_AUTH_SUCCESS;
799}
800
807static int smtp_auth_oauth(struct SmtpAccountData *adata, const char *method)
808{
809 return smtp_auth_oauth_xoauth2(adata, method, false);
810}
811
818static int smtp_auth_xoauth2(struct SmtpAccountData *adata, const char *method)
819{
820 return smtp_auth_oauth_xoauth2(adata, method, true);
821}
822
832static int smtp_auth_plain(struct SmtpAccountData *adata, const char *method)
833{
834 struct Buffer *buf = NULL;
835 struct ConnAccount *cac = &adata->conn->account;
836 int rc = -1;
837
838 /* Get username and password. Bail out of any can't be retrieved. */
839 if ((mutt_account_getuser(cac) < 0) || (mutt_account_getpass(cac) < 0))
840 goto error;
841
842 /* Build the initial client response. */
843 buf = buf_pool_get();
844 mutt_sasl_plain_msg(buf, "AUTH PLAIN", cac->user, cac->user, cac->pass);
845 buf_add_printf(buf, "\r\n");
846
847 /* Send request, receive response (with a check for OK code). */
848 if ((mutt_socket_send(adata->conn, buf_string(buf)) < 0) || smtp_get_resp(adata))
849 goto error;
850
851 rc = 0; // Auth was successful
852
853error:
854 if (rc != 0)
855 {
856 // L10N: %s is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
857 mutt_error(_("%s authentication failed"), "SASL");
858 }
859 buf_pool_release(&buf);
860 return rc;
861}
862
872static int smtp_auth_login(struct SmtpAccountData *adata, const char *method)
873{
874 char b64[1024] = { 0 };
875 char buf[1026] = { 0 };
876
877 /* Get username and password. Bail out of any can't be retrieved. */
878 if ((mutt_account_getuser(&adata->conn->account) < 0) ||
879 (mutt_account_getpass(&adata->conn->account) < 0))
880 {
881 goto error;
882 }
883
884 /* Send the AUTH LOGIN request. */
885 if (mutt_socket_send(adata->conn, "AUTH LOGIN\r\n") < 0)
886 {
887 goto error;
888 }
889
890 /* Read the 334 VXNlcm5hbWU6 challenge ("Username:" base64-encoded) */
891 int rc = mutt_socket_readln_d(buf, sizeof(buf), adata->conn, MUTT_SOCK_LOG_FULL);
892 if ((rc < 0) || !mutt_str_equal(buf, "334 VXNlcm5hbWU6"))
893 {
894 goto error;
895 }
896
897 /* Send the username */
898 size_t len = snprintf(buf, sizeof(buf), "%s", adata->conn->account.user);
899 mutt_b64_encode(buf, len, b64, sizeof(b64));
900 snprintf(buf, sizeof(buf), "%s\r\n", b64);
901 if (mutt_socket_send(adata->conn, buf) < 0)
902 {
903 goto error;
904 }
905
906 /* Read the 334 UGFzc3dvcmQ6 challenge ("Password:" base64-encoded) */
907 rc = mutt_socket_readln_d(buf, sizeof(buf), adata->conn, MUTT_SOCK_LOG_FULL);
908 if ((rc < 0) || !mutt_str_equal(buf, "334 UGFzc3dvcmQ6"))
909 {
910 goto error;
911 }
912
913 /* Send the password */
914 len = snprintf(buf, sizeof(buf), "%s", adata->conn->account.pass);
915 mutt_b64_encode(buf, len, b64, sizeof(b64));
916 snprintf(buf, sizeof(buf), "%s\r\n", b64);
917 if (mutt_socket_send(adata->conn, buf) < 0)
918 {
919 goto error;
920 }
921
922 /* Check the final response */
923 if (smtp_get_resp(adata) < 0)
924 {
925 goto error;
926 }
927
928 /* If we got here, auth was successful. */
929 return 0;
930
931error:
932 // L10N: %s is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
933 mutt_error(_("%s authentication failed"), "LOGIN");
934 return -1;
935}
936
940static const struct SmtpAuth SmtpAuthenticators[] = {
941 // clang-format off
942 { smtp_auth_oauth, "oauthbearer" },
943 { smtp_auth_xoauth2, "xoauth2" },
944 { smtp_auth_plain, "plain" },
945 { smtp_auth_login, "login" },
946#ifdef USE_SASL_CYRUS
947 { smtp_auth_sasl, NULL },
948#endif
949#ifdef USE_SASL_GNU
950 { smtp_auth_gsasl, NULL },
951#endif
952 // clang-format on
953};
954
963bool smtp_auth_is_valid(const char *authenticator)
964{
965 for (size_t i = 0; i < countof(SmtpAuthenticators); i++)
966 {
967 const struct SmtpAuth *auth = &SmtpAuthenticators[i];
968 if (auth->method && mutt_istr_equal(auth->method, authenticator))
969 return true;
970 }
971
972 return false;
973}
974
981static int smtp_authenticate(struct SmtpAccountData *adata)
982{
983 int r = SMTP_AUTH_UNAVAIL;
984
985 const struct Slist *c_smtp_authenticators = cs_subset_slist(adata->sub, "smtp_authenticators");
986 if (c_smtp_authenticators && (c_smtp_authenticators->count > 0))
987 {
988 mutt_debug(LL_DEBUG2, "Trying user-defined smtp_authenticators\n");
989
990 /* Try user-specified list of authentication methods */
991 struct ListNode *np = NULL;
992 STAILQ_FOREACH(np, &c_smtp_authenticators->head, entries)
993 {
994 mutt_debug(LL_DEBUG2, "Trying method %s\n", np->data);
995
996 for (size_t i = 0; i < countof(SmtpAuthenticators); i++)
997 {
998 const struct SmtpAuth *auth = &SmtpAuthenticators[i];
999 if (!auth->method || mutt_istr_equal(auth->method, np->data))
1000 {
1001 r = auth->authenticate(adata, np->data);
1002 if (r == SMTP_AUTH_SUCCESS)
1003 return r;
1004 }
1005 }
1006 }
1007 }
1008 else
1009 {
1010 /* Fall back to default: any authenticator */
1011#if defined(USE_SASL_CYRUS)
1012 mutt_debug(LL_DEBUG2, "Falling back to smtp_auth_sasl, if using sasl\n");
1013 r = smtp_auth_sasl(adata, adata->auth_mechs);
1014#elif defined(USE_SASL_GNU)
1015 mutt_debug(LL_DEBUG2, "Falling back to smtp_auth_gsasl, if using gsasl\n");
1016 r = smtp_auth_gsasl(adata, adata->auth_mechs);
1017#else
1018 mutt_debug(LL_DEBUG2, "Falling back to using any authenticator available\n");
1019 /* Try all available authentication methods */
1020 for (size_t i = 0; i < countof(SmtpAuthenticators); i++)
1021 {
1022 const struct SmtpAuth *auth = &SmtpAuthenticators[i];
1023 mutt_debug(LL_DEBUG2, "Trying method %s\n", auth->method ? auth->method : "<variable>");
1024 r = auth->authenticate(adata, auth->method);
1025 if (r == SMTP_AUTH_SUCCESS)
1026 return r;
1027 }
1028#endif
1029 }
1030
1031 if (r != SMTP_AUTH_SUCCESS)
1033
1034 if (r == SMTP_AUTH_FAIL)
1035 {
1036 // L10N: %s is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
1037 mutt_error(_("%s authentication failed"), "SASL");
1038 }
1039 else if (r == SMTP_AUTH_UNAVAIL)
1040 {
1041 mutt_error(_("No authenticators available"));
1042 }
1043
1044 return (r == SMTP_AUTH_SUCCESS) ? 0 : -1;
1045}
1046
1054static int smtp_open(struct SmtpAccountData *adata, bool esmtp)
1055{
1056 int rc;
1057
1058 if (mutt_socket_open(adata->conn))
1059 return -1;
1060
1061 const bool force_auth = cs_subset_string(adata->sub, "smtp_user");
1062 esmtp |= force_auth;
1063
1064 /* get greeting string */
1065 rc = smtp_get_resp(adata);
1066 if (rc != 0)
1067 return rc;
1068
1069 rc = smtp_helo(adata, esmtp);
1070 if (rc != 0)
1071 return rc;
1072
1073#ifdef USE_SSL
1074 const bool c_ssl_force_tls = cs_subset_bool(adata->sub, "ssl_force_tls");
1075 enum QuadOption ans = MUTT_NO;
1076 if (adata->conn->ssf != 0)
1077 ans = MUTT_NO;
1078 else if (c_ssl_force_tls)
1079 ans = MUTT_YES;
1080 else if ((adata->capabilities & SMTP_CAP_STARTTLS) &&
1081 ((ans = query_quadoption(_("Secure connection with TLS?"),
1082 adata->sub, "ssl_starttls")) == MUTT_ABORT))
1083 {
1084 return -1;
1085 }
1086
1087 if (ans == MUTT_YES)
1088 {
1089 if (mutt_socket_send(adata->conn, "STARTTLS\r\n") < 0)
1090 return SMTP_ERR_WRITE;
1091 rc = smtp_get_resp(adata);
1092 // Clear any data after the STARTTLS acknowledgement
1093 mutt_socket_empty(adata->conn);
1094 if (rc != 0)
1095 return rc;
1096
1097 if (mutt_ssl_starttls(adata->conn) != 0)
1098 {
1099 mutt_error(_("Could not negotiate TLS connection"));
1100 return -1;
1101 }
1102
1103 /* re-EHLO to get authentication mechanisms */
1104 rc = smtp_helo(adata, esmtp);
1105 if (rc != 0)
1106 return rc;
1107 }
1108#endif
1109
1110 if (force_auth || adata->conn->account.flags & MUTT_ACCT_USER)
1111 {
1112 if (!(adata->capabilities & SMTP_CAP_AUTH))
1113 {
1114 mutt_error(_("SMTP server does not support authentication"));
1115 return -1;
1116 }
1117
1118 return smtp_authenticate(adata);
1119 }
1120
1121 return 0;
1122}
1123
1136int mutt_smtp_send(const struct AddressList *from, const struct AddressList *to,
1137 const struct AddressList *cc, const struct AddressList *bcc,
1138 const char *msgfile, bool eightbit, struct ConfigSubset *sub)
1139{
1140 struct SmtpAccountData adata = { 0 };
1141 struct ConnAccount cac = { { 0 } };
1142 const char *envfrom = NULL;
1143 int rc = -1;
1144
1145 adata.sub = sub;
1146 adata.fqdn = mutt_fqdn(false, adata.sub);
1147 if (!adata.fqdn)
1148 adata.fqdn = NONULL(ShortHostname);
1149
1150 const struct Address *c_envelope_from_address = cs_subset_address(adata.sub, "envelope_from_address");
1151
1152 if (smtp_fill_account(&adata, &cac) < 0)
1153 return rc;
1154
1155 adata.conn = mutt_conn_find(&cac);
1156 if (!adata.conn)
1157 return -1;
1158
1159 /* it might be better to synthesize an envelope from from user and host
1160 * but this condition is most likely arrived at accidentally */
1161 if (c_envelope_from_address)
1162 {
1163 envfrom = buf_string(c_envelope_from_address->mailbox);
1164 }
1165 else if (from && !TAILQ_EMPTY(from))
1166 {
1167 envfrom = buf_string(TAILQ_FIRST(from)->mailbox);
1168 }
1169 else
1170 {
1171 mutt_error(_("No from address given"));
1172 mutt_socket_close(adata.conn);
1173 return -1;
1174 }
1175
1176 const char *const c_dsn_return = cs_subset_string(adata.sub, "dsn_return");
1177
1178 struct Buffer *buf = buf_pool_get();
1179 do
1180 {
1181 /* send our greeting */
1182 rc = smtp_open(&adata, eightbit);
1183 if (rc != 0)
1184 break;
1185 FREE(&adata.auth_mechs);
1186
1187 /* send the sender's address */
1188 buf_printf(buf, "MAIL FROM:<%s>", envfrom);
1189 if (eightbit && (adata.capabilities & SMTP_CAP_EIGHTBITMIME))
1190 buf_addstr(buf, " BODY=8BITMIME");
1191
1192 if (c_dsn_return && (adata.capabilities & SMTP_CAP_DSN))
1193 buf_add_printf(buf, " RET=%s", c_dsn_return);
1194
1195 if ((adata.capabilities & SMTP_CAP_SMTPUTF8) &&
1198 {
1199 buf_addstr(buf, " SMTPUTF8");
1200 }
1201 buf_addstr(buf, "\r\n");
1202 if (mutt_socket_send(adata.conn, buf_string(buf)) == -1)
1203 {
1204 rc = SMTP_ERR_WRITE;
1205 break;
1206 }
1207 rc = smtp_get_resp(&adata);
1208 if (rc != 0)
1209 break;
1210
1211 /* send the recipient list */
1212 if ((rc = smtp_rcpt_to(&adata, to)) || (rc = smtp_rcpt_to(&adata, cc)) ||
1213 (rc = smtp_rcpt_to(&adata, bcc)))
1214 {
1215 break;
1216 }
1217
1218 /* send the message data */
1219 rc = smtp_data(&adata, msgfile);
1220 if (rc != 0)
1221 break;
1222
1223 mutt_socket_send(adata.conn, "QUIT\r\n");
1224
1225 rc = 0;
1226 } while (false);
1227
1228 mutt_socket_close(adata.conn);
1229 FREE(&adata.conn);
1230 FREE(&adata.auth_mechs);
1231
1232 if (rc == SMTP_ERR_READ)
1233 mutt_error(_("SMTP session failed: read error"));
1234 else if (rc == SMTP_ERR_WRITE)
1235 mutt_error(_("SMTP session failed: write error"));
1236 else if (rc == SMTP_ERR_CODE)
1237 mutt_error(_("Invalid server response"));
1238
1239 buf_pool_release(&buf);
1240 return rc;
1241}
bool mutt_addrlist_uses_unicode(const struct AddressList *al)
Do any of a list of addresses use Unicode characters.
Definition address.c:1538
bool mutt_addr_uses_unicode(const char *str)
Does this address use Unicode character.
Definition address.c:1518
const struct Address * cs_subset_address(const struct ConfigSubset *sub, const char *name)
Get an Address config item by name.
Email Address Handling.
const char * mutt_str_atoi(const char *str, int *dst)
Convert ASCII string to an integer.
Definition atoi.c:191
size_t mutt_b64_encode(const char *in, size_t inlen, char *out, size_t outlen)
Convert raw bytes to a base64 string.
Definition base64.c:148
size_t mutt_b64_buffer_encode(struct Buffer *buf, const char *in, size_t len)
Convert raw bytes to NUL-terminated base64 string.
Definition base64.c:243
int mutt_b64_buffer_decode(struct Buffer *buf, const char *in)
Convert NUL-terminated base64 string to raw bytes.
Definition base64.c:261
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:168
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition buffer.c:211
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition buffer.c:497
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:89
char buf_at(const struct Buffer *buf, size_t offset)
Return the character at the given offset.
Definition buffer.c:674
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:248
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:233
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:401
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
const struct Slist * cs_subset_slist(const struct ConfigSubset *sub, const char *name)
Get a string-list config item by name.
Definition helpers.c:242
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition helpers.c:192
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
Convenience wrapper for the config headers.
Connection Library.
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.
Definition connaccount.c:51
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.
Definition connaccount.h:33
@ MUTT_CA_OAUTH_CMD
OAuth refresh command.
Definition connaccount.h:38
@ MUTT_CA_USER
User name.
Definition connaccount.h:36
@ MUTT_CA_LOGIN
Login name.
Definition connaccount.h:35
@ MUTT_CA_HOST
Server name.
Definition connaccount.h:34
@ MUTT_CA_PASS
Password.
Definition connaccount.h:37
@ MUTT_ACCT_SSL
Account uses SSL/TLS.
Definition connaccount.h:51
@ MUTT_ACCT_USER
User field has been set.
Definition connaccount.h:48
Convenience wrapper for the core headers.
Structs that make up an email.
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition file.c:1433
#define mutt_file_fclose(FP)
Definition file.h:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
char * ShortHostname
Short version of the hostname.
Definition globals.c:36
bool OptGui
(pseudo) when the gui (and curses) are started
Definition globals.c:48
Global variables.
int mutt_ssl_starttls(struct Connection *conn)
Negotiate TLS over an already opened connection.
Definition gnutls.c:1175
static const char * smtp_get_field(enum ConnAccountField field, void *gf_data)
Get connection login credentials - Implements ConnAccount::get_field() -.
Definition smtp.c:332
#define mutt_error(...)
Definition logging2.h:94
#define mutt_message(...)
Definition logging2.h:93
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
static int smtp_auth_xoauth2(struct SmtpAccountData *adata, const char *method)
Authenticate an SMTP connection using XOAUTH2 - Implements SmtpAuth::authenticate() -.
Definition smtp.c:818
static int smtp_auth_login(struct SmtpAccountData *adata, const char *method)
Authenticate using plain text - Implements SmtpAuth::authenticate() -.
Definition smtp.c:872
static int smtp_auth_plain(struct SmtpAccountData *adata, const char *method)
Authenticate using plain text - Implements SmtpAuth::authenticate() -.
Definition smtp.c:832
static int smtp_auth_oauth(struct SmtpAccountData *adata, const char *method)
Authenticate an SMTP connection using OAUTHBEARER - Implements SmtpAuth::authenticate() -.
Definition smtp.c:807
const char * mutt_gsasl_get_mech(const char *requested_mech, const char *server_mechlist)
Pick a connection mechanism.
Definition gsasl.c:166
int mutt_gsasl_client_new(struct Connection *conn, const char *mech, Gsasl_session **sctx)
Create a new GNU SASL client.
Definition gsasl.c:203
void mutt_gsasl_client_finish(Gsasl_session **sctx)
Free a GNU SASL client.
Definition gsasl.c:225
@ LL_DEBUG3
Log at debug level 3.
Definition logging2.h:47
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
#define countof(x)
Definition memory.h:49
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#define MAX(a, b)
Return the maximum of two values.
Definition memory.h:38
Convenience wrapper for the library headers.
#define _(a)
Definition message.h:28
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:678
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition string.c:809
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:666
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition string.c:246
int account_from_url(struct ConnAccount *cac, const struct Url *url)
Fill ConnAccount with information from url.
@ MUTT_ACCT_TYPE_SMTP
Smtp Account.
struct Connection * mutt_conn_find(const struct ConnAccount *cac)
Find a connection from a list.
Definition mutt_socket.c:88
NeoMutt connections.
void mutt_sleep(short s)
Sleep for a while.
Definition muttlib.c:787
Some miscellaneous functions.
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
Progress Bar.
@ MUTT_PROGRESS_NET
Progress tracks bytes, according to $net_inc
Definition lib.h:83
struct Progress * progress_new(enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition progress.c:139
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition progress.c:110
void progress_set_message(struct Progress *progress, const char *fmt,...) __attribute__((__format__(__printf__
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition progress.c:80
QuadOption
Possible values for a quad-option.
Definition quad.h:36
@ MUTT_ABORT
User aborted the question (with Ctrl-G)
Definition quad.h:37
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition quad.h:38
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition quad.h:39
Ask the user a question.
enum QuadOption query_quadoption(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
Definition question.c:384
#define TAILQ_FOREACH(var, head, field)
Definition queue.h:782
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
#define TAILQ_FIRST(head)
Definition queue.h:780
#define TAILQ_EMPTY(head)
Definition queue.h:778
int mutt_sasl_interact(sasl_interact_t *interaction)
Perform an SASL interaction with the user.
Definition sasl.c:710
int mutt_sasl_client_new(struct Connection *conn, sasl_conn_t **saslconn)
Wrapper for sasl_client_new()
Definition sasl.c:612
void mutt_sasl_setup_conn(struct Connection *conn, sasl_conn_t *saslconn)
Set up an SASL connection.
Definition sasl.c:746
size_t mutt_sasl_plain_msg(struct Buffer *buf, const char *cmd, const char *authz, const char *user, const char *pass)
Construct a base64 encoded SASL PLAIN message.
Definition sasl_plain.c:50
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition sendlib.c:717
Miscellaneous functions for sending an email.
static int smtp_get_resp(struct SmtpAccountData *adata)
Read a command response from the SMTP server.
Definition smtp.c:146
#define SMTPS_PORT
Default SMTPS (SMTP over SSL) port.
Definition smtp.c:74
uint8_t SmtpCapFlags
Definition smtp.c:94
static int smtp_authenticate(struct SmtpAccountData *adata)
Authenticate to an SMTP server.
Definition smtp.c:981
#define SMTP_ERR_READ
Error reading from server.
Definition smtp.c:69
bool smtp_auth_is_valid(const char *authenticator)
Check if string is a valid smtp authentication method.
Definition smtp.c:963
static int smtp_auth_oauth_xoauth2(struct SmtpAccountData *adata, const char *method, bool xoauth2)
Authenticate an SMTP connection using OAUTHBEARER/XOAUTH2.
Definition smtp.c:769
static const struct SmtpAuth SmtpAuthenticators[]
Accepted authentication methods.
Definition smtp.c:940
static bool valid_smtp_code(char *buf, int *n)
Is the is a valid SMTP return code?
Definition smtp.c:135
#define SMTP_AUTH_UNAVAIL
Authentication method unavailable.
Definition smtp.c:77
static int smtp_helo(struct SmtpAccountData *adata, bool esmtp)
Say hello to an SMTP Server.
Definition smtp.c:425
#define SMTP_ERR_CODE
Invalid server response code.
Definition smtp.c:71
#define smtp_success(x)
Check if SMTP response code indicates success (2xx codes)
Definition smtp.c:65
#define SMTP_AUTH_FAIL
Authentication failed.
Definition smtp.c:78
static int smtp_data(struct SmtpAccountData *adata, const char *msgfile)
Send data to an SMTP server.
Definition smtp.c:251
#define SMTP_ERR_WRITE
Error writing to server.
Definition smtp.c:70
static int smtp_fill_account(struct SmtpAccountData *adata, struct ConnAccount *cac)
Create ConnAccount object from SMTP Url.
Definition smtp.c:369
#define SMTP_AUTH_SUCCESS
Authentication completed successfully.
Definition smtp.c:76
SmtpCapFlag
SMTP server capabilities.
Definition smtp.c:84
@ SMTP_CAP_SMTPUTF8
Server accepts UTF-8 strings.
Definition smtp.c:91
@ SMTP_CAP_EIGHTBITMIME
Server supports 8-bit MIME content.
Definition smtp.c:90
@ SMTP_CAP_DSN
Server supports Delivery Status Notification.
Definition smtp.c:89
@ SMTP_CAP_NONE
No flags are set.
Definition smtp.c:86
@ SMTP_CAP_AUTH
Server supports AUTH command.
Definition smtp.c:88
@ SMTP_CAP_STARTTLS
Server supports STARTTLS command.
Definition smtp.c:87
#define SMTP_CONTINUE
SMTP server ready to accept message data.
Definition smtp.c:67
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.
Definition smtp.c:1136
static int smtp_rcpt_to(struct SmtpAccountData *adata, const struct AddressList *al)
Set the recipient to an Address.
Definition smtp.c:204
static int smtp_open(struct SmtpAccountData *adata, bool esmtp)
Open an SMTP Connection.
Definition smtp.c:1054
#define SMTP_PORT
Default SMTP port.
Definition smtp.c:73
#define SMTP_READY
SMTP server ready for authentication data.
Definition smtp.c:66
Send email to an SMTP server.
int mutt_socket_close(struct Connection *conn)
Close a socket.
Definition socket.c:100
void mutt_socket_empty(struct Connection *conn)
Clear out any queued data.
Definition socket.c:306
int mutt_socket_open(struct Connection *conn)
Simple wrapper.
Definition socket.c:76
int mutt_socket_readln_d(char *buf, size_t buflen, struct Connection *conn, int dbg)
Read a line from a socket.
Definition socket.c:238
#define MUTT_SOCK_LOG_FULL
Log everything including full protocol.
Definition socket.h:53
#define mutt_socket_readln(buf, buflen, conn)
Definition socket.h:55
#define mutt_socket_send(conn, buf)
Definition socket.h:56
#define mutt_socket_buffer_readln(buf, conn)
Definition socket.h:60
#define mutt_socket_send_d(conn, buf, dbg)
Definition socket.h:57
#define NONULL(x)
Definition string2.h:44
An email address.
Definition address.h:35
bool group
Group mailbox?
Definition address.h:38
struct Buffer * mailbox
Mailbox and host address.
Definition address.h:37
String manipulation buffer.
Definition buffer.h:36
char * data
Pointer to data.
Definition buffer.h:37
A set of inherited config items.
Definition subset.h:46
Login details for a remote server.
Definition connaccount.h:59
char user[128]
Username.
Definition connaccount.h:62
char pass[256]
Password.
Definition connaccount.h:63
const char * service
Name of the service, e.g. "imap".
Definition connaccount.h:67
const char *(* get_field)(enum ConnAccountField field, void *gf_data)
Definition connaccount.h:76
unsigned char type
Connection type, e.g. MUTT_ACCT_TYPE_IMAP.
Definition connaccount.h:65
MuttAccountFlags flags
Which fields are initialised, e.g. MUTT_ACCT_USER.
Definition connaccount.h:66
void * gf_data
Private data to pass to get_field()
Definition connaccount.h:78
unsigned short port
Port to connect to.
Definition connaccount.h:64
unsigned int ssf
Security strength factor, in bits (see notes)
Definition connection.h:50
struct ConnAccount account
Account details: username, password, etc.
Definition connection.h:49
A List node for strings.
Definition list.h:37
char * data
String.
Definition list.h:38
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
String list.
Definition slist.h:37
struct ListHead head
List containing values.
Definition slist.h:38
size_t count
Number of values in list.
Definition slist.h:39
Server connection data.
Definition smtp.c:102
const char * fqdn
Fully-qualified domain name.
Definition smtp.c:107
struct ConfigSubset * sub
Config scope.
Definition smtp.c:106
struct Connection * conn
Server Connection.
Definition smtp.c:105
const char * auth_mechs
Allowed authorisation mechanisms.
Definition smtp.c:103
SmtpCapFlags capabilities
Server capabilities.
Definition smtp.c:104
SMTP authentication multiplexor.
Definition smtp.c:114
int(* authenticate)(struct SmtpAccountData *adata, const char *method)
Definition smtp.c:123
const char * method
Name of authentication method supported, NULL means variable.
Definition smtp.c:125
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition url.h:69
char * host
Host.
Definition url.h:73
enum UrlScheme scheme
Scheme, e.g. U_SMTPS.
Definition url.h:70
struct Url * url_parse(const char *src)
Fill in Url.
Definition url.c:242
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition url.c:124
@ U_SMTPS
Url is smtps://.
Definition url.h:44
@ U_SMTP
Url is smtp://.
Definition url.h:43