masqmail
view src/smtp_out.c @ 227:cab46cefa4ce
renamed contrib/ to admin/
because the contents are for system admins
and possibly for advanced users too
author | meillo@marmaro.de |
---|---|
date | Fri, 23 Jul 2010 11:49:44 +0200 |
parents | 996b53a50f55 |
children | 4cff8638dd9b |
line source
1 /* smtp_out.c
2 Copyright (C) 1999-2001 Oliver Kurth
3 Copyright (C) 2010 markus schnalke <meillo@marmaro.de>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
20 /*
21 I always forget these rfc numbers:
22 RFC 821 (SMTP)
23 RFC 1869 (ESMTP)
24 RFC 1870 (ESMTP SIZE)
25 RFC 2197 (ESMTP PIPELINE)
26 RFC 2554 (ESMTP AUTH)
27 */
29 #include "masqmail.h"
30 #include "smtp_out.h"
31 #include "readsock.h"
33 #ifdef ENABLE_AUTH
35 #ifdef USE_LIB_CRYPTO
36 #include <openssl/hmac.h>
37 #include <openssl/md5.h>
38 #include <openssl/evp.h>
39 #else
40 #include "md5/md5.h"
41 #include "md5/hmac_md5.h"
42 #endif
44 #include "base64/base64.h"
45 #endif
47 void
48 destroy_smtpbase(smtp_base * psb)
49 {
50 fclose(psb->in);
51 fclose(psb->out);
53 close(psb->sock);
55 if (psb->helo_name)
56 g_free(psb->helo_name);
57 if (psb->buffer)
58 g_free(psb->buffer);
59 if (psb->auth_names)
60 g_strfreev(psb->auth_names);
62 if (psb->auth_name)
63 g_free(psb->auth_name);
64 if (psb->auth_login)
65 g_free(psb->auth_login);
66 if (psb->auth_secret)
67 g_free(psb->auth_secret);
68 }
70 gchar*
71 set_heloname(smtp_base * psb, gchar * default_name, gboolean do_correct)
72 {
73 struct sockaddr_in sname;
74 int len = sizeof(struct sockaddr_in);
75 struct hostent *host_entry;
77 if (do_correct) {
78 getsockname(psb->sock, (struct sockaddr *) (&sname), &len);
79 DEBUG(5) debugf("socket: name.sin_addr = %s\n", inet_ntoa(sname.sin_addr));
80 host_entry = gethostbyaddr((const char *) &(sname.sin_addr), sizeof(sname.sin_addr), AF_INET);
81 if (host_entry) {
82 psb->helo_name = g_strdup(host_entry->h_name);
83 } else {
84 /* we failed to look up our own name. Instead of giving our local hostname,
85 we may give our IP number to show the server that we are at least
86 willing to be honest. For the really picky ones. */
87 DEBUG(5) debugf("failed to look up own host name.\n");
88 psb->helo_name = g_strdup_printf("[%s]", inet_ntoa(sname.sin_addr));
89 }
90 DEBUG(5) debugf("helo_name = %s\n", psb->helo_name);
91 }
92 if (psb->helo_name == NULL) {
93 psb->helo_name = g_strdup(default_name);
94 }
95 return psb->helo_name;
96 }
98 #ifdef ENABLE_AUTH
100 gboolean
101 set_auth(smtp_base * psb, gchar * name, gchar * login, gchar * secret)
102 {
103 if ((strcasecmp(name, "CRAM-MD5") == 0) || (strcasecmp(name, "LOGIN") == 0)) {
104 psb->auth_name = g_strdup(name);
105 psb->auth_login = g_strdup(login);
106 psb->auth_secret = g_strdup(secret);
108 return TRUE;
109 }
110 return FALSE;
111 }
113 #endif
115 static smtp_base*
116 create_smtpbase(gint sock)
117 {
118 gint dup_sock;
120 smtp_base *psb = (smtp_base *) g_malloc(sizeof(smtp_base));
122 psb->sock = sock;
124 psb->use_esmtp = FALSE;
125 psb->use_size = FALSE;
126 psb->use_pipelining = FALSE;
127 psb->use_auth = FALSE;
129 psb->max_size = 0;
130 psb->auth_names = NULL;
132 psb->buffer = (gchar *) g_malloc(SMTP_BUF_LEN);
134 dup_sock = dup(sock);
135 psb->out = fdopen(sock, "w");
136 psb->in = fdopen(dup_sock, "r");
138 psb->error = smtp_ok;
140 psb->helo_name = NULL;
142 psb->auth_name = psb->auth_login = psb->auth_secret = NULL;
144 return psb;
145 }
147 static gboolean
148 read_response(smtp_base * psb, int timeout)
149 {
150 gint buf_pos = 0;
151 gchar code[5];
152 gint i, len;
154 do {
155 len = read_sockline(psb->in, &(psb->buffer[buf_pos]), SMTP_BUF_LEN - buf_pos, timeout, READSOCKL_CHUG);
156 if (len == -3) {
157 psb->error = smtp_timeout;
158 return FALSE;
159 } else if (len == -2) {
160 psb->error = smtp_syntax;
161 return FALSE;
162 } else if (len == -1) {
163 psb->error = smtp_eof;
164 return FALSE;
165 }
166 for (i = 0; i < 4; i++)
167 code[i] = psb->buffer[buf_pos + i];
168 code[i] = '\0';
169 psb->last_code = atoi(code);
171 buf_pos += len;
173 } while (code[3] == '-');
174 if (psb->buffer) {
175 DEBUG(4) debugf("S: %s\n", psb->buffer);
176 }
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_data = %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_data = %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;
237 if (!check_response(psb, FALSE))
238 return FALSE;
240 if (psb->last_code == 220) {
241 logwrite(LOG_NOTICE, "received a 220 greeting after sending EHLO,\n");
242 logwrite(LOG_NOTICE, "please remove `instant_helo' from your route config\n");
243 /* read the next response, cause that's the actual helo response */
244 if (!read_response(psb, SMTP_CMD_TIMEOUT) || !check_response(psb, FALSE)) {
245 return FALSE;
246 }
247 }
249 ptr = psb->buffer;
251 while (*ptr) {
252 if (strncasecmp(&(ptr[4]), "SIZE", 4) == 0) {
253 gchar *arg;
254 psb->use_size = TRUE;
255 arg = get_response_arg(&(ptr[8]));
256 if (arg) {
257 psb->max_size = atoi(arg);
258 g_free(arg);
259 }
260 }
262 if (strncasecmp(&(ptr[4]), "PIPELINING", 10) == 0)
263 psb->use_pipelining = TRUE;
265 if (strncasecmp(&(ptr[4]), "AUTH", 4) == 0) {
266 if ((ptr[8] == ' ') || (ptr[8] == '=') || (ptr[8] == '\t')) { /* not sure about '\t' */
267 gchar *arg;
268 psb->use_auth = TRUE;
269 arg = get_response_arg(&(ptr[9])); /* after several years I finally learnt to count */
270 if (arg) {
271 psb->auth_names = g_strsplit(arg, " ", 0);
272 g_free(arg);
274 DEBUG(4) {
275 gint i = 0;
276 debugf("in check_helo_response()\n");
277 while (psb->auth_names[i]) {
278 debugf(" offered AUTH %s\n", psb->auth_names[i]);
279 i++;
280 }
281 }
282 }
283 }
284 }
286 while (*ptr != '\n')
287 ptr++;
288 ptr++;
289 }
291 DEBUG(4) {
292 debugf(" %s\n", psb->use_size ? "uses SIZE" : "no size");
293 debugf(" %s\n", psb->use_pipelining ? "uses PIPELINING" : "no pipelining");
294 debugf(" %s\n", psb->use_auth ? "uses AUTH" : "no auth");
295 }
297 return TRUE;
298 }
300 static gboolean
301 smtp_helo(smtp_base * psb, gchar * helo)
302 {
303 while (TRUE) {
304 if (psb->use_esmtp) {
305 fprintf(psb->out, "EHLO %s\r\n", helo);
306 fflush(psb->out);
308 DEBUG(4) debugf("C: EHLO %s\r\n", helo);
310 } else {
311 fprintf(psb->out, "HELO %s\r\n", helo);
312 fflush(psb->out);
314 DEBUG(4) debugf("C: HELO %s\r\n", helo);
316 }
318 if (!read_response(psb, SMTP_CMD_TIMEOUT))
319 return FALSE;
321 if (check_helo_response(psb))
322 return TRUE;
323 else {
324 if (psb->error == smtp_fail) {
325 if (psb->use_esmtp) {
326 /* our guess that server understands EHLO was wrong, try again with HELO */
327 psb->use_esmtp = FALSE;
328 } else {
329 /* what sort of server ist THAT ?! give up... */
330 return FALSE;
331 }
332 } else
333 return FALSE;
334 }
335 }
336 }
338 static void
339 smtp_cmd_mailfrom(smtp_base * psb, address * return_path, guint size)
340 {
341 if (psb->use_size) {
342 fprintf(psb->out, "MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
343 fflush(psb->out);
345 DEBUG(4) debugf("C: MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
347 } else {
348 fprintf(psb->out, "MAIL FROM:%s\r\n", addr_string(return_path));
349 fflush(psb->out);
351 DEBUG(4) debugf("C: MAIL FROM:%s\r\n", addr_string(return_path));
352 }
353 }
355 static void
356 smtp_cmd_rcptto(smtp_base * psb, address * rcpt)
357 {
358 fprintf(psb->out, "RCPT TO:%s\r\n", addr_string(rcpt));
359 fflush(psb->out);
360 DEBUG(4) debugf("C: RCPT TO:%s\n", addr_string(rcpt));
361 }
363 static void
364 send_data_line(smtp_base * psb, gchar * data)
365 {
366 /* According to RFC 821 each line should be terminated with CRLF.
367 Since a dot on a line itself marks the end of data, each line
368 beginning with a dot is prepended with another dot.
369 */
370 gchar *ptr;
371 gboolean new_line = TRUE; /* previous versions assumed that each item was exactly one line.
372 This is no longer the case */
374 ptr = data;
375 while (*ptr) {
376 int c = (int) (*ptr);
377 if (c == '.' && new_line) {
378 /* dot-stuffing */
379 putc('.', psb->out);
380 }
381 if (c == '\n') {
382 /* CRLF line terminators */
383 putc('\r', psb->out);
384 putc('\n', psb->out);
385 new_line = TRUE;
386 } else {
387 putc(c, psb->out);
388 new_line = FALSE;
389 }
390 ptr++;
391 }
392 }
394 static void
395 send_header(smtp_base * psb, GList * hdr_list)
396 {
397 GList *node;
398 gint num_hdrs = 0;
400 /* header */
401 if (hdr_list) {
402 foreach(hdr_list, node) {
403 if (node->data) {
404 header *hdr = (header *) (node->data);
405 if (hdr->header) {
406 send_data_line(psb, hdr->header);
407 num_hdrs++;
408 }
409 }
410 }
411 }
413 /* empty line separating headers from data: */
414 putc('\r', psb->out);
415 putc('\n', psb->out);
417 DEBUG(4) debugf("sent %d headers\n", num_hdrs);
418 }
420 static void
421 send_data(smtp_base * psb, message * msg)
422 {
423 GList *node;
424 gint num_lines = 0;
426 /* data */
427 if (msg->data_list) {
428 for (node = g_list_first(msg->data_list); node; node = g_list_next(node)) {
429 if (node->data) {
430 send_data_line(psb, node->data);
431 num_lines++;
432 }
433 }
434 }
436 DEBUG(4) debugf("sent %d lines of data\n", num_lines);
438 fprintf(psb->out, ".\r\n");
439 fflush(psb->out);
440 DEBUG(4) debugf("C: .\n");
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("C: 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, "C: 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(6) debugf(" reply64 = %s\n", reply64);
599 DEBUG(6) debugf("C: %s\n", reply64);
601 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
602 ok = check_response(psb, FALSE);
604 g_free(reply64);
605 g_free(reply);
606 g_free(chall);
607 g_free(chall64);
608 }
609 }
610 return ok;
611 }
613 static gboolean
614 smtp_out_auth_login(smtp_base * psb)
615 {
616 gboolean ok = FALSE;
617 fprintf(psb->out, "AUTH LOGIN\r\n");
618 fflush(psb->out);
619 DEBUG(4) debugf("C: AUTH LOGIN\r\n");
620 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
621 if ((ok = check_response(psb, TRUE))) {
622 gchar *resp64;
623 guchar *resp;
624 gint resp_size;
625 gchar *reply64;
627 DEBUG(5) debugf("smtp_out_auth_login():\n");
628 resp64 = get_response_arg(&(psb->buffer[4]));
629 DEBUG(5) debugf(" encoded response = %s\n", resp64);
630 resp = base64_decode(resp64, &resp_size);
631 g_free(resp64);
632 DEBUG(5) debugf(" decoded response = %s, size = %d\n", resp, resp_size);
633 g_free(resp);
634 reply64 = base64_encode(psb->auth_login, strlen(psb->auth_login));
635 fprintf(psb->out, "%s\r\n", reply64);
636 fflush(psb->out);
637 DEBUG(6) debugf("C: %s\n", reply64);
638 g_free(reply64);
639 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
640 if ((ok = check_response(psb, TRUE))) {
641 resp64 = get_response_arg(&(psb->buffer[4]));
642 DEBUG(5) debugf(" encoded response = %s\n", resp64);
643 resp = base64_decode(resp64, &resp_size);
644 g_free(resp64);
645 DEBUG(5) debugf(" decoded response = %s, size = %d\n", resp, resp_size);
646 g_free(resp);
647 reply64 = base64_encode(psb->auth_secret, strlen(psb->auth_secret));
648 fprintf(psb->out, "%s\r\n", reply64);
649 fflush(psb->out);
650 DEBUG(6) debugf("C: %s\n", reply64);
651 g_free(reply64);
652 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
653 ok = check_response(psb, FALSE);
654 }
655 }
656 }
657 }
658 return ok;
659 }
661 gboolean
662 smtp_out_auth(smtp_base * psb)
663 {
664 gboolean ok = FALSE;
665 gint i = 0;
666 while (psb->auth_names[i]) {
667 if (strcasecmp(psb->auth_names[i], psb->auth_name) == 0)
668 break;
669 i++;
670 }
671 if (psb->auth_names[i]) {
672 if (strcasecmp(psb->auth_name, "cram-md5") == 0) {
673 smtp_out_auth_cram_md5(psb);
674 } else if (strcasecmp(psb->auth_name, "login") == 0) {
675 smtp_out_auth_login(psb);
676 } else {
677 logwrite(LOG_ERR, "auth method %s not supported\n", psb->auth_name);
678 }
679 } else {
680 logwrite(LOG_ERR, "no auth method %s found.\n", psb->auth_name);
681 }
682 return ok;
683 }
685 #endif
687 gboolean
688 smtp_out_init(smtp_base * psb, gboolean instant_helo)
689 {
690 gboolean ok;
692 logwrite(LOG_INFO, "smtp_out_init(): instant_helo:%d\n", instant_helo);
694 if (instant_helo) {
695 /* we say hello right away, hence we don't know if
696 ESMTP is supported; we just assume it */
697 psb->use_esmtp = 1;
698 } else {
699 if ((ok = read_response(psb, SMTP_INITIAL_TIMEOUT))) {
700 ok = check_init_response(psb);
701 }
702 if (!ok) {
703 smtp_out_log_failure(psb, NULL);
704 return ok;
705 }
706 }
708 if ((ok = smtp_helo(psb, psb->helo_name))) {
709 #ifdef ENABLE_AUTH
710 if (psb->auth_name && psb->use_auth) {
711 /* we completely disregard the response of server here. If
712 authentication fails, the server will complain later
713 anyway. I know, this is not polite... */
714 smtp_out_auth(psb);
715 }
716 #endif
717 }
718 if (!ok)
719 smtp_out_log_failure(psb, NULL);
720 return ok;
721 }
723 gint
724 smtp_out_msg(smtp_base * psb, message * msg, address * return_path, GList * rcpt_list, GList * hdr_list)
725 {
726 gint i, size;
727 gboolean ok = TRUE;
728 int rcpt_cnt;
729 int rcpt_accept = 0;
731 DEBUG(5) debugf("smtp_out_msg entered\n");
733 /* defaults: */
734 if (return_path == NULL)
735 return_path = msg->return_path;
736 if (hdr_list == NULL)
737 hdr_list = msg->hdr_list;
738 if (rcpt_list == NULL)
739 rcpt_list = msg->rcpt_list;
740 rcpt_cnt = g_list_length(rcpt_list);
742 size = msg_calc_size(msg, TRUE);
744 /* respect maximum size given by server: */
745 if ((psb->max_size > 0) && (size > psb->max_size)) {
746 logwrite(LOG_WARNING, "%s == host=%s message size (%d) > "
747 "fixed maximum message size of server (%d)",
748 msg->uid, psb->remote_host, size, psb->max_size);
749 psb->error = smtp_cancel;
750 ok = FALSE;
751 }
753 if (ok) {
754 /* pretend the message is a bit larger,
755 just in case the size calculation is buggy */
756 smtp_cmd_mailfrom(psb, return_path, psb->use_size ? size+SMTP_SIZE_ADD : 0);
758 if (!psb->use_pipelining) {
759 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
760 ok = check_response(psb, FALSE);
761 }
762 }
763 if (ok) {
764 GList *rcpt_node;
765 rcpt_accept = 0;
767 for (rcpt_node = g_list_first(rcpt_list); rcpt_node != NULL; rcpt_node = g_list_next(rcpt_node)) {
768 address *rcpt = (address *) (rcpt_node->data);
769 smtp_cmd_rcptto(psb, rcpt);
770 if (!psb->use_pipelining) {
771 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
772 if (check_response(psb, FALSE)) {
773 rcpt_accept++;
774 addr_mark_delivered(rcpt);
775 } else {
776 /* if server returned an error for one recp. we
777 may still try the others. But if it is a timeout, eof
778 or unexpected response, it is more serious and we should
779 give up. */
780 if ((psb->error != smtp_trylater) && (psb->error != smtp_fail)) {
781 ok = FALSE;
782 break;
783 } else {
784 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n",
785 msg->uid, addr_string(rcpt), psb->remote_host, psb->buffer);
786 if (psb->error == smtp_trylater) {
787 addr_mark_defered(rcpt);
788 } else {
789 addr_mark_failed(rcpt);
790 }
791 }
792 } else
793 break;
794 }
795 }
797 /* There is no point in going on if no recp.s were accpted.
798 But we can check that at this point only if not pipelining: */
799 ok = (ok && (psb->use_pipelining || (rcpt_accept > 0)));
800 if (ok) {
802 fprintf(psb->out, "DATA\r\n");
803 fflush(psb->out);
805 DEBUG(4) debugf("C: DATA\r\n");
807 if (psb->use_pipelining) {
808 /* the first pl'ed command was MAIL FROM
809 the last was DATA, whose response can be handled by the 'normal' code
810 all in between were RCPT TO:
811 */
812 /* response to MAIL FROM: */
813 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
814 if ((ok = check_response(psb, FALSE))) {
816 /* response(s) to RCPT TO:
817 this is very similar to the sequence above for no pipeline
818 */
819 for (i = 0; i < rcpt_cnt; i++) {
820 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
821 address *rcpt = g_list_nth_data(rcpt_list, i);
822 if (check_response(psb, FALSE)) {
823 rcpt_accept++;
824 addr_mark_delivered(rcpt);
825 } else {
826 /* if server returned an error 4xx or 5xx for one recp. we
827 may still try the others. But if it is a timeout, eof
828 or unexpected response, it is more serious and we
829 should give up. */
830 if ((psb->error != smtp_trylater) &&
831 (psb->error != smtp_fail)) {
832 ok = FALSE;
833 break;
834 } else {
835 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n", msg->uid,
836 addr_string(rcpt), psb->remote_host, psb->buffer);
837 if (psb->error == smtp_trylater) {
838 addr_mark_defered(rcpt);
839 } else {
840 addr_mark_failed(rcpt);
841 }
842 }
843 }
844 } else {
845 DEBUG(5) debugf("check_response failed after RCPT TO\n");
846 break;
847 }
848 }
849 if (rcpt_accept == 0)
850 ok = FALSE;
851 } else {
852 DEBUG(5) debugf("check_response failed after MAIL FROM\n");
853 }
854 } else {
855 DEBUG(5)
856 debugf("read_response failed after MAIL FROM\n");
857 }
858 }
860 /* if(psb->use_pipelining) */
861 /* response to the DATA cmd */
862 if (ok) {
863 if (read_response(psb, SMTP_DATA_TIMEOUT)) {
864 if (check_response(psb, TRUE)) {
865 send_header(psb, hdr_list);
866 send_data(psb, msg);
868 if (read_response(psb, SMTP_FINAL_TIMEOUT))
869 ok = check_response(psb, FALSE);
870 }
871 }
872 }
873 }
874 }
876 DEBUG(5) {
877 debugf("smtp_out_msg():\n");
878 debugf(" psb->error = %d\n", psb->error);
879 debugf(" ok = %d\n", ok);
880 debugf(" rcpt_accept = %d\n", rcpt_accept);
881 }
883 if (psb->error == smtp_ok) {
884 GList *rcpt_node;
885 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
886 address *rcpt = (address *) (rcpt_node->data);
887 if (addr_is_delivered(rcpt))
888 logwrite(LOG_NOTICE, "%s => %s host=%s with %s\n", msg->uid, addr_string(rcpt),
889 psb->remote_host, psb->use_esmtp ? "esmtp" : "smtp");
890 }
891 } else {
892 /* if something went wrong,
893 we have to unmark the rcpts prematurely marked as delivered
894 and mark the status */
895 smtp_out_mark_rcpts(psb, rcpt_list);
897 /* log the failure: */
898 smtp_out_log_failure(psb, msg);
899 }
900 return rcpt_accept;
901 }
903 gboolean
904 smtp_out_quit(smtp_base * psb)
905 {
906 fprintf(psb->out, "QUIT\r\n");
907 fflush(psb->out);
909 DEBUG(4) debugf("C: QUIT\n");
911 signal(SIGALRM, SIG_DFL);
913 return TRUE;
914 }
916 gint
917 smtp_deliver(gchar * host, gint port, GList * resolve_list, message * msg, address * return_path, GList * rcpt_list)
918 {
919 smtp_base *psb;
920 smtp_error err;
922 DEBUG(5) debugf("smtp_deliver entered\n");
924 if (return_path == NULL)
925 return_path = msg->return_path;
927 if ((psb = smtp_out_open(host, port, resolve_list))) {
928 set_heloname(psb, return_path->domain, TRUE);
929 /* initiate connection, send message and quit: */
930 if (smtp_out_init(psb, FALSE)) {
931 smtp_out_msg(psb, msg, return_path, rcpt_list, NULL);
932 if (psb->error == smtp_ok || (psb->error == smtp_fail) || (psb->error == smtp_trylater)
933 || (psb->error == smtp_syntax) || (psb->error == smtp_cancel))
934 smtp_out_quit(psb);
935 }
937 err = psb->error;
938 destroy_smtpbase(psb);
940 return err;
941 }
942 return -1;
943 }