masqmail-0.2

view src/smtp_out.c @ 174:087e99c7702a

added my copyright to files I worked on
author meillo@marmaro.de
date Fri, 23 Jul 2010 10:16:53 +0200
parents 349518b940db
children 805abb75b20c
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 send bugs to: kurth@innominate.de
22 */
24 /*
25 I always forget these rfc numbers:
26 RFC 821 (SMTP)
27 RFC 1869 (ESMTP)
28 RFC 1870 (ESMTP SIZE)
29 RFC 2197 (ESMTP PIPELINE)
30 RFC 2554 (ESMTP AUTH)
31 */
33 #include "masqmail.h"
34 #include "smtp_out.h"
35 #include "readsock.h"
37 #ifdef ENABLE_AUTH
39 #ifdef USE_LIB_CRYPTO
40 #include <openssl/hmac.h>
41 #include <openssl/md5.h>
42 #include <openssl/evp.h>
43 #else
44 #include "md5/md5.h"
45 #include "md5/hmac_md5.h"
46 #endif
48 #include "base64/base64.h"
49 #endif
51 void
52 destroy_smtpbase(smtp_base * psb)
53 {
54 fclose(psb->in);
55 fclose(psb->out);
57 close(psb->sock);
59 if (psb->helo_name)
60 g_free(psb->helo_name);
61 if (psb->buffer)
62 g_free(psb->buffer);
63 if (psb->auth_names)
64 g_strfreev(psb->auth_names);
66 if (psb->auth_name)
67 g_free(psb->auth_name);
68 if (psb->auth_login)
69 g_free(psb->auth_login);
70 if (psb->auth_secret)
71 g_free(psb->auth_secret);
72 }
74 gchar*
75 set_heloname(smtp_base * psb, gchar * default_name, gboolean do_correct)
76 {
77 struct sockaddr_in sname;
78 int len = sizeof(struct sockaddr_in);
79 struct hostent *host_entry;
81 if (do_correct) {
82 getsockname(psb->sock, (struct sockaddr *) (&sname), &len);
83 DEBUG(5) debugf("socket: name.sin_addr = %s\n", inet_ntoa(sname.sin_addr));
84 host_entry = gethostbyaddr((const char *) &(sname.sin_addr), sizeof(sname.sin_addr), AF_INET);
85 if (host_entry) {
86 psb->helo_name = g_strdup(host_entry->h_name);
87 } else {
88 /* we failed to look up our own name. Instead of giving our local hostname,
89 we may give our IP number to show the server that we are at least
90 willing to be honest. For the really picky ones. */
91 DEBUG(5) debugf("failed to look up own host name.\n");
92 psb->helo_name = g_strdup_printf("[%s]", inet_ntoa(sname.sin_addr));
93 }
94 DEBUG(5) debugf("helo_name = %s\n", psb->helo_name);
95 }
96 if (psb->helo_name == NULL) {
97 psb->helo_name = g_strdup(default_name);
98 }
99 return psb->helo_name;
100 }
102 #ifdef ENABLE_AUTH
104 gboolean
105 set_auth(smtp_base * psb, gchar * name, gchar * login, gchar * secret)
106 {
107 if ((strcasecmp(name, "CRAM-MD5") == 0) || (strcasecmp(name, "LOGIN") == 0)) {
108 psb->auth_name = g_strdup(name);
109 psb->auth_login = g_strdup(login);
110 psb->auth_secret = g_strdup(secret);
112 return TRUE;
113 }
114 return FALSE;
115 }
117 #endif
119 static smtp_base*
120 create_smtpbase(gint sock)
121 {
122 gint dup_sock;
124 smtp_base *psb = (smtp_base *) g_malloc(sizeof(smtp_base));
126 psb->sock = sock;
128 psb->use_esmtp = FALSE;
129 psb->use_size = FALSE;
130 psb->use_pipelining = FALSE;
131 psb->use_auth = FALSE;
133 psb->max_size = 0;
134 psb->auth_names = NULL;
136 psb->buffer = (gchar *) g_malloc(SMTP_BUF_LEN);
138 dup_sock = dup(sock);
139 psb->out = fdopen(sock, "w");
140 psb->in = fdopen(dup_sock, "r");
142 psb->error = smtp_ok;
144 psb->helo_name = NULL;
146 psb->auth_name = psb->auth_login = psb->auth_secret = NULL;
148 return psb;
149 }
151 static gboolean
152 read_response(smtp_base * psb, int timeout)
153 {
154 gint buf_pos = 0;
155 gchar code[5];
156 gint i, len;
158 do {
159 len = read_sockline(psb->in, &(psb->buffer[buf_pos]), SMTP_BUF_LEN - buf_pos, timeout, READSOCKL_CHUG);
160 if (len == -3) {
161 psb->error = smtp_timeout;
162 return FALSE;
163 } else if (len == -2) {
164 psb->error = smtp_syntax;
165 return FALSE;
166 } else if (len == -1) {
167 psb->error = smtp_eof;
168 return FALSE;
169 }
170 for (i = 0; i < 4; i++)
171 code[i] = psb->buffer[buf_pos + i];
172 code[i] = '\0';
173 psb->last_code = atoi(code);
175 buf_pos += len;
177 } while (code[3] == '-');
179 return TRUE;
180 }
182 static gboolean
183 check_response(smtp_base * psb, gboolean after_data)
184 {
185 char c = psb->buffer[0];
187 if (((c == '2') && !after_data) || ((c == '3') && after_data)) {
188 psb->error = smtp_ok;
189 DEBUG(6) debugf("response OK:'%s' after_date = %d\n", psb->buffer, (int) after_data);
190 return TRUE;
191 } else {
192 if (c == '4')
193 psb->error = smtp_trylater;
194 else if (c == '5')
195 psb->error = smtp_fail;
196 else
197 psb->error = smtp_syntax;
198 DEBUG(6) debugf("response failure:'%s' after_date = %d\n", psb->buffer, (int) after_data);
199 return FALSE;
200 }
201 }
203 static gboolean
204 check_init_response(smtp_base * psb)
205 {
206 if (check_response(psb, FALSE)) {
207 psb->use_esmtp = (strstr(psb->buffer, "ESMTP") != NULL);
209 DEBUG(4) debugf(psb->use_esmtp ? "uses esmtp\n" : "no esmtp\n");
211 return TRUE;
212 }
213 return FALSE;
214 }
216 static gchar*
217 get_response_arg(gchar * response)
218 {
219 gchar buf[SMTP_BUF_LEN];
220 gchar *p = response, *q = buf;
222 while (*p && (*p != '\n') && isspace(*p))
223 p++;
224 if (*p && (*p != '\n')) {
225 while (*p && (*p != '\n') && (*p != '\r') && (q < buf + SMTP_BUF_LEN - 1))
226 *(q++) = *(p++);
227 *q = '\0';
228 return g_strdup(buf);
229 }
230 return NULL;
231 }
233 static gboolean
234 check_helo_response(smtp_base * psb)
235 {
236 gchar *ptr;
238 if (!check_response(psb, FALSE))
239 return FALSE;
241 if (psb->last_code == 220) {
242 logwrite(LOG_NOTICE, "received a 220 greeting after sending EHLO,\n");
243 logwrite(LOG_NOTICE, "please remove `instant_helo' from your route config\n");
244 /* read the next response, cause that's the actual helo response */
245 if (!read_response(psb, SMTP_CMD_TIMEOUT) || !check_response(psb, FALSE)) {
246 return FALSE;
247 }
248 }
250 ptr = psb->buffer;
252 while (*ptr) {
253 if (strncasecmp(&(ptr[4]), "SIZE", 4) == 0) {
254 gchar *arg;
255 psb->use_size = TRUE;
256 arg = get_response_arg(&(ptr[8]));
257 if (arg) {
258 psb->max_size = atoi(arg);
259 g_free(arg);
260 }
261 }
263 if (strncasecmp(&(ptr[4]), "PIPELINING", 10) == 0)
264 psb->use_pipelining = TRUE;
266 if (strncasecmp(&(ptr[4]), "AUTH", 4) == 0) {
267 if ((ptr[8] == ' ') || (ptr[8] == '=') || (ptr[8] == '\t')) { /* not sure about '\t' */
268 gchar *arg;
269 psb->use_auth = TRUE;
270 arg = get_response_arg(&(ptr[9])); /* after several years I finally learnt to count */
271 if (arg) {
272 psb->auth_names = g_strsplit(arg, " ", 0);
273 g_free(arg);
275 DEBUG(4) {
276 gint i = 0;
277 debugf("in check_helo_response()\n");
278 while (psb->auth_names[i]) {
279 debugf(" offered AUTH %s\n", psb->auth_names[i]);
280 i++;
281 }
282 }
283 }
284 }
285 }
287 while (*ptr != '\n')
288 ptr++;
289 ptr++;
290 }
292 DEBUG(4) {
293 debugf(" %s\n", psb->use_size ? "uses SIZE" : "no size");
294 debugf(" %s\n", psb->use_pipelining ? "uses PIPELINING" : "no pipelining");
295 debugf(" %s\n", psb->use_auth ? "uses AUTH" : "no auth");
296 }
298 return TRUE;
299 }
301 static gboolean
302 smtp_helo(smtp_base * psb, gchar * helo)
303 {
304 while (TRUE) {
305 if (psb->use_esmtp) {
306 fprintf(psb->out, "EHLO %s\r\n", helo);
307 fflush(psb->out);
309 DEBUG(4) debugf("EHLO %s\r\n", helo);
311 } else {
312 fprintf(psb->out, "HELO %s\r\n", helo);
313 fflush(psb->out);
315 DEBUG(4) debugf("HELO %s\r\n", helo);
317 }
319 if (!read_response(psb, SMTP_CMD_TIMEOUT))
320 return FALSE;
322 if (check_helo_response(psb))
323 return TRUE;
324 else {
325 if (psb->error == smtp_fail) {
326 if (psb->use_esmtp) {
327 /* our guess that server understands EHLO was wrong, try again with HELO */
328 psb->use_esmtp = FALSE;
329 } else {
330 /* what sort of server ist THAT ?! give up... */
331 return FALSE;
332 }
333 } else
334 return FALSE;
335 }
336 }
337 }
339 static void
340 smtp_cmd_mailfrom(smtp_base * psb, address * return_path, guint size)
341 {
342 if (psb->use_size) {
343 fprintf(psb->out, "MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
344 fflush(psb->out);
346 DEBUG(4) debugf("MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
348 } else {
349 fprintf(psb->out, "MAIL FROM:%s\r\n", addr_string(return_path));
350 fflush(psb->out);
352 DEBUG(4) debugf("MAIL FROM:%s\r\n", addr_string(return_path));
353 }
354 }
356 static void
357 smtp_cmd_rcptto(smtp_base * psb, address * rcpt)
358 {
359 fprintf(psb->out, "RCPT TO:%s\r\n", addr_string(rcpt));
360 fflush(psb->out);
361 DEBUG(4) debugf("RCPT TO:%s\n", addr_string(rcpt));
362 }
364 static void
365 send_data_line(smtp_base * psb, gchar * data)
366 {
367 /* According to RFC 821 each line should be terminated with CRLF.
368 Since a dot on a line itself marks the end of data, each line
369 beginning with a dot is prepended with another dot.
370 */
371 gchar *ptr;
372 gboolean new_line = TRUE; /* previous versions assumed that each item was exactly one line.
373 This is no longer the case */
375 ptr = data;
376 while (*ptr) {
377 int c = (int) (*ptr);
378 if (c == '.' && new_line) {
379 /* dot-stuffing */
380 putc('.', psb->out);
381 }
382 if (c == '\n') {
383 /* CRLF line terminators */
384 putc('\r', psb->out);
385 putc('\n', psb->out);
386 new_line = TRUE;
387 } else {
388 putc(c, psb->out);
389 new_line = FALSE;
390 }
391 ptr++;
392 }
393 }
395 static void
396 send_header(smtp_base * psb, GList * hdr_list)
397 {
398 GList *node;
399 gint num_hdrs = 0;
401 /* header */
402 if (hdr_list) {
403 foreach(hdr_list, node) {
404 if (node->data) {
405 header *hdr = (header *) (node->data);
406 if (hdr->header) {
407 send_data_line(psb, hdr->header);
408 num_hdrs++;
409 }
410 }
411 }
412 }
414 /* empty line separating headers from data: */
415 putc('\r', psb->out);
416 putc('\n', psb->out);
418 DEBUG(4) debugf("sent %d headers\n", num_hdrs);
419 }
421 static void
422 send_data(smtp_base * psb, message * msg)
423 {
424 GList *node;
425 gint num_lines = 0;
427 /* data */
428 if (msg->data_list) {
429 for (node = g_list_first(msg->data_list); node; node = g_list_next(node)) {
430 if (node->data) {
431 send_data_line(psb, node->data);
432 num_lines++;
433 }
434 }
435 }
437 DEBUG(4) debugf("sent %d lines of data\n", num_lines);
439 fprintf(psb->out, ".\r\n");
440 fflush(psb->out);
441 }
443 void
444 smtp_out_mark_rcpts(smtp_base * psb, GList * rcpt_list)
445 {
446 GList *rcpt_node;
447 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
448 address *rcpt = (address *) (rcpt_node->data);
450 addr_unmark_delivered(rcpt);
452 if ((psb->error == smtp_trylater) || (psb->error == smtp_timeout) || (psb->error == smtp_eof)) {
453 addr_mark_defered(rcpt);
454 } else {
455 addr_mark_failed(rcpt);
456 }
457 }
458 }
460 void
461 smtp_out_log_failure(smtp_base * psb, message * msg)
462 {
463 gchar *err_str;
465 if (psb->error == smtp_timeout)
466 err_str = g_strdup("connection timed out.");
467 else if (psb->error == smtp_eof)
468 err_str = g_strdup("connection terminated prematurely.");
469 else if (psb->error == smtp_syntax)
470 err_str = g_strdup_printf("got unexpected response: %s", psb->buffer);
471 else if (psb->error == smtp_cancel)
472 err_str = g_strdup("delivery was canceled.\n");
473 else
474 /* error message should still be in the buffer */
475 err_str = g_strdup_printf("failed: %s\n", psb->buffer);
477 if (msg == NULL)
478 logwrite(LOG_NOTICE, "host=%s %s\n", psb->remote_host, err_str);
479 else
480 logwrite(LOG_NOTICE, "%s == host=%s %s\n", msg->uid, psb->remote_host, err_str);
482 g_free(err_str);
483 }
485 smtp_base*
486 smtp_out_open(gchar * host, gint port, GList * resolve_list)
487 {
488 smtp_base *psb;
489 gint sock;
490 mxip_addr *addr;
492 DEBUG(5) debugf("smtp_out_open entered, host = %s\n", host);
494 if ((addr = connect_resolvelist(&sock, host, port, resolve_list))) {
495 /* create structure to hold status data: */
496 psb = create_smtpbase(sock);
497 psb->remote_host = addr->name;
499 DEBUG(5) {
500 struct sockaddr_in name;
501 int len = sizeof(struct sockaddr);
502 getsockname(sock, (struct sockaddr *) (&name), &len);
503 debugf("socket: name.sin_addr = %s\n", inet_ntoa(name.sin_addr));
504 }
505 return psb;
506 } else {
507 DEBUG(5) debugf("connect_resolvelist failed: %s %s\n", strerror(errno), hstrerror(h_errno));
508 }
510 return NULL;
511 }
513 smtp_base*
514 smtp_out_open_child(gchar * cmd)
515 {
516 smtp_base *psb;
517 gint sock;
519 DEBUG(5) debugf("smtp_out_open_child entered, cmd = %s\n", cmd);
521 sock = child(cmd);
523 if (sock > 0) {
524 psb = create_smtpbase(sock);
525 psb->remote_host = NULL;
527 return psb;
528 }
530 return NULL;
531 }
533 gboolean
534 smtp_out_rset(smtp_base * psb)
535 {
536 gboolean ok;
538 fprintf(psb->out, "RSET\r\n");
539 fflush(psb->out);
540 DEBUG(4) debugf("RSET\n");
542 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
543 if (check_response(psb, FALSE))
544 return TRUE;
546 smtp_out_log_failure(psb, NULL);
548 return FALSE;
549 }
551 #ifdef ENABLE_AUTH
553 static gboolean
554 smtp_out_auth_cram_md5(smtp_base * psb)
555 {
556 gboolean ok = FALSE;
558 fprintf(psb->out, "AUTH CRAM-MD5\r\n");
559 fflush(psb->out);
560 DEBUG(4) debugf("AUTH CRAM-MD5\n");
561 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
562 if ((ok = check_response(psb, TRUE))) {
563 gchar *chall64 = get_response_arg(&(psb->buffer[4]));
564 gint chall_size;
565 gchar *chall = base64_decode(chall64, &chall_size);
566 guchar digest[16], *reply64, *reply;
567 gchar digest_string[33];
568 gint i;
569 #ifdef USE_LIB_CRYPTO
570 unsigned int digest_len;
571 #endif
573 DEBUG(5) debugf("smtp_out_auth_cram_md5():\n");
574 DEBUG(5) debugf(" encoded challenge = %s\n", chall64);
575 DEBUG(5) debugf(" decoded challenge = %s, size = %d\n", chall, chall_size);
576 DEBUG(5) debugf(" secret = %s\n", psb->auth_secret);
578 #ifdef USE_LIB_CRYPTO
579 HMAC(EVP_md5(), psb->auth_secret, strlen(psb->auth_secret), chall, chall_size, digest, &digest_len);
580 #else
581 hmac_md5(chall, chall_size, psb->auth_secret, strlen(psb->auth_secret), digest);
582 #endif
584 for (i = 0; i < 16; i++)
585 sprintf(&(digest_string[i + i]), "%02x", (unsigned int) (digest[i]));
586 digest_string[32] = '\0';
588 DEBUG(5) debugf(" digest = %s\n", digest_string);
590 reply = g_strdup_printf("%s %s", psb->auth_login, digest_string);
591 DEBUG(5) debugf(" unencoded reply = %s\n", reply);
593 reply64 = base64_encode(reply, strlen(reply));
594 DEBUG(5) debugf(" encoded reply = %s\n", reply64);
596 fprintf(psb->out, "%s\r\n", reply64);
597 fflush(psb->out);
598 DEBUG(4) debugf(" reply64 = %s\n", reply64);
600 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
601 ok = check_response(psb, FALSE);
603 g_free(reply64);
604 g_free(reply);
605 g_free(chall);
606 g_free(chall64);
607 }
608 }
609 return ok;
610 }
612 static gboolean
613 smtp_out_auth_login(smtp_base * psb)
614 {
615 gboolean ok = FALSE;
616 fprintf(psb->out, "AUTH LOGIN\r\n");
617 fflush(psb->out);
618 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
619 if ((ok = check_response(psb, TRUE))) {
620 gchar *resp64;
621 guchar *resp;
622 gint resp_size;
623 gchar *reply64;
625 DEBUG(5) debugf("smtp_out_auth_login():\n");
626 resp64 = get_response_arg(&(psb->buffer[4]));
627 DEBUG(5) debugf(" encoded response = %s\n", resp64);
628 resp = base64_decode(resp64, &resp_size);
629 g_free(resp64);
630 DEBUG(5) debugf(" decoded response = %s, size = %d\n", resp, resp_size);
631 g_free(resp);
632 reply64 = base64_encode(psb->auth_login, strlen(psb->auth_login));
633 fprintf(psb->out, "%s\r\n", reply64);
634 fflush(psb->out);
635 g_free(reply64);
636 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
637 if ((ok = check_response(psb, TRUE))) {
638 resp64 = get_response_arg(&(psb->buffer[4]));
639 DEBUG(5) debugf(" encoded response = %s\n", resp64);
640 resp = base64_decode(resp64, &resp_size);
641 g_free(resp64);
642 DEBUG(5) debugf(" decoded response = %s, size = %d\n", resp, resp_size);
643 g_free(resp);
644 reply64 = base64_encode(psb->auth_secret, strlen(psb->auth_secret));
645 fprintf(psb->out, "%s\r\n", reply64);
646 fflush(psb->out);
647 g_free(reply64);
648 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
649 ok = check_response(psb, FALSE);
650 }
651 }
652 }
653 }
654 return ok;
655 }
657 gboolean
658 smtp_out_auth(smtp_base * psb)
659 {
660 gboolean ok = FALSE;
661 gint i = 0;
662 while (psb->auth_names[i]) {
663 if (strcasecmp(psb->auth_names[i], psb->auth_name) == 0)
664 break;
665 i++;
666 }
667 if (psb->auth_names[i]) {
668 if (strcasecmp(psb->auth_name, "cram-md5") == 0) {
669 smtp_out_auth_cram_md5(psb);
670 } else if (strcasecmp(psb->auth_name, "login") == 0) {
671 smtp_out_auth_login(psb);
672 } else {
673 logwrite(LOG_ERR, "auth method %s not supported\n", psb->auth_name);
674 }
675 } else {
676 logwrite(LOG_ERR, "no auth method %s found.\n", psb->auth_name);
677 }
678 return ok;
679 }
681 #endif
683 gboolean
684 smtp_out_init(smtp_base * psb, gboolean instant_helo)
685 {
686 gboolean ok;
688 logwrite(LOG_INFO, "smtp_out_init(): instant_helo:%d\n", instant_helo);
690 if (instant_helo) {
691 /* we say hello right away, hence we don't know if
692 ESMTP is supported; we just assume it */
693 psb->use_esmtp = 1;
694 } else {
695 if ((ok = read_response(psb, SMTP_INITIAL_TIMEOUT))) {
696 ok = check_init_response(psb);
697 }
698 if (!ok) {
699 smtp_out_log_failure(psb, NULL);
700 return ok;
701 }
702 }
704 if ((ok = smtp_helo(psb, psb->helo_name))) {
705 #ifdef ENABLE_AUTH
706 if (psb->auth_name && psb->use_auth) {
707 /* we completely disregard the response of server here. If
708 authentication fails, the server will complain later
709 anyway. I know, this is not polite... */
710 smtp_out_auth(psb);
711 }
712 #endif
713 }
714 if (!ok)
715 smtp_out_log_failure(psb, NULL);
716 return ok;
717 }
719 gint
720 smtp_out_msg(smtp_base * psb, message * msg, address * return_path, GList * rcpt_list, GList * hdr_list)
721 {
722 gint i, size;
723 gboolean ok = TRUE;
724 int rcpt_cnt;
725 int rcpt_accept = 0;
727 DEBUG(5) debugf("smtp_out_msg entered\n");
729 /* defaults: */
730 if (return_path == NULL)
731 return_path = msg->return_path;
732 if (hdr_list == NULL)
733 hdr_list = msg->hdr_list;
734 if (rcpt_list == NULL)
735 rcpt_list = msg->rcpt_list;
736 rcpt_cnt = g_list_length(rcpt_list);
738 size = msg_calc_size(msg, TRUE);
740 /* respect maximum size given by server: */
741 if ((psb->max_size > 0) && (size > psb->max_size)) {
742 logwrite(LOG_WARNING, "%s == host=%s message size (%d) > "
743 "fixed maximum message size of server (%d)",
744 msg->uid, psb->remote_host, size, psb->max_size);
745 psb->error = smtp_cancel;
746 ok = FALSE;
747 }
749 if (ok) {
750 /* pretend the message is a bit larger,
751 just in case the size calculation is buggy */
752 smtp_cmd_mailfrom(psb, return_path, psb->use_size ? size+SMTP_SIZE_ADD : 0);
754 if (!psb->use_pipelining) {
755 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
756 ok = check_response(psb, FALSE);
757 }
758 }
759 if (ok) {
760 GList *rcpt_node;
761 rcpt_accept = 0;
763 for (rcpt_node = g_list_first(rcpt_list); rcpt_node != NULL; rcpt_node = g_list_next(rcpt_node)) {
764 address *rcpt = (address *) (rcpt_node->data);
765 smtp_cmd_rcptto(psb, rcpt);
766 if (!psb->use_pipelining) {
767 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
768 if (check_response(psb, FALSE)) {
769 rcpt_accept++;
770 addr_mark_delivered(rcpt);
771 } else {
772 /* if server returned an error for one recp. we
773 may still try the others. But if it is a timeout, eof
774 or unexpected response, it is more serious and we should
775 give up. */
776 if ((psb->error != smtp_trylater) && (psb->error != smtp_fail)) {
777 ok = FALSE;
778 break;
779 } else {
780 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n",
781 msg->uid, addr_string(rcpt), psb->remote_host, psb->buffer);
782 if (psb->error == smtp_trylater) {
783 addr_mark_defered(rcpt);
784 } else {
785 addr_mark_failed(rcpt);
786 }
787 }
788 } else
789 break;
790 }
791 }
793 /* There is no point in going on if no recp.s were accpted.
794 But we can check that at this point only if not pipelining: */
795 ok = (ok && (psb->use_pipelining || (rcpt_accept > 0)));
796 if (ok) {
798 fprintf(psb->out, "DATA\r\n");
799 fflush(psb->out);
801 DEBUG(4) debugf("DATA\r\n");
803 if (psb->use_pipelining) {
804 /* the first pl'ed command was MAIL FROM
805 the last was DATA, whose response can be handled by the 'normal' code
806 all in between were RCPT TO:
807 */
808 /* response to MAIL FROM: */
809 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
810 if ((ok = check_response(psb, FALSE))) {
812 /* response(s) to RCPT TO:
813 this is very similar to the sequence above for no pipeline
814 */
815 for (i = 0; i < rcpt_cnt; i++) {
816 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
817 address *rcpt = g_list_nth_data(rcpt_list, i);
818 if (check_response(psb, FALSE)) {
819 rcpt_accept++;
820 addr_mark_delivered(rcpt);
821 } else {
822 /* if server returned an error 4xx or 5xx for one recp. we
823 may still try the others. But if it is a timeout, eof
824 or unexpected response, it is more serious and we
825 should give up. */
826 if ((psb->error != smtp_trylater) &&
827 (psb->error != smtp_fail)) {
828 ok = FALSE;
829 break;
830 } else {
831 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n", msg->uid,
832 addr_string(rcpt), psb->remote_host, psb->buffer);
833 if (psb->error == smtp_trylater) {
834 addr_mark_defered(rcpt);
835 } else {
836 addr_mark_failed(rcpt);
837 }
838 }
839 }
840 } else {
841 DEBUG(5) debugf("check_response failed after RCPT TO\n");
842 break;
843 }
844 }
845 if (rcpt_accept == 0)
846 ok = FALSE;
847 } else {
848 DEBUG(5) debugf("check_response failed after MAIL FROM\n");
849 }
850 } else {
851 DEBUG(5)
852 debugf("read_response failed after MAIL FROM\n");
853 }
854 }
856 /* if(psb->use_pipelining) */
857 /* response to the DATA cmd */
858 if (ok) {
859 if (read_response(psb, SMTP_DATA_TIMEOUT)) {
860 if (check_response(psb, TRUE)) {
861 send_header(psb, hdr_list);
862 send_data(psb, msg);
864 if (read_response(psb, SMTP_FINAL_TIMEOUT))
865 ok = check_response(psb, FALSE);
866 }
867 }
868 }
869 }
870 }
872 DEBUG(5) {
873 debugf("smtp_out_msg():\n");
874 debugf(" psb->error = %d\n", psb->error);
875 debugf(" ok = %d\n", ok);
876 debugf(" rcpt_accept = %d\n", rcpt_accept);
877 }
879 if (psb->error == smtp_ok) {
880 GList *rcpt_node;
881 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
882 address *rcpt = (address *) (rcpt_node->data);
883 if (addr_is_delivered(rcpt))
884 logwrite(LOG_NOTICE, "%s => %s host=%s with %s\n", msg->uid, addr_string(rcpt),
885 psb->remote_host, psb->use_esmtp ? "esmtp" : "smtp");
886 }
887 } else {
888 /* if something went wrong,
889 we have to unmark the rcpts prematurely marked as delivered
890 and mark the status */
891 smtp_out_mark_rcpts(psb, rcpt_list);
893 /* log the failure: */
894 smtp_out_log_failure(psb, msg);
895 }
896 return rcpt_accept;
897 }
899 gboolean
900 smtp_out_quit(smtp_base * psb)
901 {
902 fprintf(psb->out, "QUIT\r\n");
903 fflush(psb->out);
905 DEBUG(4) debugf("QUIT\n");
907 signal(SIGALRM, SIG_DFL);
909 return TRUE;
910 }
912 gint
913 smtp_deliver(gchar * host, gint port, GList * resolve_list, message * msg, address * return_path, GList * rcpt_list)
914 {
915 smtp_base *psb;
916 smtp_error err;
918 DEBUG(5) debugf("smtp_deliver entered\n");
920 if (return_path == NULL)
921 return_path = msg->return_path;
923 if ((psb = smtp_out_open(host, port, resolve_list))) {
924 set_heloname(psb, return_path->domain, TRUE);
925 /* initiate connection, send message and quit: */
926 if (smtp_out_init(psb, FALSE)) {
927 smtp_out_msg(psb, msg, return_path, rcpt_list, NULL);
928 if (psb->error == smtp_ok || (psb->error == smtp_fail) || (psb->error == smtp_trylater)
929 || (psb->error == smtp_syntax) || (psb->error == smtp_cancel))
930 smtp_out_quit(psb);
931 }
933 err = psb->error;
934 destroy_smtpbase(psb);
936 return err;
937 }
938 return -1;
939 }