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_SMTP_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_SMTP_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_SMTP_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)
149 gchar buf[MSGBUFSIZE];
151 g_return_val_if_fail(session != NULL, SM_ERROR);
152 g_return_val_if_fail(from != NULL, SM_ERROR);
155 if (smtp_auth(session) != SM_OK)
159 if (strchr(from, '<'))
160 g_snprintf(buf, sizeof(buf), "MAIL FROM: %s", from);
162 g_snprintf(buf, sizeof(buf), "MAIL FROM: <%s>", from);
164 sock_printf(SESSION(session)->sock, "%s\r\n", buf);
166 log_print("SMTP> %s\n", buf);
168 return smtp_ok(SESSION(session)->sock, NULL, 0);
171 gint smtp_auth(SMTPSession *session)
173 gchar buf[MSGBUFSIZE];
174 SMTPAuthType authtype = 0;
175 guchar hexdigest[33];
176 gchar *challenge, *response, *response64;
180 g_return_val_if_fail(session != NULL, SM_ERROR);
181 g_return_val_if_fail(session->user != NULL, SM_ERROR);
183 sock = SESSION(session)->sock;
185 if ((session->avail_auth_type & SMTPAUTH_CRAM_MD5) != 0 &&
186 smtp_auth_cram_md5(sock, buf, sizeof(buf)) == SM_OK)
187 authtype = SMTPAUTH_CRAM_MD5;
188 else if ((session->avail_auth_type & SMTPAUTH_LOGIN) != 0 &&
189 smtp_auth_login(sock, buf, sizeof(buf)) == SM_OK)
190 authtype = SMTPAUTH_LOGIN;
192 log_warning(_("SMTP AUTH not available\n"));
198 if (!strncmp(buf, "334 ", 4))
199 to64frombits(buf, session->user, strlen(session->user));
201 /* Server rejects AUTH */
202 g_snprintf(buf, sizeof(buf), "*");
204 sock_printf(sock, "%s\r\n", buf);
205 if (verbose) log_print("ESMTP> [USERID]\n");
207 smtp_ok(sock, buf, sizeof(buf));
209 if (!strncmp(buf, "334 ", 4))
210 to64frombits(buf, session->pass, strlen(session->pass));
212 /* Server rejects AUTH */
213 g_snprintf(buf, sizeof(buf), "*");
215 sock_printf(sock, "%s\r\n", buf);
216 if (verbose) log_print("ESMTP> [PASSWORD]\n");
218 case SMTPAUTH_CRAM_MD5:
219 if (!strncmp(buf, "334 ", 4)) {
220 challenge = g_malloc(strlen(buf + 4) + 1);
221 challengelen = from64tobits(challenge, buf + 4);
222 challenge[challengelen] = '\0';
224 log_print("ESMTP< [Decoded: %s]\n", challenge);
226 g_snprintf(buf, sizeof(buf), "%s", session->pass);
227 md5_hex_hmac(hexdigest, challenge, challengelen,
228 buf, strlen(session->pass));
231 response = g_strdup_printf
232 ("%s %s", session->user, hexdigest);
234 log_print("ESMTP> [Encoded: %s]\n", response);
236 response64 = g_malloc((strlen(response) + 3) * 2 + 1);
237 to64frombits(response64, response, strlen(response));
240 sock_printf(sock, "%s\r\n", response64);
241 if (verbose) log_print("ESMTP> %s\n", response64);
244 /* Server rejects AUTH */
245 g_snprintf(buf, sizeof(buf), "*");
246 sock_printf(sock, "%s\r\n", buf);
248 log_print("ESMTP> %s\n", buf);
251 case SMTPAUTH_DIGEST_MD5:
253 /* stop smtp_auth when no correct authtype */
254 g_snprintf(buf, sizeof(buf), "*");
255 sock_printf(sock, "%s\r\n", buf);
256 if (verbose) log_print("ESMTP> %s\n", buf);
260 return smtp_ok(sock, NULL, 0);
263 gint smtp_ehlo(SockInfo *sock, const gchar *hostname,
264 SMTPAuthType *avail_auth_type)
266 gchar buf[MSGBUFSIZE];
268 *avail_auth_type = 0;
270 sock_printf(sock, "EHLO %s\r\n", hostname);
272 log_print("ESMTP> EHLO %s\n", hostname);
274 while ((sock_gets(sock, buf, sizeof(buf) - 1)) != -1) {
280 log_print("ESMTP< %s\n", buf);
282 if (strncmp(buf, "250-", 4) == 0) {
285 if (g_strncasecmp(p, "AUTH ", 5) == 0) {
287 if (strcasestr(p, "LOGIN"))
288 *avail_auth_type |= SMTPAUTH_LOGIN;
289 if (strcasestr(p, "CRAM-MD5"))
290 *avail_auth_type |= SMTPAUTH_CRAM_MD5;
291 if (strcasestr(p, "DIGEST-MD5"))
292 *avail_auth_type |= SMTPAUTH_DIGEST_MD5;
294 } else if ((buf[0] == '1' || buf[0] == '2' || buf[0] == '3') &&
295 (buf[3] == ' ' || buf[3] == '\0'))
297 else if (buf[3] != '-')
299 else if (buf[0] == '5' && buf[1] == '0' &&
300 (buf[2] == '4' || buf[2] == '3' || buf[2] == '1'))
304 return SM_UNRECOVERABLE;
307 static gint smtp_starttls(SockInfo *sock)
309 sock_printf(sock, "STARTTLS\r\n");
311 log_print("ESMTP> STARTTLS\n");
313 return smtp_ok(sock, NULL, 0);
316 static gint smtp_auth_cram_md5(SockInfo *sock, gchar *buf, gint len)
318 sock_printf(sock, "AUTH CRAM-MD5\r\n");
320 log_print("ESMTP> AUTH CRAM-MD5\n");
322 return smtp_ok(sock, buf, len);
325 static gint smtp_auth_login(SockInfo *sock, gchar *buf, gint len)
327 sock_printf(sock, "AUTH LOGIN\r\n");
329 log_print("ESMTP> AUTH LOGIN\n");
331 return smtp_ok(sock, buf, len);
334 gint smtp_helo(SockInfo *sock, const gchar *hostname)
336 sock_printf(sock, "HELO %s\r\n", hostname);
338 log_print("SMTP> HELO %s\n", hostname);
340 return smtp_ok(sock, NULL, 0);
343 gint smtp_rcpt(SockInfo *sock, const gchar *to)
345 gchar buf[MSGBUFSIZE];
348 g_snprintf(buf, sizeof(buf), "RCPT TO: %s", to);
350 g_snprintf(buf, sizeof(buf), "RCPT TO: <%s>", to);
352 sock_printf(sock, "%s\r\n", buf);
354 log_print("SMTP> %s\n", buf);
356 return smtp_ok(sock, NULL, 0);
359 gint smtp_data(SockInfo *sock)
361 sock_printf(sock, "DATA\r\n");
363 log_print("SMTP> DATA\n");
365 return smtp_ok(sock, NULL, 0);
368 gint smtp_rset(SockInfo *sock)
370 sock_printf(sock, "RSET\r\n");
372 log_print("SMTP> RSET\n");
374 return smtp_ok(sock, NULL, 0);
377 gint smtp_quit(SockInfo *sock)
379 sock_printf(sock, "QUIT\r\n");
381 log_print("SMTP> QUIT\n");
383 return smtp_ok(sock, NULL, 0);
386 gint smtp_eom(SockInfo *sock)
388 sock_printf(sock, ".\r\n");
390 log_print("SMTP> . (EOM)\n");
392 return smtp_ok(sock, NULL, 0);
395 static gint smtp_ok(SockInfo *sock, gchar *buf, gint len)
397 gchar tmpbuf[MSGBUFSIZE];
401 len = sizeof(tmpbuf);
404 while ((sock_gets(sock, buf, len - 1)) != -1) {
410 log_print("SMTP< %s\n", buf);
412 if ((buf[0] == '1' || buf[0] == '2' || buf[0] == '3') &&
413 (buf[3] == ' ' || buf[3] == '\0'))
415 else if (buf[3] != '-')
417 else if (buf[0] == '5' && buf[1] == '0' &&
418 (buf[2] == '4' || buf[2] == '3' || buf[2] == '1'))
422 return SM_UNRECOVERABLE;