masqmail-0.2

view src/smtp_in.c @ 40:8071dc6c6ed1

next version will be 0.3.0
author meillo@marmaro.de
date Mon, 10 May 2010 11:03:26 +0200
parents 26e34ae9a3e3
children e5090ac234cf
line source
1 /* MasqMail
2 Copyright (C) 1999-2001 Oliver Kurth
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
19 #include "masqmail.h"
20 #include "readsock.h"
22 /*
23 I always forget these rfc numbers:
24 RFC 821 (SMTP)
25 RFC 1869 (ESMTP)
26 RFC 1870 (ESMTP SIZE)
27 RFC 2197 (ESMTP PIPELINE)
28 RFC 2554 (ESMTP AUTH)
29 */
31 #ifdef ENABLE_SMTP_SERVER
33 smtp_cmd smtp_cmds[] = {
34 {SMTP_HELO, "HELO",},
35 {SMTP_EHLO, "EHLO",},
36 {SMTP_MAIL_FROM, "MAIL FROM:",},
37 {SMTP_RCPT_TO, "RCPT TO:",},
38 {SMTP_DATA, "DATA",},
39 {SMTP_QUIT, "QUIT",},
40 {SMTP_RSET, "RSET",},
41 {SMTP_NOOP, "NOOP",},
42 {SMTP_HELP, "HELP"},
43 };
45 static smtp_cmd_id
46 get_id(const gchar * line)
47 {
48 gint i;
49 for (i = 0; i < SMTP_NUM_IDS; i++) {
50 if (strncasecmp(smtp_cmds[i].cmd, line, strlen(smtp_cmds[i].cmd)) == 0)
51 return (smtp_cmd_id) i;
52 }
53 return SMTP_ERROR;
54 }
56 /* this is a quick hack: we expect the address to be syntactically correct
57 and containing the mailbox only:
58 */
59 static gboolean
60 get_address(gchar * line, gchar * addr)
61 {
62 gchar *p = line, *q = addr;
64 /* skip MAIL FROM: and RCPT TO: */
65 while (*p && (*p != ':'))
66 p++;
67 p++;
69 /* skip spaces: */
70 while (*p && isspace(*p))
71 p++;
73 /* get address: */
74 while (*p && !isspace(*p) && (q < addr + MAX_ADDRESS - 1))
75 *(q++) = *(p++);
76 *q = 0;
78 return TRUE;
79 }
81 static smtp_connection*
82 create_base(gchar * remote_host)
83 {
84 smtp_connection *base = g_malloc(sizeof(smtp_connection));
85 if (base) {
86 base->remote_host = g_strdup(remote_host);
88 base->prot = PROT_SMTP;
89 base->next_id = 0;
90 base->helo_seen = 0;
91 base->from_seen = 0;
92 base->rcpt_seen = 0;
93 base->msg = NULL;
95 return base;
96 }
97 return NULL;
98 }
100 static void
101 smtp_printf(FILE * out, gchar * fmt, ...)
102 {
103 va_list args;
104 va_start(args, fmt);
106 DEBUG(4) {
107 gchar buf[256];
108 va_list args_copy;
110 va_copy(args_copy, args);
111 vsnprintf(buf, 255, fmt, args_copy);
112 va_end(args_copy);
114 debugf(">>>%s", buf);
115 }
117 vfprintf(out, fmt, args);
118 fflush(out);
120 va_end(args);
121 }
123 void
124 smtp_in(FILE * in, FILE * out, gchar * remote_host, gchar * ident)
125 {
126 gchar *buffer;
127 smtp_cmd_id cmd_id;
128 message *msg = NULL;
129 smtp_connection *psc;
130 int len;
132 DEBUG(5) debugf("smtp_in entered, remote_host = %s\n", remote_host);
134 psc = create_base(remote_host);
135 psc->msg = msg;
137 buffer = (gchar *) g_malloc(BUF_LEN);
138 if (buffer) {
139 /* send greeting string, containing ESMTP: */
140 smtp_printf(out, "220 %s MasqMail %s ESMTP\r\n", conf.host_name, VERSION);
142 while ((len = read_sockline(in, buffer, BUF_LEN, 5 * 60, READSOCKL_CHUG)) >= 0) {
143 cmd_id = get_id(buffer);
145 switch (cmd_id) {
146 case SMTP_EHLO:
147 psc->prot = PROT_ESMTP;
148 /* fall through */
149 case SMTP_HELO:
150 psc->helo_seen = TRUE;
152 if (!conf.defer_all) { /* I need this to debug delivery failures */
153 if (psc->prot == PROT_ESMTP) {
154 smtp_printf(out, "250-%s Nice to meet you with ESMTP\r\n", conf.host_name);
155 /* not yet: fprintf(out, "250-SIZE\r\n"); */
156 smtp_printf(out, "250-PIPELINING\r\n" "250 HELP\r\n");
157 } else {
158 smtp_printf(out, "250 %s pretty old mailer, huh?\r\n", conf.host_name);
159 }
160 break;
161 } else {
162 smtp_printf(out, "421 %s service temporarily unavailable.\r\n", conf.host_name);
163 }
165 case SMTP_MAIL_FROM:
166 if (psc->helo_seen && !psc->from_seen) {
167 gchar buf[MAX_ADDRESS];
168 address *addr;
170 msg = create_message();
171 msg->received_host = remote_host ? g_strdup(remote_host) : NULL;
172 msg->received_prot = psc->prot;
173 msg->ident = ident ? g_strdup(ident) : NULL;
174 /* get transfer id and increment for next one */
175 msg->transfer_id = (psc->next_id)++;
177 get_address(buffer, buf);
178 if ((addr = remote_host
179 ? create_address(buf, TRUE)
180 : create_address_qualified(buf, TRUE, conf.host_name))) {
181 if (addr->domain != NULL) {
182 psc->from_seen = TRUE;
183 msg->return_path = addr;
184 smtp_printf(out, "250 OK %s is a nice guy.\r\n", addr->address);
185 } else {
186 smtp_printf(out, "501 return path must be qualified.\r\n", buf);
187 }
188 } else {
189 smtp_printf(out, "501 %s: syntax error.\r\n", buf);
190 }
191 } else {
192 if (!psc->helo_seen)
193 smtp_printf(out, "503 need HELO or EHLO\r\n");
194 else
195 smtp_printf(out, "503 MAIL FROM: already given.\r\n");
196 }
197 break;
199 case SMTP_RCPT_TO:
201 if (psc->helo_seen && psc->from_seen) {
202 char buf[MAX_ADDRESS];
203 address *addr;
205 get_address(buffer, buf);
206 if ((addr = remote_host
207 ? create_address(buf, TRUE)
208 : create_address_qualified(buf, TRUE, conf.host_name))) {
209 if (addr->local_part[0] != '|') {
210 if (addr->domain != NULL) {
211 gboolean do_relay = conf.do_relay;
212 if (!do_relay) {
213 if ((do_relay = addr_is_local(msg->return_path))) {
214 }
215 if (!do_relay) {
216 do_relay = addr_is_local(addr);
217 }
218 }
219 if (do_relay) {
220 psc->rcpt_seen = TRUE;
221 msg->rcpt_list = g_list_append(msg->rcpt_list, addr);
222 smtp_printf(out, "250 OK %s is our friend.\r\n", addr->address);
223 } else {
224 smtp_printf(out, "550 relaying to %s denied.\r\n", addr_string(addr));
225 }
226 } else {
227 smtp_printf(out, "501 recipient address must be qualified.\r\n", buf);
228 }
229 } else
230 smtp_printf(out, "501 %s: no pipe allowed for SMTP connections\r\n", buf);
231 } else {
232 smtp_printf(out, "501 %s: syntax error in address.\r\n", buf);
233 }
234 } else {
236 if (!psc->helo_seen)
237 smtp_printf(out, "503 need HELO or EHLO.\r\n");
238 else
239 smtp_printf(out, "503 need MAIL FROM: before RCPT TO:\r\n");
240 }
241 break;
243 case SMTP_DATA:
244 if (psc->helo_seen && psc->rcpt_seen) {
245 accept_error err;
247 smtp_printf(out, "354 okay, and do not forget the dot\r\n");
249 if ((err = accept_message(in, msg, conf.do_save_envelope_to ? ACC_SAVE_ENVELOPE_TO : 0)) == AERR_OK) {
250 if (spool_write(msg, TRUE)) {
251 pid_t pid;
252 smtp_printf(out, "250 OK id=%s\r\n", msg->uid);
254 if (remote_host != NULL)
255 logwrite(LOG_NOTICE, "%s <= <%s@%s> host=%s with %s\n", msg->uid, msg->return_path->local_part,
256 msg->return_path->domain, remote_host, prot_names[psc->prot]);
257 else
258 logwrite(LOG_NOTICE, "%s <= <%s@%s> with %s\n", msg->uid, msg->return_path->local_part,
259 msg->return_path->domain, prot_names[psc->prot]);
261 if (!conf.do_queue) {
262 if ((pid = fork()) == 0) {
264 if (deliver(msg))
265 _exit(EXIT_SUCCESS);
266 else
267 _exit(EXIT_FAILURE);
269 } else if (pid < 0) {
270 logwrite(LOG_ALERT, "could not fork for delivery, id = %s", msg->uid);
271 }
272 } else {
273 DEBUG(1) debugf("queuing forced by configuration or option.\n");
274 }
275 } else {
276 smtp_printf(out, "451 Could not write spool file\r\n");
277 return;
278 }
279 } else {
280 switch (err) {
281 case AERR_TIMEOUT:
282 return;
283 case AERR_EOF:
284 return;
285 default:
286 /* should never happen: */
287 smtp_printf(out, "451 Unknown error\r\n");
288 return;
289 }
290 }
291 psc->rcpt_seen = psc->from_seen = FALSE;
292 destroy_message(msg);
293 msg = NULL;
294 } else {
295 if (!psc->helo_seen)
296 smtp_printf(out, "503 need HELO or EHLO.\r\n");
297 else
298 smtp_printf(out, "503 need RCPT TO: before DATA\r\n");
299 }
300 break;
301 case SMTP_QUIT:
302 smtp_printf(out, "221 goodbye\r\n");
303 if (msg != NULL)
304 destroy_message(msg);
305 return;
306 case SMTP_RSET:
307 psc->from_seen = psc->rcpt_seen = FALSE;
308 if (msg != NULL)
309 destroy_message(msg);
310 msg = NULL;
311 smtp_printf(out, "250 OK\r\n");
312 break;
313 case SMTP_NOOP:
314 smtp_printf(out, "250 OK\r\n");
315 break;
316 case SMTP_HELP:
317 {
318 int i;
320 smtp_printf(out, "214-supported commands:\r\n");
321 for (i = 0; i < SMTP_NUM_IDS - 1; i++) {
322 smtp_printf(out, "214-%s\r\n", smtp_cmds[i].cmd);
323 }
324 smtp_printf(out, "214 %s\r\n", smtp_cmds[i].cmd);
325 }
326 break;
327 default:
328 smtp_printf(out, "501 command not recognized\r\n");
329 DEBUG(1) debugf("command not recognized, was '%s'\n", buffer);
330 break;
331 }
332 }
333 switch (len) {
334 case -3:
335 logwrite(LOG_NOTICE, "connection timed out\n");
336 break;
337 case -2:
338 logwrite(LOG_NOTICE, "line overflow\n");
339 break;
340 case -1:
341 logwrite(LOG_NOTICE, "received EOF\n");
342 break;
343 default:
344 break;
345 }
346 }
347 }
348 #endif