masqmail

view src/smtp_out.c @ 378:5781ba87df95

Removed ident. This had been discussed on the mailing list in Oct 2011. Ident is hardly useful in typical setups for masqmail. Probably Oliver had used it in his setup; that would make sense. Now, I know of nobody who needs it.
author markus schnalke <meillo@marmaro.de>
date Sat, 14 Jan 2012 21:36:58 +0100
parents f122535c589e
children
line source
1 /*
2 ** smtp_out.c
3 ** Copyright (C) 1999-2001 Oliver Kurth
4 ** Copyright (C) 2010 markus schnalke <meillo@marmaro.de>
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License as published by
8 ** the Free Software Foundation; either version 2 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
21 /*
22 ** I always forget these rfc numbers:
23 ** RFC 821 (SMTP)
24 ** RFC 1869 (ESMTP)
25 ** RFC 1870 (ESMTP SIZE)
26 ** RFC 2197 (ESMTP PIPELINE)
27 ** RFC 2554 (ESMTP AUTH)
28 */
30 #include "masqmail.h"
31 #include "smtp_out.h"
32 #include "readsock.h"
34 #ifdef ENABLE_AUTH
35 #include "md5/md5.h"
36 #include "md5/hmac_md5.h"
37 #include "base64/base64.h"
38 #endif
40 void
41 destroy_smtpbase(smtp_base *psb)
42 {
43 fclose(psb->in);
44 fclose(psb->out);
46 close(psb->sock);
48 if (psb->helo_name)
49 g_free(psb->helo_name);
50 if (psb->buffer)
51 g_free(psb->buffer);
52 if (psb->auth_names)
53 g_strfreev(psb->auth_names);
55 if (psb->auth_name)
56 g_free(psb->auth_name);
57 if (psb->auth_login)
58 g_free(psb->auth_login);
59 if (psb->auth_secret)
60 g_free(psb->auth_secret);
61 }
63 gchar*
64 set_heloname(smtp_base *psb, gchar *default_name, gboolean do_correct)
65 {
66 struct sockaddr_in sname;
67 int len = sizeof(struct sockaddr_in);
68 struct hostent *host_entry;
70 if (do_correct) {
71 getsockname(psb->sock, (struct sockaddr *) (&sname), &len);
72 DEBUG(5) debugf("socket: name.sin_addr = %s\n", inet_ntoa(sname.sin_addr));
73 host_entry = gethostbyaddr((const char *) &(sname.sin_addr), sizeof(sname.sin_addr), AF_INET);
74 if (host_entry) {
75 psb->helo_name = g_strdup(host_entry->h_name);
76 } else {
77 /*
78 ** we failed to look up our own name. Instead of
79 ** giving our local hostname, we may give our IP
80 ** number to show the server that we are at least
81 ** willing to be honest. For the really picky ones.
82 */
83 DEBUG(5) debugf("failed to look up own host name.\n");
84 psb->helo_name = g_strdup_printf("[%s]", inet_ntoa(sname.sin_addr));
85 }
86 DEBUG(5) debugf("helo_name = %s\n", psb->helo_name);
87 }
88 if (psb->helo_name == NULL) {
89 psb->helo_name = g_strdup(default_name);
90 }
91 return psb->helo_name;
92 }
94 #ifdef ENABLE_AUTH
96 gboolean
97 set_auth(smtp_base *psb, gchar *name, gchar *login, gchar *secret)
98 {
99 if ((strcasecmp(name, "CRAM-MD5") == 0) || (strcasecmp(name, "LOGIN") == 0)) {
100 psb->auth_name = g_strdup(name);
101 psb->auth_login = g_strdup(login);
102 psb->auth_secret = g_strdup(secret);
104 return TRUE;
105 }
106 return FALSE;
107 }
109 #endif
111 static smtp_base*
112 create_smtpbase(gint sock)
113 {
114 gint dup_sock;
116 smtp_base *psb = (smtp_base *) g_malloc(sizeof(smtp_base));
118 psb->sock = sock;
120 psb->use_size = FALSE;
121 psb->use_pipelining = FALSE;
122 psb->use_auth = FALSE;
124 psb->max_size = 0;
125 psb->auth_names = NULL;
127 psb->buffer = (gchar *) g_malloc(SMTP_BUF_LEN);
129 dup_sock = dup(sock);
130 psb->out = fdopen(sock, "w");
131 psb->in = fdopen(dup_sock, "r");
133 psb->error = smtp_ok;
135 psb->helo_name = NULL;
137 psb->auth_name = psb->auth_login = psb->auth_secret = NULL;
139 return psb;
140 }
142 static gboolean
143 read_response(smtp_base *psb, int timeout)
144 {
145 gint buf_pos = 0;
146 gchar code[5];
147 gint i, len;
149 do {
150 len = read_sockline(psb->in, &(psb->buffer[buf_pos]), SMTP_BUF_LEN - buf_pos, timeout, READSOCKL_CHUG);
151 if (len == -3) {
152 psb->error = smtp_timeout;
153 return FALSE;
154 } else if (len == -2) {
155 psb->error = smtp_syntax;
156 return FALSE;
157 } else if (len == -1) {
158 psb->error = smtp_eof;
159 return FALSE;
160 }
161 for (i = 0; i < 4; i++)
162 code[i] = psb->buffer[buf_pos + i];
163 code[i] = '\0';
164 psb->last_code = atoi(code);
166 buf_pos += len;
168 } while (code[3] == '-');
169 if (psb->buffer) {
170 DEBUG(4) debugf("S: %s\n", psb->buffer);
171 }
173 return TRUE;
174 }
176 static gboolean
177 check_response(smtp_base *psb, gboolean after_data)
178 {
179 char c = psb->buffer[0];
181 if (((c == '2') && !after_data) || ((c == '3') && after_data)) {
182 psb->error = smtp_ok;
183 DEBUG(6) debugf("response OK:'%s' after_data = %d\n", psb->buffer, (int) after_data);
184 return TRUE;
185 } else {
186 if (c == '4')
187 psb->error = smtp_trylater;
188 else if (c == '5')
189 psb->error = smtp_fail;
190 else
191 psb->error = smtp_syntax;
192 DEBUG(6) debugf("response failure:'%s' after_data = %d\n", psb->buffer, (int) after_data);
193 return FALSE;
194 }
195 }
197 static gchar*
198 get_response_arg(gchar *response)
199 {
200 gchar buf[SMTP_BUF_LEN];
201 gchar *p = response, *q = buf;
203 while (*p && (*p != '\n') && isspace(*p))
204 p++;
205 if (*p && (*p != '\n')) {
206 while (*p && (*p != '\n') && (*p != '\r') && (q < buf + SMTP_BUF_LEN - 1))
207 *(q++) = *(p++);
208 *q = '\0';
209 return g_strdup(buf);
210 }
211 return NULL;
212 }
214 static gboolean
215 check_helo_response(smtp_base *psb)
216 {
217 gchar *ptr;
219 if (!check_response(psb, FALSE))
220 return FALSE;
222 if (psb->last_code == 220) {
223 logwrite(LOG_NOTICE, "received a 220 greeting after sending EHLO,\n");
224 logwrite(LOG_NOTICE, "please remove `instant_helo' from your route config\n");
225 /* read the next response, cause that's the actual helo response */
226 if (!read_response(psb, SMTP_CMD_TIMEOUT) || !check_response(psb, FALSE)) {
227 return FALSE;
228 }
229 }
231 ptr = psb->buffer;
233 while (*ptr) {
234 if (strncasecmp(&(ptr[4]), "SIZE", 4) == 0) {
235 gchar *arg;
236 psb->use_size = TRUE;
237 arg = get_response_arg(&(ptr[8]));
238 if (arg) {
239 psb->max_size = atoi(arg);
240 g_free(arg);
241 }
242 }
244 if (strncasecmp(&(ptr[4]), "PIPELINING", 10) == 0)
245 psb->use_pipelining = TRUE;
247 if (strncasecmp(&(ptr[4]), "AUTH", 4) == 0) {
248 if ((ptr[8] == ' ') || (ptr[8] == '=') || (ptr[8] == '\t')) { /* not sure about '\t' */
249 gchar *arg;
250 psb->use_auth = TRUE;
251 arg = get_response_arg(&(ptr[9])); /* after several years I finally learnt to count */
252 if (arg) {
253 psb->auth_names = g_strsplit(arg, " ", 0);
254 g_free(arg);
256 DEBUG(4) {
257 gint i = 0;
258 debugf("in check_helo_response()\n");
259 while (psb->auth_names[i]) {
260 debugf(" offered AUTH %s\n", psb->auth_names[i]);
261 i++;
262 }
263 }
264 }
265 }
266 }
268 while (*ptr != '\n')
269 ptr++;
270 ptr++;
271 }
273 DEBUG(4) {
274 debugf(" %s\n", psb->use_size ? "uses SIZE" : "no size");
275 debugf(" %s\n", psb->use_pipelining ? "uses PIPELINING" : "no pipelining");
276 debugf(" %s\n", psb->use_auth ? "uses AUTH" : "no auth");
277 }
279 return TRUE;
280 }
282 /*
283 ** We first try EHLO, but if it fails HELO in a second fall back try.
284 ** This is what is requested by RFC 2821 (sec 3.2):
285 **
286 ** Once the server has sent the welcoming message and
287 ** the client has received it, the client normally sends
288 ** the EHLO command to the server, [...]
289 ** For a particular connection attempt, if the server
290 ** returns a "command not recognized" response to EHLO,
291 ** the client SHOULD be able to fall back and send HELO.
292 **
293 ** Up to and including version 0.3.0 masqmail used ESMTP only if the
294 ** string ``ESMTP'' appeared within the server's greeting message. This
295 ** made it impossible to use AUTH with servers that would send odd
296 ** greeting messages.
297 */
298 static gboolean
299 smtp_helo(smtp_base *psb, gchar *helo)
300 {
301 fprintf(psb->out, "EHLO %s\r\n", helo);
302 fflush(psb->out);
303 DEBUG(4) debugf("C: EHLO %s\r\n", helo);
305 if (!read_response(psb, SMTP_CMD_TIMEOUT)) {
306 return FALSE;
307 }
308 if (check_helo_response(psb)) {
309 DEBUG(4) debugf("uses esmtp\n");
310 return TRUE;
311 }
313 if (psb->error != smtp_fail) {
314 return FALSE;
315 }
317 /*
318 ** our guess that server understands EHLO could have been wrong,
319 ** try again with HELO
320 */
322 fprintf(psb->out, "HELO %s\r\n", helo);
323 fflush(psb->out);
324 DEBUG(4) debugf("C: HELO %s\r\n", helo);
326 if (!read_response(psb, SMTP_CMD_TIMEOUT)) {
327 return FALSE;
328 }
329 if (check_helo_response(psb)) {
330 DEBUG(4) debugf("uses smtp\n");
331 return TRUE;
332 }
334 /* what sort of server ist THAT ?! give up... */
335 return FALSE;
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 /*
367 ** According to RFC 821 each line should be terminated with CRLF.
368 ** Since a dot on a line itself marks the end of data, each line
369 ** beginning with a dot is prepended with another dot.
370 */
371 gchar *ptr;
372 gboolean new_line = TRUE; /* previous versions assumed that each item was exactly one line. 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);
520 sock = child(cmd);
521 if (sock <= 0) {
522 return NULL;
523 }
524 psb = create_smtpbase(sock);
525 psb->remote_host = NULL;
527 return psb;
528 }
530 gboolean
531 smtp_out_rset(smtp_base *psb)
532 {
533 gboolean ok;
535 fprintf(psb->out, "RSET\r\n");
536 fflush(psb->out);
537 DEBUG(4) debugf("C: RSET\n");
539 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
540 if (check_response(psb, FALSE))
541 return TRUE;
543 smtp_out_log_failure(psb, NULL);
545 return FALSE;
546 }
548 #ifdef ENABLE_AUTH
550 static gboolean
551 smtp_out_auth_cram_md5(smtp_base *psb)
552 {
553 gboolean ok = FALSE;
555 fprintf(psb->out, "C: AUTH CRAM-MD5\r\n");
556 fflush(psb->out);
557 DEBUG(4) debugf("AUTH CRAM-MD5\n");
558 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
559 if ((ok = check_response(psb, TRUE))) {
560 gchar *chall64 = get_response_arg(&(psb->buffer[4]));
561 gint chall_size;
562 gchar *chall = base64_decode(chall64, &chall_size);
563 guchar digest[16], *reply64, *reply;
564 gchar digest_string[33];
565 gint i;
567 DEBUG(5) debugf("smtp_out_auth_cram_md5():\n");
568 DEBUG(5) debugf(" encoded challenge = %s\n", chall64);
569 DEBUG(5) debugf(" decoded challenge = %s, size = %d\n", chall, chall_size);
570 DEBUG(5) debugf(" secret = %s\n", psb->auth_secret);
572 hmac_md5(chall, chall_size, psb->auth_secret, strlen(psb->auth_secret), digest);
573 for (i = 0; i < 16; i++)
574 sprintf(&(digest_string[i + i]), "%02x", (unsigned int) (digest[i]));
575 digest_string[32] = '\0';
577 DEBUG(5) debugf(" digest = %s\n", digest_string);
579 reply = g_strdup_printf("%s %s", psb->auth_login, digest_string);
580 DEBUG(5) debugf(" unencoded reply = %s\n", reply);
582 reply64 = base64_encode(reply, strlen(reply));
583 DEBUG(5) debugf(" encoded reply = %s\n", reply64);
585 fprintf(psb->out, "%s\r\n", reply64);
586 fflush(psb->out);
587 DEBUG(6) debugf(" reply64 = %s\n", reply64);
588 DEBUG(6) debugf("C: %s\n", reply64);
590 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
591 ok = check_response(psb, FALSE);
593 g_free(reply64);
594 g_free(reply);
595 g_free(chall);
596 g_free(chall64);
597 }
598 }
599 return ok;
600 }
602 static gboolean
603 smtp_out_auth_login(smtp_base *psb)
604 {
605 gboolean ok = FALSE;
606 fprintf(psb->out, "AUTH LOGIN\r\n");
607 fflush(psb->out);
608 DEBUG(4) debugf("C: AUTH LOGIN\r\n");
609 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
610 if ((ok = check_response(psb, TRUE))) {
611 gchar *resp64;
612 guchar *resp;
613 gint resp_size;
614 gchar *reply64;
616 DEBUG(5) debugf("smtp_out_auth_login():\n");
617 resp64 = get_response_arg(&(psb->buffer[4]));
618 DEBUG(5) debugf(" encoded response = `%s'\n", resp64);
619 resp = base64_decode(resp64, &resp_size);
620 g_free(resp64);
621 DEBUG(5) debugf(" decoded response = `%s', size = %d\n", resp, resp_size);
622 g_free(resp);
623 reply64 = base64_encode(psb->auth_login, strlen(psb->auth_login));
624 fprintf(psb->out, "%s\r\n", reply64);
625 fflush(psb->out);
626 DEBUG(6) debugf("C: %s\n", reply64);
627 g_free(reply64);
628 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
629 if ((ok = check_response(psb, TRUE))) {
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_secret, strlen(psb->auth_secret));
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 ok = check_response(psb, FALSE);
643 }
644 }
645 }
646 }
647 return ok;
648 }
650 gboolean
651 smtp_out_auth(smtp_base *psb)
652 {
653 gboolean ok = FALSE;
654 gint i = 0;
655 while (psb->auth_names[i]) {
656 if (strcasecmp(psb->auth_names[i], psb->auth_name) == 0)
657 break;
658 i++;
659 }
660 if (psb->auth_names[i]) {
661 if (strcasecmp(psb->auth_name, "cram-md5") == 0) {
662 smtp_out_auth_cram_md5(psb);
663 } else if (strcasecmp(psb->auth_name, "login") == 0) {
664 smtp_out_auth_login(psb);
665 } else {
666 logwrite(LOG_ERR, "auth method %s not supported\n", psb->auth_name);
667 }
668 } else {
669 logwrite(LOG_ERR, "no auth method %s found.\n", psb->auth_name);
670 }
671 return ok;
672 }
674 #endif
676 gboolean
677 smtp_out_init(smtp_base *psb, gboolean instant_helo)
678 {
679 gboolean ok;
681 logwrite(LOG_INFO, "smtp_out_init(): instant_helo:%d\n", instant_helo);
683 if (!instant_helo) {
684 if ((ok = read_response(psb, SMTP_INITIAL_TIMEOUT))) {
685 ok = check_response(psb, FALSE);
686 }
687 if (!ok) {
688 smtp_out_log_failure(psb, NULL);
689 return ok;
690 }
691 }
693 if ((ok = smtp_helo(psb, psb->helo_name))) {
694 #ifdef ENABLE_AUTH
695 if (psb->auth_name && psb->use_auth) {
696 /* we completely disregard the response of server here. If
697 authentication fails, the server will complain later
698 anyway. I know, this is not polite... */
699 smtp_out_auth(psb);
700 }
701 #endif
702 }
703 if (!ok)
704 smtp_out_log_failure(psb, NULL);
705 return ok;
706 }
708 gint
709 smtp_out_msg(smtp_base *psb, message *msg, address *return_path,
710 GList *rcpt_list, GList *hdr_list)
711 {
712 gint i, size;
713 gboolean ok = TRUE;
714 int rcpt_cnt;
715 int rcpt_accept = 0;
717 DEBUG(5) debugf("smtp_out_msg entered\n");
719 /* defaults: */
720 if (return_path == NULL)
721 return_path = msg->return_path;
722 if (hdr_list == NULL)
723 hdr_list = msg->hdr_list;
724 if (rcpt_list == NULL)
725 rcpt_list = msg->rcpt_list;
726 rcpt_cnt = g_list_length(rcpt_list);
728 size = msg_calc_size(msg, TRUE);
730 /* respect maximum size given by server: */
731 if ((psb->max_size > 0) && (size > psb->max_size)) {
732 logwrite(LOG_WARNING, "%s == host=%s message size (%d) > "
733 "fixed maximum message size of server (%d)",
734 msg->uid, psb->remote_host, size, psb->max_size);
735 psb->error = smtp_cancel;
736 ok = FALSE;
737 }
739 if (ok) {
740 /*
741 ** pretend the message is a bit larger,
742 ** just in case the size calculation is buggy
743 */
744 smtp_cmd_mailfrom(psb, return_path, psb->use_size ? size+SMTP_SIZE_ADD : 0);
746 if (!psb->use_pipelining) {
747 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
748 ok = check_response(psb, FALSE);
749 }
750 }
751 if (ok) {
752 GList *rcpt_node;
753 rcpt_accept = 0;
755 for (rcpt_node = g_list_first(rcpt_list); rcpt_node != NULL; rcpt_node = g_list_next(rcpt_node)) {
756 address *rcpt = (address *) (rcpt_node->data);
757 smtp_cmd_rcptto(psb, rcpt);
758 if (!psb->use_pipelining) {
759 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
760 if (check_response(psb, FALSE)) {
761 rcpt_accept++;
762 addr_mark_delivered(rcpt);
763 } else {
764 /* if server returned an error for one recp. we
765 may still try the others. But if it is a timeout, eof
766 or unexpected response, it is more serious and we should
767 give up. */
768 if ((psb->error != smtp_trylater) && (psb->error != smtp_fail)) {
769 ok = FALSE;
770 break;
771 } else {
772 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n",
773 msg->uid, addr_string(rcpt), psb->remote_host, psb->buffer);
774 if (psb->error == smtp_trylater) {
775 addr_mark_defered(rcpt);
776 } else {
777 addr_mark_failed(rcpt);
778 }
779 }
780 } else
781 break;
782 }
783 }
785 /*
786 ** There is no point in going on if no recp.s were accpted.
787 ** But we can check that at this point only if not pipelining:
788 */
789 ok = (ok && (psb->use_pipelining || (rcpt_accept > 0)));
790 if (ok) {
792 fprintf(psb->out, "DATA\r\n");
793 fflush(psb->out);
795 DEBUG(4) debugf("C: DATA\r\n");
797 if (psb->use_pipelining) {
798 /*
799 ** the first pl'ed command was MAIL FROM
800 ** the last was DATA, whose response can be
801 ** handled by the 'normal' code all in
802 ** between were RCPT TO:
803 */
804 /* response to MAIL FROM: */
805 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
806 if ((ok = check_response(psb, FALSE))) {
808 /*
809 ** response(s) to RCPT TO:
810 ** this is very similar to
811 ** the sequence above for no
812 ** pipeline
813 */
814 for (i = 0; i < rcpt_cnt; i++) {
815 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
816 address *rcpt = g_list_nth_data(rcpt_list, i);
817 if (check_response(psb, FALSE)) {
818 rcpt_accept++;
819 addr_mark_delivered(rcpt);
820 } else {
821 /*
822 ** if server returned an error 4xx or 5xx for one recp. we
823 ** may still try the others. But if it is a timeout, eof
824 ** or unexpected response, it is more serious and we
825 ** should give up.
826 */
827 if ((psb->error != smtp_trylater) &&
828 (psb->error != smtp_fail)) {
829 ok = FALSE;
830 break;
831 } else {
832 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n", msg->uid,
833 addr_string(rcpt), psb->remote_host, psb->buffer);
834 if (psb->error == smtp_trylater) {
835 addr_mark_defered(rcpt);
836 } else {
837 addr_mark_failed(rcpt);
838 }
839 }
840 }
841 } else {
842 DEBUG(5) debugf("check_response failed after RCPT TO\n");
843 break;
844 }
845 }
846 if (rcpt_accept == 0)
847 ok = FALSE;
848 } else {
849 DEBUG(5) debugf("check_response failed after MAIL FROM\n");
850 }
851 } else {
852 DEBUG(5)
853 debugf("read_response failed after MAIL FROM\n");
854 }
855 }
857 /* if(psb->use_pipelining) */
858 /* response to the DATA cmd */
859 if (ok) {
860 if (read_response(psb, SMTP_DATA_TIMEOUT)) {
861 if (check_response(psb, TRUE)) {
862 send_header(psb, hdr_list);
863 send_data(psb, msg);
865 if (read_response(psb, SMTP_FINAL_TIMEOUT))
866 ok = check_response(psb, FALSE);
867 }
868 }
869 }
870 }
871 }
873 DEBUG(5) {
874 debugf("smtp_out_msg():\n");
875 debugf(" psb->error = %d\n", psb->error);
876 debugf(" ok = %d\n", ok);
877 debugf(" rcpt_accept = %d\n", rcpt_accept);
878 }
880 if (psb->error == smtp_ok) {
881 GList *rcpt_node;
882 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
883 address *rcpt = (address *) (rcpt_node->data);
884 if (addr_is_delivered(rcpt))
885 logwrite(LOG_NOTICE, "%s => %s host=%s\n",
886 msg->uid, addr_string(rcpt), psb->remote_host);
887 }
888 } else {
889 /*
890 ** if something went wrong,
891 ** we have to unmark the rcpts prematurely marked as
892 ** delivered and mark the status
893 */
894 smtp_out_mark_rcpts(psb, rcpt_list);
896 /* log the failure: */
897 smtp_out_log_failure(psb, msg);
898 }
899 return rcpt_accept;
900 }
902 gboolean
903 smtp_out_quit(smtp_base *psb)
904 {
905 fprintf(psb->out, "QUIT\r\n");
906 fflush(psb->out);
908 DEBUG(4) debugf("C: QUIT\n");
910 signal(SIGALRM, SIG_DFL);
912 return TRUE;
913 }
915 gint
916 smtp_deliver(gchar *host, gint port, GList *resolve_list, message *msg,
917 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 }