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;
131 SESSION(session)->destroy = smtp_session_destroy;
133 session->avail_auth_type = avail_auth_type;
134 session->user = user ? g_strdup(user) : NULL;
135 session->pass = pass ? g_strdup(pass) :
136 user ? g_strdup("") : NULL;
138 return SESSION(session);
141 void smtp_session_destroy(Session *session)
143 sock_close(session->sock);
144 session->sock = NULL;
146 g_free(SMTP_SESSION(session)->user);
147 g_free(SMTP_SESSION(session)->pass);
150 gint smtp_from(SMTPSession *session, const gchar *from,
151 SMTPAuthType forced_auth_type)
153 gchar buf[MSGBUFSIZE];
155 g_return_val_if_fail(session != NULL, SM_ERROR);
156 g_return_val_if_fail(from != NULL, SM_ERROR);
159 if (smtp_auth(session, forced_auth_type) != SM_OK)
163 if (strchr(from, '<'))
164 g_snprintf(buf, sizeof(buf), "MAIL FROM: %s", from);
166 g_snprintf(buf, sizeof(buf), "MAIL FROM: <%s>", from);
168 sock_printf(SESSION(session)->sock, "%s\r\n", buf);
170 log_print("SMTP> %s\n", buf);
172 return smtp_ok(SESSION(session)->sock, NULL, 0);
175 gint smtp_auth(SMTPSession *session, SMTPAuthType forced_auth_type)
177 gchar buf[MSGBUFSIZE];
178 SMTPAuthType authtype = 0;
179 guchar hexdigest[33];
180 gchar *challenge, *response, *response64;
184 g_return_val_if_fail(session != NULL, SM_ERROR);
185 g_return_val_if_fail(session->user != NULL, SM_ERROR);
187 sock = SESSION(session)->sock;
189 if ((forced_auth_type == SMTPAUTH_CRAM_MD5 ||
190 (forced_auth_type == 0 &&
191 (session->avail_auth_type & SMTPAUTH_CRAM_MD5) != 0)) &&
192 smtp_auth_cram_md5(sock, buf, sizeof(buf)) == SM_OK)
193 authtype = SMTPAUTH_CRAM_MD5;
194 else if ((forced_auth_type == SMTPAUTH_LOGIN ||
195 (forced_auth_type == 0 &&
196 (session->avail_auth_type & SMTPAUTH_LOGIN) != 0)) &&
197 smtp_auth_login(sock, buf, sizeof(buf)) == SM_OK)
198 authtype = SMTPAUTH_LOGIN;
200 log_warning(_("SMTP AUTH not available\n"));
206 if (!strncmp(buf, "334 ", 4))
207 base64_encode(buf, session->user, strlen(session->user));
209 /* Server rejects AUTH */
210 g_snprintf(buf, sizeof(buf), "*");
212 sock_printf(sock, "%s\r\n", buf);
213 if (verbose) log_print("ESMTP> [USERID]\n");
215 smtp_ok(sock, buf, sizeof(buf));
217 if (!strncmp(buf, "334 ", 4))
218 base64_encode(buf, session->pass, strlen(session->pass));
220 /* Server rejects AUTH */
221 g_snprintf(buf, sizeof(buf), "*");
223 sock_printf(sock, "%s\r\n", buf);
224 if (verbose) log_print("ESMTP> [PASSWORD]\n");
226 case SMTPAUTH_CRAM_MD5:
227 if (!strncmp(buf, "334 ", 4)) {
228 challenge = g_malloc(strlen(buf + 4) + 1);
229 challengelen = base64_decode(challenge, buf + 4, -1);
230 challenge[challengelen] = '\0';
232 log_print("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);
242 log_print("ESMTP> [Encoded: %s]\n", response);
244 response64 = g_malloc((strlen(response) + 3) * 2 + 1);
245 base64_encode(response64, response, strlen(response));
248 sock_printf(sock, "%s\r\n", response64);
249 if (verbose) log_print("ESMTP> %s\n", response64);
252 /* Server rejects AUTH */
253 g_snprintf(buf, sizeof(buf), "*");
254 sock_printf(sock, "%s\r\n", buf);
256 log_print("ESMTP> %s\n", buf);
259 case SMTPAUTH_DIGEST_MD5:
261 /* stop smtp_auth when no correct authtype */
262 g_snprintf(buf, sizeof(buf), "*");
263 sock_printf(sock, "%s\r\n", buf);
264 if (verbose) log_print("ESMTP> %s\n", buf);
268 return smtp_ok(sock, NULL, 0);
271 gint smtp_ehlo(SockInfo *sock, const gchar *hostname,
272 SMTPAuthType *avail_auth_type)
274 gchar buf[MSGBUFSIZE];
276 *avail_auth_type = 0;
278 sock_printf(sock, "EHLO %s\r\n", hostname);
280 log_print("ESMTP> EHLO %s\n", hostname);
282 while ((sock_gets(sock, buf, sizeof(buf) - 1)) != -1) {
288 log_print("ESMTP< %s\n", buf);
290 if (strncmp(buf, "250-", 4) == 0) {
293 if (g_strncasecmp(p, "AUTH", 4) == 0) {
295 if (strcasestr(p, "LOGIN"))
296 *avail_auth_type |= SMTPAUTH_LOGIN;
297 if (strcasestr(p, "CRAM-MD5"))
298 *avail_auth_type |= SMTPAUTH_CRAM_MD5;
299 if (strcasestr(p, "DIGEST-MD5"))
300 *avail_auth_type |= SMTPAUTH_DIGEST_MD5;
302 } else if ((buf[0] == '1' || buf[0] == '2' || buf[0] == '3') &&
303 (buf[3] == ' ' || buf[3] == '\0'))
305 else if (buf[3] != '-')
307 else if (buf[0] == '5' && buf[1] == '0' &&
308 (buf[2] == '4' || buf[2] == '3' || buf[2] == '1'))
312 return SM_UNRECOVERABLE;
315 static gint smtp_starttls(SockInfo *sock)
317 sock_printf(sock, "STARTTLS\r\n");
319 log_print("ESMTP> STARTTLS\n");
321 return smtp_ok(sock, NULL, 0);
324 static gint smtp_auth_cram_md5(SockInfo *sock, gchar *buf, gint len)
326 sock_printf(sock, "AUTH CRAM-MD5\r\n");
328 log_print("ESMTP> AUTH CRAM-MD5\n");
330 return smtp_ok(sock, buf, len);
333 static gint smtp_auth_login(SockInfo *sock, gchar *buf, gint len)
335 sock_printf(sock, "AUTH LOGIN\r\n");
337 log_print("ESMTP> AUTH LOGIN\n");
339 return smtp_ok(sock, buf, len);
342 gint smtp_helo(SockInfo *sock, const gchar *hostname)
344 sock_printf(sock, "HELO %s\r\n", hostname);
346 log_print("SMTP> HELO %s\n", hostname);
348 return smtp_ok(sock, NULL, 0);
351 gint smtp_rcpt(SockInfo *sock, const gchar *to)
353 gchar buf[MSGBUFSIZE];
356 g_snprintf(buf, sizeof(buf), "RCPT TO: %s", to);
358 g_snprintf(buf, sizeof(buf), "RCPT TO: <%s>", to);
360 sock_printf(sock, "%s\r\n", buf);
362 log_print("SMTP> %s\n", buf);
364 return smtp_ok(sock, NULL, 0);
367 gint smtp_data(SockInfo *sock)
369 sock_printf(sock, "DATA\r\n");
371 log_print("SMTP> DATA\n");
373 return smtp_ok(sock, NULL, 0);
376 gint smtp_rset(SockInfo *sock)
378 sock_printf(sock, "RSET\r\n");
380 log_print("SMTP> RSET\n");
382 return smtp_ok(sock, NULL, 0);
385 gint smtp_quit(SockInfo *sock)
387 sock_printf(sock, "QUIT\r\n");
389 log_print("SMTP> QUIT\n");
391 return smtp_ok(sock, NULL, 0);
394 gint smtp_eom(SockInfo *sock)
396 sock_printf(sock, ".\r\n");
398 log_print("SMTP> . (EOM)\n");
400 return smtp_ok(sock, NULL, 0);
403 static gint smtp_ok(SockInfo *sock, gchar *buf, gint len)
405 gchar tmpbuf[MSGBUFSIZE];
409 len = sizeof(tmpbuf);
412 while ((sock_gets(sock, buf, len - 1)) != -1) {
418 log_print("SMTP< %s\n", buf);
420 if ((buf[0] == '1' || buf[0] == '2' || buf[0] == '3') &&
421 (buf[3] == ' ' || buf[3] == '\0'))
423 else if (buf[3] != '-')
425 else if (buf[0] == '5' && buf[1] == '0' &&
426 (buf[2] == '4' || buf[2] == '3' || buf[2] == '1'))
430 return SM_UNRECOVERABLE;