masqmail-0.2

view src/smtp_out.c @ 165:ca99aa7f052a

improved hmactest added the test vectors that are included in the RFC plus improved the output
author meillo@marmaro.de
date Sun, 18 Jul 2010 22:24:51 +0200
parents 1e2fd87d58ea
children 349518b940db
line source
1 /* smtp_out.c, Copyright (C) 1999-2001 Oliver Kurth,
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 */
18 /*
19 send bugs to: kurth@innominate.de
20 */
22 /*
23 I always forget these rfc numbers:
24 RFC 821 (SMTP)
25 RFC 1869 (ESMTP)
26 RFC 1870 (ESMTP SIZE)
27 RFC 2197 (ESMTP PIPELINE)
28 RFC 2554 (ESMTP AUTH)
29 */
31 #include "masqmail.h"
32 #include "smtp_out.h"
33 #include "readsock.h"
35 #ifdef ENABLE_AUTH
37 #ifdef USE_LIB_CRYPTO
38 #include <openssl/hmac.h>
39 #include <openssl/md5.h>
40 #include <openssl/evp.h>
41 #else
42 #include "md5/md5.h"
43 #include "md5/hmac_md5.h"
44 #endif
46 #include "base64/base64.h"
47 #endif
49 void
50 destroy_smtpbase(smtp_base * psb)
51 {
52 fclose(psb->in);
53 fclose(psb->out);
55 close(psb->sock);
57 if (psb->helo_name)
58 g_free(psb->helo_name);
59 if (psb->buffer)
60 g_free(psb->buffer);
61 if (psb->auth_names)
62 g_strfreev(psb->auth_names);
64 if (psb->auth_name)
65 g_free(psb->auth_name);
66 if (psb->auth_login)
67 g_free(psb->auth_login);
68 if (psb->auth_secret)
69 g_free(psb->auth_secret);
70 }
72 gchar*
73 set_heloname(smtp_base * psb, gchar * default_name, gboolean do_correct)
74 {
75 struct sockaddr_in sname;
76 int len = sizeof(struct sockaddr_in);
77 struct hostent *host_entry;
79 if (do_correct) {
80 getsockname(psb->sock, (struct sockaddr *) (&sname), &len);
81 DEBUG(5) debugf("socket: name.sin_addr = %s\n", inet_ntoa(sname.sin_addr));
82 host_entry = gethostbyaddr((const char *) &(sname.sin_addr), sizeof(sname.sin_addr), AF_INET);
83 if (host_entry) {
84 psb->helo_name = g_strdup(host_entry->h_name);
85 } else {
86 /* we failed to look up our own name. Instead of giving our local hostname,
87 we may give our IP number to show the server that we are at least
88 willing to be honest. For the really picky ones. */
89 DEBUG(5) debugf("failed to look up own host name.\n");
90 psb->helo_name = g_strdup_printf("[%s]", inet_ntoa(sname.sin_addr));
91 }
92 DEBUG(5) debugf("helo_name = %s\n", psb->helo_name);
93 }
94 if (psb->helo_name == NULL) {
95 psb->helo_name = g_strdup(default_name);
96 }
97 return psb->helo_name;
98 }
100 #ifdef ENABLE_AUTH
102 gboolean
103 set_auth(smtp_base * psb, gchar * name, gchar * login, gchar * secret)
104 {
105 if ((strcasecmp(name, "CRAM-MD5") == 0) || (strcasecmp(name, "LOGIN") == 0)) {
106 psb->auth_name = g_strdup(name);
107 psb->auth_login = g_strdup(login);
108 psb->auth_secret = g_strdup(secret);
110 return TRUE;
111 }
112 return FALSE;
113 }
115 #endif
117 static smtp_base*
118 create_smtpbase(gint sock)
119 {
120 gint dup_sock;
122 smtp_base *psb = (smtp_base *) g_malloc(sizeof(smtp_base));
124 psb->sock = sock;
126 psb->use_esmtp = FALSE;
127 psb->use_size = FALSE;
128 psb->use_pipelining = FALSE;
129 psb->use_auth = FALSE;
131 psb->max_size = 0;
132 psb->auth_names = NULL;
134 psb->buffer = (gchar *) g_malloc(SMTP_BUF_LEN);
136 dup_sock = dup(sock);
137 psb->out = fdopen(sock, "w");
138 psb->in = fdopen(dup_sock, "r");
140 psb->error = smtp_ok;
142 psb->helo_name = NULL;
144 psb->auth_name = psb->auth_login = psb->auth_secret = NULL;
146 return psb;
147 }
149 static gboolean
150 read_response(smtp_base * psb, int timeout)
151 {
152 gint buf_pos = 0;
153 gchar code[5];
154 gint i, len;
156 do {
157 len = read_sockline(psb->in, &(psb->buffer[buf_pos]), SMTP_BUF_LEN - buf_pos, timeout, READSOCKL_CHUG);
158 if (len == -3) {
159 psb->error = smtp_timeout;
160 return FALSE;
161 } else if (len == -2) {
162 psb->error = smtp_syntax;
163 return FALSE;
164 } else if (len == -1) {
165 psb->error = smtp_eof;
166 return FALSE;
167 }
168 for (i = 0; i < 4; i++)
169 code[i] = psb->buffer[buf_pos + i];
170 code[i] = '\0';
171 psb->last_code = atoi(code);
173 buf_pos += len;
175 } while (code[3] == '-');
177 return TRUE;
178 }
180 static gboolean
181 check_response(smtp_base * psb, gboolean after_data)
182 {
183 char c = psb->buffer[0];
185 if (((c == '2') && !after_data) || ((c == '3') && after_data)) {
186 psb->error = smtp_ok;
187 DEBUG(6) debugf("response OK:'%s' after_date = %d\n", psb->buffer, (int) after_data);
188 return TRUE;
189 } else {
190 if (c == '4')
191 psb->error = smtp_trylater;
192 else if (c == '5')
193 psb->error = smtp_fail;
194 else
195 psb->error = smtp_syntax;
196 DEBUG(6) debugf("response failure:'%s' after_date = %d\n", psb->buffer, (int) after_data);
197 return FALSE;
198 }
199 }
201 static gboolean
202 check_init_response(smtp_base * psb)
203 {
204 if (check_response(psb, FALSE)) {
205 psb->use_esmtp = (strstr(psb->buffer, "ESMTP") != NULL);
207 DEBUG(4) debugf(psb->use_esmtp ? "uses esmtp\n" : "no esmtp\n");
209 return TRUE;
210 }
211 return FALSE;
212 }
214 static gchar*
215 get_response_arg(gchar * response)
216 {
217 gchar buf[SMTP_BUF_LEN];
218 gchar *p = response, *q = buf;
220 while (*p && (*p != '\n') && isspace(*p))
221 p++;
222 if (*p && (*p != '\n')) {
223 while (*p && (*p != '\n') && (*p != '\r') && (q < buf + SMTP_BUF_LEN - 1))
224 *(q++) = *(p++);
225 *q = '\0';
226 return g_strdup(buf);
227 }
228 return NULL;
229 }
231 static gboolean
232 check_helo_response(smtp_base * psb)
233 {
234 gchar *ptr = psb->buffer;
236 if (!check_response(psb, FALSE))
237 return FALSE;
239 while (*ptr) {
240 if (strncasecmp(&(ptr[4]), "SIZE", 4) == 0) {
241 gchar *arg;
242 psb->use_size = TRUE;
243 arg = get_response_arg(&(ptr[8]));
244 if (arg) {
245 psb->max_size = atoi(arg);
246 g_free(arg);
247 }
248 }
250 if (strncasecmp(&(ptr[4]), "PIPELINING", 10) == 0)
251 psb->use_pipelining = TRUE;
253 if (strncasecmp(&(ptr[4]), "AUTH", 4) == 0) {
254 if ((ptr[8] == ' ') || (ptr[8] == '=') || (ptr[8] == '\t')) { /* not sure about '\t' */
255 gchar *arg;
256 psb->use_auth = TRUE;
257 arg = get_response_arg(&(ptr[9])); /* after several years I finally learnt to count */
258 if (arg) {
259 psb->auth_names = g_strsplit(arg, " ", 0);
260 g_free(arg);
262 DEBUG(4) {
263 gint i = 0;
264 debugf("in check_helo_response()\n");
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(" %s\n", psb->use_size ? "uses SIZE" : "no size");
281 debugf(" %s\n", psb->use_pipelining ? "uses PIPELINING" : "no pipelining");
282 debugf(" %s\n", psb->use_auth ? "uses AUTH" : "no auth");
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 == '.' && new_line) {
366 /* dot-stuffing */
367 putc('.', psb->out);
368 }
369 if (c == '\n') {
370 /* CRLF line terminators */
371 putc('\r', psb->out);
372 putc('\n', psb->out);
373 new_line = TRUE;
374 } else {
375 putc(c, psb->out);
376 new_line = FALSE;
377 }
378 ptr++;
379 }
380 }
382 static void
383 send_header(smtp_base * psb, GList * hdr_list)
384 {
385 GList *node;
386 gint num_hdrs = 0;
388 /* header */
389 if (hdr_list) {
390 foreach(hdr_list, node) {
391 if (node->data) {
392 header *hdr = (header *) (node->data);
393 if (hdr->header) {
394 send_data_line(psb, hdr->header);
395 num_hdrs++;
396 }
397 }
398 }
399 }
401 /* empty line separating headers from data: */
402 putc('\r', psb->out);
403 putc('\n', psb->out);
405 DEBUG(4) debugf("sent %d headers\n", num_hdrs);
406 }
408 static void
409 send_data(smtp_base * psb, message * msg)
410 {
411 GList *node;
412 gint num_lines = 0;
414 /* data */
415 if (msg->data_list) {
416 for (node = g_list_first(msg->data_list); node; node = g_list_next(node)) {
417 if (node->data) {
418 send_data_line(psb, node->data);
419 num_lines++;
420 }
421 }
422 }
424 DEBUG(4) debugf("sent %d lines of data\n", num_lines);
426 fprintf(psb->out, ".\r\n");
427 fflush(psb->out);
428 }
430 void
431 smtp_out_mark_rcpts(smtp_base * psb, GList * rcpt_list)
432 {
433 GList *rcpt_node;
434 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
435 address *rcpt = (address *) (rcpt_node->data);
437 addr_unmark_delivered(rcpt);
439 if ((psb->error == smtp_trylater) || (psb->error == smtp_timeout) || (psb->error == smtp_eof)) {
440 addr_mark_defered(rcpt);
441 } else {
442 addr_mark_failed(rcpt);
443 }
444 }
445 }
447 void
448 smtp_out_log_failure(smtp_base * psb, message * msg)
449 {
450 gchar *err_str;
452 if (psb->error == smtp_timeout)
453 err_str = g_strdup("connection timed out.");
454 else if (psb->error == smtp_eof)
455 err_str = g_strdup("connection terminated prematurely.");
456 else if (psb->error == smtp_syntax)
457 err_str = g_strdup_printf("got unexpected response: %s", psb->buffer);
458 else if (psb->error == smtp_cancel)
459 err_str = g_strdup("delivery was canceled.\n");
460 else
461 /* error message should still be in the buffer */
462 err_str = g_strdup_printf("failed: %s\n", psb->buffer);
464 if (msg == NULL)
465 logwrite(LOG_NOTICE, "host=%s %s\n", psb->remote_host, err_str);
466 else
467 logwrite(LOG_NOTICE, "%s == host=%s %s\n", msg->uid, psb->remote_host, err_str);
469 g_free(err_str);
470 }
472 smtp_base*
473 smtp_out_open(gchar * host, gint port, GList * resolve_list)
474 {
475 smtp_base *psb;
476 gint sock;
477 mxip_addr *addr;
479 DEBUG(5) debugf("smtp_out_open entered, host = %s\n", host);
481 if ((addr = connect_resolvelist(&sock, host, port, resolve_list))) {
482 /* create structure to hold status data: */
483 psb = create_smtpbase(sock);
484 psb->remote_host = addr->name;
486 DEBUG(5) {
487 struct sockaddr_in name;
488 int len = sizeof(struct sockaddr);
489 getsockname(sock, (struct sockaddr *) (&name), &len);
490 debugf("socket: name.sin_addr = %s\n", inet_ntoa(name.sin_addr));
491 }
492 return psb;
493 } else {
494 DEBUG(5) debugf("connect_resolvelist failed: %s %s\n", strerror(errno), hstrerror(h_errno));
495 }
497 return NULL;
498 }
500 smtp_base*
501 smtp_out_open_child(gchar * cmd)
502 {
503 smtp_base *psb;
504 gint sock;
506 DEBUG(5) debugf("smtp_out_open_child entered, cmd = %s\n", cmd);
508 sock = child(cmd);
510 if (sock > 0) {
511 psb = create_smtpbase(sock);
512 psb->remote_host = NULL;
514 return psb;
515 }
517 return NULL;
518 }
520 gboolean
521 smtp_out_rset(smtp_base * psb)
522 {
523 gboolean ok;
525 fprintf(psb->out, "RSET\r\n");
526 fflush(psb->out);
527 DEBUG(4) debugf("RSET\n");
529 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
530 if (check_response(psb, FALSE))
531 return TRUE;
533 smtp_out_log_failure(psb, NULL);
535 return FALSE;
536 }
538 #ifdef ENABLE_AUTH
540 static gboolean
541 smtp_out_auth_cram_md5(smtp_base * psb)
542 {
543 gboolean ok = FALSE;
545 fprintf(psb->out, "AUTH CRAM-MD5\r\n");
546 fflush(psb->out);
547 DEBUG(4) debugf("AUTH CRAM-MD5\n");
548 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
549 if ((ok = check_response(psb, TRUE))) {
550 gchar *chall64 = get_response_arg(&(psb->buffer[4]));
551 gint chall_size;
552 gchar *chall = base64_decode(chall64, &chall_size);
553 guchar digest[16], *reply64, *reply;
554 gchar digest_string[33];
555 gint i;
556 #ifdef USE_LIB_CRYPTO
557 unsigned int digest_len;
558 #endif
560 DEBUG(5) debugf("smtp_out_auth_cram_md5():\n");
561 DEBUG(5) debugf(" encoded challenge = %s\n", chall64);
562 DEBUG(5) debugf(" decoded challenge = %s, size = %d\n", chall, chall_size);
563 DEBUG(5) debugf(" secret = %s\n", psb->auth_secret);
565 #ifdef USE_LIB_CRYPTO
566 HMAC(EVP_md5(), psb->auth_secret, strlen(psb->auth_secret), chall, chall_size, digest, &digest_len);
567 #else
568 hmac_md5(chall, chall_size, psb->auth_secret, strlen(psb->auth_secret), digest);
569 #endif
571 for (i = 0; i < 16; i++)
572 sprintf(&(digest_string[i + i]), "%02x", (unsigned int) (digest[i]));
573 digest_string[32] = '\0';
575 DEBUG(5) debugf(" digest = %s\n", digest_string);
577 reply = g_strdup_printf("%s %s", psb->auth_login, digest_string);
578 DEBUG(5) debugf(" unencoded reply = %s\n", reply);
580 reply64 = base64_encode(reply, strlen(reply));
581 DEBUG(5) debugf(" encoded reply = %s\n", reply64);
583 fprintf(psb->out, "%s\r\n", reply64);
584 fflush(psb->out);
585 DEBUG(4) debugf(" reply64 = %s\n", reply64);
587 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
588 ok = check_response(psb, FALSE);
590 g_free(reply64);
591 g_free(reply);
592 g_free(chall);
593 g_free(chall64);
594 }
595 }
596 return ok;
597 }
599 static gboolean
600 smtp_out_auth_login(smtp_base * psb)
601 {
602 gboolean ok = FALSE;
603 fprintf(psb->out, "AUTH LOGIN\r\n");
604 fflush(psb->out);
605 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
606 if ((ok = check_response(psb, TRUE))) {
607 gchar *resp64;
608 guchar *resp;
609 gint resp_size;
610 gchar *reply64;
612 DEBUG(5) debugf("smtp_out_auth_login():\n");
613 resp64 = get_response_arg(&(psb->buffer[4]));
614 DEBUG(5) debugf(" encoded response = %s\n", resp64);
615 resp = base64_decode(resp64, &resp_size);
616 g_free(resp64);
617 DEBUG(5) debugf(" decoded response = %s, size = %d\n", resp, resp_size);
618 g_free(resp);
619 reply64 = base64_encode(psb->auth_login, strlen(psb->auth_login));
620 fprintf(psb->out, "%s\r\n", reply64);
621 fflush(psb->out);
622 g_free(reply64);
623 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
624 if ((ok = check_response(psb, TRUE))) {
625 resp64 = get_response_arg(&(psb->buffer[4]));
626 DEBUG(5) debugf(" encoded response = %s\n", resp64);
627 resp = base64_decode(resp64, &resp_size);
628 g_free(resp64);
629 DEBUG(5) debugf(" decoded response = %s, size = %d\n", resp, resp_size);
630 g_free(resp);
631 reply64 = base64_encode(psb->auth_secret, strlen(psb->auth_secret));
632 fprintf(psb->out, "%s\r\n", reply64);
633 fflush(psb->out);
634 g_free(reply64);
635 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
636 ok = check_response(psb, FALSE);
637 }
638 }
639 }
640 }
641 return ok;
642 }
644 gboolean
645 smtp_out_auth(smtp_base * psb)
646 {
647 gboolean ok = FALSE;
648 gint i = 0;
649 while (psb->auth_names[i]) {
650 if (strcasecmp(psb->auth_names[i], psb->auth_name) == 0)
651 break;
652 i++;
653 }
654 if (psb->auth_names[i]) {
655 if (strcasecmp(psb->auth_name, "cram-md5") == 0) {
656 smtp_out_auth_cram_md5(psb);
657 } else if (strcasecmp(psb->auth_name, "login") == 0) {
658 smtp_out_auth_login(psb);
659 } else {
660 logwrite(LOG_ERR, "auth method %s not supported\n", psb->auth_name);
661 }
662 } else {
663 logwrite(LOG_ERR, "no auth method %s found.\n", psb->auth_name);
664 }
665 return ok;
666 }
668 #endif
670 gboolean
671 smtp_out_init(smtp_base * psb)
672 {
673 gboolean ok;
675 if ((ok = read_response(psb, SMTP_INITIAL_TIMEOUT))) {
676 if ((ok = check_init_response(psb))) {
678 if ((ok = smtp_helo(psb, psb->helo_name))) {
679 #ifdef ENABLE_AUTH
680 if (psb->auth_name && psb->use_auth) {
681 /* we completely disregard the response of server here. If
682 authentication fails, the server will complain later
683 anyway. I know, this is not polite... */
684 smtp_out_auth(psb);
685 }
686 #endif
687 }
688 }
689 }
690 if (!ok)
691 smtp_out_log_failure(psb, NULL);
692 return ok;
693 }
695 gint
696 smtp_out_msg(smtp_base * psb, message * msg, address * return_path, GList * rcpt_list, GList * hdr_list)
697 {
698 gint i, size;
699 gboolean ok = TRUE;
700 int rcpt_cnt;
701 int rcpt_accept = 0;
703 DEBUG(5) debugf("smtp_out_msg entered\n");
705 /* defaults: */
706 if (return_path == NULL)
707 return_path = msg->return_path;
708 if (hdr_list == NULL)
709 hdr_list = msg->hdr_list;
710 if (rcpt_list == NULL)
711 rcpt_list = msg->rcpt_list;
712 rcpt_cnt = g_list_length(rcpt_list);
714 size = msg_calc_size(msg, TRUE);
716 /* respect maximum size given by server: */
717 if ((psb->max_size > 0) && (size > psb->max_size)) {
718 logwrite(LOG_WARNING, "%s == host=%s message size (%d) > "
719 "fixed maximum message size of server (%d)",
720 msg->uid, psb->remote_host, size, psb->max_size);
721 psb->error = smtp_cancel;
722 ok = FALSE;
723 }
725 if (ok) {
726 /* pretend the message is a bit larger,
727 just in case the size calculation is buggy */
728 smtp_cmd_mailfrom(psb, return_path, psb->use_size ? size+SMTP_SIZE_ADD : 0);
730 if (!psb->use_pipelining) {
731 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
732 ok = check_response(psb, FALSE);
733 }
734 }
735 if (ok) {
736 GList *rcpt_node;
737 rcpt_accept = 0;
739 for (rcpt_node = g_list_first(rcpt_list); rcpt_node != NULL; rcpt_node = g_list_next(rcpt_node)) {
740 address *rcpt = (address *) (rcpt_node->data);
741 smtp_cmd_rcptto(psb, rcpt);
742 if (!psb->use_pipelining) {
743 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
744 if (check_response(psb, FALSE)) {
745 rcpt_accept++;
746 addr_mark_delivered(rcpt);
747 } else {
748 /* if server returned an error for one recp. we
749 may still try the others. But if it is a timeout, eof
750 or unexpected response, it is more serious and we should
751 give up. */
752 if ((psb->error != smtp_trylater) && (psb->error != smtp_fail)) {
753 ok = FALSE;
754 break;
755 } else {
756 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n",
757 msg->uid, addr_string(rcpt), psb->remote_host, psb->buffer);
758 if (psb->error == smtp_trylater) {
759 addr_mark_defered(rcpt);
760 } else {
761 addr_mark_failed(rcpt);
762 }
763 }
764 } else
765 break;
766 }
767 }
769 /* There is no point in going on if no recp.s were accpted.
770 But we can check that at this point only if not pipelining: */
771 ok = (ok && (psb->use_pipelining || (rcpt_accept > 0)));
772 if (ok) {
774 fprintf(psb->out, "DATA\r\n");
775 fflush(psb->out);
777 DEBUG(4) debugf("DATA\r\n");
779 if (psb->use_pipelining) {
780 /* the first pl'ed command was MAIL FROM
781 the last was DATA, whose response can be handled by the 'normal' code
782 all in between were RCPT TO:
783 */
784 /* response to MAIL FROM: */
785 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
786 if ((ok = check_response(psb, FALSE))) {
788 /* response(s) to RCPT TO:
789 this is very similar to the sequence above for no pipeline
790 */
791 for (i = 0; i < rcpt_cnt; i++) {
792 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
793 address *rcpt = g_list_nth_data(rcpt_list, i);
794 if (check_response(psb, FALSE)) {
795 rcpt_accept++;
796 addr_mark_delivered(rcpt);
797 } else {
798 /* if server returned an error 4xx or 5xx for one recp. we
799 may still try the others. But if it is a timeout, eof
800 or unexpected response, it is more serious and we
801 should give up. */
802 if ((psb->error != smtp_trylater) &&
803 (psb->error != smtp_fail)) {
804 ok = FALSE;
805 break;
806 } else {
807 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n", msg->uid,
808 addr_string(rcpt), psb->remote_host, psb->buffer);
809 if (psb->error == smtp_trylater) {
810 addr_mark_defered(rcpt);
811 } else {
812 addr_mark_failed(rcpt);
813 }
814 }
815 }
816 } else {
817 DEBUG(5) debugf("check_response failed after RCPT TO\n");
818 break;
819 }
820 }
821 if (rcpt_accept == 0)
822 ok = FALSE;
823 } else {
824 DEBUG(5) debugf("check_response failed after MAIL FROM\n");
825 }
826 } else {
827 DEBUG(5)
828 debugf("read_response failed after MAIL FROM\n");
829 }
830 }
832 /* if(psb->use_pipelining) */
833 /* response to the DATA cmd */
834 if (ok) {
835 if (read_response(psb, SMTP_DATA_TIMEOUT)) {
836 if (check_response(psb, TRUE)) {
837 send_header(psb, hdr_list);
838 send_data(psb, msg);
840 if (read_response(psb, SMTP_FINAL_TIMEOUT))
841 ok = check_response(psb, FALSE);
842 }
843 }
844 }
845 }
846 }
848 DEBUG(5) {
849 debugf("smtp_out_msg():\n");
850 debugf(" psb->error = %d\n", psb->error);
851 debugf(" ok = %d\n", ok);
852 debugf(" rcpt_accept = %d\n", rcpt_accept);
853 }
855 if (psb->error == smtp_ok) {
856 GList *rcpt_node;
857 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
858 address *rcpt = (address *) (rcpt_node->data);
859 if (addr_is_delivered(rcpt))
860 logwrite(LOG_NOTICE, "%s => %s host=%s with %s\n", msg->uid, addr_string(rcpt),
861 psb->remote_host, psb->use_esmtp ? "esmtp" : "smtp");
862 }
863 } else {
864 /* if something went wrong,
865 we have to unmark the rcpts prematurely marked as delivered
866 and mark the status */
867 smtp_out_mark_rcpts(psb, rcpt_list);
869 /* log the failure: */
870 smtp_out_log_failure(psb, msg);
871 }
872 return rcpt_accept;
873 }
875 gboolean
876 smtp_out_quit(smtp_base * psb)
877 {
878 fprintf(psb->out, "QUIT\r\n");
879 fflush(psb->out);
881 DEBUG(4) debugf("QUIT\n");
883 signal(SIGALRM, SIG_DFL);
885 return TRUE;
886 }
888 gint
889 smtp_deliver(gchar * host, gint port, GList * resolve_list, message * msg, address * return_path, GList * rcpt_list)
890 {
891 smtp_base *psb;
892 smtp_error err;
894 DEBUG(5) debugf("smtp_deliver entered\n");
896 if (return_path == NULL)
897 return_path = msg->return_path;
899 if ((psb = smtp_out_open(host, port, resolve_list))) {
900 set_heloname(psb, return_path->domain, TRUE);
901 /* initiate connection, send message and quit: */
902 if (smtp_out_init(psb)) {
903 smtp_out_msg(psb, msg, return_path, rcpt_list, NULL);
904 if (psb->error == smtp_ok || (psb->error == smtp_fail) || (psb->error == smtp_trylater)
905 || (psb->error == smtp_syntax) || (psb->error == smtp_cancel))
906 smtp_out_quit(psb);
907 }
909 err = psb->error;
910 destroy_smtpbase(psb);
912 return err;
913 }
914 return -1;
915 }