masqmail
changeset 80:e5090ac234cf
refactoring plus one small bugfix
replaced deep nested conditionals with early exits
fixed a small bug in the same go (Note: it is bad to fix
bugs during refactoring): The SMTP_HELO case did not break
in case of error. Now it does.
author | meillo@marmaro.de |
---|---|
date | Sat, 19 Jun 2010 11:11:28 +0200 |
parents | d2bee9f4625c |
children | 71ce3a1568e9 |
files | src/smtp_in.c |
diffstat | 1 files changed, 238 insertions(+), 212 deletions(-) [+] |
line diff
1.1 --- a/src/smtp_in.c Sat Jun 19 10:52:24 2010 +0200 1.2 +++ b/src/smtp_in.c Sat Jun 19 11:11:28 2010 +0200 1.3 @@ -1,5 +1,6 @@ 1.4 /* MasqMail 1.5 Copyright (C) 1999-2001 Oliver Kurth 1.6 + Copyright (C) 2010 markus schnalke <meillo@marmaro.de> 1.7 1.8 This program is free software; you can redistribute it and/or modify 1.9 it under the terms of the GNU General Public License as published by 1.10 @@ -47,8 +48,9 @@ 1.11 { 1.12 gint i; 1.13 for (i = 0; i < SMTP_NUM_IDS; i++) { 1.14 - if (strncasecmp(smtp_cmds[i].cmd, line, strlen(smtp_cmds[i].cmd)) == 0) 1.15 + if (strncasecmp(smtp_cmds[i].cmd, line, strlen(smtp_cmds[i].cmd)) == 0) { 1.16 return (smtp_cmd_id) i; 1.17 + } 1.18 } 1.19 return SMTP_ERROR; 1.20 } 1.21 @@ -59,20 +61,24 @@ 1.22 static gboolean 1.23 get_address(gchar * line, gchar * addr) 1.24 { 1.25 - gchar *p = line, *q = addr; 1.26 + gchar *p = line; 1.27 + gchar *q = addr; 1.28 1.29 /* skip MAIL FROM: and RCPT TO: */ 1.30 - while (*p && (*p != ':')) 1.31 + while (*p && (*p != ':')) { 1.32 p++; 1.33 + } 1.34 p++; 1.35 1.36 /* skip spaces: */ 1.37 - while (*p && isspace(*p)) 1.38 + while (*p && isspace(*p)) { 1.39 p++; 1.40 + } 1.41 1.42 /* get address: */ 1.43 - while (*p && !isspace(*p) && (q < addr + MAX_ADDRESS - 1)) 1.44 + while (*p && !isspace(*p) && (q < addr + MAX_ADDRESS - 1)) { 1.45 *(q++) = *(p++); 1.46 + } 1.47 *q = 0; 1.48 1.49 return TRUE; 1.50 @@ -82,19 +88,20 @@ 1.51 create_base(gchar * remote_host) 1.52 { 1.53 smtp_connection *base = g_malloc(sizeof(smtp_connection)); 1.54 - if (base) { 1.55 - base->remote_host = g_strdup(remote_host); 1.56 + if (!base) { 1.57 + return NULL; 1.58 + } 1.59 1.60 - base->prot = PROT_SMTP; 1.61 - base->next_id = 0; 1.62 - base->helo_seen = 0; 1.63 - base->from_seen = 0; 1.64 - base->rcpt_seen = 0; 1.65 - base->msg = NULL; 1.66 + base->remote_host = g_strdup(remote_host); 1.67 1.68 - return base; 1.69 - } 1.70 - return NULL; 1.71 + base->prot = PROT_SMTP; 1.72 + base->next_id = 0; 1.73 + base->helo_seen = 0; 1.74 + base->from_seen = 0; 1.75 + base->rcpt_seen = 0; 1.76 + base->msg = NULL; 1.77 + 1.78 + return base; 1.79 } 1.80 1.81 static void 1.82 @@ -135,214 +142,233 @@ 1.83 psc->msg = msg; 1.84 1.85 buffer = (gchar *) g_malloc(BUF_LEN); 1.86 - if (buffer) { 1.87 - /* send greeting string, containing ESMTP: */ 1.88 - smtp_printf(out, "220 %s MasqMail %s ESMTP\r\n", conf.host_name, VERSION); 1.89 + if (!buffer) { 1.90 + /* this check is actually unneccessary as g_malloc() 1.91 + aborts on failure */ 1.92 + return; 1.93 + } 1.94 1.95 - while ((len = read_sockline(in, buffer, BUF_LEN, 5 * 60, READSOCKL_CHUG)) >= 0) { 1.96 - cmd_id = get_id(buffer); 1.97 + /* send greeting string, containing ESMTP: */ 1.98 + smtp_printf(out, "220 %s MasqMail %s ESMTP\r\n", conf.host_name, VERSION); 1.99 1.100 - switch (cmd_id) { 1.101 - case SMTP_EHLO: 1.102 - psc->prot = PROT_ESMTP; 1.103 - /* fall through */ 1.104 - case SMTP_HELO: 1.105 - psc->helo_seen = TRUE; 1.106 + while ((len = read_sockline(in, buffer, BUF_LEN, 5 * 60, READSOCKL_CHUG)) >= 0) { 1.107 + cmd_id = get_id(buffer); 1.108 1.109 - if (!conf.defer_all) { /* I need this to debug delivery failures */ 1.110 - if (psc->prot == PROT_ESMTP) { 1.111 - smtp_printf(out, "250-%s Nice to meet you with ESMTP\r\n", conf.host_name); 1.112 - /* not yet: fprintf(out, "250-SIZE\r\n"); */ 1.113 - smtp_printf(out, "250-PIPELINING\r\n" "250 HELP\r\n"); 1.114 - } else { 1.115 - smtp_printf(out, "250 %s pretty old mailer, huh?\r\n", conf.host_name); 1.116 - } 1.117 - break; 1.118 - } else { 1.119 - smtp_printf(out, "421 %s service temporarily unavailable.\r\n", conf.host_name); 1.120 - } 1.121 + switch (cmd_id) { 1.122 + case SMTP_EHLO: 1.123 + psc->prot = PROT_ESMTP; 1.124 + /* fall through */ 1.125 + case SMTP_HELO: 1.126 + psc->helo_seen = TRUE; 1.127 1.128 - case SMTP_MAIL_FROM: 1.129 - if (psc->helo_seen && !psc->from_seen) { 1.130 - gchar buf[MAX_ADDRESS]; 1.131 - address *addr; 1.132 - 1.133 - msg = create_message(); 1.134 - msg->received_host = remote_host ? g_strdup(remote_host) : NULL; 1.135 - msg->received_prot = psc->prot; 1.136 - msg->ident = ident ? g_strdup(ident) : NULL; 1.137 - /* get transfer id and increment for next one */ 1.138 - msg->transfer_id = (psc->next_id)++; 1.139 - 1.140 - get_address(buffer, buf); 1.141 - if ((addr = remote_host 1.142 - ? create_address(buf, TRUE) 1.143 - : create_address_qualified(buf, TRUE, conf.host_name))) { 1.144 - if (addr->domain != NULL) { 1.145 - psc->from_seen = TRUE; 1.146 - msg->return_path = addr; 1.147 - smtp_printf(out, "250 OK %s is a nice guy.\r\n", addr->address); 1.148 - } else { 1.149 - smtp_printf(out, "501 return path must be qualified.\r\n", buf); 1.150 - } 1.151 - } else { 1.152 - smtp_printf(out, "501 %s: syntax error.\r\n", buf); 1.153 - } 1.154 - } else { 1.155 - if (!psc->helo_seen) 1.156 - smtp_printf(out, "503 need HELO or EHLO\r\n"); 1.157 - else 1.158 - smtp_printf(out, "503 MAIL FROM: already given.\r\n"); 1.159 - } 1.160 - break; 1.161 - 1.162 - case SMTP_RCPT_TO: 1.163 - 1.164 - if (psc->helo_seen && psc->from_seen) { 1.165 - char buf[MAX_ADDRESS]; 1.166 - address *addr; 1.167 - 1.168 - get_address(buffer, buf); 1.169 - if ((addr = remote_host 1.170 - ? create_address(buf, TRUE) 1.171 - : create_address_qualified(buf, TRUE, conf.host_name))) { 1.172 - if (addr->local_part[0] != '|') { 1.173 - if (addr->domain != NULL) { 1.174 - gboolean do_relay = conf.do_relay; 1.175 - if (!do_relay) { 1.176 - if ((do_relay = addr_is_local(msg->return_path))) { 1.177 - } 1.178 - if (!do_relay) { 1.179 - do_relay = addr_is_local(addr); 1.180 - } 1.181 - } 1.182 - if (do_relay) { 1.183 - psc->rcpt_seen = TRUE; 1.184 - msg->rcpt_list = g_list_append(msg->rcpt_list, addr); 1.185 - smtp_printf(out, "250 OK %s is our friend.\r\n", addr->address); 1.186 - } else { 1.187 - smtp_printf(out, "550 relaying to %s denied.\r\n", addr_string(addr)); 1.188 - } 1.189 - } else { 1.190 - smtp_printf(out, "501 recipient address must be qualified.\r\n", buf); 1.191 - } 1.192 - } else 1.193 - smtp_printf(out, "501 %s: no pipe allowed for SMTP connections\r\n", buf); 1.194 - } else { 1.195 - smtp_printf(out, "501 %s: syntax error in address.\r\n", buf); 1.196 - } 1.197 - } else { 1.198 - 1.199 - if (!psc->helo_seen) 1.200 - smtp_printf(out, "503 need HELO or EHLO.\r\n"); 1.201 - else 1.202 - smtp_printf(out, "503 need MAIL FROM: before RCPT TO:\r\n"); 1.203 - } 1.204 - break; 1.205 - 1.206 - case SMTP_DATA: 1.207 - if (psc->helo_seen && psc->rcpt_seen) { 1.208 - accept_error err; 1.209 - 1.210 - smtp_printf(out, "354 okay, and do not forget the dot\r\n"); 1.211 - 1.212 - if ((err = accept_message(in, msg, conf.do_save_envelope_to ? ACC_SAVE_ENVELOPE_TO : 0)) == AERR_OK) { 1.213 - if (spool_write(msg, TRUE)) { 1.214 - pid_t pid; 1.215 - smtp_printf(out, "250 OK id=%s\r\n", msg->uid); 1.216 - 1.217 - if (remote_host != NULL) 1.218 - logwrite(LOG_NOTICE, "%s <= <%s@%s> host=%s with %s\n", msg->uid, msg->return_path->local_part, 1.219 - msg->return_path->domain, remote_host, prot_names[psc->prot]); 1.220 - else 1.221 - logwrite(LOG_NOTICE, "%s <= <%s@%s> with %s\n", msg->uid, msg->return_path->local_part, 1.222 - msg->return_path->domain, prot_names[psc->prot]); 1.223 - 1.224 - if (!conf.do_queue) { 1.225 - if ((pid = fork()) == 0) { 1.226 - 1.227 - if (deliver(msg)) 1.228 - _exit(EXIT_SUCCESS); 1.229 - else 1.230 - _exit(EXIT_FAILURE); 1.231 - 1.232 - } else if (pid < 0) { 1.233 - logwrite(LOG_ALERT, "could not fork for delivery, id = %s", msg->uid); 1.234 - } 1.235 - } else { 1.236 - DEBUG(1) debugf("queuing forced by configuration or option.\n"); 1.237 - } 1.238 - } else { 1.239 - smtp_printf(out, "451 Could not write spool file\r\n"); 1.240 - return; 1.241 - } 1.242 - } else { 1.243 - switch (err) { 1.244 - case AERR_TIMEOUT: 1.245 - return; 1.246 - case AERR_EOF: 1.247 - return; 1.248 - default: 1.249 - /* should never happen: */ 1.250 - smtp_printf(out, "451 Unknown error\r\n"); 1.251 - return; 1.252 - } 1.253 - } 1.254 - psc->rcpt_seen = psc->from_seen = FALSE; 1.255 - destroy_message(msg); 1.256 - msg = NULL; 1.257 - } else { 1.258 - if (!psc->helo_seen) 1.259 - smtp_printf(out, "503 need HELO or EHLO.\r\n"); 1.260 - else 1.261 - smtp_printf(out, "503 need RCPT TO: before DATA\r\n"); 1.262 - } 1.263 - break; 1.264 - case SMTP_QUIT: 1.265 - smtp_printf(out, "221 goodbye\r\n"); 1.266 - if (msg != NULL) 1.267 - destroy_message(msg); 1.268 - return; 1.269 - case SMTP_RSET: 1.270 - psc->from_seen = psc->rcpt_seen = FALSE; 1.271 - if (msg != NULL) 1.272 - destroy_message(msg); 1.273 - msg = NULL; 1.274 - smtp_printf(out, "250 OK\r\n"); 1.275 - break; 1.276 - case SMTP_NOOP: 1.277 - smtp_printf(out, "250 OK\r\n"); 1.278 - break; 1.279 - case SMTP_HELP: 1.280 - { 1.281 - int i; 1.282 - 1.283 - smtp_printf(out, "214-supported commands:\r\n"); 1.284 - for (i = 0; i < SMTP_NUM_IDS - 1; i++) { 1.285 - smtp_printf(out, "214-%s\r\n", smtp_cmds[i].cmd); 1.286 - } 1.287 - smtp_printf(out, "214 %s\r\n", smtp_cmds[i].cmd); 1.288 - } 1.289 - break; 1.290 - default: 1.291 - smtp_printf(out, "501 command not recognized\r\n"); 1.292 - DEBUG(1) debugf("command not recognized, was '%s'\n", buffer); 1.293 + if (conf.defer_all) { /* I need this to debug delivery failures */ 1.294 + smtp_printf(out, "421 %s service temporarily unavailable.\r\n", conf.host_name); 1.295 break; 1.296 } 1.297 - } 1.298 - switch (len) { 1.299 - case -3: 1.300 - logwrite(LOG_NOTICE, "connection timed out\n"); 1.301 + 1.302 + if (psc->prot == PROT_ESMTP) { 1.303 + smtp_printf(out, "250-%s Nice to meet you with ESMTP\r\n", conf.host_name); 1.304 + /* not yet: fprintf(out, "250-SIZE\r\n"); */ 1.305 + smtp_printf(out, "250-PIPELINING\r\n" "250 HELP\r\n"); 1.306 + } else { 1.307 + smtp_printf(out, "250 %s pretty old mailer, huh?\r\n", conf.host_name); 1.308 + } 1.309 break; 1.310 - case -2: 1.311 - logwrite(LOG_NOTICE, "line overflow\n"); 1.312 + 1.313 + case SMTP_MAIL_FROM: 1.314 + { 1.315 + gchar buf[MAX_ADDRESS]; 1.316 + address *addr; 1.317 + 1.318 + if (!psc->helo_seen) { 1.319 + smtp_printf(out, "503 need HELO or EHLO\r\n"); 1.320 + break; 1.321 + } 1.322 + if (psc->from_seen) { 1.323 + smtp_printf(out, "503 MAIL FROM: already given.\r\n"); 1.324 + break; 1.325 + } 1.326 + 1.327 + msg = create_message(); 1.328 + msg->received_host = remote_host ? g_strdup(remote_host) : NULL; 1.329 + msg->received_prot = psc->prot; 1.330 + msg->ident = ident ? g_strdup(ident) : NULL; 1.331 + /* get transfer id and increment for next one */ 1.332 + msg->transfer_id = (psc->next_id)++; 1.333 + 1.334 + get_address(buffer, buf); 1.335 + if (remote_host) { 1.336 + addr = create_address(buf, TRUE); 1.337 + } else { 1.338 + addr = create_address_qualified(buf, TRUE, conf.host_name); 1.339 + } 1.340 + if (!addr) { 1.341 + smtp_printf(out, "501 %s: syntax error.\r\n", buf); 1.342 + } else if (!addr->domain) { 1.343 + smtp_printf(out, "501 return path must be qualified.\r\n", buf); 1.344 + } else { 1.345 + psc->from_seen = TRUE; 1.346 + msg->return_path = addr; 1.347 + smtp_printf(out, "250 OK %s is a nice guy.\r\n", addr->address); 1.348 + } 1.349 + } 1.350 break; 1.351 - case -1: 1.352 - logwrite(LOG_NOTICE, "received EOF\n"); 1.353 + 1.354 + case SMTP_RCPT_TO: 1.355 + { 1.356 + char buf[MAX_ADDRESS]; 1.357 + address *addr; 1.358 + 1.359 + if (!psc->helo_seen) { 1.360 + smtp_printf(out, "503 need HELO or EHLO.\r\n"); 1.361 + break; 1.362 + } 1.363 + if (!psc->from_seen) { 1.364 + smtp_printf(out, "503 need MAIL FROM: before RCPT TO:\r\n"); 1.365 + break; 1.366 + } 1.367 + 1.368 + get_address(buffer, buf); 1.369 + if (remote_host) { 1.370 + addr = create_address(buf, TRUE); 1.371 + } else { 1.372 + addr = create_address_qualified(buf, TRUE, conf.host_name); 1.373 + } 1.374 + if (!addr) { 1.375 + smtp_printf(out, "501 %s: syntax error in address.\r\n", buf); 1.376 + break; 1.377 + } 1.378 + if (addr->local_part[0] == '|') { 1.379 + smtp_printf(out, "501 %s: no pipe allowed for SMTP connections\r\n", buf); 1.380 + break; 1.381 + } 1.382 + if (!addr->domain) { 1.383 + smtp_printf(out, "501 recipient address must be qualified.\r\n", buf); 1.384 + break; 1.385 + } 1.386 + gboolean do_relay = conf.do_relay; 1.387 + if (!do_relay) { 1.388 + do_relay = addr_is_local(msg->return_path); 1.389 + if (!do_relay) { 1.390 + do_relay = addr_is_local(addr); 1.391 + } 1.392 + } 1.393 + if (!do_relay) { 1.394 + smtp_printf(out, "550 relaying to %s denied.\r\n", addr_string(addr)); 1.395 + break; 1.396 + } 1.397 + psc->rcpt_seen = TRUE; 1.398 + msg->rcpt_list = g_list_append(msg->rcpt_list, addr); 1.399 + smtp_printf(out, "250 OK %s is our friend.\r\n", addr->address); 1.400 + } 1.401 break; 1.402 + 1.403 + case SMTP_DATA: 1.404 + if (!psc->helo_seen) { 1.405 + smtp_printf(out, "503 need HELO or EHLO.\r\n"); 1.406 + break; 1.407 + } 1.408 + if (!psc->rcpt_seen) { 1.409 + smtp_printf(out, "503 need RCPT TO: before DATA\r\n"); 1.410 + break; 1.411 + } 1.412 + accept_error err; 1.413 + 1.414 + smtp_printf(out, "354 okay, and do not forget the dot\r\n"); 1.415 + 1.416 + err = accept_message(in, msg, conf.do_save_envelope_to ? ACC_SAVE_ENVELOPE_TO : 0); 1.417 + if (err != AERR_OK) { 1.418 + if (err == AERR_TIMEOUT || err == AERR_EOF) { 1.419 + return; 1.420 + } 1.421 + /* should never happen: */ 1.422 + smtp_printf(out, "451 Unknown error\r\n"); 1.423 + return; 1.424 + } 1.425 + 1.426 + 1.427 + if (!spool_write(msg, TRUE)) { 1.428 + smtp_printf(out, "451 Could not write spool file\r\n"); 1.429 + return; 1.430 + } 1.431 + pid_t pid; 1.432 + smtp_printf(out, "250 OK id=%s\r\n", msg->uid); 1.433 + 1.434 + if (remote_host != NULL) { 1.435 + logwrite(LOG_NOTICE, "%s <= <%s@%s> host=%s with %s\n", msg->uid, 1.436 + msg->return_path->local_part, msg->return_path->domain, 1.437 + remote_host, prot_names[psc->prot]); 1.438 + } else { 1.439 + logwrite(LOG_NOTICE, "%s <= <%s@%s> with %s\n", msg->uid, 1.440 + msg->return_path->local_part, msg->return_path->domain, 1.441 + prot_names[psc->prot]); 1.442 + } 1.443 + 1.444 + if (conf.do_queue) { 1.445 + DEBUG(1) debugf("queuing forced by configuration or option.\n"); 1.446 + } else { 1.447 + pid = fork(); 1.448 + if (pid == 0) { 1.449 + _exit(deliver(msg)); 1.450 + } else if (pid < 0) { 1.451 + logwrite(LOG_ALERT, "could not fork for delivery, id = %s", msg->uid); 1.452 + } 1.453 + } 1.454 + psc->rcpt_seen = psc->from_seen = FALSE; 1.455 + destroy_message(msg); 1.456 + msg = NULL; 1.457 + break; 1.458 + 1.459 + case SMTP_QUIT: 1.460 + smtp_printf(out, "221 goodbye\r\n"); 1.461 + if (msg) { 1.462 + destroy_message(msg); 1.463 + } 1.464 + return; 1.465 + 1.466 + case SMTP_RSET: 1.467 + psc->from_seen = psc->rcpt_seen = FALSE; 1.468 + if (msg) { 1.469 + destroy_message(msg); 1.470 + msg = NULL; 1.471 + } 1.472 + smtp_printf(out, "250 OK\r\n"); 1.473 + break; 1.474 + 1.475 + case SMTP_NOOP: 1.476 + smtp_printf(out, "250 OK\r\n"); 1.477 + break; 1.478 + 1.479 + case SMTP_HELP: 1.480 + { 1.481 + int i; 1.482 + 1.483 + smtp_printf(out, "214-supported commands:\r\n"); 1.484 + for (i = 0; i < SMTP_NUM_IDS - 1; i++) { 1.485 + smtp_printf(out, "214-%s\r\n", smtp_cmds[i].cmd); 1.486 + } 1.487 + smtp_printf(out, "214 %s\r\n", smtp_cmds[i].cmd); 1.488 + } 1.489 + break; 1.490 + 1.491 default: 1.492 + smtp_printf(out, "501 command not recognized\r\n"); 1.493 + DEBUG(1) debugf("command not recognized, was '%s'\n", buffer); 1.494 break; 1.495 } 1.496 } 1.497 + switch (len) { 1.498 + case -3: 1.499 + logwrite(LOG_NOTICE, "connection timed out\n"); 1.500 + break; 1.501 + case -2: 1.502 + logwrite(LOG_NOTICE, "line overflow\n"); 1.503 + break; 1.504 + case -1: 1.505 + logwrite(LOG_NOTICE, "received EOF\n"); 1.506 + break; 1.507 + default: 1.508 + break; 1.509 + } 1.510 } 1.511 #endif