sync with sylpheed 0.4.65cvs10
[claws.git] / src / esmtp.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999,2000 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_auth_cram_md5(SockInfo *sock)
37 {
38         gchar buf[MSGBUFSIZE];
39
40         g_snprintf(buf, sizeof(buf), "AUTH CRAM-MD5");
41         sock_printf(sock, "%s\r\n", buf);
42
43         if (verbose)
44                 log_print("ESMTP> %s\n", buf);
45
46         return esmtp_ok(sock);
47 }
48
49 gint esmtp_auth_login(SockInfo *sock)
50 {
51         gchar buf[MSGBUFSIZE];
52
53         g_snprintf(buf, sizeof(buf), "AUTH LOGIN");
54         sock_printf(sock, "%s\r\n", buf);
55
56         if (verbose)
57                 log_print("ESMTP> %s\n", buf);
58
59         return esmtp_ok(sock);
60 }
61
62 gint esmtp_auth(SockInfo *sock, SMTPAuthType authtype,
63                 const gchar *userid, const gchar *passwd,
64                 gboolean use_smtp_auth)
65 {
66         gchar buf[MSGBUFSIZE];
67         guchar hexdigest[33];
68         gchar *challenge, *response, *response64;
69         gint challengelen;
70         //const gchar delimiters[]=" ";
71         gchar *token;
72
73         switch (authtype) {
74         case SMTPAUTH_LOGIN:
75                 if (!strncmp(esmtp_response, "334 ", 4))
76                         to64frombits(buf, userid, strlen(userid));
77                 else
78                         /* Server rejects AUTH */
79                         g_snprintf(buf, sizeof(buf), "*");
80
81                 sock_printf(sock, "%s\r\n", buf);
82                 if (verbose) log_print("ESMTP> USERID\n");
83
84                 esmtp_ok(sock); /* to read the answer from the server */
85
86                 if (!strncmp(esmtp_response, "334 ", 4))
87                         to64frombits(buf, passwd, strlen(passwd));
88                 else
89                         /* Server rejects AUTH */
90                         g_snprintf(buf, sizeof(buf), "*");
91
92                 sock_printf(sock, "%s\r\n", buf);
93                 if (verbose) log_print("ESMTP> PASSWORD\n");
94                 break;
95         case SMTPAUTH_CRAM_MD5:
96                 if (!strncmp(esmtp_response, "334 ", 4)) {
97                         /* remove 334 from esmtp_response */
98                         g_snprintf(buf, sizeof(buf), "%s",esmtp_response);
99                         token = strtok(buf, " ");
100                         token = strtok(NULL, " ");
101                         challenge = g_malloc(strlen(token)+1);
102                         challengelen = from64tobits(challenge,token);
103                         if (verbose)
104                                 log_print("ESMTP< Decoded: %s\n", challenge);
105
106                         g_snprintf(buf, sizeof(buf), "%s", passwd);
107                         md5_hex_hmac(hexdigest, challenge, challengelen,
108                                      buf, strlen(passwd));
109
110                         response = g_strdup_printf("%s %s", userid, hexdigest);
111                         if (verbose)
112                                 log_print("ESMTP> Encoded %s\n",response);
113
114                         response64 = g_malloc((strlen(response) + 3) * 2 + 1);
115                         to64frombits(response64, response, strlen(response));
116                         g_free(response);
117
118                         sock_printf(sock, "%s\r\n", response64);
119                         if (verbose) log_print("ESMTP> %s\n", response64);
120                         g_free(response64);
121                 } else {
122                         /* Server rejects AUTH */
123                         g_snprintf(buf, sizeof(buf), "*");
124                         sock_printf(sock, "%s\r\n", buf);
125                         if (verbose)
126                                 log_print("ESMTP> %s\n",buf);
127                 }
128                 break;
129         case SMTPAUTH_DIGEST_MD5:
130         default:
131                 /* stop esmtp_auth when no correct authtype */
132                 g_snprintf(buf, sizeof(buf), "*");
133                 sock_printf(sock, "%s\r\n", buf);
134                 if (verbose) log_print("ESMTP> %s\n", buf);
135                 break;
136         }
137
138         return esmtp_ok(sock);
139 }
140
141 gint esmtp_ok(SockInfo *sock)
142 {
143         while (sock_read(sock, esmtp_response, sizeof(esmtp_response) - 1)
144                != -1) {
145                 if (strlen(esmtp_response) < 4)
146                         return SM_ERROR;
147                 strretchomp(esmtp_response);
148
149                 if (verbose)
150                         log_print("ESMTP< %s\n", esmtp_response);
151
152                 if ((esmtp_response[0] == '1' || esmtp_response[0] == '2' ||
153                      esmtp_response[0] == '3') && esmtp_response[3] == ' ')
154                         return SM_OK;
155                 else if (esmtp_response[3] != '-')
156                         return SM_ERROR;
157                 else if (esmtp_response[0] == '5' &&
158                          esmtp_response[1] == '0' &&
159                          (esmtp_response[3] == '4' ||
160                           esmtp_response[3] == '3' ||
161                           esmtp_response[3] == '1'))
162                         return SM_ERROR;
163         }
164
165         return SM_UNRECOVERABLE;
166 }