masqmail

view src/smtp_out.c @ 224:996b53a50f55

added my copyright to files I worked on
author meillo@marmaro.de
date Fri, 23 Jul 2010 11:27:17 +0200
parents 8cddc65765bd
children 589c365d90b1
line source
1 /* smtp_out.c
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.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
20 /*
21 send bugs to: kurth@innominate.de
22 */
24 /*
25 I always forget these rfc numbers:
26 RFC 821 (SMTP)
27 RFC 1869 (ESMTP)
28 RFC 1870 (ESMTP SIZE)
29 RFC 2197 (ESMTP PIPELINE)
30 RFC 2554 (ESMTP AUTH)
31 */
33 #include "masqmail.h"
34 #include "smtp_out.h"
35 #include "readsock.h"
37 #ifdef ENABLE_AUTH
39 #ifdef USE_LIB_CRYPTO
40 #include <openssl/hmac.h>
41 #include <openssl/md5.h>
42 #include <openssl/evp.h>
43 #else
44 #include "md5/md5.h"
45 #include "md5/hmac_md5.h"
46 #endif
48 #include "base64/base64.h"
49 #endif
51 void
52 destroy_smtpbase(smtp_base * psb)
53 {
54 fclose(psb->in);
55 fclose(psb->out);
57 close(psb->sock);
59 if (psb->helo_name)
60 g_free(psb->helo_name);
61 if (psb->buffer)
62 g_free(psb->buffer);
63 if (psb->auth_names)
64 g_strfreev(psb->auth_names);
66 if (psb->auth_name)
67 g_free(psb->auth_name);
68 if (psb->auth_login)
69 g_free(psb->auth_login);
70 if (psb->auth_secret)
71 g_free(psb->auth_secret);
72 }
74 gchar*
75 set_heloname(smtp_base * psb, gchar * default_name, gboolean do_correct)
76 {
77 struct sockaddr_in sname;
78 int len = sizeof(struct sockaddr_in);
79 struct hostent *host_entry;
81 if (do_correct) {
82 getsockname(psb->sock, (struct sockaddr *) (&sname), &len);
83 DEBUG(5) debugf("socket: name.sin_addr = %s\n", inet_ntoa(sname.sin_addr));
84 host_entry = gethostbyaddr((const char *) &(sname.sin_addr), sizeof(sname.sin_addr), AF_INET);
85 if (host_entry) {
86 psb->helo_name = g_strdup(host_entry->h_name);
87 } else {
88 /* we failed to look up our own name. Instead of giving our local hostname,
89 we may give our IP number to show the server that we are at least
90 willing to be honest. For the really picky ones. */
91 DEBUG(5) debugf("failed to look up own host name.\n");
92 psb->helo_name = g_strdup_printf("[%s]", inet_ntoa(sname.sin_addr));
93 }
94 DEBUG(5) debugf("helo_name = %s\n", psb->helo_name);
95 }
96 if (psb->helo_name == NULL) {
97 psb->helo_name = g_strdup(default_name);
98 }
99 return psb->helo_name;
100 }
102 #ifdef ENABLE_AUTH
104 gboolean
105 set_auth(smtp_base * psb, gchar * name, gchar * login, gchar * secret)
106 {
107 if ((strcasecmp(name, "CRAM-MD5") == 0) || (strcasecmp(name, "LOGIN") == 0)) {
108 psb->auth_name = g_strdup(name);
109 psb->auth_login = g_strdup(login);
110 psb->auth_secret = g_strdup(secret);
112 return TRUE;
113 }
114 return FALSE;
115 }
117 #endif
119 static smtp_base*
120 create_smtpbase(gint sock)
121 {
122 gint dup_sock;
124 smtp_base *psb = (smtp_base *) g_malloc(sizeof(smtp_base));
126 psb->sock = sock;
128 psb->use_esmtp = FALSE;
129 psb->use_size = FALSE;
130 psb->use_pipelining = FALSE;
131 psb->use_auth = FALSE;
133 psb->max_size = 0;
134 psb->auth_names = NULL;
136 psb->buffer = (gchar *) g_malloc(SMTP_BUF_LEN);
138 dup_sock = dup(sock);
139 psb->out = fdopen(sock, "w");
140 psb->in = fdopen(dup_sock, "r");
142 psb->error = smtp_ok;
144 psb->helo_name = NULL;
146 psb->auth_name = psb->auth_login = psb->auth_secret = NULL;
148 return psb;
149 }
151 static gboolean
152 read_response(smtp_base * psb, int timeout)
153 {
154 gint buf_pos = 0;
155 gchar code[5];
156 gint i, len;
158 do {
159 len = read_sockline(psb->in, &(psb->buffer[buf_pos]), SMTP_BUF_LEN - buf_pos, timeout, READSOCKL_CHUG);
160 if (len == -3) {
161 psb->error = smtp_timeout;
162 return FALSE;
163 } else if (len == -2) {
164 psb->error = smtp_syntax;
165 return FALSE;
166 } else if (len == -1) {
167 psb->error = smtp_eof;
168 return FALSE;
169 }
170 for (i = 0; i < 4; i++)
171 code[i] = psb->buffer[buf_pos + i];
172 code[i] = '\0';
173 psb->last_code = atoi(code);
175 buf_pos += len;
177 } while (code[3] == '-');
178 if (psb->buffer) {
179 DEBUG(4) debugf("S: %s\n", psb->buffer);
180 }
182 return TRUE;
183 }
185 static gboolean
186 check_response(smtp_base * psb, gboolean after_data)
187 {
188 char c = psb->buffer[0];
190 if (((c == '2') && !after_data) || ((c == '3') && after_data)) {
191 psb->error = smtp_ok;
192 DEBUG(6) debugf("response OK:'%s' after_data = %d\n", psb->buffer, (int) after_data);
193 return TRUE;
194 } else {
195 if (c == '4')
196 psb->error = smtp_trylater;
197 else if (c == '5')
198 psb->error = smtp_fail;
199 else
200 psb->error = smtp_syntax;
201 DEBUG(6) debugf("response failure:'%s' after_data = %d\n", psb->buffer, (int) after_data);
202 return FALSE;
203 }
204 }
206 static gboolean
207 check_init_response(smtp_base * psb)
208 {
209 if (check_response(psb, FALSE)) {
210 psb->use_esmtp = (strstr(psb->buffer, "ESMTP") != NULL);
212 DEBUG(4) debugf(psb->use_esmtp ? "uses esmtp\n" : "no esmtp\n");
214 return TRUE;
215 }
216 return FALSE;
217 }
219 static gchar*
220 get_response_arg(gchar * response)
221 {
222 gchar buf[SMTP_BUF_LEN];
223 gchar *p = response, *q = buf;
225 while (*p && (*p != '\n') && isspace(*p))
226 p++;
227 if (*p && (*p != '\n')) {
228 while (*p && (*p != '\n') && (*p != '\r') && (q < buf + SMTP_BUF_LEN - 1))
229 *(q++) = *(p++);
230 *q = '\0';
231 return g_strdup(buf);
232 }
233 return NULL;
234 }
236 static gboolean
237 check_helo_response(smtp_base * psb)
238 {
239 gchar *ptr;
241 if (!check_response(psb, FALSE))
242 return FALSE;
244 if (psb->last_code == 220) {
245 logwrite(LOG_NOTICE, "received a 220 greeting after sending EHLO,\n");
246 logwrite(LOG_NOTICE, "please remove `instant_helo' from your route config\n");
247 /* read the next response, cause that's the actual helo response */
248 if (!read_response(psb, SMTP_CMD_TIMEOUT) || !check_response(psb, FALSE)) {
249 return FALSE;
250 }
251 }
253 ptr = psb->buffer;
255 while (*ptr) {
256 if (strncasecmp(&(ptr[4]), "SIZE", 4) == 0) {
257 gchar *arg;
258 psb->use_size = TRUE;
259 arg = get_response_arg(&(ptr[8]));
260 if (arg) {
261 psb->max_size = atoi(arg);
262 g_free(arg);
263 }
264 }
266 if (strncasecmp(&(ptr[4]), "PIPELINING", 10) == 0)
267 psb->use_pipelining = TRUE;
269 if (strncasecmp(&(ptr[4]), "AUTH", 4) == 0) {
270 if ((ptr[8] == ' ') || (ptr[8] == '=') || (ptr[8] == '\t')) { /* not sure about '\t' */
271 gchar *arg;
272 psb->use_auth = TRUE;
273 arg = get_response_arg(&(ptr[9])); /* after several years I finally learnt to count */
274 if (arg) {
275 psb->auth_names = g_strsplit(arg, " ", 0);
276 g_free(arg);
278 DEBUG(4) {
279 gint i = 0;
280 debugf("in check_helo_response()\n");
281 while (psb->auth_names[i]) {
282 debugf(" offered AUTH %s\n", psb->auth_names[i]);
283 i++;
284 }
285 }
286 }
287 }
288 }
290 while (*ptr != '\n')
291 ptr++;
292 ptr++;
293 }
295 DEBUG(4) {
296 debugf(" %s\n", psb->use_size ? "uses SIZE" : "no size");
297 debugf(" %s\n", psb->use_pipelining ? "uses PIPELINING" : "no pipelining");
298 debugf(" %s\n", psb->use_auth ? "uses AUTH" : "no auth");
299 }
301 return TRUE;
302 }
304 static gboolean
305 smtp_helo(smtp_base * psb, gchar * helo)
306 {
307 while (TRUE) {
308 if (psb->use_esmtp) {
309 fprintf(psb->out, "EHLO %s\r\n", helo);
310 fflush(psb->out);
312 DEBUG(4) debugf("C: EHLO %s\r\n", helo);
314 } else {
315 fprintf(psb->out, "HELO %s\r\n", helo);
316 fflush(psb->out);
318 DEBUG(4) debugf("C: HELO %s\r\n", helo);
320 }
322 if (!read_response(psb, SMTP_CMD_TIMEOUT))
323 return FALSE;
325 if (check_helo_response(psb))
326 return TRUE;
327 else {
328 if (psb->error == smtp_fail) {
329 if (psb->use_esmtp) {
330 /* our guess that server understands EHLO was wrong, try again with HELO */
331 psb->use_esmtp = FALSE;
332 } else {
333 /* what sort of server ist THAT ?! give up... */
334 return FALSE;
335 }
336 } else
337 return FALSE;
338 }
339 }
340 }
342 static void
343 smtp_cmd_mailfrom(smtp_base * psb, address * return_path, guint size)
344 {
345 if (psb->use_size) {
346 fprintf(psb->out, "MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
347 fflush(psb->out);
349 DEBUG(4) debugf("C: MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
351 } else {
352 fprintf(psb->out, "MAIL FROM:%s\r\n", addr_string(return_path));
353 fflush(psb->out);
355 DEBUG(4) debugf("C: MAIL FROM:%s\r\n", addr_string(return_path));
356 }
357 }
359 static void
360 smtp_cmd_rcptto(smtp_base * psb, address * rcpt)
361 {
362 fprintf(psb->out, "RCPT TO:%s\r\n", addr_string(rcpt));
363 fflush(psb->out);
364 DEBUG(4) debugf("C: RCPT TO:%s\n", addr_string(rcpt));
365 }
367 static void
368 send_data_line(smtp_base * psb, gchar * data)
369 {
370 /* According to RFC 821 each line should be terminated with CRLF.
371 Since a dot on a line itself marks the end of data, each line
372 beginning with a dot is prepended with another dot.
373 */
374 gchar *ptr;
375 gboolean new_line = TRUE; /* previous versions assumed that each item was exactly one line.
376 This is no longer the case */
378 ptr = data;
379 while (*ptr) {
380 int c = (int) (*ptr);
381 if (c == '.' && new_line) {
382 /* dot-stuffing */
383 putc('.', psb->out);
384 }
385 if (c == '\n') {
386 /* CRLF line terminators */
387 putc('\r', psb->out);
388 putc('\n', psb->out);
389 new_line = TRUE;
390 } else {
391 putc(c, psb->out);
392 new_line = FALSE;
393 }
394 ptr++;
395 }
396 }
398 static void
399 send_header(smtp_base * psb, GList * hdr_list)
400 {
401 GList *node;
402 gint num_hdrs = 0;
404 /* header */
405 if (hdr_list) {
406 foreach(hdr_list, node) {
407 if (node->data) {
408 header *hdr = (header *) (node->data);
409 if (hdr->header) {
410 send_data_line(psb, hdr->header);
411 num_hdrs++;
412 }
413 }
414 }
415 }
417 /* empty line separating headers from data: */
418 putc('\r', psb->out);
419 putc('\n', psb->out);
421 DEBUG(4) debugf("sent %d headers\n", num_hdrs);
422 }
424 static void
425 send_data(smtp_base * psb, message * msg)
426 {
427 GList *node;
428 gint num_lines = 0;
430 /* data */
431 if (msg->data_list) {
432 for (node = g_list_first(msg->data_list); node; node = g_list_next(node)) {
433 if (node->data) {
434 send_data_line(psb, node->data);
435 num_lines++;
436 }
437 }
438 }
440 DEBUG(4) debugf("sent %d lines of data\n", num_lines);
442 fprintf(psb->out, ".\r\n");
443 fflush(psb->out);
444 DEBUG(4) debugf("C: .\n");
445 }
447 void
448 smtp_out_mark_rcpts(smtp_base * psb, GList * rcpt_list)
449 {
450 GList *rcpt_node;
451 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
452 address *rcpt = (address *) (rcpt_node->data);
454 addr_unmark_delivered(rcpt);
456 if ((psb->error == smtp_trylater) || (psb->error == smtp_timeout) || (psb->error == smtp_eof)) {
457 addr_mark_defered(rcpt);
458 } else {
459 addr_mark_failed(rcpt);
460 }
461 }
462 }
464 void
465 smtp_out_log_failure(smtp_base * psb, message * msg)
466 {
467 gchar *err_str;
469 if (psb->error == smtp_timeout)
470 err_str = g_strdup("connection timed out.");
471 else if (psb->error == smtp_eof)
472 err_str = g_strdup("connection terminated prematurely.");
473 else if (psb->error == smtp_syntax)
474 err_str = g_strdup_printf("got unexpected response: %s", psb->buffer);
475 else if (psb->error == smtp_cancel)
476 err_str = g_strdup("delivery was canceled.\n");
477 else
478 /* error message should still be in the buffer */
479 err_str = g_strdup_printf("failed: %s\n", psb->buffer);
481 if (msg == NULL)
482 logwrite(LOG_NOTICE, "host=%s %s\n", psb->remote_host, err_str);
483 else
484 logwrite(LOG_NOTICE, "%s == host=%s %s\n", msg->uid, psb->remote_host, err_str);
486 g_free(err_str);
487 }
489 smtp_base*
490 smtp_out_open(gchar * host, gint port, GList * resolve_list)
491 {
492 smtp_base *psb;
493 gint sock;
494 mxip_addr *addr;
496 DEBUG(5) debugf("smtp_out_open entered, host = %s\n", host);
498 if ((addr = connect_resolvelist(&sock, host, port, resolve_list))) {
499 /* create structure to hold status data: */
500 psb = create_smtpbase(sock);
501 psb->remote_host = addr->name;
503 DEBUG(5) {
504 struct sockaddr_in name;
505 int len = sizeof(struct sockaddr);
506 getsockname(sock, (struct sockaddr *) (&name), &len);
507 debugf("socket: name.sin_addr = %s\n", inet_ntoa(name.sin_addr));
508 }
509 return psb;
510 } else {
511 DEBUG(5) debugf("connect_resolvelist failed: %s %s\n", strerror(errno), hstrerror(h_errno));
512 }
514 return NULL;
515 }
517 smtp_base*
518 smtp_out_open_child(gchar * cmd)
519 {
520 smtp_base *psb;
521 gint sock;
523 DEBUG(5) debugf("smtp_out_open_child entered, cmd = %s\n", cmd);
525 sock = child(cmd);
527 if (sock > 0) {
528 psb = create_smtpbase(sock);
529 psb->remote_host = NULL;
531 return psb;
532 }
534 return NULL;
535 }
537 gboolean
538 smtp_out_rset(smtp_base * psb)
539 {
540 gboolean ok;
542 fprintf(psb->out, "RSET\r\n");
543 fflush(psb->out);
544 DEBUG(4) debugf("C: RSET\n");
546 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
547 if (check_response(psb, FALSE))
548 return TRUE;
550 smtp_out_log_failure(psb, NULL);
552 return FALSE;
553 }
555 #ifdef ENABLE_AUTH
557 static gboolean
558 smtp_out_auth_cram_md5(smtp_base * psb)
559 {
560 gboolean ok = FALSE;
562 fprintf(psb->out, "C: AUTH CRAM-MD5\r\n");
563 fflush(psb->out);
564 DEBUG(4) debugf("AUTH CRAM-MD5\n");
565 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
566 if ((ok = check_response(psb, TRUE))) {
567 gchar *chall64 = get_response_arg(&(psb->buffer[4]));
568 gint chall_size;
569 gchar *chall = base64_decode(chall64, &chall_size);
570 guchar digest[16], *reply64, *reply;
571 gchar digest_string[33];
572 gint i;
573 #ifdef USE_LIB_CRYPTO
574 unsigned int digest_len;
575 #endif
577 DEBUG(5) debugf("smtp_out_auth_cram_md5():\n");
578 DEBUG(5) debugf(" encoded challenge = %s\n", chall64);
579 DEBUG(5) debugf(" decoded challenge = %s, size = %d\n", chall, chall_size);
580 DEBUG(5) debugf(" secret = %s\n", psb->auth_secret);
582 #ifdef USE_LIB_CRYPTO
583 HMAC(EVP_md5(), psb->auth_secret, strlen(psb->auth_secret), chall, chall_size, digest, &digest_len);
584 #else
585 hmac_md5(chall, chall_size, psb->auth_secret, strlen(psb->auth_secret), digest);
586 #endif
588 for (i = 0; i < 16; i++)
589 sprintf(&(digest_string[i + i]), "%02x", (unsigned int) (digest[i]));
590 digest_string[32] = '\0';
592 DEBUG(5) debugf(" digest = %s\n", digest_string);
594 reply = g_strdup_printf("%s %s", psb->auth_login, digest_string);
595 DEBUG(5) debugf(" unencoded reply = %s\n", reply);
597 reply64 = base64_encode(reply, strlen(reply));
598 DEBUG(5) debugf(" encoded reply = %s\n", reply64);
600 fprintf(psb->out, "%s\r\n", reply64);
601 fflush(psb->out);
602 DEBUG(6) debugf(" reply64 = %s\n", reply64);
603 DEBUG(6) debugf("C: %s\n", reply64);
605 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
606 ok = check_response(psb, FALSE);
608 g_free(reply64);
609 g_free(reply);
610 g_free(chall);
611 g_free(chall64);
612 }
613 }
614 return ok;
615 }
617 static gboolean
618 smtp_out_auth_login(smtp_base * psb)
619 {
620 gboolean ok = FALSE;
621 fprintf(psb->out, "AUTH LOGIN\r\n");
622 fflush(psb->out);
623 DEBUG(4) debugf("C: AUTH LOGIN\r\n");
624 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
625 if ((ok = check_response(psb, TRUE))) {
626 gchar *resp64;
627 guchar *resp;
628 gint resp_size;
629 gchar *reply64;
631 DEBUG(5) debugf("smtp_out_auth_login():\n");
632 resp64 = get_response_arg(&(psb->buffer[4]));
633 DEBUG(5) debugf(" encoded response = %s\n", resp64);
634 resp = base64_decode(resp64, &resp_size);
635 g_free(resp64);
636 DEBUG(5) debugf(" decoded response = %s, size = %d\n", resp, resp_size);
637 g_free(resp);
638 reply64 = base64_encode(psb->auth_login, strlen(psb->auth_login));
639 fprintf(psb->out, "%s\r\n", reply64);
640 fflush(psb->out);
641 DEBUG(6) debugf("C: %s\n", reply64);
642 g_free(reply64);
643 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
644 if ((ok = check_response(psb, TRUE))) {
645 resp64 = get_response_arg(&(psb->buffer[4]));
646 DEBUG(5) debugf(" encoded response = %s\n", resp64);
647 resp = base64_decode(resp64, &resp_size);
648 g_free(resp64);
649 DEBUG(5) debugf(" decoded response = %s, size = %d\n", resp, resp_size);
650 g_free(resp);
651 reply64 = base64_encode(psb->auth_secret, strlen(psb->auth_secret));
652 fprintf(psb->out, "%s\r\n", reply64);
653 fflush(psb->out);
654 DEBUG(6) debugf("C: %s\n", reply64);
655 g_free(reply64);
656 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
657 ok = check_response(psb, FALSE);
658 }
659 }
660 }
661 }
662 return ok;
663 }
665 gboolean
666 smtp_out_auth(smtp_base * psb)
667 {
668 gboolean ok = FALSE;
669 gint i = 0;
670 while (psb->auth_names[i]) {
671 if (strcasecmp(psb->auth_names[i], psb->auth_name) == 0)
672 break;
673 i++;
674 }
675 if (psb->auth_names[i]) {
676 if (strcasecmp(psb->auth_name, "cram-md5") == 0) {
677 smtp_out_auth_cram_md5(psb);
678 } else if (strcasecmp(psb->auth_name, "login") == 0) {
679 smtp_out_auth_login(psb);
680 } else {
681 logwrite(LOG_ERR, "auth method %s not supported\n", psb->auth_name);
682 }
683 } else {
684 logwrite(LOG_ERR, "no auth method %s found.\n", psb->auth_name);
685 }
686 return ok;
687 }
689 #endif
691 gboolean
692 smtp_out_init(smtp_base * psb, gboolean instant_helo)
693 {
694 gboolean ok;
696 logwrite(LOG_INFO, "smtp_out_init(): instant_helo:%d\n", instant_helo);
698 if (instant_helo) {
699 /* we say hello right away, hence we don't know if
700 ESMTP is supported; we just assume it */
701 psb->use_esmtp = 1;
702 } else {
703 if ((ok = read_response(psb, SMTP_INITIAL_TIMEOUT))) {
704 ok = check_init_response(psb);
705 }
706 if (!ok) {
707 smtp_out_log_failure(psb, NULL);
708 return ok;
709 }
710 }
712 if ((ok = smtp_helo(psb, psb->helo_name))) {
713 #ifdef ENABLE_AUTH
714 if (psb->auth_name && psb->use_auth) {
715 /* we completely disregard the response of server here. If
716 authentication fails, the server will complain later
717 anyway. I know, this is not polite... */
718 smtp_out_auth(psb);
719 }
720 #endif
721 }
722 if (!ok)
723 smtp_out_log_failure(psb, NULL);
724 return ok;
725 }
727 gint
728 smtp_out_msg(smtp_base * psb, message * msg, address * return_path, GList * rcpt_list, GList * hdr_list)
729 {
730 gint i, size;
731 gboolean ok = TRUE;
732 int rcpt_cnt;
733 int rcpt_accept = 0;
735 DEBUG(5) debugf("smtp_out_msg entered\n");
737 /* defaults: */
738 if (return_path == NULL)
739 return_path = msg->return_path;
740 if (hdr_list == NULL)
741 hdr_list = msg->hdr_list;
742 if (rcpt_list == NULL)
743 rcpt_list = msg->rcpt_list;
744 rcpt_cnt = g_list_length(rcpt_list);
746 size = msg_calc_size(msg, TRUE);
748 /* respect maximum size given by server: */
749 if ((psb->max_size > 0) && (size > psb->max_size)) {
750 logwrite(LOG_WARNING, "%s == host=%s message size (%d) > "
751 "fixed maximum message size of server (%d)",
752 msg->uid, psb->remote_host, size, psb->max_size);
753 psb->error = smtp_cancel;
754 ok = FALSE;
755 }
757 if (ok) {
758 /* pretend the message is a bit larger,
759 just in case the size calculation is buggy */
760 smtp_cmd_mailfrom(psb, return_path, psb->use_size ? size+SMTP_SIZE_ADD : 0);
762 if (!psb->use_pipelining) {
763 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
764 ok = check_response(psb, FALSE);
765 }
766 }
767 if (ok) {
768 GList *rcpt_node;
769 rcpt_accept = 0;
771 for (rcpt_node = g_list_first(rcpt_list); rcpt_node != NULL; rcpt_node = g_list_next(rcpt_node)) {
772 address *rcpt = (address *) (rcpt_node->data);
773 smtp_cmd_rcptto(psb, rcpt);
774 if (!psb->use_pipelining) {
775 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
776 if (check_response(psb, FALSE)) {
777 rcpt_accept++;
778 addr_mark_delivered(rcpt);
779 } else {
780 /* if server returned an error for one recp. we
781 may still try the others. But if it is a timeout, eof
782 or unexpected response, it is more serious and we should
783 give up. */
784 if ((psb->error != smtp_trylater) && (psb->error != smtp_fail)) {
785 ok = FALSE;
786 break;
787 } else {
788 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n",
789 msg->uid, addr_string(rcpt), psb->remote_host, psb->buffer);
790 if (psb->error == smtp_trylater) {
791 addr_mark_defered(rcpt);
792 } else {
793 addr_mark_failed(rcpt);
794 }
795 }
796 } else
797 break;
798 }
799 }
801 /* There is no point in going on if no recp.s were accpted.
802 But we can check that at this point only if not pipelining: */
803 ok = (ok && (psb->use_pipelining || (rcpt_accept > 0)));
804 if (ok) {
806 fprintf(psb->out, "DATA\r\n");
807 fflush(psb->out);
809 DEBUG(4) debugf("C: DATA\r\n");
811 if (psb->use_pipelining) {
812 /* the first pl'ed command was MAIL FROM
813 the last was DATA, whose response can be handled by the 'normal' code
814 all in between were RCPT TO:
815 */
816 /* response to MAIL FROM: */
817 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
818 if ((ok = check_response(psb, FALSE))) {
820 /* response(s) to RCPT TO:
821 this is very similar to the sequence above for no pipeline
822 */
823 for (i = 0; i < rcpt_cnt; i++) {
824 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
825 address *rcpt = g_list_nth_data(rcpt_list, i);
826 if (check_response(psb, FALSE)) {
827 rcpt_accept++;
828 addr_mark_delivered(rcpt);
829 } else {
830 /* if server returned an error 4xx or 5xx for one recp. we
831 may still try the others. But if it is a timeout, eof
832 or unexpected response, it is more serious and we
833 should give up. */
834 if ((psb->error != smtp_trylater) &&
835 (psb->error != smtp_fail)) {
836 ok = FALSE;
837 break;
838 } else {
839 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n", msg->uid,
840 addr_string(rcpt), psb->remote_host, psb->buffer);
841 if (psb->error == smtp_trylater) {
842 addr_mark_defered(rcpt);
843 } else {
844 addr_mark_failed(rcpt);
845 }
846 }
847 }
848 } else {
849 DEBUG(5) debugf("check_response failed after RCPT TO\n");
850 break;
851 }
852 }
853 if (rcpt_accept == 0)
854 ok = FALSE;
855 } else {
856 DEBUG(5) debugf("check_response failed after MAIL FROM\n");
857 }
858 } else {
859 DEBUG(5)
860 debugf("read_response failed after MAIL FROM\n");
861 }
862 }
864 /* if(psb->use_pipelining) */
865 /* response to the DATA cmd */
866 if (ok) {
867 if (read_response(psb, SMTP_DATA_TIMEOUT)) {
868 if (check_response(psb, TRUE)) {
869 send_header(psb, hdr_list);
870 send_data(psb, msg);
872 if (read_response(psb, SMTP_FINAL_TIMEOUT))
873 ok = check_response(psb, FALSE);
874 }
875 }
876 }
877 }
878 }
880 DEBUG(5) {
881 debugf("smtp_out_msg():\n");
882 debugf(" psb->error = %d\n", psb->error);
883 debugf(" ok = %d\n", ok);
884 debugf(" rcpt_accept = %d\n", rcpt_accept);
885 }
887 if (psb->error == smtp_ok) {
888 GList *rcpt_node;
889 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
890 address *rcpt = (address *) (rcpt_node->data);
891 if (addr_is_delivered(rcpt))
892 logwrite(LOG_NOTICE, "%s => %s host=%s with %s\n", msg->uid, addr_string(rcpt),
893 psb->remote_host, psb->use_esmtp ? "esmtp" : "smtp");
894 }
895 } else {
896 /* if something went wrong,
897 we have to unmark the rcpts prematurely marked as delivered
898 and mark the status */
899 smtp_out_mark_rcpts(psb, rcpt_list);
901 /* log the failure: */
902 smtp_out_log_failure(psb, msg);
903 }
904 return rcpt_accept;
905 }
907 gboolean
908 smtp_out_quit(smtp_base * psb)
909 {
910 fprintf(psb->out, "QUIT\r\n");
911 fflush(psb->out);
913 DEBUG(4) debugf("C: QUIT\n");
915 signal(SIGALRM, SIG_DFL);
917 return TRUE;
918 }
920 gint
921 smtp_deliver(gchar * host, gint port, GList * resolve_list, message * msg, address * return_path, GList * rcpt_list)
922 {
923 smtp_base *psb;
924 smtp_error err;
926 DEBUG(5) debugf("smtp_deliver entered\n");
928 if (return_path == NULL)
929 return_path = msg->return_path;
931 if ((psb = smtp_out_open(host, port, resolve_list))) {
932 set_heloname(psb, return_path->domain, TRUE);
933 /* initiate connection, send message and quit: */
934 if (smtp_out_init(psb, FALSE)) {
935 smtp_out_msg(psb, msg, return_path, rcpt_list, NULL);
936 if (psb->error == smtp_ok || (psb->error == smtp_fail) || (psb->error == smtp_trylater)
937 || (psb->error == smtp_syntax) || (psb->error == smtp_cancel))
938 smtp_out_quit(psb);
939 }
941 err = psb->error;
942 destroy_smtpbase(psb);
944 return err;
945 }
946 return -1;
947 }