masqmail

view src/smtp_out.c @ 366:41958685480d

Switched to `type *name' style Andrew Koenig's ``C Traps and Pitfalls'' (Ch.2.1) convinced me that it is best to go with the way C had been designed. The ``declaration reflects use'' concept conflicts with a ``type* name'' notation. Hence I switched.
author markus schnalke <meillo@marmaro.de>
date Thu, 22 Sep 2011 15:07:40 +0200
parents 02bc0331e390
children b27f66555ba8
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
34 #include "md5/md5.h"
35 #include "md5/hmac_md5.h"
36 #include "base64/base64.h"
37 #endif
39 void
40 destroy_smtpbase(smtp_base *psb)
41 {
42 fclose(psb->in);
43 fclose(psb->out);
45 close(psb->sock);
47 if (psb->helo_name)
48 g_free(psb->helo_name);
49 if (psb->buffer)
50 g_free(psb->buffer);
51 if (psb->auth_names)
52 g_strfreev(psb->auth_names);
54 if (psb->auth_name)
55 g_free(psb->auth_name);
56 if (psb->auth_login)
57 g_free(psb->auth_login);
58 if (psb->auth_secret)
59 g_free(psb->auth_secret);
60 }
62 gchar*
63 set_heloname(smtp_base *psb, gchar *default_name, gboolean do_correct)
64 {
65 struct sockaddr_in sname;
66 int len = sizeof(struct sockaddr_in);
67 struct hostent *host_entry;
69 if (do_correct) {
70 getsockname(psb->sock, (struct sockaddr *) (&sname), &len);
71 DEBUG(5) debugf("socket: name.sin_addr = %s\n", inet_ntoa(sname.sin_addr));
72 host_entry = gethostbyaddr((const char *) &(sname.sin_addr), sizeof(sname.sin_addr), AF_INET);
73 if (host_entry) {
74 psb->helo_name = g_strdup(host_entry->h_name);
75 } else {
76 /* we failed to look up our own name. Instead of giving our local hostname,
77 we may give our IP number to show the server that we are at least
78 willing to be honest. For the really picky ones. */
79 DEBUG(5) debugf("failed to look up own host name.\n");
80 psb->helo_name = g_strdup_printf("[%s]", inet_ntoa(sname.sin_addr));
81 }
82 DEBUG(5) debugf("helo_name = %s\n", psb->helo_name);
83 }
84 if (psb->helo_name == NULL) {
85 psb->helo_name = g_strdup(default_name);
86 }
87 return psb->helo_name;
88 }
90 #ifdef ENABLE_AUTH
92 gboolean
93 set_auth(smtp_base *psb, gchar *name, gchar *login, gchar *secret)
94 {
95 if ((strcasecmp(name, "CRAM-MD5") == 0) || (strcasecmp(name, "LOGIN") == 0)) {
96 psb->auth_name = g_strdup(name);
97 psb->auth_login = g_strdup(login);
98 psb->auth_secret = g_strdup(secret);
100 return TRUE;
101 }
102 return FALSE;
103 }
105 #endif
107 static smtp_base*
108 create_smtpbase(gint sock)
109 {
110 gint dup_sock;
112 smtp_base *psb = (smtp_base *) g_malloc(sizeof(smtp_base));
114 psb->sock = sock;
116 psb->use_size = FALSE;
117 psb->use_pipelining = FALSE;
118 psb->use_auth = FALSE;
120 psb->max_size = 0;
121 psb->auth_names = NULL;
123 psb->buffer = (gchar *) g_malloc(SMTP_BUF_LEN);
125 dup_sock = dup(sock);
126 psb->out = fdopen(sock, "w");
127 psb->in = fdopen(dup_sock, "r");
129 psb->error = smtp_ok;
131 psb->helo_name = NULL;
133 psb->auth_name = psb->auth_login = psb->auth_secret = NULL;
135 return psb;
136 }
138 static gboolean
139 read_response(smtp_base *psb, int timeout)
140 {
141 gint buf_pos = 0;
142 gchar code[5];
143 gint i, len;
145 do {
146 len = read_sockline(psb->in, &(psb->buffer[buf_pos]), SMTP_BUF_LEN - buf_pos, timeout, READSOCKL_CHUG);
147 if (len == -3) {
148 psb->error = smtp_timeout;
149 return FALSE;
150 } else if (len == -2) {
151 psb->error = smtp_syntax;
152 return FALSE;
153 } else if (len == -1) {
154 psb->error = smtp_eof;
155 return FALSE;
156 }
157 for (i = 0; i < 4; i++)
158 code[i] = psb->buffer[buf_pos + i];
159 code[i] = '\0';
160 psb->last_code = atoi(code);
162 buf_pos += len;
164 } while (code[3] == '-');
165 if (psb->buffer) {
166 DEBUG(4) debugf("S: %s\n", psb->buffer);
167 }
169 return TRUE;
170 }
172 static gboolean
173 check_response(smtp_base *psb, gboolean after_data)
174 {
175 char c = psb->buffer[0];
177 if (((c == '2') && !after_data) || ((c == '3') && after_data)) {
178 psb->error = smtp_ok;
179 DEBUG(6) debugf("response OK:'%s' after_data = %d\n", psb->buffer, (int) after_data);
180 return TRUE;
181 } else {
182 if (c == '4')
183 psb->error = smtp_trylater;
184 else if (c == '5')
185 psb->error = smtp_fail;
186 else
187 psb->error = smtp_syntax;
188 DEBUG(6) debugf("response failure:'%s' after_data = %d\n", psb->buffer, (int) after_data);
189 return FALSE;
190 }
191 }
193 static gchar*
194 get_response_arg(gchar *response)
195 {
196 gchar buf[SMTP_BUF_LEN];
197 gchar *p = response, *q = buf;
199 while (*p && (*p != '\n') && isspace(*p))
200 p++;
201 if (*p && (*p != '\n')) {
202 while (*p && (*p != '\n') && (*p != '\r') && (q < buf + SMTP_BUF_LEN - 1))
203 *(q++) = *(p++);
204 *q = '\0';
205 return g_strdup(buf);
206 }
207 return NULL;
208 }
210 static gboolean
211 check_helo_response(smtp_base *psb)
212 {
213 gchar *ptr;
215 if (!check_response(psb, FALSE))
216 return FALSE;
218 if (psb->last_code == 220) {
219 logwrite(LOG_NOTICE, "received a 220 greeting after sending EHLO,\n");
220 logwrite(LOG_NOTICE, "please remove `instant_helo' from your route config\n");
221 /* read the next response, cause that's the actual helo response */
222 if (!read_response(psb, SMTP_CMD_TIMEOUT) || !check_response(psb, FALSE)) {
223 return FALSE;
224 }
225 }
227 ptr = psb->buffer;
229 while (*ptr) {
230 if (strncasecmp(&(ptr[4]), "SIZE", 4) == 0) {
231 gchar *arg;
232 psb->use_size = TRUE;
233 arg = get_response_arg(&(ptr[8]));
234 if (arg) {
235 psb->max_size = atoi(arg);
236 g_free(arg);
237 }
238 }
240 if (strncasecmp(&(ptr[4]), "PIPELINING", 10) == 0)
241 psb->use_pipelining = TRUE;
243 if (strncasecmp(&(ptr[4]), "AUTH", 4) == 0) {
244 if ((ptr[8] == ' ') || (ptr[8] == '=') || (ptr[8] == '\t')) { /* not sure about '\t' */
245 gchar *arg;
246 psb->use_auth = TRUE;
247 arg = get_response_arg(&(ptr[9])); /* after several years I finally learnt to count */
248 if (arg) {
249 psb->auth_names = g_strsplit(arg, " ", 0);
250 g_free(arg);
252 DEBUG(4) {
253 gint i = 0;
254 debugf("in check_helo_response()\n");
255 while (psb->auth_names[i]) {
256 debugf(" offered AUTH %s\n", psb->auth_names[i]);
257 i++;
258 }
259 }
260 }
261 }
262 }
264 while (*ptr != '\n')
265 ptr++;
266 ptr++;
267 }
269 DEBUG(4) {
270 debugf(" %s\n", psb->use_size ? "uses SIZE" : "no size");
271 debugf(" %s\n", psb->use_pipelining ? "uses PIPELINING" : "no pipelining");
272 debugf(" %s\n", psb->use_auth ? "uses AUTH" : "no auth");
273 }
275 return TRUE;
276 }
278 /*
279 We first try EHLO, but if it fails HELO in a second fall back try.
280 This is what is requested by RFC 2821 (sec 3.2):
282 Once the server has sent the welcoming message and
283 the client has received it, the client normally sends
284 the EHLO command to the server, [...]
285 For a particular connection attempt, if the server
286 returns a "command not recognized" response to EHLO,
287 the client SHOULD be able to fall back and send HELO.
289 Up to and including version 0.3.0 masqmail used ESMTP only if the
290 string ``ESMTP'' appeared within the server's greeting message. This
291 made it impossible to use AUTH with servers that would send odd
292 greeting messages.
293 */
294 static gboolean
295 smtp_helo(smtp_base *psb, gchar *helo)
296 {
297 fprintf(psb->out, "EHLO %s\r\n", helo);
298 fflush(psb->out);
299 DEBUG(4) debugf("C: EHLO %s\r\n", helo);
301 if (!read_response(psb, SMTP_CMD_TIMEOUT)) {
302 return FALSE;
303 }
304 if (check_helo_response(psb)) {
305 DEBUG(4) debugf("uses esmtp\n");
306 return TRUE;
307 }
309 if (psb->error != smtp_fail) {
310 return FALSE;
311 }
313 /* our guess that server understands EHLO could have been wrong,
314 try again with HELO */
316 fprintf(psb->out, "HELO %s\r\n", helo);
317 fflush(psb->out);
318 DEBUG(4) debugf("C: HELO %s\r\n", helo);
320 if (!read_response(psb, SMTP_CMD_TIMEOUT)) {
321 return FALSE;
322 }
323 if (check_helo_response(psb)) {
324 DEBUG(4) debugf("uses smtp\n");
325 return TRUE;
326 }
328 /* what sort of server ist THAT ?! give up... */
329 return FALSE;
330 }
332 static void
333 smtp_cmd_mailfrom(smtp_base *psb, address *return_path, guint size)
334 {
335 if (psb->use_size) {
336 fprintf(psb->out, "MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
337 fflush(psb->out);
339 DEBUG(4) debugf("C: MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
341 } else {
342 fprintf(psb->out, "MAIL FROM:%s\r\n", addr_string(return_path));
343 fflush(psb->out);
345 DEBUG(4) debugf("C: MAIL FROM:%s\r\n", addr_string(return_path));
346 }
347 }
349 static void
350 smtp_cmd_rcptto(smtp_base *psb, address *rcpt)
351 {
352 fprintf(psb->out, "RCPT TO:%s\r\n", addr_string(rcpt));
353 fflush(psb->out);
354 DEBUG(4) debugf("C: RCPT TO:%s\n", addr_string(rcpt));
355 }
357 static void
358 send_data_line(smtp_base *psb, gchar *data)
359 {
360 /* According to RFC 821 each line should be terminated with CRLF.
361 Since a dot on a line itself marks the end of data, each line
362 beginning with a dot is prepended with another dot.
363 */
364 gchar *ptr;
365 gboolean new_line = TRUE; /* previous versions assumed that each item was exactly one line.
366 This is no longer the case */
368 ptr = data;
369 while (*ptr) {
370 int c = (int) (*ptr);
371 if (c == '.' && new_line) {
372 /* dot-stuffing */
373 putc('.', psb->out);
374 }
375 if (c == '\n') {
376 /* CRLF line terminators */
377 putc('\r', psb->out);
378 putc('\n', psb->out);
379 new_line = TRUE;
380 } else {
381 putc(c, psb->out);
382 new_line = FALSE;
383 }
384 ptr++;
385 }
386 }
388 static void
389 send_header(smtp_base *psb, GList *hdr_list)
390 {
391 GList *node;
392 gint num_hdrs = 0;
394 /* header */
395 if (hdr_list) {
396 foreach(hdr_list, node) {
397 if (node->data) {
398 header *hdr = (header *) (node->data);
399 if (hdr->header) {
400 send_data_line(psb, hdr->header);
401 num_hdrs++;
402 }
403 }
404 }
405 }
407 /* empty line separating headers from data: */
408 putc('\r', psb->out);
409 putc('\n', psb->out);
411 DEBUG(4) debugf("sent %d headers\n", num_hdrs);
412 }
414 static void
415 send_data(smtp_base *psb, message *msg)
416 {
417 GList *node;
418 gint num_lines = 0;
420 /* data */
421 if (msg->data_list) {
422 for (node = g_list_first(msg->data_list); node; node = g_list_next(node)) {
423 if (node->data) {
424 send_data_line(psb, node->data);
425 num_lines++;
426 }
427 }
428 }
430 DEBUG(4) debugf("sent %d lines of data\n", num_lines);
432 fprintf(psb->out, ".\r\n");
433 fflush(psb->out);
434 DEBUG(4) debugf("C: .\n");
435 }
437 void
438 smtp_out_mark_rcpts(smtp_base *psb, GList *rcpt_list)
439 {
440 GList *rcpt_node;
441 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
442 address *rcpt = (address *) (rcpt_node->data);
444 addr_unmark_delivered(rcpt);
446 if ((psb->error == smtp_trylater) || (psb->error == smtp_timeout) || (psb->error == smtp_eof)) {
447 addr_mark_defered(rcpt);
448 } else {
449 addr_mark_failed(rcpt);
450 }
451 }
452 }
454 void
455 smtp_out_log_failure(smtp_base *psb, message *msg)
456 {
457 gchar *err_str;
459 if (psb->error == smtp_timeout)
460 err_str = g_strdup("connection timed out.");
461 else if (psb->error == smtp_eof)
462 err_str = g_strdup("connection terminated prematurely.");
463 else if (psb->error == smtp_syntax)
464 err_str = g_strdup_printf("got unexpected response: %s", psb->buffer);
465 else if (psb->error == smtp_cancel)
466 err_str = g_strdup("delivery was canceled.\n");
467 else
468 /* error message should still be in the buffer */
469 err_str = g_strdup_printf("failed: %s\n", psb->buffer);
471 if (msg == NULL)
472 logwrite(LOG_NOTICE, "host=%s %s\n", psb->remote_host, err_str);
473 else
474 logwrite(LOG_NOTICE, "%s == host=%s %s\n", msg->uid, psb->remote_host, err_str);
476 g_free(err_str);
477 }
479 smtp_base*
480 smtp_out_open(gchar *host, gint port, GList *resolve_list)
481 {
482 smtp_base *psb;
483 gint sock;
484 mxip_addr *addr;
486 DEBUG(5) debugf("smtp_out_open entered, host = %s\n", host);
488 if ((addr = connect_resolvelist(&sock, host, port, resolve_list))) {
489 /* create structure to hold status data: */
490 psb = create_smtpbase(sock);
491 psb->remote_host = addr->name;
493 DEBUG(5) {
494 struct sockaddr_in name;
495 int len = sizeof(struct sockaddr);
496 getsockname(sock, (struct sockaddr *) (&name), &len);
497 debugf("socket: name.sin_addr = %s\n", inet_ntoa(name.sin_addr));
498 }
499 return psb;
500 } else {
501 DEBUG(5) debugf("connect_resolvelist failed: %s %s\n", strerror(errno), hstrerror(h_errno));
502 }
504 return NULL;
505 }
507 smtp_base*
508 smtp_out_open_child(gchar *cmd, char *host)
509 {
510 smtp_base *psb;
511 gint sock;
513 DEBUG(5) debugf("smtp_out_open_child entered, cmd = %s\n", cmd);
514 psb->remote_host = host;
515 sock = child(cmd);
516 if (sock > 0) {
517 psb = create_smtpbase(sock);
518 psb->remote_host = NULL;
520 return psb;
521 }
523 return NULL;
524 }
526 gboolean
527 smtp_out_rset(smtp_base *psb)
528 {
529 gboolean ok;
531 fprintf(psb->out, "RSET\r\n");
532 fflush(psb->out);
533 DEBUG(4) debugf("C: RSET\n");
535 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
536 if (check_response(psb, FALSE))
537 return TRUE;
539 smtp_out_log_failure(psb, NULL);
541 return FALSE;
542 }
544 #ifdef ENABLE_AUTH
546 static gboolean
547 smtp_out_auth_cram_md5(smtp_base *psb)
548 {
549 gboolean ok = FALSE;
551 fprintf(psb->out, "C: AUTH CRAM-MD5\r\n");
552 fflush(psb->out);
553 DEBUG(4) debugf("AUTH CRAM-MD5\n");
554 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
555 if ((ok = check_response(psb, TRUE))) {
556 gchar *chall64 = get_response_arg(&(psb->buffer[4]));
557 gint chall_size;
558 gchar *chall = base64_decode(chall64, &chall_size);
559 guchar digest[16], *reply64, *reply;
560 gchar digest_string[33];
561 gint i;
563 DEBUG(5) debugf("smtp_out_auth_cram_md5():\n");
564 DEBUG(5) debugf(" encoded challenge = %s\n", chall64);
565 DEBUG(5) debugf(" decoded challenge = %s, size = %d\n", chall, chall_size);
566 DEBUG(5) debugf(" secret = %s\n", psb->auth_secret);
568 hmac_md5(chall, chall_size, psb->auth_secret, strlen(psb->auth_secret), digest);
569 for (i = 0; i < 16; i++)
570 sprintf(&(digest_string[i + i]), "%02x", (unsigned int) (digest[i]));
571 digest_string[32] = '\0';
573 DEBUG(5) debugf(" digest = %s\n", digest_string);
575 reply = g_strdup_printf("%s %s", psb->auth_login, digest_string);
576 DEBUG(5) debugf(" unencoded reply = %s\n", reply);
578 reply64 = base64_encode(reply, strlen(reply));
579 DEBUG(5) debugf(" encoded reply = %s\n", reply64);
581 fprintf(psb->out, "%s\r\n", reply64);
582 fflush(psb->out);
583 DEBUG(6) debugf(" reply64 = %s\n", reply64);
584 DEBUG(6) debugf("C: %s\n", reply64);
586 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
587 ok = check_response(psb, FALSE);
589 g_free(reply64);
590 g_free(reply);
591 g_free(chall);
592 g_free(chall64);
593 }
594 }
595 return ok;
596 }
598 static gboolean
599 smtp_out_auth_login(smtp_base *psb)
600 {
601 gboolean ok = FALSE;
602 fprintf(psb->out, "AUTH LOGIN\r\n");
603 fflush(psb->out);
604 DEBUG(4) debugf("C: AUTH LOGIN\r\n");
605 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
606 if ((ok = check_response(psb, TRUE))) {
607 gchar *resp64;
608 guchar *resp;
609 gint resp_size;
610 gchar *reply64;
612 DEBUG(5) debugf("smtp_out_auth_login():\n");
613 resp64 = get_response_arg(&(psb->buffer[4]));
614 DEBUG(5) debugf(" encoded response = `%s'\n", resp64);
615 resp = base64_decode(resp64, &resp_size);
616 g_free(resp64);
617 DEBUG(5) debugf(" decoded response = `%s', size = %d\n", resp, resp_size);
618 g_free(resp);
619 reply64 = base64_encode(psb->auth_login, strlen(psb->auth_login));
620 fprintf(psb->out, "%s\r\n", reply64);
621 fflush(psb->out);
622 DEBUG(6) debugf("C: %s\n", reply64);
623 g_free(reply64);
624 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
625 if ((ok = check_response(psb, TRUE))) {
626 resp64 = get_response_arg(&(psb->buffer[4]));
627 DEBUG(5) debugf(" encoded response = `%s'\n", resp64);
628 resp = base64_decode(resp64, &resp_size);
629 g_free(resp64);
630 DEBUG(5) debugf(" decoded response = `%s', size = %d\n", resp, resp_size);
631 g_free(resp);
632 reply64 = base64_encode(psb->auth_secret, strlen(psb->auth_secret));
633 fprintf(psb->out, "%s\r\n", reply64);
634 fflush(psb->out);
635 DEBUG(6) debugf("C: %s\n", reply64);
636 g_free(reply64);
637 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
638 ok = check_response(psb, FALSE);
639 }
640 }
641 }
642 }
643 return ok;
644 }
646 gboolean
647 smtp_out_auth(smtp_base *psb)
648 {
649 gboolean ok = FALSE;
650 gint i = 0;
651 while (psb->auth_names[i]) {
652 if (strcasecmp(psb->auth_names[i], psb->auth_name) == 0)
653 break;
654 i++;
655 }
656 if (psb->auth_names[i]) {
657 if (strcasecmp(psb->auth_name, "cram-md5") == 0) {
658 smtp_out_auth_cram_md5(psb);
659 } else if (strcasecmp(psb->auth_name, "login") == 0) {
660 smtp_out_auth_login(psb);
661 } else {
662 logwrite(LOG_ERR, "auth method %s not supported\n", psb->auth_name);
663 }
664 } else {
665 logwrite(LOG_ERR, "no auth method %s found.\n", psb->auth_name);
666 }
667 return ok;
668 }
670 #endif
672 gboolean
673 smtp_out_init(smtp_base *psb, gboolean instant_helo)
674 {
675 gboolean ok;
677 logwrite(LOG_INFO, "smtp_out_init(): instant_helo:%d\n", instant_helo);
679 if (!instant_helo) {
680 if ((ok = read_response(psb, SMTP_INITIAL_TIMEOUT))) {
681 ok = check_response(psb, FALSE);
682 }
683 if (!ok) {
684 smtp_out_log_failure(psb, NULL);
685 return ok;
686 }
687 }
689 if ((ok = smtp_helo(psb, psb->helo_name))) {
690 #ifdef ENABLE_AUTH
691 if (psb->auth_name && psb->use_auth) {
692 /* we completely disregard the response of server here. If
693 authentication fails, the server will complain later
694 anyway. I know, this is not polite... */
695 smtp_out_auth(psb);
696 }
697 #endif
698 }
699 if (!ok)
700 smtp_out_log_failure(psb, NULL);
701 return ok;
702 }
704 gint
705 smtp_out_msg(smtp_base *psb, message *msg, address *return_path, GList *rcpt_list, GList *hdr_list)
706 {
707 gint i, size;
708 gboolean ok = TRUE;
709 int rcpt_cnt;
710 int rcpt_accept = 0;
712 DEBUG(5) debugf("smtp_out_msg entered\n");
714 /* defaults: */
715 if (return_path == NULL)
716 return_path = msg->return_path;
717 if (hdr_list == NULL)
718 hdr_list = msg->hdr_list;
719 if (rcpt_list == NULL)
720 rcpt_list = msg->rcpt_list;
721 rcpt_cnt = g_list_length(rcpt_list);
723 size = msg_calc_size(msg, TRUE);
725 /* respect maximum size given by server: */
726 if ((psb->max_size > 0) && (size > psb->max_size)) {
727 logwrite(LOG_WARNING, "%s == host=%s message size (%d) > "
728 "fixed maximum message size of server (%d)",
729 msg->uid, psb->remote_host, size, psb->max_size);
730 psb->error = smtp_cancel;
731 ok = FALSE;
732 }
734 if (ok) {
735 /* pretend the message is a bit larger,
736 just in case the size calculation is buggy */
737 smtp_cmd_mailfrom(psb, return_path, psb->use_size ? size+SMTP_SIZE_ADD : 0);
739 if (!psb->use_pipelining) {
740 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
741 ok = check_response(psb, FALSE);
742 }
743 }
744 if (ok) {
745 GList *rcpt_node;
746 rcpt_accept = 0;
748 for (rcpt_node = g_list_first(rcpt_list); rcpt_node != NULL; rcpt_node = g_list_next(rcpt_node)) {
749 address *rcpt = (address *) (rcpt_node->data);
750 smtp_cmd_rcptto(psb, rcpt);
751 if (!psb->use_pipelining) {
752 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
753 if (check_response(psb, FALSE)) {
754 rcpt_accept++;
755 addr_mark_delivered(rcpt);
756 } else {
757 /* if server returned an error for one recp. we
758 may still try the others. But if it is a timeout, eof
759 or unexpected response, it is more serious and we should
760 give up. */
761 if ((psb->error != smtp_trylater) && (psb->error != smtp_fail)) {
762 ok = FALSE;
763 break;
764 } else {
765 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n",
766 msg->uid, addr_string(rcpt), psb->remote_host, psb->buffer);
767 if (psb->error == smtp_trylater) {
768 addr_mark_defered(rcpt);
769 } else {
770 addr_mark_failed(rcpt);
771 }
772 }
773 } else
774 break;
775 }
776 }
778 /* There is no point in going on if no recp.s were accpted.
779 But we can check that at this point only if not pipelining: */
780 ok = (ok && (psb->use_pipelining || (rcpt_accept > 0)));
781 if (ok) {
783 fprintf(psb->out, "DATA\r\n");
784 fflush(psb->out);
786 DEBUG(4) debugf("C: DATA\r\n");
788 if (psb->use_pipelining) {
789 /* the first pl'ed command was MAIL FROM
790 the last was DATA, whose response can be handled by the 'normal' code
791 all in between were RCPT TO:
792 */
793 /* response to MAIL FROM: */
794 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
795 if ((ok = check_response(psb, FALSE))) {
797 /* response(s) to RCPT TO:
798 this is very similar to the sequence above for no pipeline
799 */
800 for (i = 0; i < rcpt_cnt; i++) {
801 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
802 address *rcpt = g_list_nth_data(rcpt_list, i);
803 if (check_response(psb, FALSE)) {
804 rcpt_accept++;
805 addr_mark_delivered(rcpt);
806 } else {
807 /* if server returned an error 4xx or 5xx for one recp. we
808 may still try the others. But if it is a timeout, eof
809 or unexpected response, it is more serious and we
810 should give up. */
811 if ((psb->error != smtp_trylater) &&
812 (psb->error != smtp_fail)) {
813 ok = FALSE;
814 break;
815 } else {
816 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n", msg->uid,
817 addr_string(rcpt), psb->remote_host, psb->buffer);
818 if (psb->error == smtp_trylater) {
819 addr_mark_defered(rcpt);
820 } else {
821 addr_mark_failed(rcpt);
822 }
823 }
824 }
825 } else {
826 DEBUG(5) debugf("check_response failed after RCPT TO\n");
827 break;
828 }
829 }
830 if (rcpt_accept == 0)
831 ok = FALSE;
832 } else {
833 DEBUG(5) debugf("check_response failed after MAIL FROM\n");
834 }
835 } else {
836 DEBUG(5)
837 debugf("read_response failed after MAIL FROM\n");
838 }
839 }
841 /* if(psb->use_pipelining) */
842 /* response to the DATA cmd */
843 if (ok) {
844 if (read_response(psb, SMTP_DATA_TIMEOUT)) {
845 if (check_response(psb, TRUE)) {
846 send_header(psb, hdr_list);
847 send_data(psb, msg);
849 if (read_response(psb, SMTP_FINAL_TIMEOUT))
850 ok = check_response(psb, FALSE);
851 }
852 }
853 }
854 }
855 }
857 DEBUG(5) {
858 debugf("smtp_out_msg():\n");
859 debugf(" psb->error = %d\n", psb->error);
860 debugf(" ok = %d\n", ok);
861 debugf(" rcpt_accept = %d\n", rcpt_accept);
862 }
864 if (psb->error == smtp_ok) {
865 GList *rcpt_node;
866 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
867 address *rcpt = (address *) (rcpt_node->data);
868 if (addr_is_delivered(rcpt))
869 logwrite(LOG_NOTICE, "%s => %s host=%s\n",
870 msg->uid, addr_string(rcpt), psb->remote_host);
871 }
872 } else {
873 /* if something went wrong,
874 we have to unmark the rcpts prematurely marked as delivered
875 and mark the status */
876 smtp_out_mark_rcpts(psb, rcpt_list);
878 /* log the failure: */
879 smtp_out_log_failure(psb, msg);
880 }
881 return rcpt_accept;
882 }
884 gboolean
885 smtp_out_quit(smtp_base *psb)
886 {
887 fprintf(psb->out, "QUIT\r\n");
888 fflush(psb->out);
890 DEBUG(4) debugf("C: QUIT\n");
892 signal(SIGALRM, SIG_DFL);
894 return TRUE;
895 }
897 gint
898 smtp_deliver(gchar *host, gint port, GList *resolve_list, message *msg, address *return_path, GList *rcpt_list)
899 {
900 smtp_base *psb;
901 smtp_error err;
903 DEBUG(5) debugf("smtp_deliver entered\n");
905 if (return_path == NULL)
906 return_path = msg->return_path;
908 if ((psb = smtp_out_open(host, port, resolve_list))) {
909 set_heloname(psb, return_path->domain, TRUE);
910 /* initiate connection, send message and quit: */
911 if (smtp_out_init(psb, FALSE)) {
912 smtp_out_msg(psb, msg, return_path, rcpt_list, NULL);
913 if (psb->error == smtp_ok || (psb->error == smtp_fail) || (psb->error == smtp_trylater)
914 || (psb->error == smtp_syntax) || (psb->error == smtp_cancel))
915 smtp_out_quit(psb);
916 }
918 err = psb->error;
919 destroy_smtpbase(psb);
921 return err;
922 }
923 return -1;
924 }