masqmail

view src/smtp_out.c @ 42:03817f849106

decided to release the next version as 0.2.22 (not as 0.3.0) I'll keep the 0.2 branch as the stable version which gets only bugfixed. Soon I'll split off a 0.3 branch for further (incompatible) development.
author meillo@marmaro.de
date Thu, 13 May 2010 17:34:23 +0200
parents 26e34ae9a3e3
children a80ebfa16cd5
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.
360 This is no longer the case */
362 ptr = data;
363 while (*ptr) {
364 int c = (int) (*ptr);
365 if (c == '.')
366 if (new_line)
367 putc('.', psb->out);
368 if (c == '\n') {
369 putc('\r', psb->out);
370 putc('\n', psb->out);
371 new_line = TRUE;
372 } else {
373 putc(c, psb->out);
374 new_line = FALSE;
375 }
376 ptr++;
377 }
378 }
380 static void
381 send_header(smtp_base * psb, GList * hdr_list)
382 {
383 GList *node;
384 gint num_hdrs = 0;
386 /* header */
387 if (hdr_list) {
388 foreach(hdr_list, node) {
389 if (node->data) {
390 header *hdr = (header *) (node->data);
391 if (hdr->header) {
392 send_data_line(psb, hdr->header);
393 num_hdrs++;
394 }
395 }
396 }
397 }
399 /* empty line separating headers from data: */
400 putc('\r', psb->out);
401 putc('\n', psb->out);
403 DEBUG(4) debugf("sent %d headers\n", num_hdrs);
404 }
406 static void
407 send_data(smtp_base * psb, message * msg)
408 {
409 GList *node;
410 gint num_lines = 0;
412 /* data */
413 if (msg->data_list) {
414 for (node = g_list_first(msg->data_list); node; node = g_list_next(node)) {
415 if (node->data) {
416 send_data_line(psb, node->data);
417 num_lines++;
418 }
419 }
420 }
422 DEBUG(4) debugf("sent %d lines of data\n", num_lines);
424 fprintf(psb->out, ".\r\n");
425 fflush(psb->out);
426 }
428 void
429 smtp_out_mark_rcpts(smtp_base * psb, GList * rcpt_list)
430 {
431 GList *rcpt_node;
432 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
433 address *rcpt = (address *) (rcpt_node->data);
435 addr_unmark_delivered(rcpt);
437 if ((psb->error == smtp_trylater) || (psb->error == smtp_timeout) || (psb->error == smtp_eof)) {
438 addr_mark_defered(rcpt);
439 } else {
440 addr_mark_failed(rcpt);
441 }
442 }
443 }
445 void
446 smtp_out_log_failure(smtp_base * psb, message * msg)
447 {
448 gchar *err_str;
450 if (psb->error == smtp_timeout)
451 err_str = g_strdup("connection timed out.");
452 else if (psb->error == smtp_eof)
453 err_str = g_strdup("connection terminated prematurely.");
454 else if (psb->error == smtp_syntax)
455 err_str = g_strdup_printf("got unexpected response: %s", psb->buffer);
456 else if (psb->error == smtp_cancel)
457 err_str = g_strdup("delivery was canceled.\n");
458 else
459 /* error message should still be in the buffer */
460 err_str = g_strdup_printf("failed: %s\n", psb->buffer);
462 if (msg == NULL)
463 logwrite(LOG_NOTICE, "host=%s %s\n", psb->remote_host, err_str);
464 else
465 logwrite(LOG_NOTICE, "%s == host=%s %s\n", msg->uid, psb->remote_host, err_str);
467 g_free(err_str);
468 }
470 smtp_base*
471 smtp_out_open(gchar * host, gint port, GList * resolve_list)
472 {
473 smtp_base *psb;
474 gint sock;
475 mxip_addr *addr;
477 DEBUG(5) debugf("smtp_out_open entered, host = %s\n", host);
479 if ((addr = connect_resolvelist(&sock, host, port, resolve_list))) {
480 /* create structure to hold status data: */
481 psb = create_smtpbase(sock);
482 psb->remote_host = addr->name;
484 DEBUG(5) {
485 struct sockaddr_in name;
486 int len = sizeof(struct sockaddr);
487 getsockname(sock, (struct sockaddr *) (&name), &len);
488 debugf("socket: name.sin_addr = %s\n", inet_ntoa(name.sin_addr));
489 }
490 return psb;
491 } else {
492 DEBUG(5) debugf("connect_resolvelist failed: %s %s\n", strerror(errno), hstrerror(h_errno));
493 }
495 return NULL;
496 }
498 smtp_base*
499 smtp_out_open_child(gchar * cmd)
500 {
501 smtp_base *psb;
502 gint sock;
504 DEBUG(5) debugf("smtp_out_open_child entered, cmd = %s\n", cmd);
506 sock = child(cmd);
508 if (sock > 0) {
509 psb = create_smtpbase(sock);
510 psb->remote_host = NULL;
512 return psb;
513 }
515 return NULL;
516 }
518 gboolean
519 smtp_out_rset(smtp_base * psb)
520 {
521 gboolean ok;
523 fprintf(psb->out, "RSET\r\n");
524 fflush(psb->out);
525 DEBUG(4) debugf("RSET\n");
527 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
528 if (check_response(psb, FALSE))
529 return TRUE;
531 smtp_out_log_failure(psb, NULL);
533 return FALSE;
534 }
536 #ifdef ENABLE_AUTH
538 static gboolean
539 smtp_out_auth_cram_md5(smtp_base * psb)
540 {
541 gboolean ok = FALSE;
543 fprintf(psb->out, "AUTH CRAM-MD5\r\n");
544 fflush(psb->out);
545 DEBUG(4) debugf("AUTH CRAM-MD5\n");
546 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
547 if ((ok = check_response(psb, TRUE))) {
548 gchar *chall64 = get_response_arg(&(psb->buffer[4]));
549 gint chall_size;
550 gchar *chall = base64_decode(chall64, &chall_size);
551 guchar digest[16], *reply64, *reply;
552 gchar digest_string[33];
553 gint i;
554 #ifdef USE_LIB_CRYPTO
555 unsigned int digest_len;
556 #endif
558 DEBUG(5) debugf("encoded challenge = %s\n", chall64);
559 DEBUG(5) debugf("decoded challenge = %s, size = %d\n", chall, chall_size);
561 DEBUG(5) debugf("secret = %s\n", psb->auth_secret);
563 #ifdef USE_LIB_CRYPTO
564 HMAC(EVP_md5(), psb->auth_secret, strlen(psb->auth_secret), chall, chall_size, digest, &digest_len);
565 #else
566 hmac_md5(chall, chall_size, psb->auth_secret, strlen(psb->auth_secret), digest);
567 #endif
569 for (i = 0; i < 16; i++)
570 sprintf(&(digest_string[i + i]), "%02x", (unsigned int) (digest[i]));
571 digest_string[32] = '\0';
573 DEBUG(5) debugf("digest = %s\n", digest_string);
575 reply = g_strdup_printf("%s %s", psb->auth_login, digest_string);
576 DEBUG(5) debugf("unencoded reply = %s\n", reply);
578 reply64 = base64_encode(reply, strlen(reply));
579 DEBUG(5) debugf("encoded reply = %s\n", reply64);
581 fprintf(psb->out, "%s\r\n", reply64);
582 fflush(psb->out);
583 DEBUG(4) debugf("%s\n", reply64);
585 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
586 ok = check_response(psb, FALSE);
588 g_free(reply64);
589 g_free(reply);
590 g_free(chall);
591 g_free(chall64);
592 }
593 }
594 return ok;
595 }
597 static gboolean
598 smtp_out_auth_login(smtp_base * psb)
599 {
600 gboolean ok = FALSE;
601 fprintf(psb->out, "AUTH LOGIN\r\n");
602 fflush(psb->out);
603 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
604 if ((ok = check_response(psb, TRUE))) {
605 gchar *resp64;
606 guchar *resp;
607 gint resp_size;
608 gchar *reply64;
610 resp64 = get_response_arg(&(psb->buffer[4]));
611 DEBUG(5) debugf("encoded response = %s\n", resp64);
612 resp = base64_decode(resp64, &resp_size);
613 g_free(resp64);
614 DEBUG(5) debugf("decoded response = %s, size = %d\n", resp, resp_size);
615 g_free(resp);
616 reply64 = base64_encode(psb->auth_login, strlen(psb->auth_login));
617 fprintf(psb->out, "%s\r\n", reply64);
618 fflush(psb->out);
619 g_free(reply64);
620 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
621 if ((ok = check_response(psb, TRUE))) {
622 resp64 = get_response_arg(&(psb->buffer[4]));
623 DEBUG(5) debugf("encoded response = %s\n", resp64);
624 resp = base64_decode(resp64, &resp_size);
625 g_free(resp64);
626 DEBUG(5) debugf("decoded response = %s, size = %d\n", resp, resp_size);
627 g_free(resp);
628 reply64 = base64_encode(psb->auth_secret, strlen(psb->auth_secret));
629 fprintf(psb->out, "%s\r\n", reply64);
630 fflush(psb->out);
631 g_free(reply64);
632 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
633 ok = check_response(psb, FALSE);
634 }
635 }
636 }
637 }
638 return ok;
639 }
641 gboolean
642 smtp_out_auth(smtp_base * psb)
643 {
644 gboolean ok = FALSE;
645 gint i = 0;
646 while (psb->auth_names[i]) {
647 if (strcasecmp(psb->auth_names[i], psb->auth_name) == 0)
648 break;
649 i++;
650 }
651 if (psb->auth_names[i]) {
652 if (strcasecmp(psb->auth_name, "cram-md5") == 0) {
653 smtp_out_auth_cram_md5(psb);
654 } else if (strcasecmp(psb->auth_name, "login") == 0) {
655 smtp_out_auth_login(psb);
656 } else {
657 logwrite(LOG_ERR, "auth method %s not supported\n", psb->auth_name);
658 }
659 } else {
660 logwrite(LOG_ERR, "no auth method %s found.\n", psb->auth_name);
661 }
662 return ok;
663 }
665 #endif
667 gboolean
668 smtp_out_init(smtp_base * psb)
669 {
670 gboolean ok;
672 if ((ok = read_response(psb, SMTP_INITIAL_TIMEOUT))) {
673 if ((ok = check_init_response(psb))) {
675 if ((ok = smtp_helo(psb, psb->helo_name))) {
676 #ifdef ENABLE_AUTH
677 if (psb->auth_name && psb->use_auth) {
678 /* we completely disregard the response of server here. If
679 authentication fails, the server will complain later
680 anyway. I know, this is not polite... */
681 smtp_out_auth(psb);
682 }
683 #endif
684 }
685 }
686 }
687 if (!ok)
688 smtp_out_log_failure(psb, NULL);
689 return ok;
690 }
692 gint
693 smtp_out_msg(smtp_base * psb, message * msg, address * return_path, GList * rcpt_list, GList * hdr_list)
694 {
695 gint i, size;
696 gboolean ok = TRUE;
697 int rcpt_cnt;
698 int rcpt_accept = 0;
700 DEBUG(5) debugf("smtp_out_msg entered\n");
702 /* defaults: */
703 if (return_path == NULL)
704 return_path = msg->return_path;
705 if (hdr_list == NULL)
706 hdr_list = msg->hdr_list;
707 if (rcpt_list == NULL)
708 rcpt_list = msg->rcpt_list;
709 rcpt_cnt = g_list_length(rcpt_list);
711 size = msg_calc_size(msg, TRUE);
713 /* respect maximum size given by server: */
714 if ((psb->max_size > 0) && (size > psb->max_size)) {
715 logwrite(LOG_WARNING, "%s == host=%s message size (%d) > fixed maximum message size of server (%d)",
716 msg->uid, psb->remote_host, size, psb->max_size);
717 psb->error = smtp_cancel;
718 ok = FALSE;
719 }
721 if (ok) {
722 smtp_cmd_mailfrom(psb, return_path, psb->use_size ? size + SMTP_SIZE_ADD : 0);
724 if (!psb->use_pipelining) {
725 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
726 ok = check_response(psb, FALSE);
727 }
728 }
729 if (ok) {
730 GList *rcpt_node;
731 rcpt_accept = 0;
733 for (rcpt_node = g_list_first(rcpt_list); rcpt_node != NULL; rcpt_node = g_list_next(rcpt_node)) {
734 address *rcpt = (address *) (rcpt_node->data);
735 smtp_cmd_rcptto(psb, rcpt);
736 if (!psb->use_pipelining) {
737 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
738 if (check_response(psb, FALSE)) {
739 rcpt_accept++;
740 addr_mark_delivered(rcpt);
741 } else {
742 /* if server returned an error for one recp. we
743 may still try the others. But if it is a timeout, eof
744 or unexpected response, it is more serious and we should
745 give up. */
746 if ((psb->error != smtp_trylater) && (psb->error != smtp_fail)) {
747 ok = FALSE;
748 break;
749 } else {
750 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s",
751 msg->uid, addr_string(rcpt), psb->remote_host, psb->buffer);
752 if (psb->error == smtp_trylater) {
753 addr_mark_defered(rcpt);
754 } else {
755 addr_mark_failed(rcpt);
756 }
757 }
758 } else
759 break;
760 }
761 }
763 /* There is no point in going on if no recp.s were accpted.
764 But we can check that at this point only if not pipelining: */
765 ok = (ok && (psb->use_pipelining || (rcpt_accept > 0)));
766 if (ok) {
768 fprintf(psb->out, "DATA\r\n");
769 fflush(psb->out);
771 DEBUG(4) debugf("DATA\r\n");
773 if (psb->use_pipelining) {
774 /* the first pl'ed command was MAIL FROM
775 the last was DATA, whose response can be handled by the 'normal' code
776 all in between were RCPT TO:
777 */
778 /* response to MAIL FROM: */
779 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
780 if ((ok = check_response(psb, FALSE))) {
782 /* response(s) to RCPT TO:
783 this is very similar to the sequence above for no pipeline
784 */
785 for (i = 0; i < rcpt_cnt; i++) {
786 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
787 address *rcpt = g_list_nth_data(rcpt_list, i);
788 if (check_response(psb, FALSE)) {
789 rcpt_accept++;
790 addr_mark_delivered(rcpt);
791 } else {
792 /* if server returned an error 4xx or 5xx for one recp. we
793 may still try the others. But if it is a timeout, eof
794 or unexpected response, it is more serious and we
795 should give up. */
796 if ((psb->error != smtp_trylater) &&
797 (psb->error != smtp_fail)) {
798 ok = FALSE;
799 break;
800 } else {
801 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s", msg->uid,
802 addr_string(rcpt), psb->remote_host, psb->buffer);
803 if (psb->error == smtp_trylater) {
804 addr_mark_defered(rcpt);
805 } else {
806 addr_mark_failed(rcpt);
807 }
808 }
809 }
810 } else {
811 DEBUG(5) debugf("check_response failed after RCPT TO\n");
812 break;
813 }
814 }
815 if (rcpt_accept == 0)
816 ok = FALSE;
817 } else {
818 DEBUG(5) debugf("check_response failed after MAIL FROM\n");
819 }
820 } else {
821 DEBUG(5)
822 debugf("read_response failed after MAIL FROM\n");
823 }
824 }
826 /* if(psb->use_pipelining) */
827 /* response to the DATA cmd */
828 if (ok) {
829 if (read_response(psb, SMTP_DATA_TIMEOUT)) {
830 if (check_response(psb, TRUE)) {
831 send_header(psb, hdr_list);
832 send_data(psb, msg);
834 if (read_response(psb, SMTP_FINAL_TIMEOUT))
835 ok = check_response(psb, FALSE);
836 }
837 }
838 }
839 }
840 }
842 DEBUG(5) {
843 debugf("psb->error = %d\n", psb->error);
844 debugf("ok = %d\n", ok);
845 debugf("rcpt_accept = %d\n", rcpt_accept);
846 }
848 if (psb->error == smtp_ok) {
849 GList *rcpt_node;
850 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
851 address *rcpt = (address *) (rcpt_node->data);
852 if (addr_is_delivered(rcpt))
853 logwrite(LOG_NOTICE, "%s => %s host=%s with %s\n", msg->uid, addr_string(rcpt),
854 psb->remote_host, psb->use_esmtp ? "esmtp" : "smtp");
855 }
856 } else {
857 /* if something went wrong,
858 we have to unmark the rcpts prematurely marked as delivered
859 and mark the status */
860 smtp_out_mark_rcpts(psb, rcpt_list);
862 /* log the failure: */
863 smtp_out_log_failure(psb, msg);
864 }
865 return rcpt_accept;
866 }
868 gboolean
869 smtp_out_quit(smtp_base * psb)
870 {
871 fprintf(psb->out, "QUIT\r\n");
872 fflush(psb->out);
874 DEBUG(4) debugf("QUIT\n");
876 signal(SIGALRM, SIG_DFL);
878 return TRUE;
879 }
881 gint
882 smtp_deliver(gchar * host, gint port, GList * resolve_list, message * msg, address * return_path, GList * rcpt_list)
883 {
884 smtp_base *psb;
885 smtp_error err;
887 DEBUG(5) debugf("smtp_deliver entered\n");
889 if (return_path == NULL)
890 return_path = msg->return_path;
892 if ((psb = smtp_out_open(host, port, resolve_list))) {
893 set_heloname(psb, return_path->domain, TRUE);
894 /* initiate connection, send message and quit: */
895 if (smtp_out_init(psb)) {
896 smtp_out_msg(psb, msg, return_path, rcpt_list, NULL);
897 if (psb->error == smtp_ok || (psb->error == smtp_fail) || (psb->error == smtp_trylater)
898 || (psb->error == smtp_syntax) || (psb->error == smtp_cancel))
899 smtp_out_quit(psb);
900 }
902 err = psb->error;
903 destroy_smtpbase(psb);
905 return err;
906 }
907 return -1;
908 }