masqmail-0.2

view src/smtp_in.c @ 91:3e7136221104

correct masqmail path in rmail script; remove docs on uninstall on install the correct path to the masqmail executable gets inserted into the rmail script now. now documentation, examples, and the templates are removed on uninstall. Empty directories are the only thing that may remain if one installs masqmail into an unusual path.
author meillo@marmaro.de
date Mon, 21 Jun 2010 09:40:16 +0200
parents e5090ac234cf
children 5ec5e6637049
line source
1 /* MasqMail
2 Copyright (C) 1999-2001 Oliver Kurth
3 Copyright (C) 2010 markus schnalke <meillo@marmaro.de>
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.
18 */
20 #include "masqmail.h"
21 #include "readsock.h"
23 /*
24 I always forget these rfc numbers:
25 RFC 821 (SMTP)
26 RFC 1869 (ESMTP)
27 RFC 1870 (ESMTP SIZE)
28 RFC 2197 (ESMTP PIPELINE)
29 RFC 2554 (ESMTP AUTH)
30 */
32 #ifdef ENABLE_SMTP_SERVER
34 smtp_cmd smtp_cmds[] = {
35 {SMTP_HELO, "HELO",},
36 {SMTP_EHLO, "EHLO",},
37 {SMTP_MAIL_FROM, "MAIL FROM:",},
38 {SMTP_RCPT_TO, "RCPT TO:",},
39 {SMTP_DATA, "DATA",},
40 {SMTP_QUIT, "QUIT",},
41 {SMTP_RSET, "RSET",},
42 {SMTP_NOOP, "NOOP",},
43 {SMTP_HELP, "HELP"},
44 };
46 static smtp_cmd_id
47 get_id(const gchar * line)
48 {
49 gint i;
50 for (i = 0; i < SMTP_NUM_IDS; i++) {
51 if (strncasecmp(smtp_cmds[i].cmd, line, strlen(smtp_cmds[i].cmd)) == 0) {
52 return (smtp_cmd_id) i;
53 }
54 }
55 return SMTP_ERROR;
56 }
58 /* this is a quick hack: we expect the address to be syntactically correct
59 and containing the mailbox only:
60 */
61 static gboolean
62 get_address(gchar * line, gchar * addr)
63 {
64 gchar *p = line;
65 gchar *q = addr;
67 /* skip MAIL FROM: and RCPT TO: */
68 while (*p && (*p != ':')) {
69 p++;
70 }
71 p++;
73 /* skip spaces: */
74 while (*p && isspace(*p)) {
75 p++;
76 }
78 /* get address: */
79 while (*p && !isspace(*p) && (q < addr + MAX_ADDRESS - 1)) {
80 *(q++) = *(p++);
81 }
82 *q = 0;
84 return TRUE;
85 }
87 static smtp_connection*
88 create_base(gchar * remote_host)
89 {
90 smtp_connection *base = g_malloc(sizeof(smtp_connection));
91 if (!base) {
92 return NULL;
93 }
95 base->remote_host = g_strdup(remote_host);
97 base->prot = PROT_SMTP;
98 base->next_id = 0;
99 base->helo_seen = 0;
100 base->from_seen = 0;
101 base->rcpt_seen = 0;
102 base->msg = NULL;
104 return base;
105 }
107 static void
108 smtp_printf(FILE * out, gchar * fmt, ...)
109 {
110 va_list args;
111 va_start(args, fmt);
113 DEBUG(4) {
114 gchar buf[256];
115 va_list args_copy;
117 va_copy(args_copy, args);
118 vsnprintf(buf, 255, fmt, args_copy);
119 va_end(args_copy);
121 debugf(">>>%s", buf);
122 }
124 vfprintf(out, fmt, args);
125 fflush(out);
127 va_end(args);
128 }
130 void
131 smtp_in(FILE * in, FILE * out, gchar * remote_host, gchar * ident)
132 {
133 gchar *buffer;
134 smtp_cmd_id cmd_id;
135 message *msg = NULL;
136 smtp_connection *psc;
137 int len;
139 DEBUG(5) debugf("smtp_in entered, remote_host = %s\n", remote_host);
141 psc = create_base(remote_host);
142 psc->msg = msg;
144 buffer = (gchar *) g_malloc(BUF_LEN);
145 if (!buffer) {
146 /* this check is actually unneccessary as g_malloc()
147 aborts on failure */
148 return;
149 }
151 /* send greeting string, containing ESMTP: */
152 smtp_printf(out, "220 %s MasqMail %s ESMTP\r\n", conf.host_name, VERSION);
154 while ((len = read_sockline(in, buffer, BUF_LEN, 5 * 60, READSOCKL_CHUG)) >= 0) {
155 cmd_id = get_id(buffer);
157 switch (cmd_id) {
158 case SMTP_EHLO:
159 psc->prot = PROT_ESMTP;
160 /* fall through */
161 case SMTP_HELO:
162 psc->helo_seen = TRUE;
164 if (conf.defer_all) { /* I need this to debug delivery failures */
165 smtp_printf(out, "421 %s service temporarily unavailable.\r\n", conf.host_name);
166 break;
167 }
169 if (psc->prot == PROT_ESMTP) {
170 smtp_printf(out, "250-%s Nice to meet you with ESMTP\r\n", conf.host_name);
171 /* not yet: fprintf(out, "250-SIZE\r\n"); */
172 smtp_printf(out, "250-PIPELINING\r\n" "250 HELP\r\n");
173 } else {
174 smtp_printf(out, "250 %s pretty old mailer, huh?\r\n", conf.host_name);
175 }
176 break;
178 case SMTP_MAIL_FROM:
179 {
180 gchar buf[MAX_ADDRESS];
181 address *addr;
183 if (!psc->helo_seen) {
184 smtp_printf(out, "503 need HELO or EHLO\r\n");
185 break;
186 }
187 if (psc->from_seen) {
188 smtp_printf(out, "503 MAIL FROM: already given.\r\n");
189 break;
190 }
192 msg = create_message();
193 msg->received_host = remote_host ? g_strdup(remote_host) : NULL;
194 msg->received_prot = psc->prot;
195 msg->ident = ident ? g_strdup(ident) : NULL;
196 /* get transfer id and increment for next one */
197 msg->transfer_id = (psc->next_id)++;
199 get_address(buffer, buf);
200 if (remote_host) {
201 addr = create_address(buf, TRUE);
202 } else {
203 addr = create_address_qualified(buf, TRUE, conf.host_name);
204 }
205 if (!addr) {
206 smtp_printf(out, "501 %s: syntax error.\r\n", buf);
207 } else if (!addr->domain) {
208 smtp_printf(out, "501 return path must be qualified.\r\n", buf);
209 } else {
210 psc->from_seen = TRUE;
211 msg->return_path = addr;
212 smtp_printf(out, "250 OK %s is a nice guy.\r\n", addr->address);
213 }
214 }
215 break;
217 case SMTP_RCPT_TO:
218 {
219 char buf[MAX_ADDRESS];
220 address *addr;
222 if (!psc->helo_seen) {
223 smtp_printf(out, "503 need HELO or EHLO.\r\n");
224 break;
225 }
226 if (!psc->from_seen) {
227 smtp_printf(out, "503 need MAIL FROM: before RCPT TO:\r\n");
228 break;
229 }
231 get_address(buffer, buf);
232 if (remote_host) {
233 addr = create_address(buf, TRUE);
234 } else {
235 addr = create_address_qualified(buf, TRUE, conf.host_name);
236 }
237 if (!addr) {
238 smtp_printf(out, "501 %s: syntax error in address.\r\n", buf);
239 break;
240 }
241 if (addr->local_part[0] == '|') {
242 smtp_printf(out, "501 %s: no pipe allowed for SMTP connections\r\n", buf);
243 break;
244 }
245 if (!addr->domain) {
246 smtp_printf(out, "501 recipient address must be qualified.\r\n", buf);
247 break;
248 }
249 gboolean do_relay = conf.do_relay;
250 if (!do_relay) {
251 do_relay = addr_is_local(msg->return_path);
252 if (!do_relay) {
253 do_relay = addr_is_local(addr);
254 }
255 }
256 if (!do_relay) {
257 smtp_printf(out, "550 relaying to %s denied.\r\n", addr_string(addr));
258 break;
259 }
260 psc->rcpt_seen = TRUE;
261 msg->rcpt_list = g_list_append(msg->rcpt_list, addr);
262 smtp_printf(out, "250 OK %s is our friend.\r\n", addr->address);
263 }
264 break;
266 case SMTP_DATA:
267 if (!psc->helo_seen) {
268 smtp_printf(out, "503 need HELO or EHLO.\r\n");
269 break;
270 }
271 if (!psc->rcpt_seen) {
272 smtp_printf(out, "503 need RCPT TO: before DATA\r\n");
273 break;
274 }
275 accept_error err;
277 smtp_printf(out, "354 okay, and do not forget the dot\r\n");
279 err = accept_message(in, msg, conf.do_save_envelope_to ? ACC_SAVE_ENVELOPE_TO : 0);
280 if (err != AERR_OK) {
281 if (err == AERR_TIMEOUT || err == AERR_EOF) {
282 return;
283 }
284 /* should never happen: */
285 smtp_printf(out, "451 Unknown error\r\n");
286 return;
287 }
290 if (!spool_write(msg, TRUE)) {
291 smtp_printf(out, "451 Could not write spool file\r\n");
292 return;
293 }
294 pid_t pid;
295 smtp_printf(out, "250 OK id=%s\r\n", msg->uid);
297 if (remote_host != NULL) {
298 logwrite(LOG_NOTICE, "%s <= <%s@%s> host=%s with %s\n", msg->uid,
299 msg->return_path->local_part, msg->return_path->domain,
300 remote_host, prot_names[psc->prot]);
301 } else {
302 logwrite(LOG_NOTICE, "%s <= <%s@%s> with %s\n", msg->uid,
303 msg->return_path->local_part, msg->return_path->domain,
304 prot_names[psc->prot]);
305 }
307 if (conf.do_queue) {
308 DEBUG(1) debugf("queuing forced by configuration or option.\n");
309 } else {
310 pid = fork();
311 if (pid == 0) {
312 _exit(deliver(msg));
313 } else if (pid < 0) {
314 logwrite(LOG_ALERT, "could not fork for delivery, id = %s", msg->uid);
315 }
316 }
317 psc->rcpt_seen = psc->from_seen = FALSE;
318 destroy_message(msg);
319 msg = NULL;
320 break;
322 case SMTP_QUIT:
323 smtp_printf(out, "221 goodbye\r\n");
324 destroy_message(msg);
325 msg = NULL;
326 return;
328 case SMTP_RSET:
329 psc->from_seen = psc->rcpt_seen = FALSE;
330 destroy_message(msg);
331 msg = NULL;
332 smtp_printf(out, "250 OK\r\n");
333 break;
335 case SMTP_NOOP:
336 smtp_printf(out, "250 OK\r\n");
337 break;
339 case SMTP_HELP:
340 {
341 int i;
343 smtp_printf(out, "214-supported commands:\r\n");
344 for (i = 0; i < SMTP_NUM_IDS - 1; i++) {
345 smtp_printf(out, "214-%s\r\n", smtp_cmds[i].cmd);
346 }
347 smtp_printf(out, "214 %s\r\n", smtp_cmds[i].cmd);
348 }
349 break;
351 default:
352 smtp_printf(out, "501 command not recognized\r\n");
353 DEBUG(1) debugf("command not recognized, was '%s'\n", buffer);
354 break;
355 }
356 }
357 switch (len) {
358 case -3:
359 logwrite(LOG_NOTICE, "connection timed out\n");
360 break;
361 case -2:
362 logwrite(LOG_NOTICE, "line overflow\n");
363 break;
364 case -1:
365 logwrite(LOG_NOTICE, "received EOF\n");
366 break;
367 default:
368 break;
369 }
370 }
371 #endif