masqmail

view src/smtp_out.c @ 303:3e3c280ca5b2

replaced header_fold() with a better implementation
author markus schnalke <meillo@marmaro.de>
date Thu, 09 Dec 2010 18:01:46 -0300
parents 589c365d90b1
children c74adb7c4f50
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_size = FALSE;
125 psb->use_pipelining = FALSE;
126 psb->use_auth = FALSE;
128 psb->max_size = 0;
129 psb->auth_names = NULL;
131 psb->buffer = (gchar *) g_malloc(SMTP_BUF_LEN);
133 dup_sock = dup(sock);
134 psb->out = fdopen(sock, "w");
135 psb->in = fdopen(dup_sock, "r");
137 psb->error = smtp_ok;
139 psb->helo_name = NULL;
141 psb->auth_name = psb->auth_login = psb->auth_secret = NULL;
143 return psb;
144 }
146 static gboolean
147 read_response(smtp_base * psb, int timeout)
148 {
149 gint buf_pos = 0;
150 gchar code[5];
151 gint i, len;
153 do {
154 len = read_sockline(psb->in, &(psb->buffer[buf_pos]), SMTP_BUF_LEN - buf_pos, timeout, READSOCKL_CHUG);
155 if (len == -3) {
156 psb->error = smtp_timeout;
157 return FALSE;
158 } else if (len == -2) {
159 psb->error = smtp_syntax;
160 return FALSE;
161 } else if (len == -1) {
162 psb->error = smtp_eof;
163 return FALSE;
164 }
165 for (i = 0; i < 4; i++)
166 code[i] = psb->buffer[buf_pos + i];
167 code[i] = '\0';
168 psb->last_code = atoi(code);
170 buf_pos += len;
172 } while (code[3] == '-');
173 if (psb->buffer) {
174 DEBUG(4) debugf("S: %s\n", psb->buffer);
175 }
177 return TRUE;
178 }
180 static gboolean
181 check_response(smtp_base * psb, gboolean after_data)
182 {
183 char c = psb->buffer[0];
185 if (((c == '2') && !after_data) || ((c == '3') && after_data)) {
186 psb->error = smtp_ok;
187 DEBUG(6) debugf("response OK:'%s' after_data = %d\n", psb->buffer, (int) after_data);
188 return TRUE;
189 } else {
190 if (c == '4')
191 psb->error = smtp_trylater;
192 else if (c == '5')
193 psb->error = smtp_fail;
194 else
195 psb->error = smtp_syntax;
196 DEBUG(6) debugf("response failure:'%s' after_data = %d\n", psb->buffer, (int) after_data);
197 return FALSE;
198 }
199 }
201 static gchar*
202 get_response_arg(gchar * response)
203 {
204 gchar buf[SMTP_BUF_LEN];
205 gchar *p = response, *q = buf;
207 while (*p && (*p != '\n') && isspace(*p))
208 p++;
209 if (*p && (*p != '\n')) {
210 while (*p && (*p != '\n') && (*p != '\r') && (q < buf + SMTP_BUF_LEN - 1))
211 *(q++) = *(p++);
212 *q = '\0';
213 return g_strdup(buf);
214 }
215 return NULL;
216 }
218 static gboolean
219 check_helo_response(smtp_base * psb)
220 {
221 gchar *ptr;
223 if (!check_response(psb, FALSE))
224 return FALSE;
226 if (psb->last_code == 220) {
227 logwrite(LOG_NOTICE, "received a 220 greeting after sending EHLO,\n");
228 logwrite(LOG_NOTICE, "please remove `instant_helo' from your route config\n");
229 /* read the next response, cause that's the actual helo response */
230 if (!read_response(psb, SMTP_CMD_TIMEOUT) || !check_response(psb, FALSE)) {
231 return FALSE;
232 }
233 }
235 ptr = psb->buffer;
237 while (*ptr) {
238 if (strncasecmp(&(ptr[4]), "SIZE", 4) == 0) {
239 gchar *arg;
240 psb->use_size = TRUE;
241 arg = get_response_arg(&(ptr[8]));
242 if (arg) {
243 psb->max_size = atoi(arg);
244 g_free(arg);
245 }
246 }
248 if (strncasecmp(&(ptr[4]), "PIPELINING", 10) == 0)
249 psb->use_pipelining = TRUE;
251 if (strncasecmp(&(ptr[4]), "AUTH", 4) == 0) {
252 if ((ptr[8] == ' ') || (ptr[8] == '=') || (ptr[8] == '\t')) { /* not sure about '\t' */
253 gchar *arg;
254 psb->use_auth = TRUE;
255 arg = get_response_arg(&(ptr[9])); /* after several years I finally learnt to count */
256 if (arg) {
257 psb->auth_names = g_strsplit(arg, " ", 0);
258 g_free(arg);
260 DEBUG(4) {
261 gint i = 0;
262 debugf("in check_helo_response()\n");
263 while (psb->auth_names[i]) {
264 debugf(" offered AUTH %s\n", psb->auth_names[i]);
265 i++;
266 }
267 }
268 }
269 }
270 }
272 while (*ptr != '\n')
273 ptr++;
274 ptr++;
275 }
277 DEBUG(4) {
278 debugf(" %s\n", psb->use_size ? "uses SIZE" : "no size");
279 debugf(" %s\n", psb->use_pipelining ? "uses PIPELINING" : "no pipelining");
280 debugf(" %s\n", psb->use_auth ? "uses AUTH" : "no auth");
281 }
283 return TRUE;
284 }
286 /*
287 We first try EHLO, but if it fails HELO in a second fall back try.
288 This is what is requested by RFC 2821 (sec 3.2):
290 Once the server has sent the welcoming message and
291 the client has received it, the client normally sends
292 the EHLO command to the server, [...]
293 For a particular connection attempt, if the server
294 returns a "command not recognized" response to EHLO,
295 the client SHOULD be able to fall back and send HELO.
297 Up to and including version 0.3.0 masqmail used ESMTP only if the
298 string ``ESMTP'' appeared within the server's greeting message. This
299 made it impossible to use AUTH with servers that would send odd
300 greeting messages.
301 */
302 static gboolean
303 smtp_helo(smtp_base * psb, gchar * helo)
304 {
305 fprintf(psb->out, "EHLO %s\r\n", helo);
306 fflush(psb->out);
307 DEBUG(4) debugf("C: EHLO %s\r\n", helo);
309 if (!read_response(psb, SMTP_CMD_TIMEOUT)) {
310 return FALSE;
311 }
312 if (check_helo_response(psb)) {
313 DEBUG(4) debugf("uses esmtp\n");
314 return TRUE;
315 }
317 if (psb->error != smtp_fail) {
318 return FALSE;
319 }
321 /* our guess that server understands EHLO could have been wrong,
322 try again with HELO */
324 fprintf(psb->out, "HELO %s\r\n", helo);
325 fflush(psb->out);
326 DEBUG(4) debugf("C: HELO %s\r\n", helo);
328 if (!read_response(psb, SMTP_CMD_TIMEOUT)) {
329 return FALSE;
330 }
331 if (check_helo_response(psb)) {
332 DEBUG(4) debugf("uses smtp\n");
333 return TRUE;
334 }
336 /* what sort of server ist THAT ?! give up... */
337 return FALSE;
338 }
340 static void
341 smtp_cmd_mailfrom(smtp_base * psb, address * return_path, guint size)
342 {
343 if (psb->use_size) {
344 fprintf(psb->out, "MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
345 fflush(psb->out);
347 DEBUG(4) debugf("C: MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
349 } else {
350 fprintf(psb->out, "MAIL FROM:%s\r\n", addr_string(return_path));
351 fflush(psb->out);
353 DEBUG(4) debugf("C: MAIL FROM:%s\r\n", addr_string(return_path));
354 }
355 }
357 static void
358 smtp_cmd_rcptto(smtp_base * psb, address * rcpt)
359 {
360 fprintf(psb->out, "RCPT TO:%s\r\n", addr_string(rcpt));
361 fflush(psb->out);
362 DEBUG(4) debugf("C: RCPT TO:%s\n", addr_string(rcpt));
363 }
365 static void
366 send_data_line(smtp_base * psb, gchar * data)
367 {
368 /* According to RFC 821 each line should be terminated with CRLF.
369 Since a dot on a line itself marks the end of data, each line
370 beginning with a dot is prepended with another dot.
371 */
372 gchar *ptr;
373 gboolean new_line = TRUE; /* previous versions assumed that each item was exactly one line.
374 This is no longer the case */
376 ptr = data;
377 while (*ptr) {
378 int c = (int) (*ptr);
379 if (c == '.' && new_line) {
380 /* dot-stuffing */
381 putc('.', psb->out);
382 }
383 if (c == '\n') {
384 /* CRLF line terminators */
385 putc('\r', psb->out);
386 putc('\n', psb->out);
387 new_line = TRUE;
388 } else {
389 putc(c, psb->out);
390 new_line = FALSE;
391 }
392 ptr++;
393 }
394 }
396 static void
397 send_header(smtp_base * psb, GList * hdr_list)
398 {
399 GList *node;
400 gint num_hdrs = 0;
402 /* header */
403 if (hdr_list) {
404 foreach(hdr_list, node) {
405 if (node->data) {
406 header *hdr = (header *) (node->data);
407 if (hdr->header) {
408 send_data_line(psb, hdr->header);
409 num_hdrs++;
410 }
411 }
412 }
413 }
415 /* empty line separating headers from data: */
416 putc('\r', psb->out);
417 putc('\n', psb->out);
419 DEBUG(4) debugf("sent %d headers\n", num_hdrs);
420 }
422 static void
423 send_data(smtp_base * psb, message * msg)
424 {
425 GList *node;
426 gint num_lines = 0;
428 /* data */
429 if (msg->data_list) {
430 for (node = g_list_first(msg->data_list); node; node = g_list_next(node)) {
431 if (node->data) {
432 send_data_line(psb, node->data);
433 num_lines++;
434 }
435 }
436 }
438 DEBUG(4) debugf("sent %d lines of data\n", num_lines);
440 fprintf(psb->out, ".\r\n");
441 fflush(psb->out);
442 DEBUG(4) debugf("C: .\n");
443 }
445 void
446 smtp_out_mark_rcpts(smtp_base * psb, GList * rcpt_list)
447 {
448 GList *rcpt_node;
449 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
450 address *rcpt = (address *) (rcpt_node->data);
452 addr_unmark_delivered(rcpt);
454 if ((psb->error == smtp_trylater) || (psb->error == smtp_timeout) || (psb->error == smtp_eof)) {
455 addr_mark_defered(rcpt);
456 } else {
457 addr_mark_failed(rcpt);
458 }
459 }
460 }
462 void
463 smtp_out_log_failure(smtp_base * psb, message * msg)
464 {
465 gchar *err_str;
467 if (psb->error == smtp_timeout)
468 err_str = g_strdup("connection timed out.");
469 else if (psb->error == smtp_eof)
470 err_str = g_strdup("connection terminated prematurely.");
471 else if (psb->error == smtp_syntax)
472 err_str = g_strdup_printf("got unexpected response: %s", psb->buffer);
473 else if (psb->error == smtp_cancel)
474 err_str = g_strdup("delivery was canceled.\n");
475 else
476 /* error message should still be in the buffer */
477 err_str = g_strdup_printf("failed: %s\n", psb->buffer);
479 if (msg == NULL)
480 logwrite(LOG_NOTICE, "host=%s %s\n", psb->remote_host, err_str);
481 else
482 logwrite(LOG_NOTICE, "%s == host=%s %s\n", msg->uid, psb->remote_host, err_str);
484 g_free(err_str);
485 }
487 smtp_base*
488 smtp_out_open(gchar * host, gint port, GList * resolve_list)
489 {
490 smtp_base *psb;
491 gint sock;
492 mxip_addr *addr;
494 DEBUG(5) debugf("smtp_out_open entered, host = %s\n", host);
496 if ((addr = connect_resolvelist(&sock, host, port, resolve_list))) {
497 /* create structure to hold status data: */
498 psb = create_smtpbase(sock);
499 psb->remote_host = addr->name;
501 DEBUG(5) {
502 struct sockaddr_in name;
503 int len = sizeof(struct sockaddr);
504 getsockname(sock, (struct sockaddr *) (&name), &len);
505 debugf("socket: name.sin_addr = %s\n", inet_ntoa(name.sin_addr));
506 }
507 return psb;
508 } else {
509 DEBUG(5) debugf("connect_resolvelist failed: %s %s\n", strerror(errno), hstrerror(h_errno));
510 }
512 return NULL;
513 }
515 smtp_base*
516 smtp_out_open_child(gchar * cmd)
517 {
518 smtp_base *psb;
519 gint sock;
521 DEBUG(5) debugf("smtp_out_open_child entered, cmd = %s\n", cmd);
523 sock = child(cmd);
525 if (sock > 0) {
526 psb = create_smtpbase(sock);
527 psb->remote_host = NULL;
529 return psb;
530 }
532 return NULL;
533 }
535 gboolean
536 smtp_out_rset(smtp_base * psb)
537 {
538 gboolean ok;
540 fprintf(psb->out, "RSET\r\n");
541 fflush(psb->out);
542 DEBUG(4) debugf("C: RSET\n");
544 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
545 if (check_response(psb, FALSE))
546 return TRUE;
548 smtp_out_log_failure(psb, NULL);
550 return FALSE;
551 }
553 #ifdef ENABLE_AUTH
555 static gboolean
556 smtp_out_auth_cram_md5(smtp_base * psb)
557 {
558 gboolean ok = FALSE;
560 fprintf(psb->out, "C: AUTH CRAM-MD5\r\n");
561 fflush(psb->out);
562 DEBUG(4) debugf("AUTH CRAM-MD5\n");
563 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
564 if ((ok = check_response(psb, TRUE))) {
565 gchar *chall64 = get_response_arg(&(psb->buffer[4]));
566 gint chall_size;
567 gchar *chall = base64_decode(chall64, &chall_size);
568 guchar digest[16], *reply64, *reply;
569 gchar digest_string[33];
570 gint i;
571 #ifdef USE_LIB_CRYPTO
572 unsigned int digest_len;
573 #endif
575 DEBUG(5) debugf("smtp_out_auth_cram_md5():\n");
576 DEBUG(5) debugf(" encoded challenge = %s\n", chall64);
577 DEBUG(5) debugf(" decoded challenge = %s, size = %d\n", chall, chall_size);
578 DEBUG(5) debugf(" secret = %s\n", psb->auth_secret);
580 #ifdef USE_LIB_CRYPTO
581 HMAC(EVP_md5(), psb->auth_secret, strlen(psb->auth_secret), chall, chall_size, digest, &digest_len);
582 #else
583 hmac_md5(chall, chall_size, psb->auth_secret, strlen(psb->auth_secret), digest);
584 #endif
586 for (i = 0; i < 16; i++)
587 sprintf(&(digest_string[i + i]), "%02x", (unsigned int) (digest[i]));
588 digest_string[32] = '\0';
590 DEBUG(5) debugf(" digest = %s\n", digest_string);
592 reply = g_strdup_printf("%s %s", psb->auth_login, digest_string);
593 DEBUG(5) debugf(" unencoded reply = %s\n", reply);
595 reply64 = base64_encode(reply, strlen(reply));
596 DEBUG(5) debugf(" encoded reply = %s\n", reply64);
598 fprintf(psb->out, "%s\r\n", reply64);
599 fflush(psb->out);
600 DEBUG(6) debugf(" reply64 = %s\n", reply64);
601 DEBUG(6) debugf("C: %s\n", reply64);
603 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
604 ok = check_response(psb, FALSE);
606 g_free(reply64);
607 g_free(reply);
608 g_free(chall);
609 g_free(chall64);
610 }
611 }
612 return ok;
613 }
615 static gboolean
616 smtp_out_auth_login(smtp_base * psb)
617 {
618 gboolean ok = FALSE;
619 fprintf(psb->out, "AUTH LOGIN\r\n");
620 fflush(psb->out);
621 DEBUG(4) debugf("C: AUTH LOGIN\r\n");
622 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
623 if ((ok = check_response(psb, TRUE))) {
624 gchar *resp64;
625 guchar *resp;
626 gint resp_size;
627 gchar *reply64;
629 DEBUG(5) debugf("smtp_out_auth_login():\n");
630 resp64 = get_response_arg(&(psb->buffer[4]));
631 DEBUG(5) debugf(" encoded response = %s\n", resp64);
632 resp = base64_decode(resp64, &resp_size);
633 g_free(resp64);
634 DEBUG(5) debugf(" decoded response = %s, size = %d\n", resp, resp_size);
635 g_free(resp);
636 reply64 = base64_encode(psb->auth_login, strlen(psb->auth_login));
637 fprintf(psb->out, "%s\r\n", reply64);
638 fflush(psb->out);
639 DEBUG(6) debugf("C: %s\n", reply64);
640 g_free(reply64);
641 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
642 if ((ok = check_response(psb, TRUE))) {
643 resp64 = get_response_arg(&(psb->buffer[4]));
644 DEBUG(5) debugf(" encoded response = %s\n", resp64);
645 resp = base64_decode(resp64, &resp_size);
646 g_free(resp64);
647 DEBUG(5) debugf(" decoded response = %s, size = %d\n", resp, resp_size);
648 g_free(resp);
649 reply64 = base64_encode(psb->auth_secret, strlen(psb->auth_secret));
650 fprintf(psb->out, "%s\r\n", reply64);
651 fflush(psb->out);
652 DEBUG(6) debugf("C: %s\n", reply64);
653 g_free(reply64);
654 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
655 ok = check_response(psb, FALSE);
656 }
657 }
658 }
659 }
660 return ok;
661 }
663 gboolean
664 smtp_out_auth(smtp_base * psb)
665 {
666 gboolean ok = FALSE;
667 gint i = 0;
668 while (psb->auth_names[i]) {
669 if (strcasecmp(psb->auth_names[i], psb->auth_name) == 0)
670 break;
671 i++;
672 }
673 if (psb->auth_names[i]) {
674 if (strcasecmp(psb->auth_name, "cram-md5") == 0) {
675 smtp_out_auth_cram_md5(psb);
676 } else if (strcasecmp(psb->auth_name, "login") == 0) {
677 smtp_out_auth_login(psb);
678 } else {
679 logwrite(LOG_ERR, "auth method %s not supported\n", psb->auth_name);
680 }
681 } else {
682 logwrite(LOG_ERR, "no auth method %s found.\n", psb->auth_name);
683 }
684 return ok;
685 }
687 #endif
689 gboolean
690 smtp_out_init(smtp_base * psb, gboolean instant_helo)
691 {
692 gboolean ok;
694 logwrite(LOG_INFO, "smtp_out_init(): instant_helo:%d\n", instant_helo);
696 if (!instant_helo) {
697 if ((ok = read_response(psb, SMTP_INITIAL_TIMEOUT))) {
698 ok = check_response(psb, FALSE);
699 }
700 if (!ok) {
701 smtp_out_log_failure(psb, NULL);
702 return ok;
703 }
704 }
706 if ((ok = smtp_helo(psb, psb->helo_name))) {
707 #ifdef ENABLE_AUTH
708 if (psb->auth_name && psb->use_auth) {
709 /* we completely disregard the response of server here. If
710 authentication fails, the server will complain later
711 anyway. I know, this is not polite... */
712 smtp_out_auth(psb);
713 }
714 #endif
715 }
716 if (!ok)
717 smtp_out_log_failure(psb, NULL);
718 return ok;
719 }
721 gint
722 smtp_out_msg(smtp_base * psb, message * msg, address * return_path, GList * rcpt_list, GList * hdr_list)
723 {
724 gint i, size;
725 gboolean ok = TRUE;
726 int rcpt_cnt;
727 int rcpt_accept = 0;
729 DEBUG(5) debugf("smtp_out_msg entered\n");
731 /* defaults: */
732 if (return_path == NULL)
733 return_path = msg->return_path;
734 if (hdr_list == NULL)
735 hdr_list = msg->hdr_list;
736 if (rcpt_list == NULL)
737 rcpt_list = msg->rcpt_list;
738 rcpt_cnt = g_list_length(rcpt_list);
740 size = msg_calc_size(msg, TRUE);
742 /* respect maximum size given by server: */
743 if ((psb->max_size > 0) && (size > psb->max_size)) {
744 logwrite(LOG_WARNING, "%s == host=%s message size (%d) > "
745 "fixed maximum message size of server (%d)",
746 msg->uid, psb->remote_host, size, psb->max_size);
747 psb->error = smtp_cancel;
748 ok = FALSE;
749 }
751 if (ok) {
752 /* pretend the message is a bit larger,
753 just in case the size calculation is buggy */
754 smtp_cmd_mailfrom(psb, return_path, psb->use_size ? size+SMTP_SIZE_ADD : 0);
756 if (!psb->use_pipelining) {
757 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
758 ok = check_response(psb, FALSE);
759 }
760 }
761 if (ok) {
762 GList *rcpt_node;
763 rcpt_accept = 0;
765 for (rcpt_node = g_list_first(rcpt_list); rcpt_node != NULL; rcpt_node = g_list_next(rcpt_node)) {
766 address *rcpt = (address *) (rcpt_node->data);
767 smtp_cmd_rcptto(psb, rcpt);
768 if (!psb->use_pipelining) {
769 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
770 if (check_response(psb, FALSE)) {
771 rcpt_accept++;
772 addr_mark_delivered(rcpt);
773 } else {
774 /* if server returned an error for one recp. we
775 may still try the others. But if it is a timeout, eof
776 or unexpected response, it is more serious and we should
777 give up. */
778 if ((psb->error != smtp_trylater) && (psb->error != smtp_fail)) {
779 ok = FALSE;
780 break;
781 } else {
782 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n",
783 msg->uid, addr_string(rcpt), psb->remote_host, psb->buffer);
784 if (psb->error == smtp_trylater) {
785 addr_mark_defered(rcpt);
786 } else {
787 addr_mark_failed(rcpt);
788 }
789 }
790 } else
791 break;
792 }
793 }
795 /* There is no point in going on if no recp.s were accpted.
796 But we can check that at this point only if not pipelining: */
797 ok = (ok && (psb->use_pipelining || (rcpt_accept > 0)));
798 if (ok) {
800 fprintf(psb->out, "DATA\r\n");
801 fflush(psb->out);
803 DEBUG(4) debugf("C: DATA\r\n");
805 if (psb->use_pipelining) {
806 /* the first pl'ed command was MAIL FROM
807 the last was DATA, whose response can be handled by the 'normal' code
808 all in between were RCPT TO:
809 */
810 /* response to MAIL FROM: */
811 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
812 if ((ok = check_response(psb, FALSE))) {
814 /* response(s) to RCPT TO:
815 this is very similar to the sequence above for no pipeline
816 */
817 for (i = 0; i < rcpt_cnt; i++) {
818 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
819 address *rcpt = g_list_nth_data(rcpt_list, i);
820 if (check_response(psb, FALSE)) {
821 rcpt_accept++;
822 addr_mark_delivered(rcpt);
823 } else {
824 /* if server returned an error 4xx or 5xx for one recp. we
825 may still try the others. But if it is a timeout, eof
826 or unexpected response, it is more serious and we
827 should give up. */
828 if ((psb->error != smtp_trylater) &&
829 (psb->error != smtp_fail)) {
830 ok = FALSE;
831 break;
832 } else {
833 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n", msg->uid,
834 addr_string(rcpt), psb->remote_host, psb->buffer);
835 if (psb->error == smtp_trylater) {
836 addr_mark_defered(rcpt);
837 } else {
838 addr_mark_failed(rcpt);
839 }
840 }
841 }
842 } else {
843 DEBUG(5) debugf("check_response failed after RCPT TO\n");
844 break;
845 }
846 }
847 if (rcpt_accept == 0)
848 ok = FALSE;
849 } else {
850 DEBUG(5) debugf("check_response failed after MAIL FROM\n");
851 }
852 } else {
853 DEBUG(5)
854 debugf("read_response failed after MAIL FROM\n");
855 }
856 }
858 /* if(psb->use_pipelining) */
859 /* response to the DATA cmd */
860 if (ok) {
861 if (read_response(psb, SMTP_DATA_TIMEOUT)) {
862 if (check_response(psb, TRUE)) {
863 send_header(psb, hdr_list);
864 send_data(psb, msg);
866 if (read_response(psb, SMTP_FINAL_TIMEOUT))
867 ok = check_response(psb, FALSE);
868 }
869 }
870 }
871 }
872 }
874 DEBUG(5) {
875 debugf("smtp_out_msg():\n");
876 debugf(" psb->error = %d\n", psb->error);
877 debugf(" ok = %d\n", ok);
878 debugf(" rcpt_accept = %d\n", rcpt_accept);
879 }
881 if (psb->error == smtp_ok) {
882 GList *rcpt_node;
883 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
884 address *rcpt = (address *) (rcpt_node->data);
885 if (addr_is_delivered(rcpt))
886 logwrite(LOG_NOTICE, "%s => %s host=%s\n",
887 msg->uid, addr_string(rcpt), psb->remote_host);
888 }
889 } else {
890 /* if something went wrong,
891 we have to unmark the rcpts prematurely marked as delivered
892 and mark the status */
893 smtp_out_mark_rcpts(psb, rcpt_list);
895 /* log the failure: */
896 smtp_out_log_failure(psb, msg);
897 }
898 return rcpt_accept;
899 }
901 gboolean
902 smtp_out_quit(smtp_base * psb)
903 {
904 fprintf(psb->out, "QUIT\r\n");
905 fflush(psb->out);
907 DEBUG(4) debugf("C: QUIT\n");
909 signal(SIGALRM, SIG_DFL);
911 return TRUE;
912 }
914 gint
915 smtp_deliver(gchar * host, gint port, GList * resolve_list, message * msg, address * return_path, GList * rcpt_list)
916 {
917 smtp_base *psb;
918 smtp_error err;
920 DEBUG(5) debugf("smtp_deliver entered\n");
922 if (return_path == NULL)
923 return_path = msg->return_path;
925 if ((psb = smtp_out_open(host, port, resolve_list))) {
926 set_heloname(psb, return_path->domain, TRUE);
927 /* initiate connection, send message and quit: */
928 if (smtp_out_init(psb, FALSE)) {
929 smtp_out_msg(psb, msg, return_path, rcpt_list, NULL);
930 if (psb->error == smtp_ok || (psb->error == smtp_fail) || (psb->error == smtp_trylater)
931 || (psb->error == smtp_syntax) || (psb->error == smtp_cancel))
932 smtp_out_quit(psb);
933 }
935 err = psb->error;
936 destroy_smtpbase(psb);
938 return err;
939 }
940 return -1;
941 }