masqmail-0.2

view src/smtp_out.c @ 171:349518b940db

added support for STARTTLS wrappers added the route config option `instant_helo' which causes masqmail, as SMTP client, not to wait for the server's 220 greeting. Instead if says EHLO right at once. You'll need this for STARTTLS wrappers that usually eat the greeting line.
author meillo@marmaro.de
date Thu, 22 Jul 2010 23:30:05 +0200
parents 52c82d755215
children 087e99c7702a
line source
1 /* smtp_out.c, Copyright (C) 1999-2001 Oliver Kurth,
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 */
18 /*
19 send bugs to: kurth@innominate.de
20 */
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 #include "masqmail.h"
32 #include "smtp_out.h"
33 #include "readsock.h"
35 #ifdef ENABLE_AUTH
37 #ifdef USE_LIB_CRYPTO
38 #include <openssl/hmac.h>
39 #include <openssl/md5.h>
40 #include <openssl/evp.h>
41 #else
42 #include "md5/md5.h"
43 #include "md5/hmac_md5.h"
44 #endif
46 #include "base64/base64.h"
47 #endif
49 void
50 destroy_smtpbase(smtp_base * psb)
51 {
52 fclose(psb->in);
53 fclose(psb->out);
55 close(psb->sock);
57 if (psb->helo_name)
58 g_free(psb->helo_name);
59 if (psb->buffer)
60 g_free(psb->buffer);
61 if (psb->auth_names)
62 g_strfreev(psb->auth_names);
64 if (psb->auth_name)
65 g_free(psb->auth_name);
66 if (psb->auth_login)
67 g_free(psb->auth_login);
68 if (psb->auth_secret)
69 g_free(psb->auth_secret);
70 }
72 gchar*
73 set_heloname(smtp_base * psb, gchar * default_name, gboolean do_correct)
74 {
75 struct sockaddr_in sname;
76 int len = sizeof(struct sockaddr_in);
77 struct hostent *host_entry;
79 if (do_correct) {
80 getsockname(psb->sock, (struct sockaddr *) (&sname), &len);
81 DEBUG(5) debugf("socket: name.sin_addr = %s\n", inet_ntoa(sname.sin_addr));
82 host_entry = gethostbyaddr((const char *) &(sname.sin_addr), sizeof(sname.sin_addr), AF_INET);
83 if (host_entry) {
84 psb->helo_name = g_strdup(host_entry->h_name);
85 } else {
86 /* we failed to look up our own name. Instead of giving our local hostname,
87 we may give our IP number to show the server that we are at least
88 willing to be honest. For the really picky ones. */
89 DEBUG(5) debugf("failed to look up own host name.\n");
90 psb->helo_name = g_strdup_printf("[%s]", inet_ntoa(sname.sin_addr));
91 }
92 DEBUG(5) debugf("helo_name = %s\n", psb->helo_name);
93 }
94 if (psb->helo_name == NULL) {
95 psb->helo_name = g_strdup(default_name);
96 }
97 return psb->helo_name;
98 }
100 #ifdef ENABLE_AUTH
102 gboolean
103 set_auth(smtp_base * psb, gchar * name, gchar * login, gchar * secret)
104 {
105 if ((strcasecmp(name, "CRAM-MD5") == 0) || (strcasecmp(name, "LOGIN") == 0)) {
106 psb->auth_name = g_strdup(name);
107 psb->auth_login = g_strdup(login);
108 psb->auth_secret = g_strdup(secret);
110 return TRUE;
111 }
112 return FALSE;
113 }
115 #endif
117 static smtp_base*
118 create_smtpbase(gint sock)
119 {
120 gint dup_sock;
122 smtp_base *psb = (smtp_base *) g_malloc(sizeof(smtp_base));
124 psb->sock = sock;
126 psb->use_esmtp = FALSE;
127 psb->use_size = FALSE;
128 psb->use_pipelining = FALSE;
129 psb->use_auth = FALSE;
131 psb->max_size = 0;
132 psb->auth_names = NULL;
134 psb->buffer = (gchar *) g_malloc(SMTP_BUF_LEN);
136 dup_sock = dup(sock);
137 psb->out = fdopen(sock, "w");
138 psb->in = fdopen(dup_sock, "r");
140 psb->error = smtp_ok;
142 psb->helo_name = NULL;
144 psb->auth_name = psb->auth_login = psb->auth_secret = NULL;
146 return psb;
147 }
149 static gboolean
150 read_response(smtp_base * psb, int timeout)
151 {
152 gint buf_pos = 0;
153 gchar code[5];
154 gint i, len;
156 do {
157 len = read_sockline(psb->in, &(psb->buffer[buf_pos]), SMTP_BUF_LEN - buf_pos, timeout, READSOCKL_CHUG);
158 if (len == -3) {
159 psb->error = smtp_timeout;
160 return FALSE;
161 } else if (len == -2) {
162 psb->error = smtp_syntax;
163 return FALSE;
164 } else if (len == -1) {
165 psb->error = smtp_eof;
166 return FALSE;
167 }
168 for (i = 0; i < 4; i++)
169 code[i] = psb->buffer[buf_pos + i];
170 code[i] = '\0';
171 psb->last_code = atoi(code);
173 buf_pos += len;
175 } while (code[3] == '-');
177 return TRUE;
178 }
180 static gboolean
181 check_response(smtp_base * psb, gboolean after_data)
182 {
183 char c = psb->buffer[0];
185 if (((c == '2') && !after_data) || ((c == '3') && after_data)) {
186 psb->error = smtp_ok;
187 DEBUG(6) debugf("response OK:'%s' after_date = %d\n", psb->buffer, (int) after_data);
188 return TRUE;
189 } else {
190 if (c == '4')
191 psb->error = smtp_trylater;
192 else if (c == '5')
193 psb->error = smtp_fail;
194 else
195 psb->error = smtp_syntax;
196 DEBUG(6) debugf("response failure:'%s' after_date = %d\n", psb->buffer, (int) after_data);
197 return FALSE;
198 }
199 }
201 static gboolean
202 check_init_response(smtp_base * psb)
203 {
204 if (check_response(psb, FALSE)) {
205 psb->use_esmtp = (strstr(psb->buffer, "ESMTP") != NULL);
207 DEBUG(4) debugf(psb->use_esmtp ? "uses esmtp\n" : "no esmtp\n");
209 return TRUE;
210 }
211 return FALSE;
212 }
214 static gchar*
215 get_response_arg(gchar * response)
216 {
217 gchar buf[SMTP_BUF_LEN];
218 gchar *p = response, *q = buf;
220 while (*p && (*p != '\n') && isspace(*p))
221 p++;
222 if (*p && (*p != '\n')) {
223 while (*p && (*p != '\n') && (*p != '\r') && (q < buf + SMTP_BUF_LEN - 1))
224 *(q++) = *(p++);
225 *q = '\0';
226 return g_strdup(buf);
227 }
228 return NULL;
229 }
231 static gboolean
232 check_helo_response(smtp_base * psb)
233 {
234 gchar *ptr;
236 if (!check_response(psb, FALSE))
237 return FALSE;
239 if (psb->last_code == 220) {
240 logwrite(LOG_NOTICE, "received a 220 greeting after sending EHLO,\n");
241 logwrite(LOG_NOTICE, "please remove `instant_helo' from your route config\n");
242 /* read the next response, cause that's the actual helo response */
243 if (!read_response(psb, SMTP_CMD_TIMEOUT) || !check_response(psb, FALSE)) {
244 return FALSE;
245 }
246 }
248 ptr = psb->buffer;
250 while (*ptr) {
251 if (strncasecmp(&(ptr[4]), "SIZE", 4) == 0) {
252 gchar *arg;
253 psb->use_size = TRUE;
254 arg = get_response_arg(&(ptr[8]));
255 if (arg) {
256 psb->max_size = atoi(arg);
257 g_free(arg);
258 }
259 }
261 if (strncasecmp(&(ptr[4]), "PIPELINING", 10) == 0)
262 psb->use_pipelining = TRUE;
264 if (strncasecmp(&(ptr[4]), "AUTH", 4) == 0) {
265 if ((ptr[8] == ' ') || (ptr[8] == '=') || (ptr[8] == '\t')) { /* not sure about '\t' */
266 gchar *arg;
267 psb->use_auth = TRUE;
268 arg = get_response_arg(&(ptr[9])); /* after several years I finally learnt to count */
269 if (arg) {
270 psb->auth_names = g_strsplit(arg, " ", 0);
271 g_free(arg);
273 DEBUG(4) {
274 gint i = 0;
275 debugf("in check_helo_response()\n");
276 while (psb->auth_names[i]) {
277 debugf(" offered AUTH %s\n", psb->auth_names[i]);
278 i++;
279 }
280 }
281 }
282 }
283 }
285 while (*ptr != '\n')
286 ptr++;
287 ptr++;
288 }
290 DEBUG(4) {
291 debugf(" %s\n", psb->use_size ? "uses SIZE" : "no size");
292 debugf(" %s\n", psb->use_pipelining ? "uses PIPELINING" : "no pipelining");
293 debugf(" %s\n", psb->use_auth ? "uses AUTH" : "no auth");
294 }
296 return TRUE;
297 }
299 static gboolean
300 smtp_helo(smtp_base * psb, gchar * helo)
301 {
302 while (TRUE) {
303 if (psb->use_esmtp) {
304 fprintf(psb->out, "EHLO %s\r\n", helo);
305 fflush(psb->out);
307 DEBUG(4) debugf("EHLO %s\r\n", helo);
309 } else {
310 fprintf(psb->out, "HELO %s\r\n", helo);
311 fflush(psb->out);
313 DEBUG(4) debugf("HELO %s\r\n", helo);
315 }
317 if (!read_response(psb, SMTP_CMD_TIMEOUT))
318 return FALSE;
320 if (check_helo_response(psb))
321 return TRUE;
322 else {
323 if (psb->error == smtp_fail) {
324 if (psb->use_esmtp) {
325 /* our guess that server understands EHLO was wrong, try again with HELO */
326 psb->use_esmtp = FALSE;
327 } else {
328 /* what sort of server ist THAT ?! give up... */
329 return FALSE;
330 }
331 } else
332 return FALSE;
333 }
334 }
335 }
337 static void
338 smtp_cmd_mailfrom(smtp_base * psb, address * return_path, guint size)
339 {
340 if (psb->use_size) {
341 fprintf(psb->out, "MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
342 fflush(psb->out);
344 DEBUG(4) debugf("MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
346 } else {
347 fprintf(psb->out, "MAIL FROM:%s\r\n", addr_string(return_path));
348 fflush(psb->out);
350 DEBUG(4) debugf("MAIL FROM:%s\r\n", addr_string(return_path));
351 }
352 }
354 static void
355 smtp_cmd_rcptto(smtp_base * psb, address * rcpt)
356 {
357 fprintf(psb->out, "RCPT TO:%s\r\n", addr_string(rcpt));
358 fflush(psb->out);
359 DEBUG(4) debugf("RCPT TO:%s\n", addr_string(rcpt));
360 }
362 static void
363 send_data_line(smtp_base * psb, gchar * data)
364 {
365 /* According to RFC 821 each line should be terminated with CRLF.
366 Since a dot on a line itself marks the end of data, each line
367 beginning with a dot is prepended with another dot.
368 */
369 gchar *ptr;
370 gboolean new_line = TRUE; /* previous versions assumed that each item was exactly one line.
371 This is no longer the case */
373 ptr = data;
374 while (*ptr) {
375 int c = (int) (*ptr);
376 if (c == '.' && new_line) {
377 /* dot-stuffing */
378 putc('.', psb->out);
379 }
380 if (c == '\n') {
381 /* CRLF line terminators */
382 putc('\r', psb->out);
383 putc('\n', psb->out);
384 new_line = TRUE;
385 } else {
386 putc(c, psb->out);
387 new_line = FALSE;
388 }
389 ptr++;
390 }
391 }
393 static void
394 send_header(smtp_base * psb, GList * hdr_list)
395 {
396 GList *node;
397 gint num_hdrs = 0;
399 /* header */
400 if (hdr_list) {
401 foreach(hdr_list, node) {
402 if (node->data) {
403 header *hdr = (header *) (node->data);
404 if (hdr->header) {
405 send_data_line(psb, hdr->header);
406 num_hdrs++;
407 }
408 }
409 }
410 }
412 /* empty line separating headers from data: */
413 putc('\r', psb->out);
414 putc('\n', psb->out);
416 DEBUG(4) debugf("sent %d headers\n", num_hdrs);
417 }
419 static void
420 send_data(smtp_base * psb, message * msg)
421 {
422 GList *node;
423 gint num_lines = 0;
425 /* data */
426 if (msg->data_list) {
427 for (node = g_list_first(msg->data_list); node; node = g_list_next(node)) {
428 if (node->data) {
429 send_data_line(psb, node->data);
430 num_lines++;
431 }
432 }
433 }
435 DEBUG(4) debugf("sent %d lines of data\n", num_lines);
437 fprintf(psb->out, ".\r\n");
438 fflush(psb->out);
439 }
441 void
442 smtp_out_mark_rcpts(smtp_base * psb, GList * rcpt_list)
443 {
444 GList *rcpt_node;
445 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
446 address *rcpt = (address *) (rcpt_node->data);
448 addr_unmark_delivered(rcpt);
450 if ((psb->error == smtp_trylater) || (psb->error == smtp_timeout) || (psb->error == smtp_eof)) {
451 addr_mark_defered(rcpt);
452 } else {
453 addr_mark_failed(rcpt);
454 }
455 }
456 }
458 void
459 smtp_out_log_failure(smtp_base * psb, message * msg)
460 {
461 gchar *err_str;
463 if (psb->error == smtp_timeout)
464 err_str = g_strdup("connection timed out.");
465 else if (psb->error == smtp_eof)
466 err_str = g_strdup("connection terminated prematurely.");
467 else if (psb->error == smtp_syntax)
468 err_str = g_strdup_printf("got unexpected response: %s", psb->buffer);
469 else if (psb->error == smtp_cancel)
470 err_str = g_strdup("delivery was canceled.\n");
471 else
472 /* error message should still be in the buffer */
473 err_str = g_strdup_printf("failed: %s\n", psb->buffer);
475 if (msg == NULL)
476 logwrite(LOG_NOTICE, "host=%s %s\n", psb->remote_host, err_str);
477 else
478 logwrite(LOG_NOTICE, "%s == host=%s %s\n", msg->uid, psb->remote_host, err_str);
480 g_free(err_str);
481 }
483 smtp_base*
484 smtp_out_open(gchar * host, gint port, GList * resolve_list)
485 {
486 smtp_base *psb;
487 gint sock;
488 mxip_addr *addr;
490 DEBUG(5) debugf("smtp_out_open entered, host = %s\n", host);
492 if ((addr = connect_resolvelist(&sock, host, port, resolve_list))) {
493 /* create structure to hold status data: */
494 psb = create_smtpbase(sock);
495 psb->remote_host = addr->name;
497 DEBUG(5) {
498 struct sockaddr_in name;
499 int len = sizeof(struct sockaddr);
500 getsockname(sock, (struct sockaddr *) (&name), &len);
501 debugf("socket: name.sin_addr = %s\n", inet_ntoa(name.sin_addr));
502 }
503 return psb;
504 } else {
505 DEBUG(5) debugf("connect_resolvelist failed: %s %s\n", strerror(errno), hstrerror(h_errno));
506 }
508 return NULL;
509 }
511 smtp_base*
512 smtp_out_open_child(gchar * cmd)
513 {
514 smtp_base *psb;
515 gint sock;
517 DEBUG(5) debugf("smtp_out_open_child entered, cmd = %s\n", cmd);
519 sock = child(cmd);
521 if (sock > 0) {
522 psb = create_smtpbase(sock);
523 psb->remote_host = NULL;
525 return psb;
526 }
528 return NULL;
529 }
531 gboolean
532 smtp_out_rset(smtp_base * psb)
533 {
534 gboolean ok;
536 fprintf(psb->out, "RSET\r\n");
537 fflush(psb->out);
538 DEBUG(4) debugf("RSET\n");
540 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
541 if (check_response(psb, FALSE))
542 return TRUE;
544 smtp_out_log_failure(psb, NULL);
546 return FALSE;
547 }
549 #ifdef ENABLE_AUTH
551 static gboolean
552 smtp_out_auth_cram_md5(smtp_base * psb)
553 {
554 gboolean ok = FALSE;
556 fprintf(psb->out, "AUTH CRAM-MD5\r\n");
557 fflush(psb->out);
558 DEBUG(4) debugf("AUTH CRAM-MD5\n");
559 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
560 if ((ok = check_response(psb, TRUE))) {
561 gchar *chall64 = get_response_arg(&(psb->buffer[4]));
562 gint chall_size;
563 gchar *chall = base64_decode(chall64, &chall_size);
564 guchar digest[16], *reply64, *reply;
565 gchar digest_string[33];
566 gint i;
567 #ifdef USE_LIB_CRYPTO
568 unsigned int digest_len;
569 #endif
571 DEBUG(5) debugf("smtp_out_auth_cram_md5():\n");
572 DEBUG(5) debugf(" encoded challenge = %s\n", chall64);
573 DEBUG(5) debugf(" decoded challenge = %s, size = %d\n", chall, chall_size);
574 DEBUG(5) debugf(" secret = %s\n", psb->auth_secret);
576 #ifdef USE_LIB_CRYPTO
577 HMAC(EVP_md5(), psb->auth_secret, strlen(psb->auth_secret), chall, chall_size, digest, &digest_len);
578 #else
579 hmac_md5(chall, chall_size, psb->auth_secret, strlen(psb->auth_secret), digest);
580 #endif
582 for (i = 0; i < 16; i++)
583 sprintf(&(digest_string[i + i]), "%02x", (unsigned int) (digest[i]));
584 digest_string[32] = '\0';
586 DEBUG(5) debugf(" digest = %s\n", digest_string);
588 reply = g_strdup_printf("%s %s", psb->auth_login, digest_string);
589 DEBUG(5) debugf(" unencoded reply = %s\n", reply);
591 reply64 = base64_encode(reply, strlen(reply));
592 DEBUG(5) debugf(" encoded reply = %s\n", reply64);
594 fprintf(psb->out, "%s\r\n", reply64);
595 fflush(psb->out);
596 DEBUG(4) debugf(" reply64 = %s\n", reply64);
598 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
599 ok = check_response(psb, FALSE);
601 g_free(reply64);
602 g_free(reply);
603 g_free(chall);
604 g_free(chall64);
605 }
606 }
607 return ok;
608 }
610 static gboolean
611 smtp_out_auth_login(smtp_base * psb)
612 {
613 gboolean ok = FALSE;
614 fprintf(psb->out, "AUTH LOGIN\r\n");
615 fflush(psb->out);
616 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
617 if ((ok = check_response(psb, TRUE))) {
618 gchar *resp64;
619 guchar *resp;
620 gint resp_size;
621 gchar *reply64;
623 DEBUG(5) debugf("smtp_out_auth_login():\n");
624 resp64 = get_response_arg(&(psb->buffer[4]));
625 DEBUG(5) debugf(" encoded response = %s\n", resp64);
626 resp = base64_decode(resp64, &resp_size);
627 g_free(resp64);
628 DEBUG(5) debugf(" decoded response = %s, size = %d\n", resp, resp_size);
629 g_free(resp);
630 reply64 = base64_encode(psb->auth_login, strlen(psb->auth_login));
631 fprintf(psb->out, "%s\r\n", reply64);
632 fflush(psb->out);
633 g_free(reply64);
634 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
635 if ((ok = check_response(psb, TRUE))) {
636 resp64 = get_response_arg(&(psb->buffer[4]));
637 DEBUG(5) debugf(" encoded response = %s\n", resp64);
638 resp = base64_decode(resp64, &resp_size);
639 g_free(resp64);
640 DEBUG(5) debugf(" decoded response = %s, size = %d\n", resp, resp_size);
641 g_free(resp);
642 reply64 = base64_encode(psb->auth_secret, strlen(psb->auth_secret));
643 fprintf(psb->out, "%s\r\n", reply64);
644 fflush(psb->out);
645 g_free(reply64);
646 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
647 ok = check_response(psb, FALSE);
648 }
649 }
650 }
651 }
652 return ok;
653 }
655 gboolean
656 smtp_out_auth(smtp_base * psb)
657 {
658 gboolean ok = FALSE;
659 gint i = 0;
660 while (psb->auth_names[i]) {
661 if (strcasecmp(psb->auth_names[i], psb->auth_name) == 0)
662 break;
663 i++;
664 }
665 if (psb->auth_names[i]) {
666 if (strcasecmp(psb->auth_name, "cram-md5") == 0) {
667 smtp_out_auth_cram_md5(psb);
668 } else if (strcasecmp(psb->auth_name, "login") == 0) {
669 smtp_out_auth_login(psb);
670 } else {
671 logwrite(LOG_ERR, "auth method %s not supported\n", psb->auth_name);
672 }
673 } else {
674 logwrite(LOG_ERR, "no auth method %s found.\n", psb->auth_name);
675 }
676 return ok;
677 }
679 #endif
681 gboolean
682 smtp_out_init(smtp_base * psb, gboolean instant_helo)
683 {
684 gboolean ok;
686 logwrite(LOG_INFO, "smtp_out_init(): instant_helo:%d\n", instant_helo);
688 if (instant_helo) {
689 /* we say hello right away, hence we don't know if
690 ESMTP is supported; we just assume it */
691 psb->use_esmtp = 1;
692 } else {
693 if ((ok = read_response(psb, SMTP_INITIAL_TIMEOUT))) {
694 ok = check_init_response(psb);
695 }
696 if (!ok) {
697 smtp_out_log_failure(psb, NULL);
698 return ok;
699 }
700 }
702 if ((ok = smtp_helo(psb, psb->helo_name))) {
703 #ifdef ENABLE_AUTH
704 if (psb->auth_name && psb->use_auth) {
705 /* we completely disregard the response of server here. If
706 authentication fails, the server will complain later
707 anyway. I know, this is not polite... */
708 smtp_out_auth(psb);
709 }
710 #endif
711 }
712 if (!ok)
713 smtp_out_log_failure(psb, NULL);
714 return ok;
715 }
717 gint
718 smtp_out_msg(smtp_base * psb, message * msg, address * return_path, GList * rcpt_list, GList * hdr_list)
719 {
720 gint i, size;
721 gboolean ok = TRUE;
722 int rcpt_cnt;
723 int rcpt_accept = 0;
725 DEBUG(5) debugf("smtp_out_msg entered\n");
727 /* defaults: */
728 if (return_path == NULL)
729 return_path = msg->return_path;
730 if (hdr_list == NULL)
731 hdr_list = msg->hdr_list;
732 if (rcpt_list == NULL)
733 rcpt_list = msg->rcpt_list;
734 rcpt_cnt = g_list_length(rcpt_list);
736 size = msg_calc_size(msg, TRUE);
738 /* respect maximum size given by server: */
739 if ((psb->max_size > 0) && (size > psb->max_size)) {
740 logwrite(LOG_WARNING, "%s == host=%s message size (%d) > "
741 "fixed maximum message size of server (%d)",
742 msg->uid, psb->remote_host, size, psb->max_size);
743 psb->error = smtp_cancel;
744 ok = FALSE;
745 }
747 if (ok) {
748 /* pretend the message is a bit larger,
749 just in case the size calculation is buggy */
750 smtp_cmd_mailfrom(psb, return_path, psb->use_size ? size+SMTP_SIZE_ADD : 0);
752 if (!psb->use_pipelining) {
753 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
754 ok = check_response(psb, FALSE);
755 }
756 }
757 if (ok) {
758 GList *rcpt_node;
759 rcpt_accept = 0;
761 for (rcpt_node = g_list_first(rcpt_list); rcpt_node != NULL; rcpt_node = g_list_next(rcpt_node)) {
762 address *rcpt = (address *) (rcpt_node->data);
763 smtp_cmd_rcptto(psb, rcpt);
764 if (!psb->use_pipelining) {
765 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
766 if (check_response(psb, FALSE)) {
767 rcpt_accept++;
768 addr_mark_delivered(rcpt);
769 } else {
770 /* if server returned an error for one recp. we
771 may still try the others. But if it is a timeout, eof
772 or unexpected response, it is more serious and we should
773 give up. */
774 if ((psb->error != smtp_trylater) && (psb->error != smtp_fail)) {
775 ok = FALSE;
776 break;
777 } else {
778 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n",
779 msg->uid, addr_string(rcpt), psb->remote_host, psb->buffer);
780 if (psb->error == smtp_trylater) {
781 addr_mark_defered(rcpt);
782 } else {
783 addr_mark_failed(rcpt);
784 }
785 }
786 } else
787 break;
788 }
789 }
791 /* There is no point in going on if no recp.s were accpted.
792 But we can check that at this point only if not pipelining: */
793 ok = (ok && (psb->use_pipelining || (rcpt_accept > 0)));
794 if (ok) {
796 fprintf(psb->out, "DATA\r\n");
797 fflush(psb->out);
799 DEBUG(4) debugf("DATA\r\n");
801 if (psb->use_pipelining) {
802 /* the first pl'ed command was MAIL FROM
803 the last was DATA, whose response can be handled by the 'normal' code
804 all in between were RCPT TO:
805 */
806 /* response to MAIL FROM: */
807 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
808 if ((ok = check_response(psb, FALSE))) {
810 /* response(s) to RCPT TO:
811 this is very similar to the sequence above for no pipeline
812 */
813 for (i = 0; i < rcpt_cnt; i++) {
814 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
815 address *rcpt = g_list_nth_data(rcpt_list, i);
816 if (check_response(psb, FALSE)) {
817 rcpt_accept++;
818 addr_mark_delivered(rcpt);
819 } else {
820 /* if server returned an error 4xx or 5xx for one recp. we
821 may still try the others. But if it is a timeout, eof
822 or unexpected response, it is more serious and we
823 should give up. */
824 if ((psb->error != smtp_trylater) &&
825 (psb->error != smtp_fail)) {
826 ok = FALSE;
827 break;
828 } else {
829 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n", msg->uid,
830 addr_string(rcpt), psb->remote_host, psb->buffer);
831 if (psb->error == smtp_trylater) {
832 addr_mark_defered(rcpt);
833 } else {
834 addr_mark_failed(rcpt);
835 }
836 }
837 }
838 } else {
839 DEBUG(5) debugf("check_response failed after RCPT TO\n");
840 break;
841 }
842 }
843 if (rcpt_accept == 0)
844 ok = FALSE;
845 } else {
846 DEBUG(5) debugf("check_response failed after MAIL FROM\n");
847 }
848 } else {
849 DEBUG(5)
850 debugf("read_response failed after MAIL FROM\n");
851 }
852 }
854 /* if(psb->use_pipelining) */
855 /* response to the DATA cmd */
856 if (ok) {
857 if (read_response(psb, SMTP_DATA_TIMEOUT)) {
858 if (check_response(psb, TRUE)) {
859 send_header(psb, hdr_list);
860 send_data(psb, msg);
862 if (read_response(psb, SMTP_FINAL_TIMEOUT))
863 ok = check_response(psb, FALSE);
864 }
865 }
866 }
867 }
868 }
870 DEBUG(5) {
871 debugf("smtp_out_msg():\n");
872 debugf(" psb->error = %d\n", psb->error);
873 debugf(" ok = %d\n", ok);
874 debugf(" rcpt_accept = %d\n", rcpt_accept);
875 }
877 if (psb->error == smtp_ok) {
878 GList *rcpt_node;
879 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
880 address *rcpt = (address *) (rcpt_node->data);
881 if (addr_is_delivered(rcpt))
882 logwrite(LOG_NOTICE, "%s => %s host=%s with %s\n", msg->uid, addr_string(rcpt),
883 psb->remote_host, psb->use_esmtp ? "esmtp" : "smtp");
884 }
885 } else {
886 /* if something went wrong,
887 we have to unmark the rcpts prematurely marked as delivered
888 and mark the status */
889 smtp_out_mark_rcpts(psb, rcpt_list);
891 /* log the failure: */
892 smtp_out_log_failure(psb, msg);
893 }
894 return rcpt_accept;
895 }
897 gboolean
898 smtp_out_quit(smtp_base * psb)
899 {
900 fprintf(psb->out, "QUIT\r\n");
901 fflush(psb->out);
903 DEBUG(4) debugf("QUIT\n");
905 signal(SIGALRM, SIG_DFL);
907 return TRUE;
908 }
910 gint
911 smtp_deliver(gchar * host, gint port, GList * resolve_list, message * msg, address * return_path, GList * rcpt_list)
912 {
913 smtp_base *psb;
914 smtp_error err;
916 DEBUG(5) debugf("smtp_deliver entered\n");
918 if (return_path == NULL)
919 return_path = msg->return_path;
921 if ((psb = smtp_out_open(host, port, resolve_list))) {
922 set_heloname(psb, return_path->domain, TRUE);
923 /* initiate connection, send message and quit: */
924 if (smtp_out_init(psb, FALSE)) {
925 smtp_out_msg(psb, msg, return_path, rcpt_list, NULL);
926 if (psb->error == smtp_ok || (psb->error == smtp_fail) || (psb->error == smtp_trylater)
927 || (psb->error == smtp_syntax) || (psb->error == smtp_cancel))
928 smtp_out_quit(psb);
929 }
931 err = psb->error;
932 destroy_smtpbase(psb);
934 return err;
935 }
936 return -1;
937 }