masqmail-0.2
view src/smtp_out.c @ 189:bdd343cc4e19
bumped version number
author | markus schnalke <meillo@marmaro.de> |
---|---|
date | Sat, 27 Aug 2011 18:51:46 +0200 |
parents | 087e99c7702a |
children |
line source
1 /* smtp_out.c
2 Copyright (C) 1999-2001 Oliver Kurth
3 Copyright (C) 2010 markus schnalke <meillo@marmaro.de>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
20 /*
21 I always forget these rfc numbers:
22 RFC 821 (SMTP)
23 RFC 1869 (ESMTP)
24 RFC 1870 (ESMTP SIZE)
25 RFC 2197 (ESMTP PIPELINE)
26 RFC 2554 (ESMTP AUTH)
27 */
29 #include "masqmail.h"
30 #include "smtp_out.h"
31 #include "readsock.h"
33 #ifdef ENABLE_AUTH
35 #ifdef USE_LIB_CRYPTO
36 #include <openssl/hmac.h>
37 #include <openssl/md5.h>
38 #include <openssl/evp.h>
39 #else
40 #include "md5/md5.h"
41 #include "md5/hmac_md5.h"
42 #endif
44 #include "base64/base64.h"
45 #endif
47 void
48 destroy_smtpbase(smtp_base * psb)
49 {
50 fclose(psb->in);
51 fclose(psb->out);
53 close(psb->sock);
55 if (psb->helo_name)
56 g_free(psb->helo_name);
57 if (psb->buffer)
58 g_free(psb->buffer);
59 if (psb->auth_names)
60 g_strfreev(psb->auth_names);
62 if (psb->auth_name)
63 g_free(psb->auth_name);
64 if (psb->auth_login)
65 g_free(psb->auth_login);
66 if (psb->auth_secret)
67 g_free(psb->auth_secret);
68 }
70 gchar*
71 set_heloname(smtp_base * psb, gchar * default_name, gboolean do_correct)
72 {
73 struct sockaddr_in sname;
74 int len = sizeof(struct sockaddr_in);
75 struct hostent *host_entry;
77 if (do_correct) {
78 getsockname(psb->sock, (struct sockaddr *) (&sname), &len);
79 DEBUG(5) debugf("socket: name.sin_addr = %s\n", inet_ntoa(sname.sin_addr));
80 host_entry = gethostbyaddr((const char *) &(sname.sin_addr), sizeof(sname.sin_addr), AF_INET);
81 if (host_entry) {
82 psb->helo_name = g_strdup(host_entry->h_name);
83 } else {
84 /* we failed to look up our own name. Instead of giving our local hostname,
85 we may give our IP number to show the server that we are at least
86 willing to be honest. For the really picky ones. */
87 DEBUG(5) debugf("failed to look up own host name.\n");
88 psb->helo_name = g_strdup_printf("[%s]", inet_ntoa(sname.sin_addr));
89 }
90 DEBUG(5) debugf("helo_name = %s\n", psb->helo_name);
91 }
92 if (psb->helo_name == NULL) {
93 psb->helo_name = g_strdup(default_name);
94 }
95 return psb->helo_name;
96 }
98 #ifdef ENABLE_AUTH
100 gboolean
101 set_auth(smtp_base * psb, gchar * name, gchar * login, gchar * secret)
102 {
103 if ((strcasecmp(name, "CRAM-MD5") == 0) || (strcasecmp(name, "LOGIN") == 0)) {
104 psb->auth_name = g_strdup(name);
105 psb->auth_login = g_strdup(login);
106 psb->auth_secret = g_strdup(secret);
108 return TRUE;
109 }
110 return FALSE;
111 }
113 #endif
115 static smtp_base*
116 create_smtpbase(gint sock)
117 {
118 gint dup_sock;
120 smtp_base *psb = (smtp_base *) g_malloc(sizeof(smtp_base));
122 psb->sock = sock;
124 psb->use_esmtp = FALSE;
125 psb->use_size = FALSE;
126 psb->use_pipelining = FALSE;
127 psb->use_auth = FALSE;
129 psb->max_size = 0;
130 psb->auth_names = NULL;
132 psb->buffer = (gchar *) g_malloc(SMTP_BUF_LEN);
134 dup_sock = dup(sock);
135 psb->out = fdopen(sock, "w");
136 psb->in = fdopen(dup_sock, "r");
138 psb->error = smtp_ok;
140 psb->helo_name = NULL;
142 psb->auth_name = psb->auth_login = psb->auth_secret = NULL;
144 return psb;
145 }
147 static gboolean
148 read_response(smtp_base * psb, int timeout)
149 {
150 gint buf_pos = 0;
151 gchar code[5];
152 gint i, len;
154 do {
155 len = read_sockline(psb->in, &(psb->buffer[buf_pos]), SMTP_BUF_LEN - buf_pos, timeout, READSOCKL_CHUG);
156 if (len == -3) {
157 psb->error = smtp_timeout;
158 return FALSE;
159 } else if (len == -2) {
160 psb->error = smtp_syntax;
161 return FALSE;
162 } else if (len == -1) {
163 psb->error = smtp_eof;
164 return FALSE;
165 }
166 for (i = 0; i < 4; i++)
167 code[i] = psb->buffer[buf_pos + i];
168 code[i] = '\0';
169 psb->last_code = atoi(code);
171 buf_pos += len;
173 } while (code[3] == '-');
175 return TRUE;
176 }
178 static gboolean
179 check_response(smtp_base * psb, gboolean after_data)
180 {
181 char c = psb->buffer[0];
183 if (((c == '2') && !after_data) || ((c == '3') && after_data)) {
184 psb->error = smtp_ok;
185 DEBUG(6) debugf("response OK:'%s' after_date = %d\n", psb->buffer, (int) after_data);
186 return TRUE;
187 } else {
188 if (c == '4')
189 psb->error = smtp_trylater;
190 else if (c == '5')
191 psb->error = smtp_fail;
192 else
193 psb->error = smtp_syntax;
194 DEBUG(6) debugf("response failure:'%s' after_date = %d\n", psb->buffer, (int) after_data);
195 return FALSE;
196 }
197 }
199 static gboolean
200 check_init_response(smtp_base * psb)
201 {
202 if (check_response(psb, FALSE)) {
203 psb->use_esmtp = (strstr(psb->buffer, "ESMTP") != NULL);
205 DEBUG(4) debugf(psb->use_esmtp ? "uses esmtp\n" : "no esmtp\n");
207 return TRUE;
208 }
209 return FALSE;
210 }
212 static gchar*
213 get_response_arg(gchar * response)
214 {
215 gchar buf[SMTP_BUF_LEN];
216 gchar *p = response, *q = buf;
218 while (*p && (*p != '\n') && isspace(*p))
219 p++;
220 if (*p && (*p != '\n')) {
221 while (*p && (*p != '\n') && (*p != '\r') && (q < buf + SMTP_BUF_LEN - 1))
222 *(q++) = *(p++);
223 *q = '\0';
224 return g_strdup(buf);
225 }
226 return NULL;
227 }
229 static gboolean
230 check_helo_response(smtp_base * psb)
231 {
232 gchar *ptr;
234 if (!check_response(psb, FALSE))
235 return FALSE;
237 if (psb->last_code == 220) {
238 logwrite(LOG_NOTICE, "received a 220 greeting after sending EHLO,\n");
239 logwrite(LOG_NOTICE, "please remove `instant_helo' from your route config\n");
240 /* read the next response, cause that's the actual helo response */
241 if (!read_response(psb, SMTP_CMD_TIMEOUT) || !check_response(psb, FALSE)) {
242 return FALSE;
243 }
244 }
246 ptr = psb->buffer;
248 while (*ptr) {
249 if (strncasecmp(&(ptr[4]), "SIZE", 4) == 0) {
250 gchar *arg;
251 psb->use_size = TRUE;
252 arg = get_response_arg(&(ptr[8]));
253 if (arg) {
254 psb->max_size = atoi(arg);
255 g_free(arg);
256 }
257 }
259 if (strncasecmp(&(ptr[4]), "PIPELINING", 10) == 0)
260 psb->use_pipelining = TRUE;
262 if (strncasecmp(&(ptr[4]), "AUTH", 4) == 0) {
263 if ((ptr[8] == ' ') || (ptr[8] == '=') || (ptr[8] == '\t')) { /* not sure about '\t' */
264 gchar *arg;
265 psb->use_auth = TRUE;
266 arg = get_response_arg(&(ptr[9])); /* after several years I finally learnt to count */
267 if (arg) {
268 psb->auth_names = g_strsplit(arg, " ", 0);
269 g_free(arg);
271 DEBUG(4) {
272 gint i = 0;
273 debugf("in check_helo_response()\n");
274 while (psb->auth_names[i]) {
275 debugf(" offered AUTH %s\n", psb->auth_names[i]);
276 i++;
277 }
278 }
279 }
280 }
281 }
283 while (*ptr != '\n')
284 ptr++;
285 ptr++;
286 }
288 DEBUG(4) {
289 debugf(" %s\n", psb->use_size ? "uses SIZE" : "no size");
290 debugf(" %s\n", psb->use_pipelining ? "uses PIPELINING" : "no pipelining");
291 debugf(" %s\n", psb->use_auth ? "uses AUTH" : "no auth");
292 }
294 return TRUE;
295 }
297 static gboolean
298 smtp_helo(smtp_base * psb, gchar * helo)
299 {
300 while (TRUE) {
301 if (psb->use_esmtp) {
302 fprintf(psb->out, "EHLO %s\r\n", helo);
303 fflush(psb->out);
305 DEBUG(4) debugf("EHLO %s\r\n", helo);
307 } else {
308 fprintf(psb->out, "HELO %s\r\n", helo);
309 fflush(psb->out);
311 DEBUG(4) debugf("HELO %s\r\n", helo);
313 }
315 if (!read_response(psb, SMTP_CMD_TIMEOUT))
316 return FALSE;
318 if (check_helo_response(psb))
319 return TRUE;
320 else {
321 if (psb->error == smtp_fail) {
322 if (psb->use_esmtp) {
323 /* our guess that server understands EHLO was wrong, try again with HELO */
324 psb->use_esmtp = FALSE;
325 } else {
326 /* what sort of server ist THAT ?! give up... */
327 return FALSE;
328 }
329 } else
330 return FALSE;
331 }
332 }
333 }
335 static void
336 smtp_cmd_mailfrom(smtp_base * psb, address * return_path, guint size)
337 {
338 if (psb->use_size) {
339 fprintf(psb->out, "MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
340 fflush(psb->out);
342 DEBUG(4) debugf("MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
344 } else {
345 fprintf(psb->out, "MAIL FROM:%s\r\n", addr_string(return_path));
346 fflush(psb->out);
348 DEBUG(4) debugf("MAIL FROM:%s\r\n", addr_string(return_path));
349 }
350 }
352 static void
353 smtp_cmd_rcptto(smtp_base * psb, address * rcpt)
354 {
355 fprintf(psb->out, "RCPT TO:%s\r\n", addr_string(rcpt));
356 fflush(psb->out);
357 DEBUG(4) debugf("RCPT TO:%s\n", addr_string(rcpt));
358 }
360 static void
361 send_data_line(smtp_base * psb, gchar * data)
362 {
363 /* According to RFC 821 each line should be terminated with CRLF.
364 Since a dot on a line itself marks the end of data, each line
365 beginning with a dot is prepended with another dot.
366 */
367 gchar *ptr;
368 gboolean new_line = TRUE; /* previous versions assumed that each item was exactly one line.
369 This is no longer the case */
371 ptr = data;
372 while (*ptr) {
373 int c = (int) (*ptr);
374 if (c == '.' && new_line) {
375 /* dot-stuffing */
376 putc('.', psb->out);
377 }
378 if (c == '\n') {
379 /* CRLF line terminators */
380 putc('\r', psb->out);
381 putc('\n', psb->out);
382 new_line = TRUE;
383 } else {
384 putc(c, psb->out);
385 new_line = FALSE;
386 }
387 ptr++;
388 }
389 }
391 static void
392 send_header(smtp_base * psb, GList * hdr_list)
393 {
394 GList *node;
395 gint num_hdrs = 0;
397 /* header */
398 if (hdr_list) {
399 foreach(hdr_list, node) {
400 if (node->data) {
401 header *hdr = (header *) (node->data);
402 if (hdr->header) {
403 send_data_line(psb, hdr->header);
404 num_hdrs++;
405 }
406 }
407 }
408 }
410 /* empty line separating headers from data: */
411 putc('\r', psb->out);
412 putc('\n', psb->out);
414 DEBUG(4) debugf("sent %d headers\n", num_hdrs);
415 }
417 static void
418 send_data(smtp_base * psb, message * msg)
419 {
420 GList *node;
421 gint num_lines = 0;
423 /* data */
424 if (msg->data_list) {
425 for (node = g_list_first(msg->data_list); node; node = g_list_next(node)) {
426 if (node->data) {
427 send_data_line(psb, node->data);
428 num_lines++;
429 }
430 }
431 }
433 DEBUG(4) debugf("sent %d lines of data\n", num_lines);
435 fprintf(psb->out, ".\r\n");
436 fflush(psb->out);
437 }
439 void
440 smtp_out_mark_rcpts(smtp_base * psb, GList * rcpt_list)
441 {
442 GList *rcpt_node;
443 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
444 address *rcpt = (address *) (rcpt_node->data);
446 addr_unmark_delivered(rcpt);
448 if ((psb->error == smtp_trylater) || (psb->error == smtp_timeout) || (psb->error == smtp_eof)) {
449 addr_mark_defered(rcpt);
450 } else {
451 addr_mark_failed(rcpt);
452 }
453 }
454 }
456 void
457 smtp_out_log_failure(smtp_base * psb, message * msg)
458 {
459 gchar *err_str;
461 if (psb->error == smtp_timeout)
462 err_str = g_strdup("connection timed out.");
463 else if (psb->error == smtp_eof)
464 err_str = g_strdup("connection terminated prematurely.");
465 else if (psb->error == smtp_syntax)
466 err_str = g_strdup_printf("got unexpected response: %s", psb->buffer);
467 else if (psb->error == smtp_cancel)
468 err_str = g_strdup("delivery was canceled.\n");
469 else
470 /* error message should still be in the buffer */
471 err_str = g_strdup_printf("failed: %s\n", psb->buffer);
473 if (msg == NULL)
474 logwrite(LOG_NOTICE, "host=%s %s\n", psb->remote_host, err_str);
475 else
476 logwrite(LOG_NOTICE, "%s == host=%s %s\n", msg->uid, psb->remote_host, err_str);
478 g_free(err_str);
479 }
481 smtp_base*
482 smtp_out_open(gchar * host, gint port, GList * resolve_list)
483 {
484 smtp_base *psb;
485 gint sock;
486 mxip_addr *addr;
488 DEBUG(5) debugf("smtp_out_open entered, host = %s\n", host);
490 if ((addr = connect_resolvelist(&sock, host, port, resolve_list))) {
491 /* create structure to hold status data: */
492 psb = create_smtpbase(sock);
493 psb->remote_host = addr->name;
495 DEBUG(5) {
496 struct sockaddr_in name;
497 int len = sizeof(struct sockaddr);
498 getsockname(sock, (struct sockaddr *) (&name), &len);
499 debugf("socket: name.sin_addr = %s\n", inet_ntoa(name.sin_addr));
500 }
501 return psb;
502 } else {
503 DEBUG(5) debugf("connect_resolvelist failed: %s %s\n", strerror(errno), hstrerror(h_errno));
504 }
506 return NULL;
507 }
509 smtp_base*
510 smtp_out_open_child(gchar * cmd)
511 {
512 smtp_base *psb;
513 gint sock;
515 DEBUG(5) debugf("smtp_out_open_child entered, cmd = %s\n", cmd);
517 sock = child(cmd);
519 if (sock > 0) {
520 psb = create_smtpbase(sock);
521 psb->remote_host = NULL;
523 return psb;
524 }
526 return NULL;
527 }
529 gboolean
530 smtp_out_rset(smtp_base * psb)
531 {
532 gboolean ok;
534 fprintf(psb->out, "RSET\r\n");
535 fflush(psb->out);
536 DEBUG(4) debugf("RSET\n");
538 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
539 if (check_response(psb, FALSE))
540 return TRUE;
542 smtp_out_log_failure(psb, NULL);
544 return FALSE;
545 }
547 #ifdef ENABLE_AUTH
549 static gboolean
550 smtp_out_auth_cram_md5(smtp_base * psb)
551 {
552 gboolean ok = FALSE;
554 fprintf(psb->out, "AUTH CRAM-MD5\r\n");
555 fflush(psb->out);
556 DEBUG(4) debugf("AUTH CRAM-MD5\n");
557 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
558 if ((ok = check_response(psb, TRUE))) {
559 gchar *chall64 = get_response_arg(&(psb->buffer[4]));
560 gint chall_size;
561 gchar *chall = base64_decode(chall64, &chall_size);
562 guchar digest[16], *reply64, *reply;
563 gchar digest_string[33];
564 gint i;
565 #ifdef USE_LIB_CRYPTO
566 unsigned int digest_len;
567 #endif
569 DEBUG(5) debugf("smtp_out_auth_cram_md5():\n");
570 DEBUG(5) debugf(" encoded challenge = %s\n", chall64);
571 DEBUG(5) debugf(" decoded challenge = %s, size = %d\n", chall, chall_size);
572 DEBUG(5) debugf(" secret = %s\n", psb->auth_secret);
574 #ifdef USE_LIB_CRYPTO
575 HMAC(EVP_md5(), psb->auth_secret, strlen(psb->auth_secret), chall, chall_size, digest, &digest_len);
576 #else
577 hmac_md5(chall, chall_size, psb->auth_secret, strlen(psb->auth_secret), digest);
578 #endif
580 for (i = 0; i < 16; i++)
581 sprintf(&(digest_string[i + i]), "%02x", (unsigned int) (digest[i]));
582 digest_string[32] = '\0';
584 DEBUG(5) debugf(" digest = %s\n", digest_string);
586 reply = g_strdup_printf("%s %s", psb->auth_login, digest_string);
587 DEBUG(5) debugf(" unencoded reply = %s\n", reply);
589 reply64 = base64_encode(reply, strlen(reply));
590 DEBUG(5) debugf(" encoded reply = %s\n", reply64);
592 fprintf(psb->out, "%s\r\n", reply64);
593 fflush(psb->out);
594 DEBUG(4) debugf(" reply64 = %s\n", reply64);
596 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
597 ok = check_response(psb, FALSE);
599 g_free(reply64);
600 g_free(reply);
601 g_free(chall);
602 g_free(chall64);
603 }
604 }
605 return ok;
606 }
608 static gboolean
609 smtp_out_auth_login(smtp_base * psb)
610 {
611 gboolean ok = FALSE;
612 fprintf(psb->out, "AUTH LOGIN\r\n");
613 fflush(psb->out);
614 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
615 if ((ok = check_response(psb, TRUE))) {
616 gchar *resp64;
617 guchar *resp;
618 gint resp_size;
619 gchar *reply64;
621 DEBUG(5) debugf("smtp_out_auth_login():\n");
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_login, strlen(psb->auth_login));
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 if ((ok = check_response(psb, TRUE))) {
634 resp64 = get_response_arg(&(psb->buffer[4]));
635 DEBUG(5) debugf(" encoded response = %s\n", resp64);
636 resp = base64_decode(resp64, &resp_size);
637 g_free(resp64);
638 DEBUG(5) debugf(" decoded response = %s, size = %d\n", resp, resp_size);
639 g_free(resp);
640 reply64 = base64_encode(psb->auth_secret, strlen(psb->auth_secret));
641 fprintf(psb->out, "%s\r\n", reply64);
642 fflush(psb->out);
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, gboolean instant_helo)
681 {
682 gboolean ok;
684 logwrite(LOG_INFO, "smtp_out_init(): instant_helo:%d\n", instant_helo);
686 if (instant_helo) {
687 /* we say hello right away, hence we don't know if
688 ESMTP is supported; we just assume it */
689 psb->use_esmtp = 1;
690 } else {
691 if ((ok = read_response(psb, SMTP_INITIAL_TIMEOUT))) {
692 ok = check_init_response(psb);
693 }
694 if (!ok) {
695 smtp_out_log_failure(psb, NULL);
696 return ok;
697 }
698 }
700 if ((ok = smtp_helo(psb, psb->helo_name))) {
701 #ifdef ENABLE_AUTH
702 if (psb->auth_name && psb->use_auth) {
703 /* we completely disregard the response of server here. If
704 authentication fails, the server will complain later
705 anyway. I know, this is not polite... */
706 smtp_out_auth(psb);
707 }
708 #endif
709 }
710 if (!ok)
711 smtp_out_log_failure(psb, NULL);
712 return ok;
713 }
715 gint
716 smtp_out_msg(smtp_base * psb, message * msg, address * return_path, GList * rcpt_list, GList * hdr_list)
717 {
718 gint i, size;
719 gboolean ok = TRUE;
720 int rcpt_cnt;
721 int rcpt_accept = 0;
723 DEBUG(5) debugf("smtp_out_msg entered\n");
725 /* defaults: */
726 if (return_path == NULL)
727 return_path = msg->return_path;
728 if (hdr_list == NULL)
729 hdr_list = msg->hdr_list;
730 if (rcpt_list == NULL)
731 rcpt_list = msg->rcpt_list;
732 rcpt_cnt = g_list_length(rcpt_list);
734 size = msg_calc_size(msg, TRUE);
736 /* respect maximum size given by server: */
737 if ((psb->max_size > 0) && (size > psb->max_size)) {
738 logwrite(LOG_WARNING, "%s == host=%s message size (%d) > "
739 "fixed maximum message size of server (%d)",
740 msg->uid, psb->remote_host, size, psb->max_size);
741 psb->error = smtp_cancel;
742 ok = FALSE;
743 }
745 if (ok) {
746 /* pretend the message is a bit larger,
747 just in case the size calculation is buggy */
748 smtp_cmd_mailfrom(psb, return_path, psb->use_size ? size+SMTP_SIZE_ADD : 0);
750 if (!psb->use_pipelining) {
751 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
752 ok = check_response(psb, FALSE);
753 }
754 }
755 if (ok) {
756 GList *rcpt_node;
757 rcpt_accept = 0;
759 for (rcpt_node = g_list_first(rcpt_list); rcpt_node != NULL; rcpt_node = g_list_next(rcpt_node)) {
760 address *rcpt = (address *) (rcpt_node->data);
761 smtp_cmd_rcptto(psb, rcpt);
762 if (!psb->use_pipelining) {
763 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
764 if (check_response(psb, FALSE)) {
765 rcpt_accept++;
766 addr_mark_delivered(rcpt);
767 } else {
768 /* if server returned an error for one recp. we
769 may still try the others. But if it is a timeout, eof
770 or unexpected response, it is more serious and we should
771 give up. */
772 if ((psb->error != smtp_trylater) && (psb->error != smtp_fail)) {
773 ok = FALSE;
774 break;
775 } else {
776 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n",
777 msg->uid, addr_string(rcpt), psb->remote_host, psb->buffer);
778 if (psb->error == smtp_trylater) {
779 addr_mark_defered(rcpt);
780 } else {
781 addr_mark_failed(rcpt);
782 }
783 }
784 } else
785 break;
786 }
787 }
789 /* There is no point in going on if no recp.s were accpted.
790 But we can check that at this point only if not pipelining: */
791 ok = (ok && (psb->use_pipelining || (rcpt_accept > 0)));
792 if (ok) {
794 fprintf(psb->out, "DATA\r\n");
795 fflush(psb->out);
797 DEBUG(4) debugf("DATA\r\n");
799 if (psb->use_pipelining) {
800 /* the first pl'ed command was MAIL FROM
801 the last was DATA, whose response can be handled by the 'normal' code
802 all in between were RCPT TO:
803 */
804 /* response to MAIL FROM: */
805 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
806 if ((ok = check_response(psb, FALSE))) {
808 /* response(s) to RCPT TO:
809 this is very similar to the sequence above for no pipeline
810 */
811 for (i = 0; i < rcpt_cnt; i++) {
812 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
813 address *rcpt = g_list_nth_data(rcpt_list, i);
814 if (check_response(psb, FALSE)) {
815 rcpt_accept++;
816 addr_mark_delivered(rcpt);
817 } else {
818 /* if server returned an error 4xx or 5xx for one recp. we
819 may still try the others. But if it is a timeout, eof
820 or unexpected response, it is more serious and we
821 should give up. */
822 if ((psb->error != smtp_trylater) &&
823 (psb->error != smtp_fail)) {
824 ok = FALSE;
825 break;
826 } else {
827 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n", msg->uid,
828 addr_string(rcpt), psb->remote_host, psb->buffer);
829 if (psb->error == smtp_trylater) {
830 addr_mark_defered(rcpt);
831 } else {
832 addr_mark_failed(rcpt);
833 }
834 }
835 }
836 } else {
837 DEBUG(5) debugf("check_response failed after RCPT TO\n");
838 break;
839 }
840 }
841 if (rcpt_accept == 0)
842 ok = FALSE;
843 } else {
844 DEBUG(5) debugf("check_response failed after MAIL FROM\n");
845 }
846 } else {
847 DEBUG(5)
848 debugf("read_response failed after MAIL FROM\n");
849 }
850 }
852 /* if(psb->use_pipelining) */
853 /* response to the DATA cmd */
854 if (ok) {
855 if (read_response(psb, SMTP_DATA_TIMEOUT)) {
856 if (check_response(psb, TRUE)) {
857 send_header(psb, hdr_list);
858 send_data(psb, msg);
860 if (read_response(psb, SMTP_FINAL_TIMEOUT))
861 ok = check_response(psb, FALSE);
862 }
863 }
864 }
865 }
866 }
868 DEBUG(5) {
869 debugf("smtp_out_msg():\n");
870 debugf(" psb->error = %d\n", psb->error);
871 debugf(" ok = %d\n", ok);
872 debugf(" rcpt_accept = %d\n", rcpt_accept);
873 }
875 if (psb->error == smtp_ok) {
876 GList *rcpt_node;
877 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
878 address *rcpt = (address *) (rcpt_node->data);
879 if (addr_is_delivered(rcpt))
880 logwrite(LOG_NOTICE, "%s => %s host=%s with %s\n", msg->uid, addr_string(rcpt),
881 psb->remote_host, psb->use_esmtp ? "esmtp" : "smtp");
882 }
883 } else {
884 /* if something went wrong,
885 we have to unmark the rcpts prematurely marked as delivered
886 and mark the status */
887 smtp_out_mark_rcpts(psb, rcpt_list);
889 /* log the failure: */
890 smtp_out_log_failure(psb, msg);
891 }
892 return rcpt_accept;
893 }
895 gboolean
896 smtp_out_quit(smtp_base * psb)
897 {
898 fprintf(psb->out, "QUIT\r\n");
899 fflush(psb->out);
901 DEBUG(4) debugf("QUIT\n");
903 signal(SIGALRM, SIG_DFL);
905 return TRUE;
906 }
908 gint
909 smtp_deliver(gchar * host, gint port, GList * resolve_list, message * msg, address * return_path, GList * rcpt_list)
910 {
911 smtp_base *psb;
912 smtp_error err;
914 DEBUG(5) debugf("smtp_deliver entered\n");
916 if (return_path == NULL)
917 return_path = msg->return_path;
919 if ((psb = smtp_out_open(host, port, resolve_list))) {
920 set_heloname(psb, return_path->domain, TRUE);
921 /* initiate connection, send message and quit: */
922 if (smtp_out_init(psb, FALSE)) {
923 smtp_out_msg(psb, msg, return_path, rcpt_list, NULL);
924 if (psb->error == smtp_ok || (psb->error == smtp_fail) || (psb->error == smtp_trylater)
925 || (psb->error == smtp_syntax) || (psb->error == smtp_cancel))
926 smtp_out_quit(psb);
927 }
929 err = psb->error;
930 destroy_smtpbase(psb);
932 return err;
933 }
934 return -1;
935 }