masqmail
view src/smtp_out.c @ 198:c5e964e6ddbe
the goal is to have less config options
especially less compile-time config options
this is where oku and I differ in opinion
author | meillo@marmaro.de |
---|---|
date | Fri, 16 Jul 2010 10:08:06 +0200 |
parents | a39c8ee61185 |
children | 10da50168dab |
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] == '-');
177 if (psb->buffer) {
178 DEBUG(4) debugf("S: %s\n", psb->buffer);
179 }
181 return TRUE;
182 }
184 static gboolean
185 check_response(smtp_base * psb, gboolean after_data)
186 {
187 char c = psb->buffer[0];
189 if (((c == '2') && !after_data) || ((c == '3') && after_data)) {
190 psb->error = smtp_ok;
191 DEBUG(6) debugf("response OK:'%s' after_data = %d\n", psb->buffer, (int) after_data);
192 return TRUE;
193 } else {
194 if (c == '4')
195 psb->error = smtp_trylater;
196 else if (c == '5')
197 psb->error = smtp_fail;
198 else
199 psb->error = smtp_syntax;
200 DEBUG(6) debugf("response failure:'%s' after_data = %d\n", psb->buffer, (int) after_data);
201 return FALSE;
202 }
203 }
205 static gboolean
206 check_init_response(smtp_base * psb)
207 {
208 if (check_response(psb, FALSE)) {
209 psb->use_esmtp = (strstr(psb->buffer, "ESMTP") != NULL);
211 DEBUG(4) debugf(psb->use_esmtp ? "uses esmtp\n" : "no esmtp\n");
213 return TRUE;
214 }
215 return FALSE;
216 }
218 static gchar*
219 get_response_arg(gchar * response)
220 {
221 gchar buf[SMTP_BUF_LEN];
222 gchar *p = response, *q = buf;
224 while (*p && (*p != '\n') && isspace(*p))
225 p++;
226 if (*p && (*p != '\n')) {
227 while (*p && (*p != '\n') && (*p != '\r') && (q < buf + SMTP_BUF_LEN - 1))
228 *(q++) = *(p++);
229 *q = '\0';
230 return g_strdup(buf);
231 }
232 return NULL;
233 }
235 static gboolean
236 check_helo_response(smtp_base * psb)
237 {
238 gchar *ptr = psb->buffer;
240 if (!check_response(psb, FALSE))
241 return FALSE;
243 while (*ptr) {
244 if (strncasecmp(&(ptr[4]), "SIZE", 4) == 0) {
245 gchar *arg;
246 psb->use_size = TRUE;
247 arg = get_response_arg(&(ptr[8]));
248 if (arg) {
249 psb->max_size = atoi(arg);
250 g_free(arg);
251 }
252 }
254 if (strncasecmp(&(ptr[4]), "PIPELINING", 10) == 0)
255 psb->use_pipelining = TRUE;
257 if (strncasecmp(&(ptr[4]), "AUTH", 4) == 0) {
258 if ((ptr[8] == ' ') || (ptr[8] == '=') || (ptr[8] == '\t')) { /* not sure about '\t' */
259 gchar *arg;
260 psb->use_auth = TRUE;
261 arg = get_response_arg(&(ptr[9])); /* after several years I finally learnt to count */
262 if (arg) {
263 psb->auth_names = g_strsplit(arg, " ", 0);
264 g_free(arg);
266 DEBUG(4) {
267 gint i = 0;
268 debugf("in check_helo_response()\n");
269 while (psb->auth_names[i]) {
270 debugf(" offered AUTH %s\n", psb->auth_names[i]);
271 i++;
272 }
273 }
274 }
275 }
276 }
278 while (*ptr != '\n')
279 ptr++;
280 ptr++;
281 }
283 DEBUG(4) {
284 debugf(" %s\n", psb->use_size ? "uses SIZE" : "no size");
285 debugf(" %s\n", psb->use_pipelining ? "uses PIPELINING" : "no pipelining");
286 debugf(" %s\n", psb->use_auth ? "uses AUTH" : "no auth");
287 }
289 return TRUE;
290 }
292 static gboolean
293 smtp_helo(smtp_base * psb, gchar * helo)
294 {
295 while (TRUE) {
296 if (psb->use_esmtp) {
297 fprintf(psb->out, "EHLO %s\r\n", helo);
298 fflush(psb->out);
300 DEBUG(4) debugf("C: EHLO %s\r\n", helo);
302 } else {
303 fprintf(psb->out, "HELO %s\r\n", helo);
304 fflush(psb->out);
306 DEBUG(4) debugf("C: HELO %s\r\n", helo);
308 }
310 if (!read_response(psb, SMTP_CMD_TIMEOUT))
311 return FALSE;
313 if (check_helo_response(psb))
314 return TRUE;
315 else {
316 if (psb->error == smtp_fail) {
317 if (psb->use_esmtp) {
318 /* our guess that server understands EHLO was wrong, try again with HELO */
319 psb->use_esmtp = FALSE;
320 } else {
321 /* what sort of server ist THAT ?! give up... */
322 return FALSE;
323 }
324 } else
325 return FALSE;
326 }
327 }
328 }
330 static void
331 smtp_cmd_mailfrom(smtp_base * psb, address * return_path, guint size)
332 {
333 if (psb->use_size) {
334 fprintf(psb->out, "MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
335 fflush(psb->out);
337 DEBUG(4) debugf("C: MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
339 } else {
340 fprintf(psb->out, "MAIL FROM:%s\r\n", addr_string(return_path));
341 fflush(psb->out);
343 DEBUG(4) debugf("C: MAIL FROM:%s\r\n", addr_string(return_path));
344 }
345 }
347 static void
348 smtp_cmd_rcptto(smtp_base * psb, address * rcpt)
349 {
350 fprintf(psb->out, "RCPT TO:%s\r\n", addr_string(rcpt));
351 fflush(psb->out);
352 DEBUG(4) debugf("C: RCPT TO:%s\n", addr_string(rcpt));
353 }
355 static void
356 send_data_line(smtp_base * psb, gchar * data)
357 {
358 /* According to RFC 821 each line should be terminated with CRLF.
359 Since a dot on a line itself marks the end of data, each line
360 beginning with a dot is prepended with another dot.
361 */
362 gchar *ptr;
363 gboolean new_line = TRUE; /* previous versions assumed that each item was exactly one line.
364 This is no longer the case */
366 ptr = data;
367 while (*ptr) {
368 int c = (int) (*ptr);
369 if (c == '.' && new_line) {
370 /* dot-stuffing */
371 putc('.', psb->out);
372 }
373 if (c == '\n') {
374 /* CRLF line terminators */
375 putc('\r', psb->out);
376 putc('\n', psb->out);
377 new_line = TRUE;
378 } else {
379 putc(c, psb->out);
380 new_line = FALSE;
381 }
382 ptr++;
383 }
384 }
386 static void
387 send_header(smtp_base * psb, GList * hdr_list)
388 {
389 GList *node;
390 gint num_hdrs = 0;
392 /* header */
393 if (hdr_list) {
394 foreach(hdr_list, node) {
395 if (node->data) {
396 header *hdr = (header *) (node->data);
397 if (hdr->header) {
398 send_data_line(psb, hdr->header);
399 num_hdrs++;
400 }
401 }
402 }
403 }
405 /* empty line separating headers from data: */
406 putc('\r', psb->out);
407 putc('\n', psb->out);
409 DEBUG(4) debugf("sent %d headers\n", num_hdrs);
410 }
412 static void
413 send_data(smtp_base * psb, message * msg)
414 {
415 GList *node;
416 gint num_lines = 0;
418 /* data */
419 if (msg->data_list) {
420 for (node = g_list_first(msg->data_list); node; node = g_list_next(node)) {
421 if (node->data) {
422 send_data_line(psb, node->data);
423 num_lines++;
424 }
425 }
426 }
428 DEBUG(4) debugf("sent %d lines of data\n", num_lines);
430 fprintf(psb->out, ".\r\n");
431 fflush(psb->out);
432 DEBUG(4) debugf("C: .\n");
433 }
435 void
436 smtp_out_mark_rcpts(smtp_base * psb, GList * rcpt_list)
437 {
438 GList *rcpt_node;
439 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
440 address *rcpt = (address *) (rcpt_node->data);
442 addr_unmark_delivered(rcpt);
444 if ((psb->error == smtp_trylater) || (psb->error == smtp_timeout) || (psb->error == smtp_eof)) {
445 addr_mark_defered(rcpt);
446 } else {
447 addr_mark_failed(rcpt);
448 }
449 }
450 }
452 void
453 smtp_out_log_failure(smtp_base * psb, message * msg)
454 {
455 gchar *err_str;
457 if (psb->error == smtp_timeout)
458 err_str = g_strdup("connection timed out.");
459 else if (psb->error == smtp_eof)
460 err_str = g_strdup("connection terminated prematurely.");
461 else if (psb->error == smtp_syntax)
462 err_str = g_strdup_printf("got unexpected response: %s", psb->buffer);
463 else if (psb->error == smtp_cancel)
464 err_str = g_strdup("delivery was canceled.\n");
465 else
466 /* error message should still be in the buffer */
467 err_str = g_strdup_printf("failed: %s\n", psb->buffer);
469 if (msg == NULL)
470 logwrite(LOG_NOTICE, "host=%s %s\n", psb->remote_host, err_str);
471 else
472 logwrite(LOG_NOTICE, "%s == host=%s %s\n", msg->uid, psb->remote_host, err_str);
474 g_free(err_str);
475 }
477 smtp_base*
478 smtp_out_open(gchar * host, gint port, GList * resolve_list)
479 {
480 smtp_base *psb;
481 gint sock;
482 mxip_addr *addr;
484 DEBUG(5) debugf("smtp_out_open entered, host = %s\n", host);
486 if ((addr = connect_resolvelist(&sock, host, port, resolve_list))) {
487 /* create structure to hold status data: */
488 psb = create_smtpbase(sock);
489 psb->remote_host = addr->name;
491 DEBUG(5) {
492 struct sockaddr_in name;
493 int len = sizeof(struct sockaddr);
494 getsockname(sock, (struct sockaddr *) (&name), &len);
495 debugf("socket: name.sin_addr = %s\n", inet_ntoa(name.sin_addr));
496 }
497 return psb;
498 } else {
499 DEBUG(5) debugf("connect_resolvelist failed: %s %s\n", strerror(errno), hstrerror(h_errno));
500 }
502 return NULL;
503 }
505 smtp_base*
506 smtp_out_open_child(gchar * cmd)
507 {
508 smtp_base *psb;
509 gint sock;
511 DEBUG(5) debugf("smtp_out_open_child entered, cmd = %s\n", cmd);
513 sock = child(cmd);
515 if (sock > 0) {
516 psb = create_smtpbase(sock);
517 psb->remote_host = NULL;
519 return psb;
520 }
522 return NULL;
523 }
525 gboolean
526 smtp_out_rset(smtp_base * psb)
527 {
528 gboolean ok;
530 fprintf(psb->out, "RSET\r\n");
531 fflush(psb->out);
532 DEBUG(4) debugf("C: RSET\n");
534 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
535 if (check_response(psb, FALSE))
536 return TRUE;
538 smtp_out_log_failure(psb, NULL);
540 return FALSE;
541 }
543 #ifdef ENABLE_AUTH
545 static gboolean
546 smtp_out_auth_cram_md5(smtp_base * psb)
547 {
548 gboolean ok = FALSE;
550 fprintf(psb->out, "C: AUTH CRAM-MD5\r\n");
551 fflush(psb->out);
552 DEBUG(4) debugf("AUTH CRAM-MD5\n");
553 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
554 if ((ok = check_response(psb, TRUE))) {
555 gchar *chall64 = get_response_arg(&(psb->buffer[4]));
556 gint chall_size;
557 gchar *chall = base64_decode(chall64, &chall_size);
558 guchar digest[16], *reply64, *reply;
559 gchar digest_string[33];
560 gint i;
561 #ifdef USE_LIB_CRYPTO
562 unsigned int digest_len;
563 #endif
565 DEBUG(5) debugf("smtp_out_auth_cram_md5():\n");
566 DEBUG(5) debugf(" encoded challenge = %s\n", chall64);
567 DEBUG(5) debugf(" decoded challenge = %s, size = %d\n", chall, chall_size);
568 DEBUG(5) debugf(" secret = %s\n", psb->auth_secret);
570 #ifdef USE_LIB_CRYPTO
571 HMAC(EVP_md5(), psb->auth_secret, strlen(psb->auth_secret), chall, chall_size, digest, &digest_len);
572 #else
573 hmac_md5(chall, chall_size, psb->auth_secret, strlen(psb->auth_secret), digest);
574 #endif
576 for (i = 0; i < 16; i++)
577 sprintf(&(digest_string[i + i]), "%02x", (unsigned int) (digest[i]));
578 digest_string[32] = '\0';
580 DEBUG(5) debugf(" digest = %s\n", digest_string);
582 reply = g_strdup_printf("%s %s", psb->auth_login, digest_string);
583 DEBUG(5) debugf(" unencoded reply = %s\n", reply);
585 reply64 = base64_encode(reply, strlen(reply));
586 DEBUG(5) debugf(" encoded reply = %s\n", reply64);
588 fprintf(psb->out, "%s\r\n", reply64);
589 fflush(psb->out);
590 DEBUG(6) debugf(" reply64 = %s\n", reply64);
591 DEBUG(6) debugf("C: %s\n", reply64);
593 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
594 ok = check_response(psb, FALSE);
596 g_free(reply64);
597 g_free(reply);
598 g_free(chall);
599 g_free(chall64);
600 }
601 }
602 return ok;
603 }
605 static gboolean
606 smtp_out_auth_login(smtp_base * psb)
607 {
608 gboolean ok = FALSE;
609 fprintf(psb->out, "AUTH LOGIN\r\n");
610 fflush(psb->out);
611 DEBUG(4) debugf("C: AUTH LOGIN\r\n");
612 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
613 if ((ok = check_response(psb, TRUE))) {
614 gchar *resp64;
615 guchar *resp;
616 gint resp_size;
617 gchar *reply64;
619 DEBUG(5) debugf("smtp_out_auth_login():\n");
620 resp64 = get_response_arg(&(psb->buffer[4]));
621 DEBUG(5) debugf(" encoded response = %s\n", resp64);
622 resp = base64_decode(resp64, &resp_size);
623 g_free(resp64);
624 DEBUG(5) debugf(" decoded response = %s, size = %d\n", resp, resp_size);
625 g_free(resp);
626 reply64 = base64_encode(psb->auth_login, strlen(psb->auth_login));
627 fprintf(psb->out, "%s\r\n", reply64);
628 fflush(psb->out);
629 DEBUG(6) debugf("C: %s\n", reply64);
630 g_free(reply64);
631 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
632 if ((ok = check_response(psb, TRUE))) {
633 resp64 = get_response_arg(&(psb->buffer[4]));
634 DEBUG(5) debugf(" encoded response = %s\n", resp64);
635 resp = base64_decode(resp64, &resp_size);
636 g_free(resp64);
637 DEBUG(5) debugf(" decoded response = %s, size = %d\n", resp, resp_size);
638 g_free(resp);
639 reply64 = base64_encode(psb->auth_secret, strlen(psb->auth_secret));
640 fprintf(psb->out, "%s\r\n", reply64);
641 fflush(psb->out);
642 DEBUG(6) debugf("C: %s\n", reply64);
643 g_free(reply64);
644 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
645 ok = check_response(psb, FALSE);
646 }
647 }
648 }
649 }
650 return ok;
651 }
653 gboolean
654 smtp_out_auth(smtp_base * psb)
655 {
656 gboolean ok = FALSE;
657 gint i = 0;
658 while (psb->auth_names[i]) {
659 if (strcasecmp(psb->auth_names[i], psb->auth_name) == 0)
660 break;
661 i++;
662 }
663 if (psb->auth_names[i]) {
664 if (strcasecmp(psb->auth_name, "cram-md5") == 0) {
665 smtp_out_auth_cram_md5(psb);
666 } else if (strcasecmp(psb->auth_name, "login") == 0) {
667 smtp_out_auth_login(psb);
668 } else {
669 logwrite(LOG_ERR, "auth method %s not supported\n", psb->auth_name);
670 }
671 } else {
672 logwrite(LOG_ERR, "no auth method %s found.\n", psb->auth_name);
673 }
674 return ok;
675 }
677 #endif
679 gboolean
680 smtp_out_init(smtp_base * psb)
681 {
682 gboolean ok;
684 if ((ok = read_response(psb, SMTP_INITIAL_TIMEOUT))) {
685 if ((ok = check_init_response(psb))) {
687 if ((ok = smtp_helo(psb, psb->helo_name))) {
688 #ifdef ENABLE_AUTH
689 if (psb->auth_name && psb->use_auth) {
690 /* we completely disregard the response of server here. If
691 authentication fails, the server will complain later
692 anyway. I know, this is not polite... */
693 smtp_out_auth(psb);
694 }
695 #endif
696 }
697 }
698 }
699 if (!ok)
700 smtp_out_log_failure(psb, NULL);
701 return ok;
702 }
704 gint
705 smtp_out_msg(smtp_base * psb, message * msg, address * return_path, GList * rcpt_list, GList * hdr_list)
706 {
707 gint i, size;
708 gboolean ok = TRUE;
709 int rcpt_cnt;
710 int rcpt_accept = 0;
712 DEBUG(5) debugf("smtp_out_msg entered\n");
714 /* defaults: */
715 if (return_path == NULL)
716 return_path = msg->return_path;
717 if (hdr_list == NULL)
718 hdr_list = msg->hdr_list;
719 if (rcpt_list == NULL)
720 rcpt_list = msg->rcpt_list;
721 rcpt_cnt = g_list_length(rcpt_list);
723 size = msg_calc_size(msg, TRUE);
725 /* respect maximum size given by server: */
726 if ((psb->max_size > 0) && (size > psb->max_size)) {
727 logwrite(LOG_WARNING, "%s == host=%s message size (%d) > "
728 "fixed maximum message size of server (%d)",
729 msg->uid, psb->remote_host, size, psb->max_size);
730 psb->error = smtp_cancel;
731 ok = FALSE;
732 }
734 if (ok) {
735 /* pretend the message is a bit larger,
736 just in case the size calculation is buggy */
737 smtp_cmd_mailfrom(psb, return_path, psb->use_size ? size+SMTP_SIZE_ADD : 0);
739 if (!psb->use_pipelining) {
740 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
741 ok = check_response(psb, FALSE);
742 }
743 }
744 if (ok) {
745 GList *rcpt_node;
746 rcpt_accept = 0;
748 for (rcpt_node = g_list_first(rcpt_list); rcpt_node != NULL; rcpt_node = g_list_next(rcpt_node)) {
749 address *rcpt = (address *) (rcpt_node->data);
750 smtp_cmd_rcptto(psb, rcpt);
751 if (!psb->use_pipelining) {
752 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
753 if (check_response(psb, FALSE)) {
754 rcpt_accept++;
755 addr_mark_delivered(rcpt);
756 } else {
757 /* if server returned an error for one recp. we
758 may still try the others. But if it is a timeout, eof
759 or unexpected response, it is more serious and we should
760 give up. */
761 if ((psb->error != smtp_trylater) && (psb->error != smtp_fail)) {
762 ok = FALSE;
763 break;
764 } else {
765 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n",
766 msg->uid, addr_string(rcpt), psb->remote_host, psb->buffer);
767 if (psb->error == smtp_trylater) {
768 addr_mark_defered(rcpt);
769 } else {
770 addr_mark_failed(rcpt);
771 }
772 }
773 } else
774 break;
775 }
776 }
778 /* There is no point in going on if no recp.s were accpted.
779 But we can check that at this point only if not pipelining: */
780 ok = (ok && (psb->use_pipelining || (rcpt_accept > 0)));
781 if (ok) {
783 fprintf(psb->out, "DATA\r\n");
784 fflush(psb->out);
786 DEBUG(4) debugf("C: DATA\r\n");
788 if (psb->use_pipelining) {
789 /* the first pl'ed command was MAIL FROM
790 the last was DATA, whose response can be handled by the 'normal' code
791 all in between were RCPT TO:
792 */
793 /* response to MAIL FROM: */
794 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
795 if ((ok = check_response(psb, FALSE))) {
797 /* response(s) to RCPT TO:
798 this is very similar to the sequence above for no pipeline
799 */
800 for (i = 0; i < rcpt_cnt; i++) {
801 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
802 address *rcpt = g_list_nth_data(rcpt_list, i);
803 if (check_response(psb, FALSE)) {
804 rcpt_accept++;
805 addr_mark_delivered(rcpt);
806 } else {
807 /* if server returned an error 4xx or 5xx for one recp. we
808 may still try the others. But if it is a timeout, eof
809 or unexpected response, it is more serious and we
810 should give up. */
811 if ((psb->error != smtp_trylater) &&
812 (psb->error != smtp_fail)) {
813 ok = FALSE;
814 break;
815 } else {
816 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n", msg->uid,
817 addr_string(rcpt), psb->remote_host, psb->buffer);
818 if (psb->error == smtp_trylater) {
819 addr_mark_defered(rcpt);
820 } else {
821 addr_mark_failed(rcpt);
822 }
823 }
824 }
825 } else {
826 DEBUG(5) debugf("check_response failed after RCPT TO\n");
827 break;
828 }
829 }
830 if (rcpt_accept == 0)
831 ok = FALSE;
832 } else {
833 DEBUG(5) debugf("check_response failed after MAIL FROM\n");
834 }
835 } else {
836 DEBUG(5)
837 debugf("read_response failed after MAIL FROM\n");
838 }
839 }
841 /* if(psb->use_pipelining) */
842 /* response to the DATA cmd */
843 if (ok) {
844 if (read_response(psb, SMTP_DATA_TIMEOUT)) {
845 if (check_response(psb, TRUE)) {
846 send_header(psb, hdr_list);
847 send_data(psb, msg);
849 if (read_response(psb, SMTP_FINAL_TIMEOUT))
850 ok = check_response(psb, FALSE);
851 }
852 }
853 }
854 }
855 }
857 DEBUG(5) {
858 debugf("smtp_out_msg():\n");
859 debugf(" psb->error = %d\n", psb->error);
860 debugf(" ok = %d\n", ok);
861 debugf(" rcpt_accept = %d\n", rcpt_accept);
862 }
864 if (psb->error == smtp_ok) {
865 GList *rcpt_node;
866 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
867 address *rcpt = (address *) (rcpt_node->data);
868 if (addr_is_delivered(rcpt))
869 logwrite(LOG_NOTICE, "%s => %s host=%s with %s\n", msg->uid, addr_string(rcpt),
870 psb->remote_host, psb->use_esmtp ? "esmtp" : "smtp");
871 }
872 } else {
873 /* if something went wrong,
874 we have to unmark the rcpts prematurely marked as delivered
875 and mark the status */
876 smtp_out_mark_rcpts(psb, rcpt_list);
878 /* log the failure: */
879 smtp_out_log_failure(psb, msg);
880 }
881 return rcpt_accept;
882 }
884 gboolean
885 smtp_out_quit(smtp_base * psb)
886 {
887 fprintf(psb->out, "QUIT\r\n");
888 fflush(psb->out);
890 DEBUG(4) debugf("C: QUIT\n");
892 signal(SIGALRM, SIG_DFL);
894 return TRUE;
895 }
897 gint
898 smtp_deliver(gchar * host, gint port, GList * resolve_list, message * msg, address * return_path, GList * rcpt_list)
899 {
900 smtp_base *psb;
901 smtp_error err;
903 DEBUG(5) debugf("smtp_deliver entered\n");
905 if (return_path == NULL)
906 return_path = msg->return_path;
908 if ((psb = smtp_out_open(host, port, resolve_list))) {
909 set_heloname(psb, return_path->domain, TRUE);
910 /* initiate connection, send message and quit: */
911 if (smtp_out_init(psb)) {
912 smtp_out_msg(psb, msg, return_path, rcpt_list, NULL);
913 if (psb->error == smtp_ok || (psb->error == smtp_fail) || (psb->error == smtp_trylater)
914 || (psb->error == smtp_syntax) || (psb->error == smtp_cancel))
915 smtp_out_quit(psb);
916 }
918 err = psb->error;
919 destroy_smtpbase(psb);
921 return err;
922 }
923 return -1;
924 }