2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2002 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 2 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, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
35 static gint verbose = 1;
37 static gint smtp_starttls(SockInfo *sock);
38 static gint smtp_auth_cram_md5(SockInfo *sock, gchar *buf, gint len);
39 static gint smtp_auth_login(SockInfo *sock, gchar *buf, gint len);
40 static gint smtp_ok(SockInfo *sock, gchar *buf, gint len);
43 Session *smtp_session_new(const gchar *server, gushort port,
45 const gchar *user, const gchar *pass,
48 Session *smtp_session_new(const gchar *server, gushort port,
50 const gchar *user, const gchar *pass)
56 SMTPAuthType avail_auth_type = 0;
59 g_return_val_if_fail(server != NULL, NULL);
62 use_esmtp = user != NULL || ssl_type == SSL_STARTTLS;
64 use_esmtp = user != NULL;
67 if ((sock = sock_connect(server, port)) == NULL) {
68 log_warning(_("Can't connect to SMTP server: %s:%d\n"),
74 if (ssl_type == SSL_TUNNEL && !ssl_init_socket(sock)) {
75 log_warning(_("SSL connection failed"));
81 if (smtp_ok(sock, NULL, 0) != SM_OK) {
82 log_warning(_("Error occurred while connecting to %s:%d\n"),
89 domain = get_domain_name();
92 val = smtp_ehlo(sock, domain, &avail_auth_type);
94 val = smtp_helo(sock, domain);
96 log_warning(_("Error occurred while sending HELO\n"));
102 if (ssl_type == SSL_STARTTLS) {
103 val = smtp_starttls(sock);
105 log_warning(_("Error occurred while sending STARTTLS\n"));
109 if (!ssl_init_socket_with_method(sock, SSL_METHOD_TLSv1)) {
113 val = smtp_ehlo(sock, domain, &avail_auth_type);
115 log_warning(_("Error occurred while sending EHLO\n"));
122 session = g_new(SMTPSession, 1);
123 SESSION(session)->type = SESSION_SMTP;
124 SESSION(session)->server = g_strdup(server);
125 SESSION(session)->sock = sock;
126 SESSION(session)->connected = TRUE;
127 SESSION(session)->phase = SESSION_READY;
128 SESSION(session)->last_access_time = 0;
129 SESSION(session)->data = NULL;
130 session->avail_auth_type = avail_auth_type;
131 session->user = user ? g_strdup(user) : NULL;
132 session->pass = pass ? g_strdup(pass) :
133 user ? g_strdup("") : NULL;
135 return SESSION(session);
138 void smtp_session_destroy(SMTPSession *session)
140 sock_close(SESSION(session)->sock);
141 SESSION(session)->sock = NULL;
143 g_free(session->user);
144 g_free(session->pass);
147 gint smtp_from(SMTPSession *session, const gchar *from,
148 SMTPAuthType forced_auth_type)
150 gchar buf[MSGBUFSIZE];
152 g_return_val_if_fail(session != NULL, SM_ERROR);
153 g_return_val_if_fail(from != NULL, SM_ERROR);
156 if (smtp_auth(session, forced_auth_type) != SM_OK)
160 if (strchr(from, '<'))
161 g_snprintf(buf, sizeof(buf), "MAIL FROM: %s", from);
163 g_snprintf(buf, sizeof(buf), "MAIL FROM: <%s>", from);
165 sock_printf(SESSION(session)->sock, "%s\r\n", buf);
167 log_print("SMTP> %s\n", buf);
169 return smtp_ok(SESSION(session)->sock, NULL, 0);
172 gint smtp_auth(SMTPSession *session, SMTPAuthType forced_auth_type)
174 gchar buf[MSGBUFSIZE];
175 SMTPAuthType authtype = 0;
176 guchar hexdigest[33];
177 gchar *challenge, *response, *response64;
181 g_return_val_if_fail(session != NULL, SM_ERROR);
182 g_return_val_if_fail(session->user != NULL, SM_ERROR);
184 sock = SESSION(session)->sock;
186 if ((forced_auth_type == SMTPAUTH_CRAM_MD5 ||
187 (forced_auth_type == 0 &&
188 (session->avail_auth_type & SMTPAUTH_CRAM_MD5) != 0)) &&
189 smtp_auth_cram_md5(sock, buf, sizeof(buf)) == SM_OK)
190 authtype = SMTPAUTH_CRAM_MD5;
191 else if ((forced_auth_type == SMTPAUTH_LOGIN ||
192 (forced_auth_type == 0 &&
193 (session->avail_auth_type & SMTPAUTH_LOGIN) != 0)) &&
194 smtp_auth_login(sock, buf, sizeof(buf)) == SM_OK)
195 authtype = SMTPAUTH_LOGIN;
197 log_warning(_("SMTP AUTH not available\n"));
203 if (!strncmp(buf, "334 ", 4))
204 base64_encode(buf, session->user, strlen(session->user));
206 /* Server rejects AUTH */
207 g_snprintf(buf, sizeof(buf), "*");
209 sock_printf(sock, "%s\r\n", buf);
210 if (verbose) log_print("ESMTP> [USERID]\n");
212 smtp_ok(sock, buf, sizeof(buf));
214 if (!strncmp(buf, "334 ", 4))
215 base64_encode(buf, session->pass, strlen(session->pass));
217 /* Server rejects AUTH */
218 g_snprintf(buf, sizeof(buf), "*");
220 sock_printf(sock, "%s\r\n", buf);
221 if (verbose) log_print("ESMTP> [PASSWORD]\n");
223 case SMTPAUTH_CRAM_MD5:
224 if (!strncmp(buf, "334 ", 4)) {
225 challenge = g_malloc(strlen(buf + 4) + 1);
226 challengelen = base64_decode(challenge, buf + 4, -1);
227 challenge[challengelen] = '\0';
229 log_print("ESMTP< [Decoded: %s]\n", challenge);
231 g_snprintf(buf, sizeof(buf), "%s", session->pass);
232 md5_hex_hmac(hexdigest, challenge, challengelen,
233 buf, strlen(session->pass));
236 response = g_strdup_printf
237 ("%s %s", session->user, hexdigest);
239 log_print("ESMTP> [Encoded: %s]\n", response);
241 response64 = g_malloc((strlen(response) + 3) * 2 + 1);
242 base64_encode(response64, response, strlen(response));
245 sock_printf(sock, "%s\r\n", response64);
246 if (verbose) log_print("ESMTP> %s\n", response64);
249 /* Server rejects AUTH */
250 g_snprintf(buf, sizeof(buf), "*");
251 sock_printf(sock, "%s\r\n", buf);
253 log_print("ESMTP> %s\n", buf);
256 case SMTPAUTH_DIGEST_MD5:
258 /* stop smtp_auth when no correct authtype */
259 g_snprintf(buf, sizeof(buf), "*");
260 sock_printf(sock, "%s\r\n", buf);
261 if (verbose) log_print("ESMTP> %s\n", buf);
265 return smtp_ok(sock, NULL, 0);
268 gint smtp_ehlo(SockInfo *sock, const gchar *hostname,
269 SMTPAuthType *avail_auth_type)
271 gchar buf[MSGBUFSIZE];
273 *avail_auth_type = 0;
275 sock_printf(sock, "EHLO %s\r\n", hostname);
277 log_print("ESMTP> EHLO %s\n", hostname);
279 while ((sock_gets(sock, buf, sizeof(buf) - 1)) != -1) {
285 log_print("ESMTP< %s\n", buf);
287 if (strncmp(buf, "250-", 4) == 0) {
290 if (g_strncasecmp(p, "AUTH", 4) == 0) {
292 if (strcasestr(p, "LOGIN"))
293 *avail_auth_type |= SMTPAUTH_LOGIN;
294 if (strcasestr(p, "CRAM-MD5"))
295 *avail_auth_type |= SMTPAUTH_CRAM_MD5;
296 if (strcasestr(p, "DIGEST-MD5"))
297 *avail_auth_type |= SMTPAUTH_DIGEST_MD5;
299 } else if ((buf[0] == '1' || buf[0] == '2' || buf[0] == '3') &&
300 (buf[3] == ' ' || buf[3] == '\0'))
302 else if (buf[3] != '-')
304 else if (buf[0] == '5' && buf[1] == '0' &&
305 (buf[2] == '4' || buf[2] == '3' || buf[2] == '1'))
309 return SM_UNRECOVERABLE;
312 static gint smtp_starttls(SockInfo *sock)
314 sock_printf(sock, "STARTTLS\r\n");
316 log_print("ESMTP> STARTTLS\n");
318 return smtp_ok(sock, NULL, 0);
321 static gint smtp_auth_cram_md5(SockInfo *sock, gchar *buf, gint len)
323 sock_printf(sock, "AUTH CRAM-MD5\r\n");
325 log_print("ESMTP> AUTH CRAM-MD5\n");
327 return smtp_ok(sock, buf, len);
330 static gint smtp_auth_login(SockInfo *sock, gchar *buf, gint len)
332 sock_printf(sock, "AUTH LOGIN\r\n");
334 log_print("ESMTP> AUTH LOGIN\n");
336 return smtp_ok(sock, buf, len);
339 gint smtp_helo(SockInfo *sock, const gchar *hostname)
341 sock_printf(sock, "HELO %s\r\n", hostname);
343 log_print("SMTP> HELO %s\n", hostname);
345 return smtp_ok(sock, NULL, 0);
348 gint smtp_rcpt(SockInfo *sock, const gchar *to)
350 gchar buf[MSGBUFSIZE];
353 g_snprintf(buf, sizeof(buf), "RCPT TO: %s", to);
355 g_snprintf(buf, sizeof(buf), "RCPT TO: <%s>", to);
357 sock_printf(sock, "%s\r\n", buf);
359 log_print("SMTP> %s\n", buf);
361 return smtp_ok(sock, NULL, 0);
364 gint smtp_data(SockInfo *sock)
366 sock_printf(sock, "DATA\r\n");
368 log_print("SMTP> DATA\n");
370 return smtp_ok(sock, NULL, 0);
373 gint smtp_rset(SockInfo *sock)
375 sock_printf(sock, "RSET\r\n");
377 log_print("SMTP> RSET\n");
379 return smtp_ok(sock, NULL, 0);
382 gint smtp_quit(SockInfo *sock)
384 sock_printf(sock, "QUIT\r\n");
386 log_print("SMTP> QUIT\n");
388 return smtp_ok(sock, NULL, 0);
391 gint smtp_eom(SockInfo *sock)
393 sock_printf(sock, ".\r\n");
395 log_print("SMTP> . (EOM)\n");
397 return smtp_ok(sock, NULL, 0);
400 static gint smtp_ok(SockInfo *sock, gchar *buf, gint len)
402 gchar tmpbuf[MSGBUFSIZE];
406 len = sizeof(tmpbuf);
409 while ((sock_gets(sock, buf, len - 1)) != -1) {
415 log_print("SMTP< %s\n", buf);
417 if ((buf[0] == '1' || buf[0] == '2' || buf[0] == '3') &&
418 (buf[3] == ' ' || buf[3] == '\0'))
420 else if (buf[3] != '-')
422 else if (buf[0] == '5' && buf[1] == '0' &&
423 (buf[2] == '4' || buf[2] == '3' || buf[2] == '1'))
427 return SM_UNRECOVERABLE;