masqmail-0.2

view src/smtp_out.c @ 119:1e2fd87d58ea

some annotations related to mail sending with SMTP SIZE
author meillo@marmaro.de
date Thu, 01 Jul 2010 13:11:38 +0200
parents a80ebfa16cd5
children 52c82d755215
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 debugf("in check_helo_response()\n");
266 while (psb->auth_names[i]) {
267 debugf(" offered AUTH %s\n", psb->auth_names[i]);
268 i++;
269 }
270 }
271 }
272 }
273 }
275 while (*ptr != '\n')
276 ptr++;
277 ptr++;
278 }
280 DEBUG(4) {
281 debugf(" %s\n", psb->use_size ? "uses SIZE" : "no size");
282 debugf(" %s\n", psb->use_pipelining ? "uses PIPELINING" : "no pipelining");
283 debugf(" %s\n", psb->use_auth ? "uses AUTH" : "no auth");
284 }
286 return TRUE;
287 }
289 static gboolean
290 smtp_helo(smtp_base * psb, gchar * helo)
291 {
292 while (TRUE) {
293 if (psb->use_esmtp) {
294 fprintf(psb->out, "EHLO %s\r\n", helo);
295 fflush(psb->out);
297 DEBUG(4) debugf("EHLO %s\r\n", helo);
299 } else {
300 fprintf(psb->out, "HELO %s\r\n", helo);
301 fflush(psb->out);
303 DEBUG(4) debugf("HELO %s\r\n", helo);
305 }
307 if (!read_response(psb, SMTP_CMD_TIMEOUT))
308 return FALSE;
310 if (check_helo_response(psb))
311 return TRUE;
312 else {
313 if (psb->error == smtp_fail) {
314 if (psb->use_esmtp) {
315 /* our guess that server understands EHLO was wrong, try again with HELO */
316 psb->use_esmtp = FALSE;
317 } else {
318 /* what sort of server ist THAT ?! give up... */
319 return FALSE;
320 }
321 } else
322 return FALSE;
323 }
324 }
325 }
327 static void
328 smtp_cmd_mailfrom(smtp_base * psb, address * return_path, guint size)
329 {
330 if (psb->use_size) {
331 fprintf(psb->out, "MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
332 fflush(psb->out);
334 DEBUG(4) debugf("MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
336 } else {
337 fprintf(psb->out, "MAIL FROM:%s\r\n", addr_string(return_path));
338 fflush(psb->out);
340 DEBUG(4) debugf("MAIL FROM:%s\r\n", addr_string(return_path));
341 }
342 }
344 static void
345 smtp_cmd_rcptto(smtp_base * psb, address * rcpt)
346 {
347 fprintf(psb->out, "RCPT TO:%s\r\n", addr_string(rcpt));
348 fflush(psb->out);
349 DEBUG(4) debugf("RCPT TO:%s\n", addr_string(rcpt));
350 }
352 static void
353 send_data_line(smtp_base * psb, gchar * data)
354 {
355 /* According to RFC 821 each line should be terminated with CRLF.
356 Since a dot on a line itself marks the end of data, each line
357 beginning with a dot is prepended with another dot.
358 */
359 gchar *ptr;
360 gboolean new_line = TRUE; /* previous versions assumed that each item was exactly one line.
361 This is no longer the case */
363 ptr = data;
364 while (*ptr) {
365 int c = (int) (*ptr);
366 if (c == '.' && new_line) {
367 /* dot-stuffing */
368 putc('.', psb->out);
369 }
370 if (c == '\n') {
371 /* CRLF line terminators */
372 putc('\r', psb->out);
373 putc('\n', psb->out);
374 new_line = TRUE;
375 } else {
376 putc(c, psb->out);
377 new_line = FALSE;
378 }
379 ptr++;
380 }
381 }
383 static void
384 send_header(smtp_base * psb, GList * hdr_list)
385 {
386 GList *node;
387 gint num_hdrs = 0;
389 /* header */
390 if (hdr_list) {
391 foreach(hdr_list, node) {
392 if (node->data) {
393 header *hdr = (header *) (node->data);
394 if (hdr->header) {
395 send_data_line(psb, hdr->header);
396 num_hdrs++;
397 }
398 }
399 }
400 }
402 /* empty line separating headers from data: */
403 putc('\r', psb->out);
404 putc('\n', psb->out);
406 DEBUG(4) debugf("sent %d headers\n", num_hdrs);
407 }
409 static void
410 send_data(smtp_base * psb, message * msg)
411 {
412 GList *node;
413 gint num_lines = 0;
415 /* data */
416 if (msg->data_list) {
417 for (node = g_list_first(msg->data_list); node; node = g_list_next(node)) {
418 if (node->data) {
419 send_data_line(psb, node->data);
420 num_lines++;
421 }
422 }
423 }
425 DEBUG(4) debugf("sent %d lines of data\n", num_lines);
427 fprintf(psb->out, ".\r\n");
428 fflush(psb->out);
429 }
431 void
432 smtp_out_mark_rcpts(smtp_base * psb, GList * rcpt_list)
433 {
434 GList *rcpt_node;
435 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
436 address *rcpt = (address *) (rcpt_node->data);
438 addr_unmark_delivered(rcpt);
440 if ((psb->error == smtp_trylater) || (psb->error == smtp_timeout) || (psb->error == smtp_eof)) {
441 addr_mark_defered(rcpt);
442 } else {
443 addr_mark_failed(rcpt);
444 }
445 }
446 }
448 void
449 smtp_out_log_failure(smtp_base * psb, message * msg)
450 {
451 gchar *err_str;
453 if (psb->error == smtp_timeout)
454 err_str = g_strdup("connection timed out.");
455 else if (psb->error == smtp_eof)
456 err_str = g_strdup("connection terminated prematurely.");
457 else if (psb->error == smtp_syntax)
458 err_str = g_strdup_printf("got unexpected response: %s", psb->buffer);
459 else if (psb->error == smtp_cancel)
460 err_str = g_strdup("delivery was canceled.\n");
461 else
462 /* error message should still be in the buffer */
463 err_str = g_strdup_printf("failed: %s\n", psb->buffer);
465 if (msg == NULL)
466 logwrite(LOG_NOTICE, "host=%s %s\n", psb->remote_host, err_str);
467 else
468 logwrite(LOG_NOTICE, "%s == host=%s %s\n", msg->uid, psb->remote_host, err_str);
470 g_free(err_str);
471 }
473 smtp_base*
474 smtp_out_open(gchar * host, gint port, GList * resolve_list)
475 {
476 smtp_base *psb;
477 gint sock;
478 mxip_addr *addr;
480 DEBUG(5) debugf("smtp_out_open entered, host = %s\n", host);
482 if ((addr = connect_resolvelist(&sock, host, port, resolve_list))) {
483 /* create structure to hold status data: */
484 psb = create_smtpbase(sock);
485 psb->remote_host = addr->name;
487 DEBUG(5) {
488 struct sockaddr_in name;
489 int len = sizeof(struct sockaddr);
490 getsockname(sock, (struct sockaddr *) (&name), &len);
491 debugf("socket: name.sin_addr = %s\n", inet_ntoa(name.sin_addr));
492 }
493 return psb;
494 } else {
495 DEBUG(5) debugf("connect_resolvelist failed: %s %s\n", strerror(errno), hstrerror(h_errno));
496 }
498 return NULL;
499 }
501 smtp_base*
502 smtp_out_open_child(gchar * cmd)
503 {
504 smtp_base *psb;
505 gint sock;
507 DEBUG(5) debugf("smtp_out_open_child entered, cmd = %s\n", cmd);
509 sock = child(cmd);
511 if (sock > 0) {
512 psb = create_smtpbase(sock);
513 psb->remote_host = NULL;
515 return psb;
516 }
518 return NULL;
519 }
521 gboolean
522 smtp_out_rset(smtp_base * psb)
523 {
524 gboolean ok;
526 fprintf(psb->out, "RSET\r\n");
527 fflush(psb->out);
528 DEBUG(4) debugf("RSET\n");
530 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
531 if (check_response(psb, FALSE))
532 return TRUE;
534 smtp_out_log_failure(psb, NULL);
536 return FALSE;
537 }
539 #ifdef ENABLE_AUTH
541 static gboolean
542 smtp_out_auth_cram_md5(smtp_base * psb)
543 {
544 gboolean ok = FALSE;
546 fprintf(psb->out, "AUTH CRAM-MD5\r\n");
547 fflush(psb->out);
548 DEBUG(4) debugf("AUTH CRAM-MD5\n");
549 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
550 if ((ok = check_response(psb, TRUE))) {
551 gchar *chall64 = get_response_arg(&(psb->buffer[4]));
552 gint chall_size;
553 gchar *chall = base64_decode(chall64, &chall_size);
554 guchar digest[16], *reply64, *reply;
555 gchar digest_string[33];
556 gint i;
557 #ifdef USE_LIB_CRYPTO
558 unsigned int digest_len;
559 #endif
561 DEBUG(5) debugf("smtp_out_auth_cram_md5():\n");
562 DEBUG(5) debugf(" encoded challenge = %s\n", chall64);
563 DEBUG(5) debugf(" decoded challenge = %s, size = %d\n", chall, chall_size);
564 DEBUG(5) debugf(" secret = %s\n", psb->auth_secret);
566 #ifdef USE_LIB_CRYPTO
567 HMAC(EVP_md5(), psb->auth_secret, strlen(psb->auth_secret), chall, chall_size, digest, &digest_len);
568 #else
569 hmac_md5(chall, chall_size, psb->auth_secret, strlen(psb->auth_secret), digest);
570 #endif
572 for (i = 0; i < 16; i++)
573 sprintf(&(digest_string[i + i]), "%02x", (unsigned int) (digest[i]));
574 digest_string[32] = '\0';
576 DEBUG(5) debugf(" digest = %s\n", digest_string);
578 reply = g_strdup_printf("%s %s", psb->auth_login, digest_string);
579 DEBUG(5) debugf(" unencoded reply = %s\n", reply);
581 reply64 = base64_encode(reply, strlen(reply));
582 DEBUG(5) debugf(" encoded reply = %s\n", reply64);
584 fprintf(psb->out, "%s\r\n", reply64);
585 fflush(psb->out);
586 DEBUG(4) debugf(" reply64 = %s\n", reply64);
588 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
589 ok = check_response(psb, FALSE);
591 g_free(reply64);
592 g_free(reply);
593 g_free(chall);
594 g_free(chall64);
595 }
596 }
597 return ok;
598 }
600 static gboolean
601 smtp_out_auth_login(smtp_base * psb)
602 {
603 gboolean ok = FALSE;
604 fprintf(psb->out, "AUTH LOGIN\r\n");
605 fflush(psb->out);
606 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
607 if ((ok = check_response(psb, TRUE))) {
608 gchar *resp64;
609 guchar *resp;
610 gint resp_size;
611 gchar *reply64;
613 DEBUG(5) debugf("smtp_out_auth_login():\n");
614 resp64 = get_response_arg(&(psb->buffer[4]));
615 DEBUG(5) debugf(" encoded response = %s\n", resp64);
616 resp = base64_decode(resp64, &resp_size);
617 g_free(resp64);
618 DEBUG(5) debugf(" decoded response = %s, size = %d\n", resp, resp_size);
619 g_free(resp);
620 reply64 = base64_encode(psb->auth_login, strlen(psb->auth_login));
621 fprintf(psb->out, "%s\r\n", reply64);
622 fflush(psb->out);
623 g_free(reply64);
624 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
625 if ((ok = check_response(psb, TRUE))) {
626 resp64 = get_response_arg(&(psb->buffer[4]));
627 DEBUG(5) debugf(" encoded response = %s\n", resp64);
628 resp = base64_decode(resp64, &resp_size);
629 g_free(resp64);
630 DEBUG(5) debugf(" decoded response = %s, size = %d\n", resp, resp_size);
631 g_free(resp);
632 reply64 = base64_encode(psb->auth_secret, strlen(psb->auth_secret));
633 fprintf(psb->out, "%s\r\n", reply64);
634 fflush(psb->out);
635 g_free(reply64);
636 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
637 ok = check_response(psb, FALSE);
638 }
639 }
640 }
641 }
642 return ok;
643 }
645 gboolean
646 smtp_out_auth(smtp_base * psb)
647 {
648 gboolean ok = FALSE;
649 gint i = 0;
650 while (psb->auth_names[i]) {
651 if (strcasecmp(psb->auth_names[i], psb->auth_name) == 0)
652 break;
653 i++;
654 }
655 if (psb->auth_names[i]) {
656 if (strcasecmp(psb->auth_name, "cram-md5") == 0) {
657 smtp_out_auth_cram_md5(psb);
658 } else if (strcasecmp(psb->auth_name, "login") == 0) {
659 smtp_out_auth_login(psb);
660 } else {
661 logwrite(LOG_ERR, "auth method %s not supported\n", psb->auth_name);
662 }
663 } else {
664 logwrite(LOG_ERR, "no auth method %s found.\n", psb->auth_name);
665 }
666 return ok;
667 }
669 #endif
671 gboolean
672 smtp_out_init(smtp_base * psb)
673 {
674 gboolean ok;
676 if ((ok = read_response(psb, SMTP_INITIAL_TIMEOUT))) {
677 if ((ok = check_init_response(psb))) {
679 if ((ok = smtp_helo(psb, psb->helo_name))) {
680 #ifdef ENABLE_AUTH
681 if (psb->auth_name && psb->use_auth) {
682 /* we completely disregard the response of server here. If
683 authentication fails, the server will complain later
684 anyway. I know, this is not polite... */
685 smtp_out_auth(psb);
686 }
687 #endif
688 }
689 }
690 }
691 if (!ok)
692 smtp_out_log_failure(psb, NULL);
693 return ok;
694 }
696 gint
697 smtp_out_msg(smtp_base * psb, message * msg, address * return_path, GList * rcpt_list, GList * hdr_list)
698 {
699 gint i, size;
700 gboolean ok = TRUE;
701 int rcpt_cnt;
702 int rcpt_accept = 0;
704 DEBUG(5) debugf("smtp_out_msg entered\n");
706 /* defaults: */
707 if (return_path == NULL)
708 return_path = msg->return_path;
709 if (hdr_list == NULL)
710 hdr_list = msg->hdr_list;
711 if (rcpt_list == NULL)
712 rcpt_list = msg->rcpt_list;
713 rcpt_cnt = g_list_length(rcpt_list);
715 size = msg_calc_size(msg, TRUE);
717 /* respect maximum size given by server: */
718 if ((psb->max_size > 0) && (size > psb->max_size)) {
719 logwrite(LOG_WARNING, "%s == host=%s message size (%d) > "
720 "fixed maximum message size of server (%d)",
721 msg->uid, psb->remote_host, size, psb->max_size);
722 psb->error = smtp_cancel;
723 ok = FALSE;
724 }
726 if (ok) {
727 /* pretend the message is a bit larger,
728 just in case the size calculation is buggy */
729 smtp_cmd_mailfrom(psb, return_path, psb->use_size ? size+SMTP_SIZE_ADD : 0);
731 if (!psb->use_pipelining) {
732 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
733 ok = check_response(psb, FALSE);
734 }
735 }
736 if (ok) {
737 GList *rcpt_node;
738 rcpt_accept = 0;
740 for (rcpt_node = g_list_first(rcpt_list); rcpt_node != NULL; rcpt_node = g_list_next(rcpt_node)) {
741 address *rcpt = (address *) (rcpt_node->data);
742 smtp_cmd_rcptto(psb, rcpt);
743 if (!psb->use_pipelining) {
744 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
745 if (check_response(psb, FALSE)) {
746 rcpt_accept++;
747 addr_mark_delivered(rcpt);
748 } else {
749 /* if server returned an error for one recp. we
750 may still try the others. But if it is a timeout, eof
751 or unexpected response, it is more serious and we should
752 give up. */
753 if ((psb->error != smtp_trylater) && (psb->error != smtp_fail)) {
754 ok = FALSE;
755 break;
756 } else {
757 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n",
758 msg->uid, addr_string(rcpt), psb->remote_host, psb->buffer);
759 if (psb->error == smtp_trylater) {
760 addr_mark_defered(rcpt);
761 } else {
762 addr_mark_failed(rcpt);
763 }
764 }
765 } else
766 break;
767 }
768 }
770 /* There is no point in going on if no recp.s were accpted.
771 But we can check that at this point only if not pipelining: */
772 ok = (ok && (psb->use_pipelining || (rcpt_accept > 0)));
773 if (ok) {
775 fprintf(psb->out, "DATA\r\n");
776 fflush(psb->out);
778 DEBUG(4) debugf("DATA\r\n");
780 if (psb->use_pipelining) {
781 /* the first pl'ed command was MAIL FROM
782 the last was DATA, whose response can be handled by the 'normal' code
783 all in between were RCPT TO:
784 */
785 /* response to MAIL FROM: */
786 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
787 if ((ok = check_response(psb, FALSE))) {
789 /* response(s) to RCPT TO:
790 this is very similar to the sequence above for no pipeline
791 */
792 for (i = 0; i < rcpt_cnt; i++) {
793 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
794 address *rcpt = g_list_nth_data(rcpt_list, i);
795 if (check_response(psb, FALSE)) {
796 rcpt_accept++;
797 addr_mark_delivered(rcpt);
798 } else {
799 /* if server returned an error 4xx or 5xx for one recp. we
800 may still try the others. But if it is a timeout, eof
801 or unexpected response, it is more serious and we
802 should give up. */
803 if ((psb->error != smtp_trylater) &&
804 (psb->error != smtp_fail)) {
805 ok = FALSE;
806 break;
807 } else {
808 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n", msg->uid,
809 addr_string(rcpt), psb->remote_host, psb->buffer);
810 if (psb->error == smtp_trylater) {
811 addr_mark_defered(rcpt);
812 } else {
813 addr_mark_failed(rcpt);
814 }
815 }
816 }
817 } else {
818 DEBUG(5) debugf("check_response failed after RCPT TO\n");
819 break;
820 }
821 }
822 if (rcpt_accept == 0)
823 ok = FALSE;
824 } else {
825 DEBUG(5) debugf("check_response failed after MAIL FROM\n");
826 }
827 } else {
828 DEBUG(5)
829 debugf("read_response failed after MAIL FROM\n");
830 }
831 }
833 /* if(psb->use_pipelining) */
834 /* response to the DATA cmd */
835 if (ok) {
836 if (read_response(psb, SMTP_DATA_TIMEOUT)) {
837 if (check_response(psb, TRUE)) {
838 send_header(psb, hdr_list);
839 send_data(psb, msg);
841 if (read_response(psb, SMTP_FINAL_TIMEOUT))
842 ok = check_response(psb, FALSE);
843 }
844 }
845 }
846 }
847 }
849 DEBUG(5) {
850 debugf("smtp_out_msg():\n");
851 debugf(" psb->error = %d\n", psb->error);
852 debugf(" ok = %d\n", ok);
853 debugf(" rcpt_accept = %d\n", rcpt_accept);
854 }
856 if (psb->error == smtp_ok) {
857 GList *rcpt_node;
858 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
859 address *rcpt = (address *) (rcpt_node->data);
860 if (addr_is_delivered(rcpt))
861 logwrite(LOG_NOTICE, "%s => %s host=%s with %s\n", msg->uid, addr_string(rcpt),
862 psb->remote_host, psb->use_esmtp ? "esmtp" : "smtp");
863 }
864 } else {
865 /* if something went wrong,
866 we have to unmark the rcpts prematurely marked as delivered
867 and mark the status */
868 smtp_out_mark_rcpts(psb, rcpt_list);
870 /* log the failure: */
871 smtp_out_log_failure(psb, msg);
872 }
873 return rcpt_accept;
874 }
876 gboolean
877 smtp_out_quit(smtp_base * psb)
878 {
879 fprintf(psb->out, "QUIT\r\n");
880 fflush(psb->out);
882 DEBUG(4) debugf("QUIT\n");
884 signal(SIGALRM, SIG_DFL);
886 return TRUE;
887 }
889 gint
890 smtp_deliver(gchar * host, gint port, GList * resolve_list, message * msg, address * return_path, GList * rcpt_list)
891 {
892 smtp_base *psb;
893 smtp_error err;
895 DEBUG(5) debugf("smtp_deliver entered\n");
897 if (return_path == NULL)
898 return_path = msg->return_path;
900 if ((psb = smtp_out_open(host, port, resolve_list))) {
901 set_heloname(psb, return_path->domain, TRUE);
902 /* initiate connection, send message and quit: */
903 if (smtp_out_init(psb)) {
904 smtp_out_msg(psb, msg, return_path, rcpt_list, NULL);
905 if (psb->error == smtp_ok || (psb->error == smtp_fail) || (psb->error == smtp_trylater)
906 || (psb->error == smtp_syntax) || (psb->error == smtp_cancel))
907 smtp_out_quit(psb);
908 }
910 err = psb->error;
911 destroy_smtpbase(psb);
913 return err;
914 }
915 return -1;
916 }