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
->avail_auth_type
= 0;
102 session
->forced_auth_type
= 0;
103 session
->auth_type
= 0;
104 session
->esmtp_flags
= 0;
106 session
->error_val
= SM_OK
;
107 session
->error_msg
= NULL
;
109 return SESSION(session
);
112 static void smtp_session_destroy(Session
*session
)
114 SMTPSession
*smtp_session
= SMTP_SESSION(session
);
116 g_free(smtp_session
->hostname
);
117 g_free(smtp_session
->user
);
118 g_free(smtp_session
->pass
);
119 g_free(smtp_session
->from
);
121 g_free(smtp_session
->send_data
);
123 g_free(smtp_session
->error_msg
);
126 gint
smtp_from(SMTPSession
*session
)
128 gchar buf
[MESSAGEBUFSIZE
];
129 gchar
*mail_size
= NULL
;
131 cm_return_val_if_fail(session
->from
!= NULL
, SM_ERROR
);
133 session
->state
= SMTP_FROM
;
135 if (session
->is_esmtp
&& (session
->esmtp_flags
& ESMTP_SIZE
)!=0)
136 mail_size
= g_strdup_printf(" SIZE=%d", session
->send_data_len
);
138 mail_size
= g_strdup("");
141 if (strchr(session
->from
, '<'))
142 g_snprintf(buf
, sizeof(buf
), "MAIL FROM:%s%s", session
->from
,
145 g_snprintf(buf
, sizeof(buf
), "MAIL FROM:<%s>%s", session
->from
,
150 if (session_send_msg(SESSION(session
), buf
) < 0)
152 log_print(LOG_PROTOCOL
, "%sSMTP> %s\n", (session
->is_esmtp
?"E":""), buf
);
157 static gint
smtp_auth(SMTPSession
*session
)
160 cm_return_val_if_fail(session
->user
!= NULL
, SM_ERROR
);
162 session
->state
= SMTP_AUTH
;
164 if ((session
->forced_auth_type
== SMTPAUTH_CRAM_MD5
165 || session
->forced_auth_type
== 0)
167 (session
->avail_auth_type
& SMTPAUTH_CRAM_MD5
) != 0)
168 smtp_auth_cram_md5(session
);
169 else if ((session
->forced_auth_type
== SMTPAUTH_LOGIN
170 || session
->forced_auth_type
== 0)
172 (session
->avail_auth_type
& SMTPAUTH_LOGIN
) != 0)
173 smtp_auth_login(session
);
174 else if ((session
->forced_auth_type
== SMTPAUTH_PLAIN
175 || session
->forced_auth_type
== 0)
177 (session
->avail_auth_type
& SMTPAUTH_PLAIN
) != 0)
178 smtp_auth_plain(session
);
180 else if ((session
->forced_auth_type
== SMTPAUTH_OAUTH2
181 || session
->forced_auth_type
== 0)
183 (session
->avail_auth_type
& SMTPAUTH_OAUTH2
) != 0)
184 smtp_auth_oauth2(session
);
186 else if (session
->forced_auth_type
== 0) {
187 log_warning(LOG_PROTOCOL
, _("No SMTP AUTH method available\n"));
190 log_warning(LOG_PROTOCOL
, _("Selected SMTP AUTH method not available\n"));
197 static gint
smtp_auth_recv(SMTPSession
*session
, const gchar
*msg
)
199 gchar buf
[MESSAGEBUFSIZE
], *tmp
;
201 switch (session
->auth_type
) {
203 session
->state
= SMTP_AUTH_LOGIN_USER
;
205 if (!strncmp(msg
, "334 ", 4)) {
206 tmp
= g_base64_encode(session
->user
, strlen(session
->user
));
208 if (session_send_msg(SESSION(session
), tmp
) < 0) {
213 log_print(LOG_PROTOCOL
, "ESMTP> [USERID]\n");
215 /* Server rejects AUTH */
216 if (session_send_msg(SESSION(session
), "*") < 0)
218 log_print(LOG_PROTOCOL
, "ESMTP> *\n");
221 case SMTPAUTH_CRAM_MD5
:
222 session
->state
= SMTP_AUTH_CRAM_MD5
;
224 if (!strncmp(msg
, "334 ", 4)) {
229 guchar hexdigest
[33];
231 challenge
= g_base64_decode_zero(msg
+ 4, &challengelen
);
232 log_print(LOG_PROTOCOL
, "ESMTP< [Decoded: %s]\n", challenge
);
234 g_snprintf(buf
, sizeof(buf
), "%s", session
->pass
);
235 md5_hex_hmac(hexdigest
, challenge
, challengelen
,
236 buf
, strlen(session
->pass
));
239 response
= g_strdup_printf
240 ("%s %s", session
->user
, hexdigest
);
241 log_print(LOG_PROTOCOL
, "ESMTP> [Encoded: %s]\n", response
);
243 response64
= g_base64_encode(response
, strlen(response
));
246 if (session_send_msg(SESSION(session
), response64
) < 0) {
250 log_print(LOG_PROTOCOL
, "ESMTP> %s\n", response64
);
253 /* Server rejects AUTH */
254 if (session_send_msg(SESSION(session
), "*") < 0)
256 log_print(LOG_PROTOCOL
, "ESMTP> *\n");
259 case SMTPAUTH_DIGEST_MD5
:
261 /* stop smtp_auth when no correct authtype */
262 if (session_send_msg(SESSION(session
), "*") < 0)
264 log_print(LOG_PROTOCOL
, "ESMTP> *\n");
271 static gint
smtp_auth_login_user_recv(SMTPSession
*session
, const gchar
*msg
)
275 session
->state
= SMTP_AUTH_LOGIN_PASS
;
277 if (!strncmp(msg
, "334 ", 4)) {
278 tmp
= g_base64_encode(session
->pass
, strlen(session
->pass
));
280 /* Server rejects AUTH */
284 if (session_send_msg(SESSION(session
), tmp
) < 0) {
290 log_print(LOG_PROTOCOL
, "ESMTP> [PASSWORD]\n");
295 static gint
smtp_ehlo(SMTPSession
*session
)
297 gchar buf
[MESSAGEBUFSIZE
];
299 session
->state
= SMTP_EHLO
;
301 session
->avail_auth_type
= 0;
303 g_snprintf(buf
, sizeof(buf
), "EHLO %s",
304 session
->hostname
? session
->hostname
: get_domain_name());
305 if (session_send_msg(SESSION(session
), buf
) < 0)
307 log_print(LOG_PROTOCOL
, "ESMTP> %s\n", buf
);
312 static gint
smtp_ehlo_recv(SMTPSession
*session
, const gchar
*msg
)
314 if (strncmp(msg
, "250", 3) == 0) {
315 const gchar
*p
= msg
;
317 if (*p
== '-' || *p
== ' ') p
++;
318 if (g_ascii_strncasecmp(p
, "AUTH", 4) == 0) {
320 if (strcasestr(p
, "PLAIN"))
321 session
->avail_auth_type
|= SMTPAUTH_PLAIN
;
322 if (strcasestr(p
, "LOGIN"))
323 session
->avail_auth_type
|= SMTPAUTH_LOGIN
;
324 if (strcasestr(p
, "CRAM-MD5"))
325 session
->avail_auth_type
|= SMTPAUTH_CRAM_MD5
;
326 if (strcasestr(p
, "DIGEST-MD5"))
327 session
->avail_auth_type
|= SMTPAUTH_DIGEST_MD5
;
329 if (strcasestr(p
, "XOAUTH2"))
330 session
->avail_auth_type
|= SMTPAUTH_OAUTH2
;
333 if (g_ascii_strncasecmp(p
, "SIZE", 4) == 0) {
335 session
->max_message_size
= atoi(p
);
336 session
->esmtp_flags
|= ESMTP_SIZE
;
338 if (g_ascii_strncasecmp(p
, "STARTTLS", 8) == 0) {
340 session
->avail_auth_type
|= SMTPAUTH_TLS_AVAILABLE
;
343 } else if ((msg
[0] == '1' || msg
[0] == '2' || msg
[0] == '3') &&
344 (msg
[3] == ' ' || msg
[3] == '\0'))
346 else if (msg
[0] == '5' && msg
[1] == '0' &&
347 (msg
[2] == '4' || msg
[2] == '3' || msg
[2] == '1'))
354 static gint
smtp_starttls(SMTPSession
*session
)
356 session
->state
= SMTP_STARTTLS
;
358 if (session_send_msg(SESSION(session
), "STARTTLS") < 0)
360 log_print(LOG_PROTOCOL
, "ESMTP> STARTTLS\n");
366 static gint
smtp_auth_cram_md5(SMTPSession
*session
)
368 session
->state
= SMTP_AUTH
;
369 session
->auth_type
= SMTPAUTH_CRAM_MD5
;
371 if (session_send_msg(SESSION(session
), "AUTH CRAM-MD5") < 0)
373 log_print(LOG_PROTOCOL
, "ESMTP> AUTH CRAM-MD5\n");
378 static gint
smtp_auth_plain(SMTPSession
*session
)
380 gchar buf
[MESSAGEBUFSIZE
], *b64buf
, *out
;
383 session
->state
= SMTP_AUTH_PLAIN
;
384 session
->auth_type
= SMTPAUTH_PLAIN
;
386 memset(buf
, 0, sizeof buf
);
388 /* "\0user\0password" */
389 len
= sprintf(buf
, "%c%s%c%s", '\0', session
->user
, '\0', session
->pass
);
390 b64buf
= g_base64_encode(buf
, len
);
391 out
= g_strconcat("AUTH PLAIN ", b64buf
, NULL
);
394 if (session_send_msg(SESSION(session
), out
) < 0) {
401 log_print(LOG_PROTOCOL
, "ESMTP> [AUTH PLAIN]\n");
407 static gint
smtp_auth_oauth2(SMTPSession
*session
)
409 gchar buf
[MESSAGEBUFSIZE
], *b64buf
, *out
;
412 session
->state
= SMTP_AUTH_OAUTH2
;
413 session
->auth_type
= SMTPAUTH_OAUTH2
;
415 memset(buf
, 0, sizeof buf
);
417 /* "user=" {User} "^Aauth=Bearer " {Access Token} "^A^A"*/
418 /* session->pass contains the OAUTH2 Access Token*/
419 len
= sprintf(buf
, "user=%s\1auth=Bearer %s\1\1", session
->user
, session
->pass
);
420 b64buf
= g_base64_encode(buf
, len
);
421 out
= g_strconcat("AUTH XOAUTH2 ", b64buf
, NULL
);
424 if (session_send_msg(SESSION(session
), out
) < 0) {
431 log_print(LOG_PROTOCOL
, "ESMTP> [AUTH XOAUTH2]\n");
437 static gint
smtp_auth_login(SMTPSession
*session
)
439 session
->state
= SMTP_AUTH
;
440 session
->auth_type
= SMTPAUTH_LOGIN
;
442 if (session_send_msg(SESSION(session
), "AUTH LOGIN") < 0)
444 log_print(LOG_PROTOCOL
, "ESMTP> AUTH LOGIN\n");
449 static gint
smtp_helo(SMTPSession
*session
)
451 gchar buf
[MESSAGEBUFSIZE
];
453 session
->state
= SMTP_HELO
;
455 g_snprintf(buf
, sizeof(buf
), "HELO %s",
456 session
->hostname
? session
->hostname
: get_domain_name());
457 if (session_send_msg(SESSION(session
), buf
) < 0)
459 log_print(LOG_PROTOCOL
, "SMTP> %s\n", buf
);
464 static gint
smtp_rcpt(SMTPSession
*session
)
466 gchar buf
[MESSAGEBUFSIZE
];
469 cm_return_val_if_fail(session
->cur_to
!= NULL
, SM_ERROR
);
471 session
->state
= SMTP_RCPT
;
473 to
= (gchar
*)session
->cur_to
->data
;
476 g_snprintf(buf
, sizeof(buf
), "RCPT TO:%s", to
);
478 g_snprintf(buf
, sizeof(buf
), "RCPT TO:<%s>", to
);
479 if (session_send_msg(SESSION(session
), buf
) < 0)
481 log_print(LOG_PROTOCOL
, "SMTP> %s\n", buf
);
483 session
->cur_to
= session
->cur_to
->next
;
488 static gint
smtp_data(SMTPSession
*session
)
490 session
->state
= SMTP_DATA
;
492 if (session_send_msg(SESSION(session
), "DATA") < 0)
494 log_print(LOG_PROTOCOL
, "SMTP> DATA\n");
499 static gint
smtp_send_data(SMTPSession
*session
)
501 session
->state
= SMTP_SEND_DATA
;
503 session_send_data(SESSION(session
), session
->send_data
,
504 session
->send_data_len
);
509 static gint
smtp_make_ready(SMTPSession
*session
)
511 session
->state
= SMTP_MAIL_SENT_OK
;
516 gint
smtp_quit(SMTPSession
*session
)
518 session
->state
= SMTP_QUIT
;
520 session_send_msg(SESSION(session
), "QUIT");
521 log_print(LOG_PROTOCOL
, "SMTP> QUIT\n");
526 static gint
smtp_eom(SMTPSession
*session
)
528 session
->state
= SMTP_EOM
;
530 if (session_send_msg(SESSION(session
), ".") < 0)
532 log_print(LOG_PROTOCOL
, "SMTP> . (EOM)\n");
537 static gint
smtp_session_recv_msg(Session
*session
, const gchar
*msg
)
539 SMTPSession
*smtp_session
= SMTP_SESSION(session
);
540 gboolean cont
= FALSE
;
543 if (strlen(msg
) < 4) {
544 log_warning(LOG_PROTOCOL
, _("bad SMTP response\n"));
548 switch (smtp_session
->state
) {
552 case SMTP_AUTH_PLAIN
:
553 case SMTP_AUTH_LOGIN_USER
:
554 case SMTP_AUTH_LOGIN_PASS
:
556 case SMTP_AUTH_OAUTH2
:
558 case SMTP_AUTH_CRAM_MD5
:
559 log_print(LOG_PROTOCOL
, "ESMTP< %s\n", msg
);
562 log_print(LOG_PROTOCOL
, "SMTP< %s\n", msg
);
566 /* ignore all multiline responses except for EHLO */
567 if (msg
[3] == '-' && smtp_session
->state
!= SMTP_EHLO
)
568 return session_recv_msg(session
);
570 if (msg
[0] == '5' && msg
[1] == '0' &&
571 (msg
[2] == '4' || msg
[2] == '3' || msg
[2] == '1')) {
572 log_warning(LOG_PROTOCOL
, _("error occurred on SMTP session\n"));
573 smtp_session
->state
= SMTP_ERROR
;
574 smtp_session
->error_val
= SM_ERROR
;
575 g_free(smtp_session
->error_msg
);
576 smtp_session
->error_msg
= g_strdup(msg
);
580 if (!strncmp(msg
, "535", 3)) {
581 log_warning(LOG_PROTOCOL
, _("error occurred on authentication\n"));
582 smtp_session
->state
= SMTP_ERROR
;
583 smtp_session
->error_val
= SM_AUTHFAIL
;
584 g_free(smtp_session
->error_msg
);
585 smtp_session
->error_msg
= g_strdup(msg
);
589 if (msg
[0] != '1' && msg
[0] != '2' && msg
[0] != '3') {
590 log_warning(LOG_PROTOCOL
, _("error occurred on SMTP session\n"));
591 smtp_session
->state
= SMTP_ERROR
;
592 smtp_session
->error_val
= SM_ERROR
;
593 g_free(smtp_session
->error_msg
);
594 smtp_session
->error_msg
= g_strdup(msg
);
600 else if (msg
[3] != ' ' && msg
[3] != '\0') {
601 log_warning(LOG_PROTOCOL
, _("bad SMTP response\n"));
602 smtp_session
->state
= SMTP_ERROR
;
603 smtp_session
->error_val
= SM_UNRECOVERABLE
;
607 switch (smtp_session
->state
) {
609 if (strstr(msg
, "ESMTP"))
610 smtp_session
->is_esmtp
= TRUE
;
612 if (smtp_session
->user
|| session
->ssl_type
!= SSL_NONE
||
613 smtp_session
->is_esmtp
)
615 if (smtp_session
->user
|| smtp_session
->is_esmtp
)
617 ret
= smtp_ehlo(smtp_session
);
619 ret
= smtp_helo(smtp_session
);
622 ret
= smtp_from(smtp_session
);
625 ret
= smtp_ehlo_recv(smtp_session
, msg
);
628 if (smtp_session
->max_message_size
> 0
629 && smtp_session
->max_message_size
<
630 smtp_session
->send_data_len
) {
631 log_warning(LOG_PROTOCOL
, _("Message is too big "
632 "(Maximum size is %s)\n"),
634 (goffset
)(smtp_session
->max_message_size
)));
635 smtp_session
->state
= SMTP_ERROR
;
636 smtp_session
->error_val
= SM_ERROR
;
640 if (session
->ssl_type
== SSL_STARTTLS
&&
641 smtp_session
->tls_init_done
== FALSE
) {
642 ret
= smtp_starttls(smtp_session
);
646 if (smtp_session
->user
) {
647 if (smtp_auth(smtp_session
) != SM_OK
) {
649 if (session
->ssl_type
== SSL_NONE
650 && smtp_session
->tls_init_done
== FALSE
651 && (smtp_session
->avail_auth_type
& SMTPAUTH_TLS_AVAILABLE
))
652 ret
= smtp_starttls(smtp_session
);
655 ret
= smtp_from(smtp_session
);
658 ret
= smtp_from(smtp_session
);
662 if (session_start_tls(session
) < 0) {
663 log_warning(LOG_PROTOCOL
, _("couldn't start STARTTLS session\n"));
664 smtp_session
->state
= SMTP_ERROR
;
665 smtp_session
->error_val
= SM_ERROR
;
668 smtp_session
->tls_init_done
= TRUE
;
669 ret
= smtp_ehlo(smtp_session
);
673 ret
= smtp_auth_recv(smtp_session
, msg
);
675 case SMTP_AUTH_LOGIN_USER
:
676 ret
= smtp_auth_login_user_recv(smtp_session
, msg
);
678 case SMTP_AUTH_PLAIN
:
679 case SMTP_AUTH_LOGIN_PASS
:
681 case SMTP_AUTH_OAUTH2
:
683 case SMTP_AUTH_CRAM_MD5
:
684 ret
= smtp_from(smtp_session
);
687 if (smtp_session
->cur_to
)
688 ret
= smtp_rcpt(smtp_session
);
691 if (smtp_session
->cur_to
)
692 ret
= smtp_rcpt(smtp_session
);
694 ret
= smtp_data(smtp_session
);
697 ret
= smtp_send_data(smtp_session
);
700 smtp_make_ready(smtp_session
);
703 session_disconnect(session
);
707 log_warning(LOG_PROTOCOL
, _("error occurred on SMTP session\n"));
708 smtp_session
->error_val
= SM_ERROR
;
712 if (cont
&& ret
== SM_OK
)
713 return session_recv_msg(session
);
716 smtp_session
->error_val
= SM_ERROR
;
718 return ret
== SM_OK
? 0 : -1;
721 static gint
smtp_session_send_data_finished(Session
*session
, guint len
)
723 return smtp_eom(SMTP_SESSION(session
));