2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2022 the Claws Mail team and Hiroyuki Yamamoto
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "claws-features.h"
27 #include <glib/gi18n.h>
40 static void smtp_session_destroy(Session
*session
);
42 static gint
smtp_auth(SMTPSession
*session
);
44 static gint
smtp_starttls(SMTPSession
*session
);
47 static gint
smtp_auth_oauth2(SMTPSession
*session
);
49 static gint
smtp_auth_cram_md5(SMTPSession
*session
);
50 static gint
smtp_auth_login(SMTPSession
*session
);
51 static gint
smtp_auth_plain(SMTPSession
*session
);
53 static gint
smtp_ehlo(SMTPSession
*session
);
54 static gint
smtp_ehlo_recv(SMTPSession
*session
, const gchar
*msg
);
56 static gint
smtp_helo(SMTPSession
*session
);
57 static gint
smtp_rcpt(SMTPSession
*session
);
58 static gint
smtp_data(SMTPSession
*session
);
59 static gint
smtp_send_data(SMTPSession
*session
);
60 static gint
smtp_make_ready(SMTPSession
*session
);
61 static gint
smtp_eom(SMTPSession
*session
);
63 static gint
smtp_session_recv_msg(Session
*session
, const gchar
*msg
);
64 static gint
smtp_session_send_data_finished(Session
*session
, guint len
);
67 Session
*smtp_session_new(void *prefs_account
)
71 session
= g_new0(SMTPSession
, 1);
73 session_init(SESSION(session
), prefs_account
, TRUE
);
75 SESSION(session
)->type
= SESSION_SMTP
;
77 SESSION(session
)->recv_msg
= smtp_session_recv_msg
;
79 SESSION(session
)->recv_data_finished
= NULL
;
80 SESSION(session
)->send_data_finished
= smtp_session_send_data_finished
;
82 SESSION(session
)->destroy
= smtp_session_destroy
;
84 session
->state
= SMTP_READY
;
87 session
->tls_init_done
= FALSE
;
90 session
->hostname
= NULL
;
95 session
->to_list
= NULL
;
96 session
->cur_to
= NULL
;
98 session
->send_data
= NULL
;
99 session
->send_data_len
= 0;
101 session
->max_message_size
= -1;
103 session
->avail_auth_type
= 0;
104 session
->forced_auth_type
= 0;
105 session
->auth_type
= 0;
106 session
->esmtp_flags
= 0;
108 session
->error_val
= SM_OK
;
109 session
->error_msg
= NULL
;
111 return SESSION(session
);
114 static void smtp_session_destroy(Session
*session
)
116 SMTPSession
*smtp_session
= SMTP_SESSION(session
);
118 g_free(smtp_session
->hostname
);
119 g_free(smtp_session
->user
);
120 g_free(smtp_session
->pass
);
121 g_free(smtp_session
->from
);
123 g_free(smtp_session
->send_data
);
125 g_free(smtp_session
->error_msg
);
128 gint
smtp_from(SMTPSession
*session
)
130 gchar buf
[MESSAGEBUFSIZE
];
131 gchar
*mail_size
= NULL
;
133 cm_return_val_if_fail(session
->from
!= NULL
, SM_ERROR
);
135 session
->state
= SMTP_FROM
;
137 if (session
->is_esmtp
&& (session
->esmtp_flags
& ESMTP_SIZE
)!=0)
138 mail_size
= g_strdup_printf(" SIZE=%d", session
->send_data_len
);
140 mail_size
= g_strdup("");
143 if (strchr(session
->from
, '<'))
144 g_snprintf(buf
, sizeof(buf
), "MAIL FROM:%s%s", session
->from
,
147 g_snprintf(buf
, sizeof(buf
), "MAIL FROM:<%s>%s", session
->from
,
152 if (session_send_msg(SESSION(session
), buf
) < 0)
154 log_print(LOG_PROTOCOL
, "%sSMTP> %s\n", (session
->is_esmtp
?"E":""), buf
);
159 static gint
smtp_auth(SMTPSession
*session
)
162 cm_return_val_if_fail(session
->user
!= NULL
, SM_ERROR
);
164 session
->state
= SMTP_AUTH
;
166 if ((session
->forced_auth_type
== SMTPAUTH_CRAM_MD5
167 || session
->forced_auth_type
== 0)
169 (session
->avail_auth_type
& SMTPAUTH_CRAM_MD5
) != 0)
170 smtp_auth_cram_md5(session
);
171 else if ((session
->forced_auth_type
== SMTPAUTH_LOGIN
172 || session
->forced_auth_type
== 0)
174 (session
->avail_auth_type
& SMTPAUTH_LOGIN
) != 0)
175 smtp_auth_login(session
);
176 else if ((session
->forced_auth_type
== SMTPAUTH_PLAIN
177 || session
->forced_auth_type
== 0)
179 (session
->avail_auth_type
& SMTPAUTH_PLAIN
) != 0)
180 smtp_auth_plain(session
);
182 else if ((session
->forced_auth_type
== SMTPAUTH_OAUTH2
183 || session
->forced_auth_type
== 0)
185 (session
->avail_auth_type
& SMTPAUTH_OAUTH2
) != 0)
186 smtp_auth_oauth2(session
);
188 else if (session
->forced_auth_type
== 0) {
189 log_warning(LOG_PROTOCOL
, _("No SMTP AUTH method available\n"));
192 log_warning(LOG_PROTOCOL
, _("Selected SMTP AUTH method not available\n"));
199 static gint
smtp_auth_recv(SMTPSession
*session
, const gchar
*msg
)
201 gchar buf
[MESSAGEBUFSIZE
], *tmp
;
203 switch (session
->auth_type
) {
205 session
->state
= SMTP_AUTH_LOGIN_USER
;
207 if (!strncmp(msg
, "334 ", 4)) {
208 tmp
= g_base64_encode(session
->user
, strlen(session
->user
));
210 if (session_send_msg(SESSION(session
), tmp
) < 0) {
215 log_print(LOG_PROTOCOL
, "ESMTP> [USERID]\n");
217 /* Server rejects AUTH */
218 if (session_send_msg(SESSION(session
), "*") < 0)
220 log_print(LOG_PROTOCOL
, "ESMTP> *\n");
223 case SMTPAUTH_CRAM_MD5
:
224 session
->state
= SMTP_AUTH_CRAM_MD5
;
226 if (!strncmp(msg
, "334 ", 4)) {
231 guchar hexdigest
[33];
233 challenge
= g_base64_decode_zero(msg
+ 4, &challengelen
);
234 log_print(LOG_PROTOCOL
, "ESMTP< [Decoded: %s]\n", challenge
);
236 g_snprintf(buf
, sizeof(buf
), "%s", session
->pass
);
237 md5_hex_hmac(hexdigest
, challenge
, challengelen
,
238 buf
, strlen(session
->pass
));
241 response
= g_strdup_printf
242 ("%s %s", session
->user
, hexdigest
);
243 log_print(LOG_PROTOCOL
, "ESMTP> [Encoded: %s]\n", response
);
245 response64
= g_base64_encode(response
, strlen(response
));
248 if (session_send_msg(SESSION(session
), response64
) < 0) {
252 log_print(LOG_PROTOCOL
, "ESMTP> %s\n", response64
);
255 /* Server rejects AUTH */
256 if (session_send_msg(SESSION(session
), "*") < 0)
258 log_print(LOG_PROTOCOL
, "ESMTP> *\n");
261 case SMTPAUTH_DIGEST_MD5
:
263 /* stop smtp_auth when no correct authtype */
264 if (session_send_msg(SESSION(session
), "*") < 0)
266 log_print(LOG_PROTOCOL
, "ESMTP> *\n");
273 static gint
smtp_auth_login_user_recv(SMTPSession
*session
, const gchar
*msg
)
277 session
->state
= SMTP_AUTH_LOGIN_PASS
;
279 if (!strncmp(msg
, "334 ", 4)) {
280 tmp
= g_base64_encode(session
->pass
, strlen(session
->pass
));
282 /* Server rejects AUTH */
286 if (session_send_msg(SESSION(session
), tmp
) < 0) {
292 log_print(LOG_PROTOCOL
, "ESMTP> [PASSWORD]\n");
297 static gint
smtp_ehlo(SMTPSession
*session
)
299 gchar buf
[MESSAGEBUFSIZE
];
301 session
->state
= SMTP_EHLO
;
303 session
->avail_auth_type
= 0;
305 g_snprintf(buf
, sizeof(buf
), "EHLO %s",
306 session
->hostname
? session
->hostname
: get_domain_name());
307 if (session_send_msg(SESSION(session
), buf
) < 0)
309 log_print(LOG_PROTOCOL
, "ESMTP> %s\n", buf
);
314 static gint
smtp_ehlo_recv(SMTPSession
*session
, const gchar
*msg
)
316 if (strncmp(msg
, "250", 3) == 0) {
317 const gchar
*p
= msg
;
319 if (*p
== '-' || *p
== ' ') p
++;
320 if (g_ascii_strncasecmp(p
, "AUTH", 4) == 0) {
322 if (strcasestr(p
, "PLAIN"))
323 session
->avail_auth_type
|= SMTPAUTH_PLAIN
;
324 if (strcasestr(p
, "LOGIN"))
325 session
->avail_auth_type
|= SMTPAUTH_LOGIN
;
326 if (strcasestr(p
, "CRAM-MD5"))
327 session
->avail_auth_type
|= SMTPAUTH_CRAM_MD5
;
328 if (strcasestr(p
, "DIGEST-MD5"))
329 session
->avail_auth_type
|= SMTPAUTH_DIGEST_MD5
;
331 if (strcasestr(p
, "XOAUTH2"))
332 session
->avail_auth_type
|= SMTPAUTH_OAUTH2
;
335 if (g_ascii_strncasecmp(p
, "SIZE", 4) == 0) {
337 session
->max_message_size
= atoi(p
);
338 session
->esmtp_flags
|= ESMTP_SIZE
;
340 if (g_ascii_strncasecmp(p
, "STARTTLS", 8) == 0) {
342 session
->avail_auth_type
|= SMTPAUTH_TLS_AVAILABLE
;
345 } else if ((msg
[0] == '1' || msg
[0] == '2' || msg
[0] == '3') &&
346 (msg
[3] == ' ' || msg
[3] == '\0'))
348 else if (msg
[0] == '5' && msg
[1] == '0' &&
349 (msg
[2] == '4' || msg
[2] == '3' || msg
[2] == '1'))
356 static gint
smtp_starttls(SMTPSession
*session
)
358 session
->state
= SMTP_STARTTLS
;
360 if (session_send_msg(SESSION(session
), "STARTTLS") < 0)
362 log_print(LOG_PROTOCOL
, "ESMTP> STARTTLS\n");
368 static gint
smtp_auth_cram_md5(SMTPSession
*session
)
370 session
->state
= SMTP_AUTH
;
371 session
->auth_type
= SMTPAUTH_CRAM_MD5
;
373 if (session_send_msg(SESSION(session
), "AUTH CRAM-MD5") < 0)
375 log_print(LOG_PROTOCOL
, "ESMTP> AUTH CRAM-MD5\n");
380 static gint
smtp_auth_plain(SMTPSession
*session
)
382 gchar buf
[MESSAGEBUFSIZE
], *b64buf
, *out
;
385 session
->state
= SMTP_AUTH_PLAIN
;
386 session
->auth_type
= SMTPAUTH_PLAIN
;
388 memset(buf
, 0, sizeof buf
);
390 /* "\0user\0password" */
391 len
= sprintf(buf
, "%c%s%c%s", '\0', session
->user
, '\0', session
->pass
);
392 b64buf
= g_base64_encode(buf
, len
);
393 out
= g_strconcat("AUTH PLAIN ", b64buf
, NULL
);
396 if (session_send_msg(SESSION(session
), out
) < 0) {
403 log_print(LOG_PROTOCOL
, "ESMTP> [AUTH PLAIN]\n");
409 static gint
smtp_auth_oauth2(SMTPSession
*session
)
411 gchar buf
[MESSAGEBUFSIZE
], *b64buf
, *out
;
414 session
->state
= SMTP_AUTH_OAUTH2
;
415 session
->auth_type
= SMTPAUTH_OAUTH2
;
417 memset(buf
, 0, sizeof buf
);
419 /* "user=" {User} "^Aauth=Bearer " {Access Token} "^A^A"*/
420 /* session->pass contains the OAUTH2 Access Token*/
421 len
= sprintf(buf
, "user=%s\1auth=Bearer %s\1\1", session
->user
, session
->pass
);
422 b64buf
= g_base64_encode(buf
, len
);
423 out
= g_strconcat("AUTH XOAUTH2 ", b64buf
, NULL
);
426 if (session_send_msg(SESSION(session
), out
) < 0) {
433 log_print(LOG_PROTOCOL
, "ESMTP> [AUTH XOAUTH2]\n");
439 static gint
smtp_auth_login(SMTPSession
*session
)
441 session
->state
= SMTP_AUTH
;
442 session
->auth_type
= SMTPAUTH_LOGIN
;
444 if (session_send_msg(SESSION(session
), "AUTH LOGIN") < 0)
446 log_print(LOG_PROTOCOL
, "ESMTP> AUTH LOGIN\n");
451 static gint
smtp_helo(SMTPSession
*session
)
453 gchar buf
[MESSAGEBUFSIZE
];
455 session
->state
= SMTP_HELO
;
457 g_snprintf(buf
, sizeof(buf
), "HELO %s",
458 session
->hostname
? session
->hostname
: get_domain_name());
459 if (session_send_msg(SESSION(session
), buf
) < 0)
461 log_print(LOG_PROTOCOL
, "SMTP> %s\n", buf
);
466 static gint
smtp_rcpt(SMTPSession
*session
)
468 gchar buf
[MESSAGEBUFSIZE
];
471 cm_return_val_if_fail(session
->cur_to
!= NULL
, SM_ERROR
);
473 session
->state
= SMTP_RCPT
;
475 to
= (gchar
*)session
->cur_to
->data
;
478 g_snprintf(buf
, sizeof(buf
), "RCPT TO:%s", to
);
480 g_snprintf(buf
, sizeof(buf
), "RCPT TO:<%s>", to
);
481 if (session_send_msg(SESSION(session
), buf
) < 0)
483 log_print(LOG_PROTOCOL
, "SMTP> %s\n", buf
);
485 session
->cur_to
= session
->cur_to
->next
;
490 static gint
smtp_data(SMTPSession
*session
)
492 session
->state
= SMTP_DATA
;
494 if (session_send_msg(SESSION(session
), "DATA") < 0)
496 log_print(LOG_PROTOCOL
, "SMTP> DATA\n");
501 static gint
smtp_send_data(SMTPSession
*session
)
503 session
->state
= SMTP_SEND_DATA
;
505 session_send_data(SESSION(session
), session
->send_data
,
506 session
->send_data_len
);
511 static gint
smtp_make_ready(SMTPSession
*session
)
513 session
->state
= SMTP_MAIL_SENT_OK
;
518 gint
smtp_quit(SMTPSession
*session
)
520 session
->state
= SMTP_QUIT
;
522 session_send_msg(SESSION(session
), "QUIT");
523 log_print(LOG_PROTOCOL
, "SMTP> QUIT\n");
528 static gint
smtp_eom(SMTPSession
*session
)
530 session
->state
= SMTP_EOM
;
532 if (session_send_msg(SESSION(session
), ".") < 0)
534 log_print(LOG_PROTOCOL
, "SMTP> . (EOM)\n");
539 static gint
smtp_session_recv_msg(Session
*session
, const gchar
*msg
)
541 SMTPSession
*smtp_session
= SMTP_SESSION(session
);
542 gboolean cont
= FALSE
;
545 if (strlen(msg
) < 4) {
546 log_warning(LOG_PROTOCOL
, _("bad SMTP response\n"));
550 switch (smtp_session
->state
) {
554 case SMTP_AUTH_PLAIN
:
555 case SMTP_AUTH_LOGIN_USER
:
556 case SMTP_AUTH_LOGIN_PASS
:
558 case SMTP_AUTH_OAUTH2
:
560 case SMTP_AUTH_CRAM_MD5
:
561 log_print(LOG_PROTOCOL
, "ESMTP< %s\n", msg
);
564 log_print(LOG_PROTOCOL
, "SMTP< %s\n", msg
);
568 /* ignore all multiline responses except for EHLO */
569 if (msg
[3] == '-' && smtp_session
->state
!= SMTP_EHLO
)
570 return session_recv_msg(session
);
572 if (msg
[0] == '5' && msg
[1] == '0' &&
573 (msg
[2] == '4' || msg
[2] == '3' || msg
[2] == '1')) {
574 log_warning(LOG_PROTOCOL
, _("error occurred on SMTP session\n"));
575 smtp_session
->state
= SMTP_ERROR
;
576 smtp_session
->error_val
= SM_ERROR
;
577 g_free(smtp_session
->error_msg
);
578 smtp_session
->error_msg
= g_strdup(msg
);
582 if (!strncmp(msg
, "535", 3)) {
583 log_warning(LOG_PROTOCOL
, _("error occurred on authentication\n"));
584 smtp_session
->state
= SMTP_ERROR
;
585 smtp_session
->error_val
= SM_AUTHFAIL
;
586 g_free(smtp_session
->error_msg
);
587 smtp_session
->error_msg
= g_strdup(msg
);
591 if (msg
[0] != '1' && msg
[0] != '2' && msg
[0] != '3') {
592 log_warning(LOG_PROTOCOL
, _("error occurred on SMTP session\n"));
593 smtp_session
->state
= SMTP_ERROR
;
594 smtp_session
->error_val
= SM_ERROR
;
595 g_free(smtp_session
->error_msg
);
596 smtp_session
->error_msg
= g_strdup(msg
);
602 else if (msg
[3] != ' ' && msg
[3] != '\0') {
603 log_warning(LOG_PROTOCOL
, _("bad SMTP response\n"));
604 smtp_session
->state
= SMTP_ERROR
;
605 smtp_session
->error_val
= SM_UNRECOVERABLE
;
609 switch (smtp_session
->state
) {
611 if (strstr(msg
, "ESMTP"))
612 smtp_session
->is_esmtp
= TRUE
;
614 if (smtp_session
->user
|| session
->ssl_type
!= SSL_NONE
||
615 smtp_session
->is_esmtp
)
617 if (smtp_session
->user
|| smtp_session
->is_esmtp
)
619 ret
= smtp_ehlo(smtp_session
);
621 ret
= smtp_helo(smtp_session
);
624 ret
= smtp_from(smtp_session
);
627 ret
= smtp_ehlo_recv(smtp_session
, msg
);
630 if (smtp_session
->max_message_size
> 0
631 && smtp_session
->max_message_size
<
632 smtp_session
->send_data_len
) {
633 log_warning(LOG_PROTOCOL
, _("Message is too big "
634 "(Maximum size is %s)\n"),
636 (goffset
)(smtp_session
->max_message_size
)));
637 smtp_session
->state
= SMTP_ERROR
;
638 smtp_session
->error_val
= SM_ERROR
;
642 if (session
->ssl_type
== SSL_STARTTLS
&&
643 smtp_session
->tls_init_done
== FALSE
) {
644 ret
= smtp_starttls(smtp_session
);
648 if (smtp_session
->user
) {
649 if (smtp_auth(smtp_session
) != SM_OK
) {
651 if (session
->ssl_type
== SSL_NONE
652 && smtp_session
->tls_init_done
== FALSE
653 && (smtp_session
->avail_auth_type
& SMTPAUTH_TLS_AVAILABLE
))
654 ret
= smtp_starttls(smtp_session
);
657 ret
= smtp_from(smtp_session
);
660 ret
= smtp_from(smtp_session
);
664 if (session_start_tls(session
) < 0) {
665 log_warning(LOG_PROTOCOL
, _("couldn't start STARTTLS session\n"));
666 smtp_session
->state
= SMTP_ERROR
;
667 smtp_session
->error_val
= SM_ERROR
;
670 smtp_session
->tls_init_done
= TRUE
;
671 ret
= smtp_ehlo(smtp_session
);
675 ret
= smtp_auth_recv(smtp_session
, msg
);
677 case SMTP_AUTH_LOGIN_USER
:
678 ret
= smtp_auth_login_user_recv(smtp_session
, msg
);
680 case SMTP_AUTH_PLAIN
:
681 case SMTP_AUTH_LOGIN_PASS
:
683 case SMTP_AUTH_OAUTH2
:
685 case SMTP_AUTH_CRAM_MD5
:
686 ret
= smtp_from(smtp_session
);
689 if (smtp_session
->cur_to
)
690 ret
= smtp_rcpt(smtp_session
);
693 if (smtp_session
->cur_to
)
694 ret
= smtp_rcpt(smtp_session
);
696 ret
= smtp_data(smtp_session
);
699 ret
= smtp_send_data(smtp_session
);
702 smtp_make_ready(smtp_session
);
705 session_disconnect(session
);
709 log_warning(LOG_PROTOCOL
, _("error occurred on SMTP session\n"));
710 smtp_session
->error_val
= SM_ERROR
;
714 if (cont
&& ret
== SM_OK
)
715 return session_recv_msg(session
);
718 smtp_session
->error_val
= SM_ERROR
;
720 return ret
== SM_OK
? 0 : -1;
723 static gint
smtp_session_send_data_finished(Session
*session
, guint len
)
725 return smtp_eom(SMTP_SESSION(session
));