masqmail

view src/smtp_out.c @ 209:10da50168dab

replaced the MD5 implementation with the one of Solar Designer Until now, the sample code of RFC 1321 was used. It had an ugly license. Now we use the implementation of Solar Designer, which is in the Public Domain. http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
author meillo@marmaro.de
date Sun, 18 Jul 2010 21:58:15 +0200
parents 6530806d418f
children 8cddc65765bd
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] == '-');
176 if (psb->buffer) {
177 DEBUG(4) debugf("S: %s\n", psb->buffer);
178 }
180 return TRUE;
181 }
183 static gboolean
184 check_response(smtp_base * psb, gboolean after_data)
185 {
186 char c = psb->buffer[0];
188 if (((c == '2') && !after_data) || ((c == '3') && after_data)) {
189 psb->error = smtp_ok;
190 DEBUG(6) debugf("response OK:'%s' after_data = %d\n", psb->buffer, (int) after_data);
191 return TRUE;
192 } else {
193 if (c == '4')
194 psb->error = smtp_trylater;
195 else if (c == '5')
196 psb->error = smtp_fail;
197 else
198 psb->error = smtp_syntax;
199 DEBUG(6) debugf("response failure:'%s' after_data = %d\n", psb->buffer, (int) after_data);
200 return FALSE;
201 }
202 }
204 static gboolean
205 check_init_response(smtp_base * psb)
206 {
207 if (check_response(psb, FALSE)) {
208 psb->use_esmtp = (strstr(psb->buffer, "ESMTP") != NULL);
210 DEBUG(4) debugf(psb->use_esmtp ? "uses esmtp\n" : "no esmtp\n");
212 return TRUE;
213 }
214 return FALSE;
215 }
217 static gchar*
218 get_response_arg(gchar * response)
219 {
220 gchar buf[SMTP_BUF_LEN];
221 gchar *p = response, *q = buf;
223 while (*p && (*p != '\n') && isspace(*p))
224 p++;
225 if (*p && (*p != '\n')) {
226 while (*p && (*p != '\n') && (*p != '\r') && (q < buf + SMTP_BUF_LEN - 1))
227 *(q++) = *(p++);
228 *q = '\0';
229 return g_strdup(buf);
230 }
231 return NULL;
232 }
234 static gboolean
235 check_helo_response(smtp_base * psb)
236 {
237 gchar *ptr = psb->buffer;
239 if (!check_response(psb, FALSE))
240 return FALSE;
242 while (*ptr) {
243 if (strncasecmp(&(ptr[4]), "SIZE", 4) == 0) {
244 gchar *arg;
245 psb->use_size = TRUE;
246 arg = get_response_arg(&(ptr[8]));
247 if (arg) {
248 psb->max_size = atoi(arg);
249 g_free(arg);
250 }
251 }
253 if (strncasecmp(&(ptr[4]), "PIPELINING", 10) == 0)
254 psb->use_pipelining = TRUE;
256 if (strncasecmp(&(ptr[4]), "AUTH", 4) == 0) {
257 if ((ptr[8] == ' ') || (ptr[8] == '=') || (ptr[8] == '\t')) { /* not sure about '\t' */
258 gchar *arg;
259 psb->use_auth = TRUE;
260 arg = get_response_arg(&(ptr[9])); /* after several years I finally learnt to count */
261 if (arg) {
262 psb->auth_names = g_strsplit(arg, " ", 0);
263 g_free(arg);
265 DEBUG(4) {
266 gint i = 0;
267 debugf("in check_helo_response()\n");
268 while (psb->auth_names[i]) {
269 debugf(" offered AUTH %s\n", psb->auth_names[i]);
270 i++;
271 }
272 }
273 }
274 }
275 }
277 while (*ptr != '\n')
278 ptr++;
279 ptr++;
280 }
282 DEBUG(4) {
283 debugf(" %s\n", psb->use_size ? "uses SIZE" : "no size");
284 debugf(" %s\n", psb->use_pipelining ? "uses PIPELINING" : "no pipelining");
285 debugf(" %s\n", psb->use_auth ? "uses AUTH" : "no auth");
286 }
288 return TRUE;
289 }
291 static gboolean
292 smtp_helo(smtp_base * psb, gchar * helo)
293 {
294 while (TRUE) {
295 if (psb->use_esmtp) {
296 fprintf(psb->out, "EHLO %s\r\n", helo);
297 fflush(psb->out);
299 DEBUG(4) debugf("C: EHLO %s\r\n", helo);
301 } else {
302 fprintf(psb->out, "HELO %s\r\n", helo);
303 fflush(psb->out);
305 DEBUG(4) debugf("C: HELO %s\r\n", helo);
307 }
309 if (!read_response(psb, SMTP_CMD_TIMEOUT))
310 return FALSE;
312 if (check_helo_response(psb))
313 return TRUE;
314 else {
315 if (psb->error == smtp_fail) {
316 if (psb->use_esmtp) {
317 /* our guess that server understands EHLO was wrong, try again with HELO */
318 psb->use_esmtp = FALSE;
319 } else {
320 /* what sort of server ist THAT ?! give up... */
321 return FALSE;
322 }
323 } else
324 return FALSE;
325 }
326 }
327 }
329 static void
330 smtp_cmd_mailfrom(smtp_base * psb, address * return_path, guint size)
331 {
332 if (psb->use_size) {
333 fprintf(psb->out, "MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
334 fflush(psb->out);
336 DEBUG(4) debugf("C: MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
338 } else {
339 fprintf(psb->out, "MAIL FROM:%s\r\n", addr_string(return_path));
340 fflush(psb->out);
342 DEBUG(4) debugf("C: MAIL FROM:%s\r\n", addr_string(return_path));
343 }
344 }
346 static void
347 smtp_cmd_rcptto(smtp_base * psb, address * rcpt)
348 {
349 fprintf(psb->out, "RCPT TO:%s\r\n", addr_string(rcpt));
350 fflush(psb->out);
351 DEBUG(4) debugf("C: RCPT TO:%s\n", addr_string(rcpt));
352 }
354 static void
355 send_data_line(smtp_base * psb, gchar * data)
356 {
357 /* According to RFC 821 each line should be terminated with CRLF.
358 Since a dot on a line itself marks the end of data, each line
359 beginning with a dot is prepended with another dot.
360 */
361 gchar *ptr;
362 gboolean new_line = TRUE; /* previous versions assumed that each item was exactly one line.
363 This is no longer the case */
365 ptr = data;
366 while (*ptr) {
367 int c = (int) (*ptr);
368 if (c == '.' && new_line) {
369 /* dot-stuffing */
370 putc('.', psb->out);
371 }
372 if (c == '\n') {
373 /* CRLF line terminators */
374 putc('\r', psb->out);
375 putc('\n', psb->out);
376 new_line = TRUE;
377 } else {
378 putc(c, psb->out);
379 new_line = FALSE;
380 }
381 ptr++;
382 }
383 }
385 static void
386 send_header(smtp_base * psb, GList * hdr_list)
387 {
388 GList *node;
389 gint num_hdrs = 0;
391 /* header */
392 if (hdr_list) {
393 foreach(hdr_list, node) {
394 if (node->data) {
395 header *hdr = (header *) (node->data);
396 if (hdr->header) {
397 send_data_line(psb, hdr->header);
398 num_hdrs++;
399 }
400 }
401 }
402 }
404 /* empty line separating headers from data: */
405 putc('\r', psb->out);
406 putc('\n', psb->out);
408 DEBUG(4) debugf("sent %d headers\n", num_hdrs);
409 }
411 static void
412 send_data(smtp_base * psb, message * msg)
413 {
414 GList *node;
415 gint num_lines = 0;
417 /* data */
418 if (msg->data_list) {
419 for (node = g_list_first(msg->data_list); node; node = g_list_next(node)) {
420 if (node->data) {
421 send_data_line(psb, node->data);
422 num_lines++;
423 }
424 }
425 }
427 DEBUG(4) debugf("sent %d lines of data\n", num_lines);
429 fprintf(psb->out, ".\r\n");
430 fflush(psb->out);
431 DEBUG(4) debugf("C: .\n");
432 }
434 void
435 smtp_out_mark_rcpts(smtp_base * psb, GList * rcpt_list)
436 {
437 GList *rcpt_node;
438 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
439 address *rcpt = (address *) (rcpt_node->data);
441 addr_unmark_delivered(rcpt);
443 if ((psb->error == smtp_trylater) || (psb->error == smtp_timeout) || (psb->error == smtp_eof)) {
444 addr_mark_defered(rcpt);
445 } else {
446 addr_mark_failed(rcpt);
447 }
448 }
449 }
451 void
452 smtp_out_log_failure(smtp_base * psb, message * msg)
453 {
454 gchar *err_str;
456 if (psb->error == smtp_timeout)
457 err_str = g_strdup("connection timed out.");
458 else if (psb->error == smtp_eof)
459 err_str = g_strdup("connection terminated prematurely.");
460 else if (psb->error == smtp_syntax)
461 err_str = g_strdup_printf("got unexpected response: %s", psb->buffer);
462 else if (psb->error == smtp_cancel)
463 err_str = g_strdup("delivery was canceled.\n");
464 else
465 /* error message should still be in the buffer */
466 err_str = g_strdup_printf("failed: %s\n", psb->buffer);
468 if (msg == NULL)
469 logwrite(LOG_NOTICE, "host=%s %s\n", psb->remote_host, err_str);
470 else
471 logwrite(LOG_NOTICE, "%s == host=%s %s\n", msg->uid, psb->remote_host, err_str);
473 g_free(err_str);
474 }
476 smtp_base*
477 smtp_out_open(gchar * host, gint port, GList * resolve_list)
478 {
479 smtp_base *psb;
480 gint sock;
481 mxip_addr *addr;
483 DEBUG(5) debugf("smtp_out_open entered, host = %s\n", host);
485 if ((addr = connect_resolvelist(&sock, host, port, resolve_list))) {
486 /* create structure to hold status data: */
487 psb = create_smtpbase(sock);
488 psb->remote_host = addr->name;
490 DEBUG(5) {
491 struct sockaddr_in name;
492 int len = sizeof(struct sockaddr);
493 getsockname(sock, (struct sockaddr *) (&name), &len);
494 debugf("socket: name.sin_addr = %s\n", inet_ntoa(name.sin_addr));
495 }
496 return psb;
497 } else {
498 DEBUG(5) debugf("connect_resolvelist failed: %s %s\n", strerror(errno), hstrerror(h_errno));
499 }
501 return NULL;
502 }
504 smtp_base*
505 smtp_out_open_child(gchar * cmd)
506 {
507 smtp_base *psb;
508 gint sock;
510 DEBUG(5) debugf("smtp_out_open_child entered, cmd = %s\n", cmd);
512 sock = child(cmd);
514 if (sock > 0) {
515 psb = create_smtpbase(sock);
516 psb->remote_host = NULL;
518 return psb;
519 }
521 return NULL;
522 }
524 gboolean
525 smtp_out_rset(smtp_base * psb)
526 {
527 gboolean ok;
529 fprintf(psb->out, "RSET\r\n");
530 fflush(psb->out);
531 DEBUG(4) debugf("C: RSET\n");
533 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
534 if (check_response(psb, FALSE))
535 return TRUE;
537 smtp_out_log_failure(psb, NULL);
539 return FALSE;
540 }
542 #ifdef ENABLE_AUTH
544 static gboolean
545 smtp_out_auth_cram_md5(smtp_base * psb)
546 {
547 gboolean ok = FALSE;
549 fprintf(psb->out, "C: AUTH CRAM-MD5\r\n");
550 fflush(psb->out);
551 DEBUG(4) debugf("AUTH CRAM-MD5\n");
552 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
553 if ((ok = check_response(psb, TRUE))) {
554 gchar *chall64 = get_response_arg(&(psb->buffer[4]));
555 gint chall_size;
556 gchar *chall = base64_decode(chall64, &chall_size);
557 guchar digest[16], *reply64, *reply;
558 gchar digest_string[33];
559 gint i;
560 #ifdef USE_LIB_CRYPTO
561 unsigned int digest_len;
562 #endif
564 DEBUG(5) debugf("smtp_out_auth_cram_md5():\n");
565 DEBUG(5) debugf(" encoded challenge = %s\n", chall64);
566 DEBUG(5) debugf(" decoded challenge = %s, size = %d\n", chall, chall_size);
567 DEBUG(5) debugf(" secret = %s\n", psb->auth_secret);
569 #ifdef USE_LIB_CRYPTO
570 HMAC(EVP_md5(), psb->auth_secret, strlen(psb->auth_secret), chall, chall_size, digest, &digest_len);
571 #else
572 hmac_md5(chall, chall_size, psb->auth_secret, strlen(psb->auth_secret), digest);
573 #endif
575 for (i = 0; i < 16; i++)
576 sprintf(&(digest_string[i + i]), "%02x", (unsigned int) (digest[i]));
577 digest_string[32] = '\0';
579 DEBUG(5) debugf(" digest = %s\n", digest_string);
581 reply = g_strdup_printf("%s %s", psb->auth_login, digest_string);
582 DEBUG(5) debugf(" unencoded reply = %s\n", reply);
584 reply64 = base64_encode(reply, strlen(reply));
585 DEBUG(5) debugf(" encoded reply = %s\n", reply64);
587 fprintf(psb->out, "%s\r\n", reply64);
588 fflush(psb->out);
589 DEBUG(6) debugf(" reply64 = %s\n", reply64);
590 DEBUG(6) debugf("C: %s\n", reply64);
592 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
593 ok = check_response(psb, FALSE);
595 g_free(reply64);
596 g_free(reply);
597 g_free(chall);
598 g_free(chall64);
599 }
600 }
601 return ok;
602 }
604 static gboolean
605 smtp_out_auth_login(smtp_base * psb)
606 {
607 gboolean ok = FALSE;
608 fprintf(psb->out, "AUTH LOGIN\r\n");
609 fflush(psb->out);
610 DEBUG(4) debugf("C: AUTH LOGIN\r\n");
611 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
612 if ((ok = check_response(psb, TRUE))) {
613 gchar *resp64;
614 guchar *resp;
615 gint resp_size;
616 gchar *reply64;
618 DEBUG(5) debugf("smtp_out_auth_login():\n");
619 resp64 = get_response_arg(&(psb->buffer[4]));
620 DEBUG(5) debugf(" encoded response = %s\n", resp64);
621 resp = base64_decode(resp64, &resp_size);
622 g_free(resp64);
623 DEBUG(5) debugf(" decoded response = %s, size = %d\n", resp, resp_size);
624 g_free(resp);
625 reply64 = base64_encode(psb->auth_login, strlen(psb->auth_login));
626 fprintf(psb->out, "%s\r\n", reply64);
627 fflush(psb->out);
628 DEBUG(6) debugf("C: %s\n", reply64);
629 g_free(reply64);
630 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
631 if ((ok = check_response(psb, TRUE))) {
632 resp64 = get_response_arg(&(psb->buffer[4]));
633 DEBUG(5) debugf(" encoded response = %s\n", resp64);
634 resp = base64_decode(resp64, &resp_size);
635 g_free(resp64);
636 DEBUG(5) debugf(" decoded response = %s, size = %d\n", resp, resp_size);
637 g_free(resp);
638 reply64 = base64_encode(psb->auth_secret, strlen(psb->auth_secret));
639 fprintf(psb->out, "%s\r\n", reply64);
640 fflush(psb->out);
641 DEBUG(6) debugf("C: %s\n", reply64);
642 g_free(reply64);
643 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
644 ok = check_response(psb, FALSE);
645 }
646 }
647 }
648 }
649 return ok;
650 }
652 gboolean
653 smtp_out_auth(smtp_base * psb)
654 {
655 gboolean ok = FALSE;
656 gint i = 0;
657 while (psb->auth_names[i]) {
658 if (strcasecmp(psb->auth_names[i], psb->auth_name) == 0)
659 break;
660 i++;
661 }
662 if (psb->auth_names[i]) {
663 if (strcasecmp(psb->auth_name, "cram-md5") == 0) {
664 smtp_out_auth_cram_md5(psb);
665 } else if (strcasecmp(psb->auth_name, "login") == 0) {
666 smtp_out_auth_login(psb);
667 } else {
668 logwrite(LOG_ERR, "auth method %s not supported\n", psb->auth_name);
669 }
670 } else {
671 logwrite(LOG_ERR, "no auth method %s found.\n", psb->auth_name);
672 }
673 return ok;
674 }
676 #endif
678 gboolean
679 smtp_out_init(smtp_base * psb)
680 {
681 gboolean ok;
683 if ((ok = read_response(psb, SMTP_INITIAL_TIMEOUT))) {
684 if ((ok = check_init_response(psb))) {
686 if ((ok = smtp_helo(psb, psb->helo_name))) {
687 #ifdef ENABLE_AUTH
688 if (psb->auth_name && psb->use_auth) {
689 /* we completely disregard the response of server here. If
690 authentication fails, the server will complain later
691 anyway. I know, this is not polite... */
692 smtp_out_auth(psb);
693 }
694 #endif
695 }
696 }
697 }
698 if (!ok)
699 smtp_out_log_failure(psb, NULL);
700 return ok;
701 }
703 gint
704 smtp_out_msg(smtp_base * psb, message * msg, address * return_path, GList * rcpt_list, GList * hdr_list)
705 {
706 gint i, size;
707 gboolean ok = TRUE;
708 int rcpt_cnt;
709 int rcpt_accept = 0;
711 DEBUG(5) debugf("smtp_out_msg entered\n");
713 /* defaults: */
714 if (return_path == NULL)
715 return_path = msg->return_path;
716 if (hdr_list == NULL)
717 hdr_list = msg->hdr_list;
718 if (rcpt_list == NULL)
719 rcpt_list = msg->rcpt_list;
720 rcpt_cnt = g_list_length(rcpt_list);
722 size = msg_calc_size(msg, TRUE);
724 /* respect maximum size given by server: */
725 if ((psb->max_size > 0) && (size > psb->max_size)) {
726 logwrite(LOG_WARNING, "%s == host=%s message size (%d) > "
727 "fixed maximum message size of server (%d)",
728 msg->uid, psb->remote_host, size, psb->max_size);
729 psb->error = smtp_cancel;
730 ok = FALSE;
731 }
733 if (ok) {
734 /* pretend the message is a bit larger,
735 just in case the size calculation is buggy */
736 smtp_cmd_mailfrom(psb, return_path, psb->use_size ? size+SMTP_SIZE_ADD : 0);
738 if (!psb->use_pipelining) {
739 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
740 ok = check_response(psb, FALSE);
741 }
742 }
743 if (ok) {
744 GList *rcpt_node;
745 rcpt_accept = 0;
747 for (rcpt_node = g_list_first(rcpt_list); rcpt_node != NULL; rcpt_node = g_list_next(rcpt_node)) {
748 address *rcpt = (address *) (rcpt_node->data);
749 smtp_cmd_rcptto(psb, rcpt);
750 if (!psb->use_pipelining) {
751 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
752 if (check_response(psb, FALSE)) {
753 rcpt_accept++;
754 addr_mark_delivered(rcpt);
755 } else {
756 /* if server returned an error for one recp. we
757 may still try the others. But if it is a timeout, eof
758 or unexpected response, it is more serious and we should
759 give up. */
760 if ((psb->error != smtp_trylater) && (psb->error != smtp_fail)) {
761 ok = FALSE;
762 break;
763 } else {
764 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n",
765 msg->uid, addr_string(rcpt), psb->remote_host, psb->buffer);
766 if (psb->error == smtp_trylater) {
767 addr_mark_defered(rcpt);
768 } else {
769 addr_mark_failed(rcpt);
770 }
771 }
772 } else
773 break;
774 }
775 }
777 /* There is no point in going on if no recp.s were accpted.
778 But we can check that at this point only if not pipelining: */
779 ok = (ok && (psb->use_pipelining || (rcpt_accept > 0)));
780 if (ok) {
782 fprintf(psb->out, "DATA\r\n");
783 fflush(psb->out);
785 DEBUG(4) debugf("C: DATA\r\n");
787 if (psb->use_pipelining) {
788 /* the first pl'ed command was MAIL FROM
789 the last was DATA, whose response can be handled by the 'normal' code
790 all in between were RCPT TO:
791 */
792 /* response to MAIL FROM: */
793 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
794 if ((ok = check_response(psb, FALSE))) {
796 /* response(s) to RCPT TO:
797 this is very similar to the sequence above for no pipeline
798 */
799 for (i = 0; i < rcpt_cnt; i++) {
800 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
801 address *rcpt = g_list_nth_data(rcpt_list, i);
802 if (check_response(psb, FALSE)) {
803 rcpt_accept++;
804 addr_mark_delivered(rcpt);
805 } else {
806 /* if server returned an error 4xx or 5xx for one recp. we
807 may still try the others. But if it is a timeout, eof
808 or unexpected response, it is more serious and we
809 should give up. */
810 if ((psb->error != smtp_trylater) &&
811 (psb->error != smtp_fail)) {
812 ok = FALSE;
813 break;
814 } else {
815 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n", msg->uid,
816 addr_string(rcpt), psb->remote_host, psb->buffer);
817 if (psb->error == smtp_trylater) {
818 addr_mark_defered(rcpt);
819 } else {
820 addr_mark_failed(rcpt);
821 }
822 }
823 }
824 } else {
825 DEBUG(5) debugf("check_response failed after RCPT TO\n");
826 break;
827 }
828 }
829 if (rcpt_accept == 0)
830 ok = FALSE;
831 } else {
832 DEBUG(5) debugf("check_response failed after MAIL FROM\n");
833 }
834 } else {
835 DEBUG(5)
836 debugf("read_response failed after MAIL FROM\n");
837 }
838 }
840 /* if(psb->use_pipelining) */
841 /* response to the DATA cmd */
842 if (ok) {
843 if (read_response(psb, SMTP_DATA_TIMEOUT)) {
844 if (check_response(psb, TRUE)) {
845 send_header(psb, hdr_list);
846 send_data(psb, msg);
848 if (read_response(psb, SMTP_FINAL_TIMEOUT))
849 ok = check_response(psb, FALSE);
850 }
851 }
852 }
853 }
854 }
856 DEBUG(5) {
857 debugf("smtp_out_msg():\n");
858 debugf(" psb->error = %d\n", psb->error);
859 debugf(" ok = %d\n", ok);
860 debugf(" rcpt_accept = %d\n", rcpt_accept);
861 }
863 if (psb->error == smtp_ok) {
864 GList *rcpt_node;
865 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
866 address *rcpt = (address *) (rcpt_node->data);
867 if (addr_is_delivered(rcpt))
868 logwrite(LOG_NOTICE, "%s => %s host=%s with %s\n", msg->uid, addr_string(rcpt),
869 psb->remote_host, psb->use_esmtp ? "esmtp" : "smtp");
870 }
871 } else {
872 /* if something went wrong,
873 we have to unmark the rcpts prematurely marked as delivered
874 and mark the status */
875 smtp_out_mark_rcpts(psb, rcpt_list);
877 /* log the failure: */
878 smtp_out_log_failure(psb, msg);
879 }
880 return rcpt_accept;
881 }
883 gboolean
884 smtp_out_quit(smtp_base * psb)
885 {
886 fprintf(psb->out, "QUIT\r\n");
887 fflush(psb->out);
889 DEBUG(4) debugf("C: QUIT\n");
891 signal(SIGALRM, SIG_DFL);
893 return TRUE;
894 }
896 gint
897 smtp_deliver(gchar * host, gint port, GList * resolve_list, message * msg, address * return_path, GList * rcpt_list)
898 {
899 smtp_base *psb;
900 smtp_error err;
902 DEBUG(5) debugf("smtp_deliver entered\n");
904 if (return_path == NULL)
905 return_path = msg->return_path;
907 if ((psb = smtp_out_open(host, port, resolve_list))) {
908 set_heloname(psb, return_path->domain, TRUE);
909 /* initiate connection, send message and quit: */
910 if (smtp_out_init(psb)) {
911 smtp_out_msg(psb, msg, return_path, rcpt_list, NULL);
912 if (psb->error == smtp_ok || (psb->error == smtp_fail) || (psb->error == smtp_trylater)
913 || (psb->error == smtp_syntax) || (psb->error == smtp_cancel))
914 smtp_out_quit(psb);
915 }
917 err = psb->error;
918 destroy_smtpbase(psb);
920 return err;
921 }
922 return -1;
923 }