masqmail-0.2

view src/smtp_out.c @ 10:26e34ae9a3e3

changed indention and line wrapping to a more consistent style
author meillo@marmaro.de
date Mon, 27 Oct 2008 16:23:10 +0100
parents 08114f7dcc23
children f671821d8222
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/global.h"
43 #include "md5/md5.h"
44 #include "md5/hmac_md5.h"
45 #endif
47 #include "base64/base64.h"
48 #endif
50 void
51 destroy_smtpbase(smtp_base * psb)
52 {
53 fclose(psb->in);
54 fclose(psb->out);
56 close(psb->sock);
58 if (psb->helo_name)
59 g_free(psb->helo_name);
60 if (psb->buffer)
61 g_free(psb->buffer);
62 if (psb->auth_names)
63 g_strfreev(psb->auth_names);
65 if (psb->auth_name)
66 g_free(psb->auth_name);
67 if (psb->auth_login)
68 g_free(psb->auth_login);
69 if (psb->auth_secret)
70 g_free(psb->auth_secret);
71 }
73 gchar*
74 set_heloname(smtp_base * psb, gchar * default_name, gboolean do_correct)
75 {
76 struct sockaddr_in sname;
77 int len = sizeof(struct sockaddr_in);
78 struct hostent *host_entry;
80 if (do_correct) {
81 getsockname(psb->sock, (struct sockaddr *) (&sname), &len);
82 DEBUG(5) debugf("socket: name.sin_addr = %s\n", inet_ntoa(sname.sin_addr));
83 host_entry = gethostbyaddr((const char *) &(sname.sin_addr), sizeof(sname.sin_addr), AF_INET);
84 if (host_entry) {
85 psb->helo_name = g_strdup(host_entry->h_name);
86 } else {
87 /* we failed to look up our own name. Instead of giving our local hostname,
88 we may give our IP number to show the server that we are at least
89 willing to be honest. For the really picky ones. */
90 DEBUG(5) debugf("failed to look up own host name.\n");
91 psb->helo_name = g_strdup_printf("[%s]", inet_ntoa(sname.sin_addr));
92 }
93 DEBUG(5) debugf("helo_name = %s\n", psb->helo_name);
94 }
95 if (psb->helo_name == NULL) {
96 psb->helo_name = g_strdup(default_name);
97 }
98 return psb->helo_name;
99 }
101 #ifdef ENABLE_AUTH
103 gboolean
104 set_auth(smtp_base * psb, gchar * name, gchar * login, gchar * secret)
105 {
106 if ((strcasecmp(name, "CRAM-MD5") == 0) || (strcasecmp(name, "LOGIN") == 0)) {
107 psb->auth_name = g_strdup(name);
108 psb->auth_login = g_strdup(login);
109 psb->auth_secret = g_strdup(secret);
111 return TRUE;
112 }
113 return FALSE;
114 }
116 #endif
118 static smtp_base*
119 create_smtpbase(gint sock)
120 {
121 gint dup_sock;
123 smtp_base *psb = (smtp_base *) g_malloc(sizeof(smtp_base));
125 psb->sock = sock;
127 psb->use_esmtp = FALSE;
128 psb->use_size = FALSE;
129 psb->use_pipelining = FALSE;
130 psb->use_auth = FALSE;
132 psb->max_size = 0;
133 psb->auth_names = NULL;
135 psb->buffer = (gchar *) g_malloc(SMTP_BUF_LEN);
137 dup_sock = dup(sock);
138 psb->out = fdopen(sock, "w");
139 psb->in = fdopen(dup_sock, "r");
141 psb->error = smtp_ok;
143 psb->helo_name = NULL;
145 psb->auth_name = psb->auth_login = psb->auth_secret = NULL;
147 return psb;
148 }
150 static gboolean
151 read_response(smtp_base * psb, int timeout)
152 {
153 gint buf_pos = 0;
154 gchar code[5];
155 gint i, len;
157 do {
158 len = read_sockline(psb->in, &(psb->buffer[buf_pos]), SMTP_BUF_LEN - buf_pos, timeout, READSOCKL_CHUG);
159 if (len == -3) {
160 psb->error = smtp_timeout;
161 return FALSE;
162 } else if (len == -2) {
163 psb->error = smtp_syntax;
164 return FALSE;
165 } else if (len == -1) {
166 psb->error = smtp_eof;
167 return FALSE;
168 }
169 for (i = 0; i < 4; i++)
170 code[i] = psb->buffer[buf_pos + i];
171 code[i] = 0;
172 psb->last_code = atoi(code);
174 buf_pos += len;
176 } while (code[3] == '-');
178 return TRUE;
179 }
181 static gboolean
182 check_response(smtp_base * psb, gboolean after_data)
183 {
184 char c = psb->buffer[0];
186 if (((c == '2') && !after_data) || ((c == '3') && after_data)) {
187 psb->error = smtp_ok;
188 DEBUG(6) debugf("response OK:'%s' after_date = %d\n", psb->buffer, (int) after_data);
189 return TRUE;
190 } else {
191 if (c == '4')
192 psb->error = smtp_trylater;
193 else if (c == '5')
194 psb->error = smtp_fail;
195 else
196 psb->error = smtp_syntax;
197 DEBUG(6) debugf("response failure:'%s' after_date = %d\n", psb->buffer, (int) after_data);
198 return FALSE;
199 }
200 }
202 static gboolean
203 check_init_response(smtp_base * psb)
204 {
205 if (check_response(psb, FALSE)) {
206 psb->use_esmtp = (strstr(psb->buffer, "ESMTP") != NULL);
208 DEBUG(4) debugf(psb->use_esmtp ? "uses esmtp\n" : "no esmtp\n");
210 return TRUE;
211 }
212 return FALSE;
213 }
215 static gchar*
216 get_response_arg(gchar * response)
217 {
218 gchar buf[SMTP_BUF_LEN];
219 gchar *p = response, *q = buf;
221 while (*p && (*p != '\n') && isspace(*p))
222 p++;
223 if (*p && (*p != '\n')) {
224 while (*p && (*p != '\n') && (*p != '\r') && (q < buf + SMTP_BUF_LEN - 1))
225 *(q++) = *(p++);
226 *q = 0;
227 return g_strdup(buf);
228 }
229 return NULL;
230 }
232 static gboolean
233 check_helo_response(smtp_base * psb)
234 {
235 gchar *ptr = psb->buffer;
237 if (!check_response(psb, FALSE))
238 return FALSE;
240 while (*ptr) {
241 if (strncasecmp(&(ptr[4]), "SIZE", 4) == 0) {
242 gchar *arg;
243 psb->use_size = TRUE;
244 arg = get_response_arg(&(ptr[8]));
245 if (arg) {
246 psb->max_size = atoi(arg);
247 g_free(arg);
248 }
249 }
251 if (strncasecmp(&(ptr[4]), "PIPELINING", 10) == 0)
252 psb->use_pipelining = TRUE;
254 if (strncasecmp(&(ptr[4]), "AUTH", 4) == 0) {
255 if ((ptr[8] == ' ') || (ptr[8] == '=') || (ptr[8] == '\t')) { /* not sure about '\t' */
256 gchar *arg;
257 psb->use_auth = TRUE;
258 arg = get_response_arg(&(ptr[9])); /* after several years I finally learnt to count */
259 if (arg) {
260 psb->auth_names = g_strsplit(arg, " ", 0);
261 g_free(arg);
263 DEBUG(4) {
264 gint i = 0;
265 while (psb->auth_names[i]) {
266 debugf("offered AUTH %s\n", psb->auth_names[i]);
267 i++;
268 }
269 }
270 }
271 }
272 }
274 while (*ptr != '\n')
275 ptr++;
276 ptr++;
277 }
279 DEBUG(4) {
280 debugf(psb->use_size ? "uses SIZE\n" : "no size\n");
281 debugf(psb->use_pipelining ? "uses PIPELINING\n" : "no pipelining\n");
282 debugf(psb->use_auth ? "uses AUTH\n" : "no auth\n");
283 }
285 return TRUE;
286 }
288 static gboolean
289 smtp_helo(smtp_base * psb, gchar * helo)
290 {
291 while (TRUE) {
292 if (psb->use_esmtp) {
293 fprintf(psb->out, "EHLO %s\r\n", helo);
294 fflush(psb->out);
296 DEBUG(4) debugf("EHLO %s\r\n", helo);
298 } else {
299 fprintf(psb->out, "HELO %s\r\n", helo);
300 fflush(psb->out);
302 DEBUG(4) debugf("HELO %s\r\n", helo);
304 }
306 if (!read_response(psb, SMTP_CMD_TIMEOUT))
307 return FALSE;
309 if (check_helo_response(psb))
310 return TRUE;
311 else {
312 if (psb->error == smtp_fail) {
313 if (psb->use_esmtp) {
314 /* our guess that server understands EHLO was wrong, try again with HELO */
315 psb->use_esmtp = FALSE;
316 } else {
317 /* what sort of server ist THAT ?! give up... */
318 return FALSE;
319 }
320 } else
321 return FALSE;
322 }
323 }
324 }
326 static void
327 smtp_cmd_mailfrom(smtp_base * psb, address * return_path, guint size)
328 {
329 if (psb->use_size) {
330 fprintf(psb->out, "MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
331 fflush(psb->out);
333 DEBUG(4) debugf("MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
335 } else {
336 fprintf(psb->out, "MAIL FROM:%s\r\n", addr_string(return_path));
337 fflush(psb->out);
339 DEBUG(4) debugf("MAIL FROM:%s\r\n", addr_string(return_path));
340 }
341 }
343 static void
344 smtp_cmd_rcptto(smtp_base * psb, address * rcpt)
345 {
346 fprintf(psb->out, "RCPT TO:%s\r\n", addr_string(rcpt));
347 fflush(psb->out);
348 DEBUG(4) debugf("RCPT TO:%s\n", addr_string(rcpt));
349 }
351 static void
352 send_data_line(smtp_base * psb, gchar * data)
353 {
354 /* According to RFC 821 each line should be terminated with CRLF.
355 Since a dot on a line itself marks the end of data, each line
356 beginning with a dot is prepended with another dot.
357 */
358 gchar *ptr;
359 gboolean new_line = TRUE; /* previous versions assumed that each item was exactly one line. This is no longer the case */
361 ptr = data;
362 while (*ptr) {
363 int c = (int) (*ptr);
364 if (c == '.')
365 if (new_line)
366 putc('.', psb->out);
367 if (c == '\n') {
368 putc('\r', psb->out);
369 putc('\n', psb->out);
370 new_line = TRUE;
371 } else {
372 putc(c, psb->out);
373 new_line = FALSE;
374 }
375 ptr++;
376 }
377 }
379 static void
380 send_header(smtp_base * psb, GList * hdr_list)
381 {
382 GList *node;
383 gint num_hdrs = 0;
385 /* header */
386 if (hdr_list) {
387 foreach(hdr_list, node) {
388 if (node->data) {
389 header *hdr = (header *) (node->data);
390 if (hdr->header) {
391 send_data_line(psb, hdr->header);
392 num_hdrs++;
393 }
394 }
395 }
396 }
398 /* empty line separating headers from data: */
399 putc('\r', psb->out);
400 putc('\n', psb->out);
402 DEBUG(4) debugf("sent %d headers\n", num_hdrs);
403 }
405 static void
406 send_data(smtp_base * psb, message * msg)
407 {
408 GList *node;
409 gint num_lines = 0;
411 /* data */
412 if (msg->data_list) {
413 for (node = g_list_first(msg->data_list); node; node = g_list_next(node)) {
414 if (node->data) {
415 send_data_line(psb, node->data);
416 num_lines++;
417 }
418 }
419 }
421 DEBUG(4) debugf("sent %d lines of data\n", num_lines);
423 fprintf(psb->out, ".\r\n");
424 fflush(psb->out);
425 }
427 void
428 smtp_out_mark_rcpts(smtp_base * psb, GList * rcpt_list)
429 {
430 GList *rcpt_node;
431 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
432 address *rcpt = (address *) (rcpt_node->data);
434 addr_unmark_delivered(rcpt);
436 if ((psb->error == smtp_trylater) || (psb->error == smtp_timeout) || (psb->error == smtp_eof)) {
437 addr_mark_defered(rcpt);
438 } else {
439 addr_mark_failed(rcpt);
440 }
441 }
442 }
444 void
445 smtp_out_log_failure(smtp_base * psb, message * msg)
446 {
447 gchar *err_str;
449 if (psb->error == smtp_timeout)
450 err_str = g_strdup("connection timed out.");
451 else if (psb->error == smtp_eof)
452 err_str = g_strdup("connection terminated prematurely.");
453 else if (psb->error == smtp_syntax)
454 err_str = g_strdup_printf("got unexpected response: %s", psb->buffer);
455 else if (psb->error == smtp_cancel)
456 err_str = g_strdup("delivery was canceled.\n");
457 else
458 /* error message should still be in the buffer */
459 err_str = g_strdup_printf("failed: %s\n", psb->buffer);
461 if (msg == NULL)
462 logwrite(LOG_NOTICE, "host=%s %s\n", psb->remote_host, err_str);
463 else
464 logwrite(LOG_NOTICE, "%s == host=%s %s\n", msg->uid, psb->remote_host, err_str);
466 g_free(err_str);
467 }
469 smtp_base*
470 smtp_out_open(gchar * host, gint port, GList * resolve_list)
471 {
472 smtp_base *psb;
473 gint sock;
474 mxip_addr *addr;
476 DEBUG(5) debugf("smtp_out_open entered, host = %s\n", host);
478 if ((addr = connect_resolvelist(&sock, host, port, resolve_list))) {
479 /* create structure to hold status data: */
480 psb = create_smtpbase(sock);
481 psb->remote_host = addr->name;
483 DEBUG(5) {
484 struct sockaddr_in name;
485 int len = sizeof(struct sockaddr);
486 getsockname(sock, (struct sockaddr *) (&name), &len);
487 debugf("socket: name.sin_addr = %s\n", inet_ntoa(name.sin_addr));
488 }
489 return psb;
490 } else {
491 DEBUG(5) debugf("connect_resolvelist failed: %s %s\n", strerror(errno), hstrerror(h_errno));
492 }
494 return NULL;
495 }
497 smtp_base*
498 smtp_out_open_child(gchar * cmd)
499 {
500 smtp_base *psb;
501 gint sock;
503 DEBUG(5) debugf("smtp_out_open_child entered, cmd = %s\n", cmd);
505 sock = child(cmd);
507 if (sock > 0) {
508 psb = create_smtpbase(sock);
509 psb->remote_host = NULL;
511 return psb;
512 }
514 return NULL;
515 }
517 gboolean
518 smtp_out_rset(smtp_base * psb)
519 {
520 gboolean ok;
522 fprintf(psb->out, "RSET\r\n");
523 fflush(psb->out);
524 DEBUG(4) debugf("RSET\n");
526 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
527 if (check_response(psb, FALSE))
528 return TRUE;
530 smtp_out_log_failure(psb, NULL);
532 return FALSE;
533 }
535 #ifdef ENABLE_AUTH
537 static gboolean
538 smtp_out_auth_cram_md5(smtp_base * psb)
539 {
540 gboolean ok = FALSE;
542 fprintf(psb->out, "AUTH CRAM-MD5\r\n");
543 fflush(psb->out);
544 DEBUG(4) debugf("AUTH CRAM-MD5\n");
545 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
546 if ((ok = check_response(psb, TRUE))) {
547 gchar *chall64 = get_response_arg(&(psb->buffer[4]));
548 gint chall_size;
549 gchar *chall = base64_decode(chall64, &chall_size);
550 guchar digest[16], *reply64, *reply;
551 gchar digest_string[33];
552 gint i;
553 #ifdef USE_LIB_CRYPTO
554 unsigned int digest_len;
555 #endif
557 DEBUG(5) debugf("encoded challenge = %s\n", chall64);
558 DEBUG(5) debugf("decoded challenge = %s, size = %d\n", chall, chall_size);
560 DEBUG(5) debugf("secret = %s\n", psb->auth_secret);
562 #ifdef USE_LIB_CRYPTO
563 HMAC(EVP_md5(), psb->auth_secret, strlen(psb->auth_secret), chall, chall_size, digest, &digest_len);
564 #else
565 hmac_md5(chall, chall_size, psb->auth_secret, strlen(psb->auth_secret), digest);
566 #endif
568 for (i = 0; i < 16; i++)
569 sprintf(&(digest_string[i + i]), "%02x", (unsigned int) (digest[i]));
570 digest_string[32] = 0;
572 DEBUG(5) debugf("digest = %s\n", digest_string);
574 reply = g_strdup_printf("%s %s", psb->auth_login, digest_string);
575 DEBUG(5) debugf("unencoded reply = %s\n", reply);
577 reply64 = base64_encode(reply, strlen(reply));
578 DEBUG(5) debugf("encoded reply = %s\n", reply64);
580 fprintf(psb->out, "%s\r\n", reply64);
581 fflush(psb->out);
582 DEBUG(4) debugf("%s\n", reply64);
584 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
585 ok = check_response(psb, FALSE);
587 g_free(reply64);
588 g_free(reply);
589 g_free(chall);
590 g_free(chall64);
591 }
592 }
593 return ok;
594 }
596 static gboolean
597 smtp_out_auth_login(smtp_base * psb)
598 {
599 gboolean ok = FALSE;
600 fprintf(psb->out, "AUTH LOGIN\r\n");
601 fflush(psb->out);
602 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
603 if ((ok = check_response(psb, TRUE))) {
604 gchar *resp64;
605 guchar *resp;
606 gint resp_size;
607 gchar *reply64;
609 resp64 = get_response_arg(&(psb->buffer[4]));
610 DEBUG(5) debugf("encoded response = %s\n", resp64);
611 resp = base64_decode(resp64, &resp_size);
612 g_free(resp64);
613 DEBUG(5) debugf("decoded response = %s, size = %d\n", resp, resp_size);
614 g_free(resp);
615 reply64 = base64_encode(psb->auth_login, strlen(psb->auth_login));
616 fprintf(psb->out, "%s\r\n", reply64);
617 fflush(psb->out);
618 g_free(reply64);
619 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
620 if ((ok = check_response(psb, TRUE))) {
621 resp64 = get_response_arg(&(psb->buffer[4]));
622 DEBUG(5) debugf("encoded response = %s\n", resp64);
623 resp = base64_decode(resp64, &resp_size);
624 g_free(resp64);
625 DEBUG(5) debugf("decoded response = %s, size = %d\n", resp, resp_size);
626 g_free(resp);
627 reply64 = base64_encode(psb->auth_secret, strlen(psb->auth_secret));
628 fprintf(psb->out, "%s\r\n", reply64);
629 fflush(psb->out);
630 g_free(reply64);
631 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
632 ok = check_response(psb, FALSE);
633 }
634 }
635 }
636 }
637 return ok;
638 }
640 gboolean
641 smtp_out_auth(smtp_base * psb)
642 {
643 gboolean ok = FALSE;
644 gint i = 0;
645 while (psb->auth_names[i]) {
646 if (strcasecmp(psb->auth_names[i], psb->auth_name) == 0)
647 break;
648 i++;
649 }
650 if (psb->auth_names[i]) {
651 if (strcasecmp(psb->auth_name, "cram-md5") == 0) {
652 smtp_out_auth_cram_md5(psb);
653 } else if (strcasecmp(psb->auth_name, "login") == 0) {
654 smtp_out_auth_login(psb);
655 } else {
656 logwrite(LOG_ERR, "auth method %s not supported\n", psb->auth_name);
657 }
658 } else {
659 logwrite(LOG_ERR, "no auth method %s found.\n", psb->auth_name);
660 }
661 return ok;
662 }
664 #endif
666 gboolean
667 smtp_out_init(smtp_base * psb)
668 {
669 gboolean ok;
671 if ((ok = read_response(psb, SMTP_INITIAL_TIMEOUT))) {
672 if ((ok = check_init_response(psb))) {
674 if ((ok = smtp_helo(psb, psb->helo_name))) {
675 #ifdef ENABLE_AUTH
676 if (psb->auth_name && psb->use_auth) {
677 /* we completely disregard the response of server here. If
678 authentication fails, the server will complain later
679 anyway. I know, this is not polite... */
680 smtp_out_auth(psb);
681 }
682 #endif
683 }
684 }
685 }
686 if (!ok)
687 smtp_out_log_failure(psb, NULL);
688 return ok;
689 }
691 gint
692 smtp_out_msg(smtp_base * psb, message * msg, address * return_path, GList * rcpt_list, GList * hdr_list)
693 {
694 gint i, size;
695 gboolean ok = TRUE;
696 int rcpt_cnt;
697 int rcpt_accept = 0;
699 DEBUG(5) debugf("smtp_out_msg entered\n");
701 /* defaults: */
702 if (return_path == NULL)
703 return_path = msg->return_path;
704 if (hdr_list == NULL)
705 hdr_list = msg->hdr_list;
706 if (rcpt_list == NULL)
707 rcpt_list = msg->rcpt_list;
708 rcpt_cnt = g_list_length(rcpt_list);
710 size = msg_calc_size(msg, TRUE);
712 /* respect maximum size given by server: */
713 if ((psb->max_size > 0) && (size > psb->max_size)) {
714 logwrite(LOG_WARNING, "%s == host=%s message size (%d) > fixed maximum message size of server (%d)",
715 msg->uid, psb->remote_host, size, psb->max_size);
716 psb->error = smtp_cancel;
717 ok = FALSE;
718 }
720 if (ok) {
721 smtp_cmd_mailfrom(psb, return_path, psb->use_size ? size + SMTP_SIZE_ADD : 0);
723 if (!psb->use_pipelining) {
724 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
725 ok = check_response(psb, FALSE);
726 }
727 }
728 if (ok) {
729 GList *rcpt_node;
730 rcpt_accept = 0;
732 for (rcpt_node = g_list_first(rcpt_list); rcpt_node != NULL; rcpt_node = g_list_next(rcpt_node)) {
733 address *rcpt = (address *) (rcpt_node->data);
734 smtp_cmd_rcptto(psb, rcpt);
735 if (!psb->use_pipelining) {
736 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
737 if (check_response(psb, FALSE)) {
738 rcpt_accept++;
739 addr_mark_delivered(rcpt);
740 } else {
741 /* if server returned an error for one recp. we
742 may still try the others. But if it is a timeout, eof
743 or unexpected response, it is more serious and we should
744 give up. */
745 if ((psb->error != smtp_trylater) && (psb->error != smtp_fail)) {
746 ok = FALSE;
747 break;
748 } else {
749 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s", msg->uid, addr_string(rcpt), psb->remote_host, psb->buffer);
750 if (psb->error == smtp_trylater) {
751 addr_mark_defered(rcpt);
752 } else {
753 addr_mark_failed(rcpt);
754 }
755 }
756 } else
757 break;
758 }
759 }
761 /* There is no point in going on if no recp.s were accpted.
762 But we can check that at this point only if not pipelining: */
763 ok = (ok && (psb->use_pipelining || (rcpt_accept > 0)));
764 if (ok) {
766 fprintf(psb->out, "DATA\r\n");
767 fflush(psb->out);
769 DEBUG(4) debugf("DATA\r\n");
771 if (psb->use_pipelining) {
772 /* the first pl'ed command was MAIL FROM
773 the last was DATA, whose response can be handled by the 'normal' code
774 all in between were RCPT TO:
775 */
776 /* response to MAIL FROM: */
777 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
778 if ((ok = check_response(psb, FALSE))) {
780 /* response(s) to RCPT TO:
781 this is very similar to the sequence above for no pipeline
782 */
783 for (i = 0; i < rcpt_cnt; i++) {
784 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
785 address *rcpt = g_list_nth_data(rcpt_list, i);
786 if (check_response(psb, FALSE)) {
787 rcpt_accept++;
788 addr_mark_delivered(rcpt);
789 } else {
790 /* if server returned an error 4xx or 5xx for one recp. we
791 may still try the others. But if it is a timeout, eof
792 or unexpected response, it is more serious and we
793 should give up. */
794 if ((psb->error != smtp_trylater) &&
795 (psb->error != smtp_fail)) {
796 ok = FALSE;
797 break;
798 } else {
799 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s", msg->uid,
800 addr_string(rcpt), psb->remote_host, psb->buffer);
801 if (psb->error == smtp_trylater) {
802 addr_mark_defered(rcpt);
803 } else {
804 addr_mark_failed(rcpt);
805 }
806 }
807 }
808 } else {
809 DEBUG(5) debugf("check_response failed after RCPT TO\n");
810 break;
811 }
812 }
813 if (rcpt_accept == 0)
814 ok = FALSE;
815 } else {
816 DEBUG(5) debugf("check_response failed after MAIL FROM\n");
817 }
818 } else {
819 DEBUG(5)
820 debugf("read_response failed after MAIL FROM\n");
821 }
822 }
824 /* if(psb->use_pipelining) */
825 /* response to the DATA cmd */
826 if (ok) {
827 if (read_response(psb, SMTP_DATA_TIMEOUT)) {
828 if (check_response(psb, TRUE)) {
829 send_header(psb, hdr_list);
830 send_data(psb, msg);
832 if (read_response(psb, SMTP_FINAL_TIMEOUT))
833 ok = check_response(psb, FALSE);
834 }
835 }
836 }
837 }
838 }
840 DEBUG(5) {
841 debugf("psb->error = %d\n", psb->error);
842 debugf("ok = %d\n", ok);
843 debugf("rcpt_accept = %d\n", rcpt_accept);
844 }
846 if (psb->error == smtp_ok) {
847 GList *rcpt_node;
848 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
849 address *rcpt = (address *) (rcpt_node->data);
850 if (addr_is_delivered(rcpt))
851 logwrite(LOG_NOTICE, "%s => %s host=%s with %s\n", msg->uid, addr_string(rcpt),
852 psb->remote_host, psb->use_esmtp ? "esmtp" : "smtp");
853 }
854 } else {
855 /* if something went wrong,
856 we have to unmark the rcpts prematurely marked as delivered
857 and mark the status */
858 smtp_out_mark_rcpts(psb, rcpt_list);
860 /* log the failure: */
861 smtp_out_log_failure(psb, msg);
862 }
863 return rcpt_accept;
864 }
866 gboolean
867 smtp_out_quit(smtp_base * psb)
868 {
869 fprintf(psb->out, "QUIT\r\n");
870 fflush(psb->out);
872 DEBUG(4) debugf("QUIT\n");
874 signal(SIGALRM, SIG_DFL);
876 return TRUE;
877 }
879 gint
880 smtp_deliver(gchar * host, gint port, GList * resolve_list, message * msg, address * return_path, GList * rcpt_list)
881 {
882 smtp_base *psb;
883 smtp_error err;
885 DEBUG(5) debugf("smtp_deliver entered\n");
887 if (return_path == NULL)
888 return_path = msg->return_path;
890 if ((psb = smtp_out_open(host, port, resolve_list))) {
891 set_heloname(psb, return_path->domain, TRUE);
892 /* initiate connection, send message and quit: */
893 if (smtp_out_init(psb)) {
894 smtp_out_msg(psb, msg, return_path, rcpt_list, NULL);
895 if (psb->error == smtp_ok || (psb->error == smtp_fail) || (psb->error == smtp_trylater)
896 || (psb->error == smtp_syntax) || (psb->error == smtp_cancel))
897 smtp_out_quit(psb);
898 }
900 err = psb->error;
901 destroy_smtpbase(psb);
903 return err;
904 }
905 return -1;
906 }