masqmail-0.2

view src/smtp_out.c @ 118:7f1f364c2a29

annotations at msg_calc_size()
author meillo@marmaro.de
date Thu, 01 Jul 2010 13:09:40 +0200
parents f671821d8222
children 1e2fd87d58ea
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 debugf("in check_helo_response()\n");
266 while (psb->auth_names[i]) {
267 debugf(" offered AUTH %s\n", psb->auth_names[i]);
268 i++;
269 }
270 }
271 }
272 }
273 }
275 while (*ptr != '\n')
276 ptr++;
277 ptr++;
278 }
280 DEBUG(4) {
281 debugf(" %s\n", psb->use_size ? "uses SIZE" : "no size");
282 debugf(" %s\n", psb->use_pipelining ? "uses PIPELINING" : "no pipelining");
283 debugf(" %s\n", psb->use_auth ? "uses AUTH" : "no auth");
284 }
286 return TRUE;
287 }
289 static gboolean
290 smtp_helo(smtp_base * psb, gchar * helo)
291 {
292 while (TRUE) {
293 if (psb->use_esmtp) {
294 fprintf(psb->out, "EHLO %s\r\n", helo);
295 fflush(psb->out);
297 DEBUG(4) debugf("EHLO %s\r\n", helo);
299 } else {
300 fprintf(psb->out, "HELO %s\r\n", helo);
301 fflush(psb->out);
303 DEBUG(4) debugf("HELO %s\r\n", helo);
305 }
307 if (!read_response(psb, SMTP_CMD_TIMEOUT))
308 return FALSE;
310 if (check_helo_response(psb))
311 return TRUE;
312 else {
313 if (psb->error == smtp_fail) {
314 if (psb->use_esmtp) {
315 /* our guess that server understands EHLO was wrong, try again with HELO */
316 psb->use_esmtp = FALSE;
317 } else {
318 /* what sort of server ist THAT ?! give up... */
319 return FALSE;
320 }
321 } else
322 return FALSE;
323 }
324 }
325 }
327 static void
328 smtp_cmd_mailfrom(smtp_base * psb, address * return_path, guint size)
329 {
330 if (psb->use_size) {
331 fprintf(psb->out, "MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
332 fflush(psb->out);
334 DEBUG(4) debugf("MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
336 } else {
337 fprintf(psb->out, "MAIL FROM:%s\r\n", addr_string(return_path));
338 fflush(psb->out);
340 DEBUG(4) debugf("MAIL FROM:%s\r\n", addr_string(return_path));
341 }
342 }
344 static void
345 smtp_cmd_rcptto(smtp_base * psb, address * rcpt)
346 {
347 fprintf(psb->out, "RCPT TO:%s\r\n", addr_string(rcpt));
348 fflush(psb->out);
349 DEBUG(4) debugf("RCPT TO:%s\n", addr_string(rcpt));
350 }
352 static void
353 send_data_line(smtp_base * psb, gchar * data)
354 {
355 /* According to RFC 821 each line should be terminated with CRLF.
356 Since a dot on a line itself marks the end of data, each line
357 beginning with a dot is prepended with another dot.
358 */
359 gchar *ptr;
360 gboolean new_line = TRUE; /* previous versions assumed that each item was exactly one line.
361 This is no longer the case */
363 ptr = data;
364 while (*ptr) {
365 int c = (int) (*ptr);
366 if (c == '.')
367 if (new_line)
368 putc('.', psb->out);
369 if (c == '\n') {
370 putc('\r', psb->out);
371 putc('\n', psb->out);
372 new_line = TRUE;
373 } else {
374 putc(c, psb->out);
375 new_line = FALSE;
376 }
377 ptr++;
378 }
379 }
381 static void
382 send_header(smtp_base * psb, GList * hdr_list)
383 {
384 GList *node;
385 gint num_hdrs = 0;
387 /* header */
388 if (hdr_list) {
389 foreach(hdr_list, node) {
390 if (node->data) {
391 header *hdr = (header *) (node->data);
392 if (hdr->header) {
393 send_data_line(psb, hdr->header);
394 num_hdrs++;
395 }
396 }
397 }
398 }
400 /* empty line separating headers from data: */
401 putc('\r', psb->out);
402 putc('\n', psb->out);
404 DEBUG(4) debugf("sent %d headers\n", num_hdrs);
405 }
407 static void
408 send_data(smtp_base * psb, message * msg)
409 {
410 GList *node;
411 gint num_lines = 0;
413 /* data */
414 if (msg->data_list) {
415 for (node = g_list_first(msg->data_list); node; node = g_list_next(node)) {
416 if (node->data) {
417 send_data_line(psb, node->data);
418 num_lines++;
419 }
420 }
421 }
423 DEBUG(4) debugf("sent %d lines of data\n", num_lines);
425 fprintf(psb->out, ".\r\n");
426 fflush(psb->out);
427 }
429 void
430 smtp_out_mark_rcpts(smtp_base * psb, GList * rcpt_list)
431 {
432 GList *rcpt_node;
433 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
434 address *rcpt = (address *) (rcpt_node->data);
436 addr_unmark_delivered(rcpt);
438 if ((psb->error == smtp_trylater) || (psb->error == smtp_timeout) || (psb->error == smtp_eof)) {
439 addr_mark_defered(rcpt);
440 } else {
441 addr_mark_failed(rcpt);
442 }
443 }
444 }
446 void
447 smtp_out_log_failure(smtp_base * psb, message * msg)
448 {
449 gchar *err_str;
451 if (psb->error == smtp_timeout)
452 err_str = g_strdup("connection timed out.");
453 else if (psb->error == smtp_eof)
454 err_str = g_strdup("connection terminated prematurely.");
455 else if (psb->error == smtp_syntax)
456 err_str = g_strdup_printf("got unexpected response: %s", psb->buffer);
457 else if (psb->error == smtp_cancel)
458 err_str = g_strdup("delivery was canceled.\n");
459 else
460 /* error message should still be in the buffer */
461 err_str = g_strdup_printf("failed: %s\n", psb->buffer);
463 if (msg == NULL)
464 logwrite(LOG_NOTICE, "host=%s %s\n", psb->remote_host, err_str);
465 else
466 logwrite(LOG_NOTICE, "%s == host=%s %s\n", msg->uid, psb->remote_host, err_str);
468 g_free(err_str);
469 }
471 smtp_base*
472 smtp_out_open(gchar * host, gint port, GList * resolve_list)
473 {
474 smtp_base *psb;
475 gint sock;
476 mxip_addr *addr;
478 DEBUG(5) debugf("smtp_out_open entered, host = %s\n", host);
480 if ((addr = connect_resolvelist(&sock, host, port, resolve_list))) {
481 /* create structure to hold status data: */
482 psb = create_smtpbase(sock);
483 psb->remote_host = addr->name;
485 DEBUG(5) {
486 struct sockaddr_in name;
487 int len = sizeof(struct sockaddr);
488 getsockname(sock, (struct sockaddr *) (&name), &len);
489 debugf("socket: name.sin_addr = %s\n", inet_ntoa(name.sin_addr));
490 }
491 return psb;
492 } else {
493 DEBUG(5) debugf("connect_resolvelist failed: %s %s\n", strerror(errno), hstrerror(h_errno));
494 }
496 return NULL;
497 }
499 smtp_base*
500 smtp_out_open_child(gchar * cmd)
501 {
502 smtp_base *psb;
503 gint sock;
505 DEBUG(5) debugf("smtp_out_open_child entered, cmd = %s\n", cmd);
507 sock = child(cmd);
509 if (sock > 0) {
510 psb = create_smtpbase(sock);
511 psb->remote_host = NULL;
513 return psb;
514 }
516 return NULL;
517 }
519 gboolean
520 smtp_out_rset(smtp_base * psb)
521 {
522 gboolean ok;
524 fprintf(psb->out, "RSET\r\n");
525 fflush(psb->out);
526 DEBUG(4) debugf("RSET\n");
528 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
529 if (check_response(psb, FALSE))
530 return TRUE;
532 smtp_out_log_failure(psb, NULL);
534 return FALSE;
535 }
537 #ifdef ENABLE_AUTH
539 static gboolean
540 smtp_out_auth_cram_md5(smtp_base * psb)
541 {
542 gboolean ok = FALSE;
544 fprintf(psb->out, "AUTH CRAM-MD5\r\n");
545 fflush(psb->out);
546 DEBUG(4) debugf("AUTH CRAM-MD5\n");
547 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
548 if ((ok = check_response(psb, TRUE))) {
549 gchar *chall64 = get_response_arg(&(psb->buffer[4]));
550 gint chall_size;
551 gchar *chall = base64_decode(chall64, &chall_size);
552 guchar digest[16], *reply64, *reply;
553 gchar digest_string[33];
554 gint i;
555 #ifdef USE_LIB_CRYPTO
556 unsigned int digest_len;
557 #endif
559 DEBUG(5) debugf("smtp_out_auth_cram_md5():\n");
560 DEBUG(5) debugf(" encoded challenge = %s\n", chall64);
561 DEBUG(5) debugf(" decoded challenge = %s, size = %d\n", chall, chall_size);
562 DEBUG(5) debugf(" secret = %s\n", psb->auth_secret);
564 #ifdef USE_LIB_CRYPTO
565 HMAC(EVP_md5(), psb->auth_secret, strlen(psb->auth_secret), chall, chall_size, digest, &digest_len);
566 #else
567 hmac_md5(chall, chall_size, psb->auth_secret, strlen(psb->auth_secret), digest);
568 #endif
570 for (i = 0; i < 16; i++)
571 sprintf(&(digest_string[i + i]), "%02x", (unsigned int) (digest[i]));
572 digest_string[32] = '\0';
574 DEBUG(5) debugf(" digest = %s\n", digest_string);
576 reply = g_strdup_printf("%s %s", psb->auth_login, digest_string);
577 DEBUG(5) debugf(" unencoded reply = %s\n", reply);
579 reply64 = base64_encode(reply, strlen(reply));
580 DEBUG(5) debugf(" encoded reply = %s\n", reply64);
582 fprintf(psb->out, "%s\r\n", reply64);
583 fflush(psb->out);
584 DEBUG(4) debugf(" reply64 = %s\n", reply64);
586 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
587 ok = check_response(psb, FALSE);
589 g_free(reply64);
590 g_free(reply);
591 g_free(chall);
592 g_free(chall64);
593 }
594 }
595 return ok;
596 }
598 static gboolean
599 smtp_out_auth_login(smtp_base * psb)
600 {
601 gboolean ok = FALSE;
602 fprintf(psb->out, "AUTH LOGIN\r\n");
603 fflush(psb->out);
604 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
605 if ((ok = check_response(psb, TRUE))) {
606 gchar *resp64;
607 guchar *resp;
608 gint resp_size;
609 gchar *reply64;
611 DEBUG(5) debugf("smtp_out_auth_login():\n");
612 resp64 = get_response_arg(&(psb->buffer[4]));
613 DEBUG(5) debugf(" encoded response = %s\n", resp64);
614 resp = base64_decode(resp64, &resp_size);
615 g_free(resp64);
616 DEBUG(5) debugf(" decoded response = %s, size = %d\n", resp, resp_size);
617 g_free(resp);
618 reply64 = base64_encode(psb->auth_login, strlen(psb->auth_login));
619 fprintf(psb->out, "%s\r\n", reply64);
620 fflush(psb->out);
621 g_free(reply64);
622 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
623 if ((ok = check_response(psb, TRUE))) {
624 resp64 = get_response_arg(&(psb->buffer[4]));
625 DEBUG(5) debugf(" encoded response = %s\n", resp64);
626 resp = base64_decode(resp64, &resp_size);
627 g_free(resp64);
628 DEBUG(5) debugf(" decoded response = %s, size = %d\n", resp, resp_size);
629 g_free(resp);
630 reply64 = base64_encode(psb->auth_secret, strlen(psb->auth_secret));
631 fprintf(psb->out, "%s\r\n", reply64);
632 fflush(psb->out);
633 g_free(reply64);
634 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
635 ok = check_response(psb, FALSE);
636 }
637 }
638 }
639 }
640 return ok;
641 }
643 gboolean
644 smtp_out_auth(smtp_base * psb)
645 {
646 gboolean ok = FALSE;
647 gint i = 0;
648 while (psb->auth_names[i]) {
649 if (strcasecmp(psb->auth_names[i], psb->auth_name) == 0)
650 break;
651 i++;
652 }
653 if (psb->auth_names[i]) {
654 if (strcasecmp(psb->auth_name, "cram-md5") == 0) {
655 smtp_out_auth_cram_md5(psb);
656 } else if (strcasecmp(psb->auth_name, "login") == 0) {
657 smtp_out_auth_login(psb);
658 } else {
659 logwrite(LOG_ERR, "auth method %s not supported\n", psb->auth_name);
660 }
661 } else {
662 logwrite(LOG_ERR, "no auth method %s found.\n", psb->auth_name);
663 }
664 return ok;
665 }
667 #endif
669 gboolean
670 smtp_out_init(smtp_base * psb)
671 {
672 gboolean ok;
674 if ((ok = read_response(psb, SMTP_INITIAL_TIMEOUT))) {
675 if ((ok = check_init_response(psb))) {
677 if ((ok = smtp_helo(psb, psb->helo_name))) {
678 #ifdef ENABLE_AUTH
679 if (psb->auth_name && psb->use_auth) {
680 /* we completely disregard the response of server here. If
681 authentication fails, the server will complain later
682 anyway. I know, this is not polite... */
683 smtp_out_auth(psb);
684 }
685 #endif
686 }
687 }
688 }
689 if (!ok)
690 smtp_out_log_failure(psb, NULL);
691 return ok;
692 }
694 gint
695 smtp_out_msg(smtp_base * psb, message * msg, address * return_path, GList * rcpt_list, GList * hdr_list)
696 {
697 gint i, size;
698 gboolean ok = TRUE;
699 int rcpt_cnt;
700 int rcpt_accept = 0;
702 DEBUG(5) debugf("smtp_out_msg entered\n");
704 /* defaults: */
705 if (return_path == NULL)
706 return_path = msg->return_path;
707 if (hdr_list == NULL)
708 hdr_list = msg->hdr_list;
709 if (rcpt_list == NULL)
710 rcpt_list = msg->rcpt_list;
711 rcpt_cnt = g_list_length(rcpt_list);
713 size = msg_calc_size(msg, TRUE);
715 /* respect maximum size given by server: */
716 if ((psb->max_size > 0) && (size > psb->max_size)) {
717 logwrite(LOG_WARNING, "%s == host=%s message size (%d) > "
718 "fixed maximum message size of server (%d)",
719 msg->uid, psb->remote_host, size, psb->max_size);
720 psb->error = smtp_cancel;
721 ok = FALSE;
722 }
724 if (ok) {
725 smtp_cmd_mailfrom(psb, return_path, psb->use_size ? size + SMTP_SIZE_ADD : 0);
727 if (!psb->use_pipelining) {
728 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
729 ok = check_response(psb, FALSE);
730 }
731 }
732 if (ok) {
733 GList *rcpt_node;
734 rcpt_accept = 0;
736 for (rcpt_node = g_list_first(rcpt_list); rcpt_node != NULL; rcpt_node = g_list_next(rcpt_node)) {
737 address *rcpt = (address *) (rcpt_node->data);
738 smtp_cmd_rcptto(psb, rcpt);
739 if (!psb->use_pipelining) {
740 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
741 if (check_response(psb, FALSE)) {
742 rcpt_accept++;
743 addr_mark_delivered(rcpt);
744 } else {
745 /* if server returned an error for one recp. we
746 may still try the others. But if it is a timeout, eof
747 or unexpected response, it is more serious and we should
748 give up. */
749 if ((psb->error != smtp_trylater) && (psb->error != smtp_fail)) {
750 ok = FALSE;
751 break;
752 } else {
753 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n",
754 msg->uid, addr_string(rcpt), psb->remote_host, psb->buffer);
755 if (psb->error == smtp_trylater) {
756 addr_mark_defered(rcpt);
757 } else {
758 addr_mark_failed(rcpt);
759 }
760 }
761 } else
762 break;
763 }
764 }
766 /* There is no point in going on if no recp.s were accpted.
767 But we can check that at this point only if not pipelining: */
768 ok = (ok && (psb->use_pipelining || (rcpt_accept > 0)));
769 if (ok) {
771 fprintf(psb->out, "DATA\r\n");
772 fflush(psb->out);
774 DEBUG(4) debugf("DATA\r\n");
776 if (psb->use_pipelining) {
777 /* the first pl'ed command was MAIL FROM
778 the last was DATA, whose response can be handled by the 'normal' code
779 all in between were RCPT TO:
780 */
781 /* response to MAIL FROM: */
782 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
783 if ((ok = check_response(psb, FALSE))) {
785 /* response(s) to RCPT TO:
786 this is very similar to the sequence above for no pipeline
787 */
788 for (i = 0; i < rcpt_cnt; i++) {
789 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
790 address *rcpt = g_list_nth_data(rcpt_list, i);
791 if (check_response(psb, FALSE)) {
792 rcpt_accept++;
793 addr_mark_delivered(rcpt);
794 } else {
795 /* if server returned an error 4xx or 5xx for one recp. we
796 may still try the others. But if it is a timeout, eof
797 or unexpected response, it is more serious and we
798 should give up. */
799 if ((psb->error != smtp_trylater) &&
800 (psb->error != smtp_fail)) {
801 ok = FALSE;
802 break;
803 } else {
804 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n", msg->uid,
805 addr_string(rcpt), psb->remote_host, psb->buffer);
806 if (psb->error == smtp_trylater) {
807 addr_mark_defered(rcpt);
808 } else {
809 addr_mark_failed(rcpt);
810 }
811 }
812 }
813 } else {
814 DEBUG(5) debugf("check_response failed after RCPT TO\n");
815 break;
816 }
817 }
818 if (rcpt_accept == 0)
819 ok = FALSE;
820 } else {
821 DEBUG(5) debugf("check_response failed after MAIL FROM\n");
822 }
823 } else {
824 DEBUG(5)
825 debugf("read_response failed after MAIL FROM\n");
826 }
827 }
829 /* if(psb->use_pipelining) */
830 /* response to the DATA cmd */
831 if (ok) {
832 if (read_response(psb, SMTP_DATA_TIMEOUT)) {
833 if (check_response(psb, TRUE)) {
834 send_header(psb, hdr_list);
835 send_data(psb, msg);
837 if (read_response(psb, SMTP_FINAL_TIMEOUT))
838 ok = check_response(psb, FALSE);
839 }
840 }
841 }
842 }
843 }
845 DEBUG(5) {
846 debugf("smtp_out_msg():\n");
847 debugf(" psb->error = %d\n", psb->error);
848 debugf(" ok = %d\n", ok);
849 debugf(" rcpt_accept = %d\n", rcpt_accept);
850 }
852 if (psb->error == smtp_ok) {
853 GList *rcpt_node;
854 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
855 address *rcpt = (address *) (rcpt_node->data);
856 if (addr_is_delivered(rcpt))
857 logwrite(LOG_NOTICE, "%s => %s host=%s with %s\n", msg->uid, addr_string(rcpt),
858 psb->remote_host, psb->use_esmtp ? "esmtp" : "smtp");
859 }
860 } else {
861 /* if something went wrong,
862 we have to unmark the rcpts prematurely marked as delivered
863 and mark the status */
864 smtp_out_mark_rcpts(psb, rcpt_list);
866 /* log the failure: */
867 smtp_out_log_failure(psb, msg);
868 }
869 return rcpt_accept;
870 }
872 gboolean
873 smtp_out_quit(smtp_base * psb)
874 {
875 fprintf(psb->out, "QUIT\r\n");
876 fflush(psb->out);
878 DEBUG(4) debugf("QUIT\n");
880 signal(SIGALRM, SIG_DFL);
882 return TRUE;
883 }
885 gint
886 smtp_deliver(gchar * host, gint port, GList * resolve_list, message * msg, address * return_path, GList * rcpt_list)
887 {
888 smtp_base *psb;
889 smtp_error err;
891 DEBUG(5) debugf("smtp_deliver entered\n");
893 if (return_path == NULL)
894 return_path = msg->return_path;
896 if ((psb = smtp_out_open(host, port, resolve_list))) {
897 set_heloname(psb, return_path->domain, TRUE);
898 /* initiate connection, send message and quit: */
899 if (smtp_out_init(psb)) {
900 smtp_out_msg(psb, msg, return_path, rcpt_list, NULL);
901 if (psb->error == smtp_ok || (psb->error == smtp_fail) || (psb->error == smtp_trylater)
902 || (psb->error == smtp_syntax) || (psb->error == smtp_cancel))
903 smtp_out_quit(psb);
904 }
906 err = psb->error;
907 destroy_smtpbase(psb);
909 return err;
910 }
911 return -1;
912 }