masqmail

view src/smtp_in.c @ 75:257a9e6d1a8e

fixed correct processing of mails with data lines longer 4096 chars Mail messages with lines longer than 4096 chars were already read correctly, i.e. the spool files were correct. This commit fixes the reading of spool files with long lines. The old behavior was that the message body was truncated right before the first line longer 4096 chars. The number comes from MAX_DATALINE.
author meillo@marmaro.de
date Wed, 16 Jun 2010 19:06:34 +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