80eec301fc7f297d4af27028a4f01952c464b861
[claws.git] / src / esmtp.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2002 Hiroyuki Yamamoto
4  *
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.
9  *
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.
14  *
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.
18  */
19
20 #include <glib.h>
21 #include <stdio.h>
22 #include <string.h>
23
24 #include "esmtp.h"
25 #include "smtp.h"
26 #include "socket.h"
27 #include "utils.h"
28 #include "md5.h"
29 #include "base64.h"
30
31 #define MSGBUFSIZE      8192
32
33 static gint verbose = 1;
34 static gchar esmtp_response[MSGBUFSIZE];
35
36 gint esmtp_ehlo(SockInfo *sock, const gchar *hostname)
37 {
38         sock_printf(sock, "EHLO %s\r\n", hostname);
39         if (verbose)
40                 log_print("ESMTP> EHLO %s\n", hostname);
41
42         return esmtp_ok(sock);
43 }
44
45 gint esmtp_starttls(SockInfo *sock)
46 {
47         sock_printf(sock, "STARTTLS\r\n");
48         if (verbose)
49                 log_print("ESMTP> STARTTLS\n");
50
51         return esmtp_ok(sock);
52 }
53
54 gint esmtp_auth_cram_md5(SockInfo *sock)
55 {
56         sock_printf(sock, "AUTH CRAM-MD5\r\n");
57         if (verbose)
58                 log_print("ESMTP> AUTH CRAM-MD5\n");
59
60         return esmtp_ok(sock);
61 }
62
63 gint esmtp_auth_login(SockInfo *sock)
64 {
65         sock_printf(sock, "AUTH LOGIN\r\n");
66         if (verbose)
67                 log_print("ESMTP> AUTH LOGIN\n");
68
69         return esmtp_ok(sock);
70 }
71
72 gint esmtp_auth(SockInfo *sock, SMTPAuthType authtype,
73                 const gchar *userid, const gchar *passwd)
74 {
75         gchar buf[MSGBUFSIZE];
76         guchar hexdigest[33];
77         gchar *challenge, *response, *response64;
78         gint challengelen;
79
80         switch (authtype) {
81         case SMTPAUTH_LOGIN:
82                 if (!strncmp(esmtp_response, "334 ", 4))
83                         to64frombits(buf, userid, strlen(userid));
84                 else
85                         /* Server rejects AUTH */
86                         g_snprintf(buf, sizeof(buf), "*");
87
88                 sock_printf(sock, "%s\r\n", buf);
89                 if (verbose) log_print("ESMTP> USERID\n");
90
91                 esmtp_ok(sock); /* to read the answer from the server */
92
93                 if (!strncmp(esmtp_response, "334 ", 4))
94                         to64frombits(buf, passwd, strlen(passwd));
95                 else
96                         /* Server rejects AUTH */
97                         g_snprintf(buf, sizeof(buf), "*");
98
99                 sock_printf(sock, "%s\r\n", buf);
100                 if (verbose) log_print("ESMTP> PASSWORD\n");
101                 break;
102         case SMTPAUTH_CRAM_MD5:
103                 if (!strncmp(esmtp_response, "334 ", 4)) {
104                         /* remove 334 from esmtp_response */
105                         gchar *p = esmtp_response + 4;
106
107                         challenge = g_malloc(strlen(p) + 1);
108                         challengelen = from64tobits(challenge, p);
109                         challenge[challengelen] = '\0';
110                         if (verbose)
111                                 log_print("ESMTP< [Decoded: %s]\n", challenge);
112
113                         g_snprintf(buf, sizeof(buf), "%s", passwd);
114                         md5_hex_hmac(hexdigest, challenge, challengelen,
115                                      buf, strlen(passwd));
116                         g_free(challenge);
117
118                         response = g_strdup_printf("%s %s", userid, hexdigest);
119                         if (verbose)
120                                 log_print("ESMTP> [Encoded: %s]\n", response);
121
122                         response64 = g_malloc((strlen(response) + 3) * 2 + 1);
123                         to64frombits(response64, response, strlen(response));
124                         g_free(response);
125
126                         sock_printf(sock, "%s\r\n", response64);
127                         if (verbose) log_print("ESMTP> %s\n", response64);
128                         g_free(response64);
129                 } else {
130                         /* Server rejects AUTH */
131                         g_snprintf(buf, sizeof(buf), "*");
132                         sock_printf(sock, "%s\r\n", buf);
133                         if (verbose)
134                                 log_print("ESMTP> %s\n",buf);
135                 }
136                 break;
137         case SMTPAUTH_DIGEST_MD5:
138         default:
139                 /* stop esmtp_auth when no correct authtype */
140                 g_snprintf(buf, sizeof(buf), "*");
141                 sock_printf(sock, "%s\r\n", buf);
142                 if (verbose) log_print("ESMTP> %s\n", buf);
143                 break;
144         }
145
146         return esmtp_ok(sock);
147 }
148
149 gint esmtp_ok(SockInfo *sock)
150 {
151         while (sock_gets(sock, esmtp_response, sizeof(esmtp_response) - 1)
152                != -1) {
153                 if (strlen(esmtp_response) < 4)
154                         return SM_ERROR;
155                 strretchomp(esmtp_response);
156
157                 if (verbose)
158                         log_print("ESMTP< %s\n", esmtp_response);
159
160                 if ((esmtp_response[0] == '1' || esmtp_response[0] == '2' ||
161                      esmtp_response[0] == '3') && esmtp_response[3] == ' ')
162                         return SM_OK;
163                 else if (esmtp_response[3] != '-')
164                         return SM_ERROR;
165                 else if (esmtp_response[0] == '5' &&
166                          esmtp_response[1] == '0' &&
167                          (esmtp_response[2] == '4' ||
168                           esmtp_response[2] == '3' ||
169                           esmtp_response[2] == '1'))
170                         return SM_ERROR;
171         }
172
173         return SM_UNRECOVERABLE;
174 }