masqmail-0.2
view src/smtp_out.c @ 3:8c55886cacd8
man pages will be maintained in troff now
author | meillo@marmaro.de |
---|---|
date | Fri, 26 Sep 2008 21:40:10 +0200 |
parents | |
children | 26e34ae9a3e3 |
line source
1 /* smtp_out.c, Copyright (C) 1999-2001 Oliver Kurth,
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 */
18 /*
19 send bugs to: kurth@innominate.de
20 */
22 /*
23 I always forget these rfc numbers:
24 RFC 821 (SMTP)
25 RFC 1869 (ESMTP)
26 RFC 1870 (ESMTP SIZE)
27 RFC 2197 (ESMTP PIPELINE)
28 RFC 2554 (ESMTP AUTH)
29 */
31 #include "masqmail.h"
32 #include "smtp_out.h"
33 #include "readsock.h"
35 #ifdef ENABLE_AUTH
37 #ifdef USE_LIB_CRYPTO
38 #include <openssl/hmac.h>
39 #include <openssl/md5.h>
40 #include <openssl/evp.h>
41 #else
42 #include "md5/global.h"
43 #include "md5/md5.h"
44 #include "md5/hmac_md5.h"
45 #endif
47 #include "base64/base64.h"
48 #endif
50 void destroy_smtpbase(smtp_base *psb)
51 {
52 fclose(psb->in);
53 fclose(psb->out);
55 close(psb->sock);
57 if(psb->helo_name) g_free(psb->helo_name);
58 if(psb->buffer) g_free(psb->buffer);
59 if(psb->auth_names) g_strfreev(psb->auth_names);
61 if(psb->auth_name) g_free(psb->auth_name);
62 if(psb->auth_login) g_free(psb->auth_login);
63 if(psb->auth_secret) g_free(psb->auth_secret);
64 }
66 gchar *set_heloname(smtp_base *psb, gchar *default_name, gboolean do_correct)
67 {
68 struct sockaddr_in sname;
69 int len = sizeof(struct sockaddr_in);
70 struct hostent *host_entry;
72 if(do_correct){
73 getsockname(psb->sock, (struct sockaddr *)(&sname), &len);
74 DEBUG(5) debugf("socket: name.sin_addr = %s\n", inet_ntoa(sname.sin_addr));
75 host_entry =
76 gethostbyaddr((const char *)&(sname.sin_addr),
77 sizeof(sname.sin_addr), AF_INET);
78 if(host_entry){
79 psb->helo_name = g_strdup(host_entry->h_name);
80 }else{
81 /* we failed to look up our own name. Instead of giving our local hostname,
82 we may give our IP number to show the server that we are at least
83 willing to be honest. For the really picky ones.*/
84 DEBUG(5) debugf("failed to look up own host name.\n");
85 psb->helo_name = g_strdup_printf("[%s]", inet_ntoa(sname.sin_addr));
86 }
87 DEBUG(5) debugf("helo_name = %s\n", psb->helo_name);
88 }
89 if(psb->helo_name == NULL){
90 psb->helo_name = g_strdup(default_name);
91 }
92 return psb->helo_name;
93 }
95 #ifdef ENABLE_AUTH
97 gboolean set_auth(smtp_base *psb, gchar *name, gchar *login, gchar *secret)
98 {
99 if((strcasecmp(name, "CRAM-MD5") == 0) ||
100 (strcasecmp(name, "LOGIN") == 0)) {
101 psb->auth_name = g_strdup(name);
102 psb->auth_login = g_strdup(login);
103 psb->auth_secret = g_strdup(secret);
105 return TRUE;
106 }
107 return FALSE;
108 }
110 #endif
112 static
113 smtp_base *create_smtpbase(gint sock)
114 {
115 gint dup_sock;
117 smtp_base *psb = (smtp_base *)g_malloc(sizeof(smtp_base));
119 psb->sock = sock;
121 psb->use_esmtp = FALSE;
122 psb->use_size = FALSE;
123 psb->use_pipelining = FALSE;
124 psb->use_auth = FALSE;
126 psb->max_size = 0;
127 psb->auth_names = NULL;
129 psb->buffer = (gchar *)g_malloc(SMTP_BUF_LEN);
131 dup_sock = dup(sock);
132 psb->out = fdopen(sock, "w");
133 psb->in = fdopen(dup_sock, "r");
135 psb->error = smtp_ok;
137 psb->helo_name = NULL;
139 psb->auth_name = psb->auth_login = psb->auth_secret = NULL;
141 return psb;
142 }
144 static
145 gboolean read_response(smtp_base *psb, int timeout)
146 {
147 gint buf_pos = 0;
148 gchar code[5];
149 gint i, len;
151 do{
152 len = read_sockline(psb->in, &(psb->buffer[buf_pos]),
153 SMTP_BUF_LEN - buf_pos, timeout, READSOCKL_CHUG);
154 if(len == -3){
155 psb->error = smtp_timeout;
156 return FALSE;
157 }
158 else if(len == -2){
159 psb->error = smtp_syntax;
160 return FALSE;
161 }
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] == '-');
175 return TRUE;
176 }
178 static
179 gboolean check_response(smtp_base *psb, gboolean after_data)
180 {
181 char c = psb->buffer[0];
183 if(((c == '2') && !after_data) || ((c == '3') && after_data)){
184 psb->error = smtp_ok;
185 DEBUG(6) debugf("response OK:'%s' after_date = %d\n", psb->buffer, (int)after_data);
186 return TRUE;
187 }else{
188 if(c == '4')
189 psb->error = smtp_trylater;
190 else if(c == '5')
191 psb->error = smtp_fail;
192 else
193 psb->error = smtp_syntax;
194 DEBUG(6) debugf("response failure:'%s' after_date = %d\n", psb->buffer, (int)after_data);
195 return FALSE;
196 }
197 }
199 static
200 gboolean check_init_response(smtp_base *psb)
201 {
202 if(check_response(psb, FALSE)){
203 psb->use_esmtp = (strstr(psb->buffer, "ESMTP") != NULL);
205 DEBUG(4) debugf(psb->use_esmtp ? "uses esmtp\n" : "no esmtp\n");
207 return TRUE;
208 }
209 return FALSE;
210 }
212 static
213 gchar *get_response_arg(gchar *response)
214 {
215 gchar buf[SMTP_BUF_LEN];
216 gchar *p = response, *q = buf;
218 while(*p && (*p != '\n') && isspace(*p)) p++;
219 if(*p && (*p != '\n')){
220 while(*p && (*p != '\n') && (*p != '\r') && (q < buf+SMTP_BUF_LEN-1)) *(q++) = *(p++);
221 *q = 0;
222 return g_strdup(buf);
223 }
224 return NULL;
225 }
227 static
228 gboolean check_helo_response(smtp_base *psb)
229 {
230 gchar *ptr = psb->buffer;
232 if(!check_response(psb, FALSE))
233 return FALSE;
235 while(*ptr){
236 if(strncasecmp(&(ptr[4]), "SIZE", 4) == 0){
237 gchar *arg;
238 psb->use_size = TRUE;
239 arg = get_response_arg(&(ptr[8]));
240 if(arg){
241 psb->max_size = atoi(arg);
242 g_free(arg);
243 }
244 }
246 if(strncasecmp(&(ptr[4]), "PIPELINING", 10) == 0)
247 psb->use_pipelining = TRUE;
249 if(strncasecmp(&(ptr[4]), "AUTH", 4) == 0){
250 if((ptr[8] == ' ') || (ptr[8] == '=') || (ptr[8] == '\t')){ /* not sure about '\t' */
251 gchar *arg;
252 psb->use_auth = TRUE;
253 arg = get_response_arg(&(ptr[9])); /* after several years I finally learnt to count */
254 if(arg){
255 psb->auth_names = g_strsplit(arg, " " , 0);
256 g_free(arg);
258 DEBUG(4){
259 gint i = 0;
260 while(psb->auth_names[i]){
261 debugf("offered AUTH %s\n", psb->auth_names[i]);
262 i++;
263 }
264 }
265 }
266 }
267 }
269 while(*ptr != '\n') ptr++;
270 ptr++;
271 }
273 DEBUG(4){
274 debugf(psb->use_size ? "uses SIZE\n" : "no size\n");
275 debugf(psb->use_pipelining ? "uses PIPELINING\n" : "no pipelining\n");
276 debugf(psb->use_auth ? "uses AUTH\n" : "no auth\n");
277 }
279 return TRUE;
280 }
282 static
283 gboolean smtp_helo(smtp_base *psb, gchar *helo)
284 {
285 while(TRUE){
286 if(psb->use_esmtp){
287 fprintf(psb->out, "EHLO %s\r\n", helo); fflush(psb->out);
289 DEBUG(4) debugf("EHLO %s\r\n", helo);
291 }else{
292 fprintf(psb->out, "HELO %s\r\n", helo); fflush(psb->out);
294 DEBUG(4) debugf("HELO %s\r\n", helo);
296 }
298 if(!read_response(psb, SMTP_CMD_TIMEOUT))
299 return FALSE;
301 if(check_helo_response(psb))
302 return TRUE;
303 else{
304 if(psb->error == smtp_fail){
305 if(psb->use_esmtp){
306 /* our guess that server understands EHLO was wrong,
307 try again with HELO
308 */
309 psb->use_esmtp = FALSE;
310 }else{
311 /* what sort of server ist THAT ?!
312 give up...
313 */
314 return FALSE;
315 }
316 }else
317 return FALSE;
318 }
319 }
320 }
322 static
323 void smtp_cmd_mailfrom(smtp_base *psb, address *return_path, guint size)
324 {
325 if(psb->use_size){
326 fprintf(psb->out, "MAIL FROM:%s SIZE=%d\r\n",
327 addr_string(return_path), size);
328 fflush(psb->out);
330 DEBUG(4) debugf("MAIL FROM:%s SIZE=%d\r\n",
331 addr_string(return_path), size);
333 }else{
334 fprintf(psb->out, "MAIL FROM:%s\r\n", addr_string(return_path));
335 fflush(psb->out);
337 DEBUG(4) debugf("MAIL FROM:%s\r\n", addr_string(return_path));
338 }
339 }
341 static
342 void smtp_cmd_rcptto(smtp_base *psb, address *rcpt)
343 {
344 fprintf(psb->out, "RCPT TO:%s\r\n", addr_string(rcpt));
345 fflush(psb->out);
346 DEBUG(4) debugf("RCPT TO:%s\n", addr_string(rcpt));
347 }
349 static
350 void send_data_line(smtp_base *psb, gchar *data)
351 {
352 /* According to RFC 821 each line should be terminated with CRLF.
353 Since a dot on a line itself marks the end of data, each line
354 beginning with a dot is prepended with another dot.
355 */
356 gchar *ptr;
357 gboolean new_line = TRUE; /* previous versions assumed that each item was
358 exactly one line. This is no longer the case */
360 ptr = data;
361 while(*ptr){
362 int c = (int)(*ptr);
363 if(c == '.')
364 if(new_line)
365 putc('.', psb->out);
366 if(c == '\n'){
367 putc('\r', psb->out);
368 putc('\n', psb->out);
369 new_line = TRUE;
370 }else{
371 putc(c, psb->out);
372 new_line = FALSE;
373 }
374 ptr++;
375 }
376 }
378 static
379 void send_header(smtp_base *psb, GList *hdr_list)
380 {
381 GList *node;
382 gint num_hdrs = 0;
384 /* header */
385 if(hdr_list){
386 foreach(hdr_list, node){
387 if(node->data){
388 header *hdr = (header *)(node->data);
389 if(hdr->header){
390 send_data_line(psb, hdr->header);
391 num_hdrs++;
392 }
393 }
394 }
395 }
397 /* empty line separating headers from data: */
398 putc('\r', psb->out);
399 putc('\n', psb->out);
401 DEBUG(4) debugf("sent %d headers\n", num_hdrs);
402 }
404 static
405 void send_data(smtp_base *psb, message *msg)
406 {
407 GList *node;
408 gint num_lines = 0;
410 /* data */
411 if(msg->data_list){
412 for(node = g_list_first(msg->data_list); node; node = g_list_next(node)){
413 if(node->data){
414 send_data_line(psb, node->data);
415 num_lines++;
416 }
417 }
418 }
420 DEBUG(4) debugf("sent %d lines of data\n", num_lines);
422 fprintf(psb->out, ".\r\n");
423 fflush(psb->out);
424 }
426 void smtp_out_mark_rcpts(smtp_base *psb, GList *rcpt_list)
427 {
428 GList *rcpt_node;
429 for(rcpt_node = g_list_first(rcpt_list);
430 rcpt_node;
431 rcpt_node = g_list_next(rcpt_node)){
432 address *rcpt = (address *)(rcpt_node->data);
434 addr_unmark_delivered(rcpt);
436 if((psb->error == smtp_trylater) || (psb->error == smtp_timeout) ||
437 (psb->error == smtp_eof)){
438 addr_mark_defered(rcpt);
439 }else{
440 addr_mark_failed(rcpt);
441 }
442 }
443 }
445 void smtp_out_log_failure(smtp_base *psb, message *msg)
446 {
447 gchar *err_str;
449 if(psb->error == smtp_timeout)
450 err_str = g_strdup("connection timed out.");
451 else if(psb->error == smtp_eof)
452 err_str = g_strdup("connection terminated prematurely.");
453 else if(psb->error == smtp_syntax)
454 err_str = g_strdup_printf("got unexpected response: %s", psb->buffer);
455 else if(psb->error == smtp_cancel)
456 err_str = g_strdup("delivery was canceled.\n");
457 else
458 /* error message should still be in the buffer */
459 err_str = g_strdup_printf("failed: %s\n", psb->buffer);
461 if(msg == NULL)
462 logwrite(LOG_NOTICE, "host=%s %s\n",
463 psb->remote_host, err_str);
464 else
465 logwrite(LOG_NOTICE, "%s == host=%s %s\n",
466 msg->uid, psb->remote_host, err_str);
468 g_free(err_str);
469 }
471 smtp_base *smtp_out_open(gchar *host, gint port, GList *resolve_list)
472 {
473 smtp_base *psb;
474 gint sock;
475 mxip_addr *addr;
477 DEBUG(5) debugf("smtp_out_open entered, host = %s\n", host);
479 if((addr = connect_resolvelist(&sock, host, port, resolve_list))){
480 /* create structure to hold status data: */
481 psb = create_smtpbase(sock);
482 psb->remote_host = addr->name;
484 DEBUG(5){
485 struct sockaddr_in name;
486 int len = sizeof(struct sockaddr);
487 getsockname(sock, (struct sockaddr *)(&name), &len);
488 debugf("socket: name.sin_addr = %s\n", inet_ntoa(name.sin_addr));
489 }
490 return psb;
491 }else{
492 DEBUG(5) debugf("connect_resolvelist failed: %s %s\n", strerror(errno), hstrerror(h_errno));
493 }
495 return NULL;
496 }
498 smtp_base *smtp_out_open_child(gchar *cmd)
499 {
500 smtp_base *psb;
501 gint sock;
503 DEBUG(5) debugf("smtp_out_open_child entered, cmd = %s\n", cmd);
505 sock = child(cmd);
507 if(sock > 0){
508 psb = create_smtpbase(sock);
509 psb->remote_host = NULL;
511 return psb;
512 }
514 return NULL;
515 }
517 gboolean smtp_out_rset(smtp_base *psb)
518 {
519 gboolean ok;
521 fprintf(psb->out, "RSET\r\n"); fflush(psb->out);
522 DEBUG(4) debugf("RSET\n");
524 if((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
525 if(check_response(psb, FALSE))
526 return TRUE;
528 smtp_out_log_failure(psb, NULL);
530 return FALSE;
531 }
533 #ifdef ENABLE_AUTH
535 static
536 gboolean smtp_out_auth_cram_md5(smtp_base *psb)
537 {
538 gboolean ok = FALSE;
540 fprintf(psb->out, "AUTH CRAM-MD5\r\n"); fflush(psb->out);
541 DEBUG(4) debugf("AUTH CRAM-MD5\n");
542 if((ok = read_response(psb, SMTP_CMD_TIMEOUT))){
543 if((ok = check_response(psb, TRUE))){
544 gchar *chall64 = get_response_arg(&(psb->buffer[4]));
545 gint chall_size;
546 gchar *chall = base64_decode(chall64, &chall_size);
547 guchar digest[16], *reply64, *reply;
548 gchar digest_string[33];
549 gint i;
550 #ifdef USE_LIB_CRYPTO
551 unsigned int digest_len;
552 #endif
554 DEBUG(5) debugf("encoded challenge = %s\n", chall64);
555 DEBUG(5) debugf("decoded challenge = %s, size = %d\n", chall, chall_size);
557 DEBUG(5) debugf("secret = %s\n", psb->auth_secret);
559 #ifdef USE_LIB_CRYPTO
560 HMAC(EVP_md5(), psb->auth_secret, strlen(psb->auth_secret), chall, chall_size, digest, &digest_len);
561 #else
562 hmac_md5(chall, chall_size, psb->auth_secret, strlen(psb->auth_secret), digest);
563 #endif
565 for(i = 0; i < 16; i++)
566 sprintf(&(digest_string[i+i]), "%02x", (unsigned int)(digest[i]));
567 digest_string[32] = 0;
569 DEBUG(5) debugf("digest = %s\n", digest_string);
571 reply = g_strdup_printf("%s %s", psb->auth_login, digest_string);
572 DEBUG(5) debugf("unencoded reply = %s\n", reply);
574 reply64 = base64_encode(reply, strlen(reply));
575 DEBUG(5) debugf("encoded reply = %s\n", reply64);
577 fprintf(psb->out, "%s\r\n", reply64); fflush(psb->out);
578 DEBUG(4) debugf("%s\n", reply64);
580 if((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
581 ok = check_response(psb, FALSE);
583 g_free(reply64);
584 g_free(reply);
585 g_free(chall);
586 g_free(chall64);
587 }
588 }
589 return ok;
590 }
592 static
593 gboolean smtp_out_auth_login(smtp_base *psb)
594 {
595 gboolean ok = FALSE;
596 fprintf(psb->out, "AUTH LOGIN\r\n"); fflush(psb->out);
597 if((ok = read_response(psb, SMTP_CMD_TIMEOUT))){
598 if((ok = check_response(psb, TRUE))){
599 gchar *resp64;
600 guchar *resp;
601 gint resp_size;
602 gchar *reply64;
604 resp64 = get_response_arg(&(psb->buffer[4]));
605 DEBUG(5) debugf("encoded response = %s\n", resp64);
606 resp = base64_decode(resp64, &resp_size);
607 g_free(resp64);
608 DEBUG(5) debugf("decoded response = %s, size = %d\n",
609 resp, resp_size);
610 g_free(resp);
611 reply64 = base64_encode(psb->auth_login,
612 strlen(psb->auth_login));
613 fprintf(psb->out, "%s\r\n", reply64); fflush(psb->out);
614 g_free(reply64);
615 if((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
616 if ((ok = check_response(psb, TRUE))) {
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",
622 resp, resp_size);
623 g_free(resp);
624 reply64 = base64_encode(psb->auth_secret,
625 strlen(psb->auth_secret));
626 fprintf(psb->out, "%s\r\n", reply64); fflush(psb->out);
627 g_free(reply64);
628 if((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
629 ok = check_response(psb, FALSE);
630 }
631 }
632 }
633 }
634 return ok;
635 }
637 gboolean smtp_out_auth(smtp_base *psb)
638 {
639 gboolean ok = FALSE;
640 gint i = 0;
641 while(psb->auth_names[i]){
642 if(strcasecmp(psb->auth_names[i], psb->auth_name) == 0)
643 break;
644 i++;
645 }
646 if(psb->auth_names[i]){
647 if(strcasecmp(psb->auth_name, "cram-md5") == 0){
648 smtp_out_auth_cram_md5(psb);
649 }else if(strcasecmp(psb->auth_name, "login") == 0){
650 smtp_out_auth_login(psb);
651 }else{
652 logwrite(LOG_ERR, "auth method %s not supported\n", psb->auth_name);
653 }
654 }else{
655 logwrite(LOG_ERR, "no auth method %s found.\n", psb->auth_name);
656 }
657 return ok;
658 }
660 #endif
662 gboolean smtp_out_init(smtp_base *psb)
663 {
664 gboolean ok;
666 if((ok = read_response(psb, SMTP_INITIAL_TIMEOUT))){
667 if((ok = check_init_response(psb))){
669 if((ok = smtp_helo(psb, psb->helo_name))){
670 #ifdef ENABLE_AUTH
671 if(psb->auth_name && psb->use_auth){
672 /* we completely disregard the response of server here. If
673 authentication fails, the server will complain later
674 anyway. I know, this is not polite... */
675 smtp_out_auth(psb);
676 }
677 #endif
678 }
679 }
680 }
681 if(!ok)
682 smtp_out_log_failure(psb, NULL);
683 return ok;
684 }
686 gint smtp_out_msg(smtp_base *psb,
687 message *msg, address *return_path, GList *rcpt_list,
688 GList *hdr_list)
689 {
690 gint i, size;
691 gboolean ok = TRUE;
692 int rcpt_cnt;
693 int rcpt_accept = 0;
695 DEBUG(5) debugf("smtp_out_msg entered\n");
697 /* defaults: */
698 if(return_path == NULL)
699 return_path = msg->return_path;
700 if(hdr_list == NULL)
701 hdr_list = msg->hdr_list;
702 if(rcpt_list == NULL)
703 rcpt_list = msg->rcpt_list;
704 rcpt_cnt = g_list_length(rcpt_list);
706 size = msg_calc_size(msg, TRUE);
708 /* respect maximum size given by server: */
709 if((psb->max_size > 0) && (size > psb->max_size)){
710 logwrite(LOG_WARNING,
711 "%s == host=%s message size (%d) > fixed maximum message size of server (%d)",
712 msg->uid, psb->remote_host, size, psb->max_size);
713 psb->error = smtp_cancel;
714 ok = FALSE;
715 }
717 if(ok){
718 smtp_cmd_mailfrom(psb, return_path,
719 psb->use_size ?
720 size + SMTP_SIZE_ADD : 0);
722 if(!psb->use_pipelining){
723 if((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
724 ok = check_response(psb, FALSE);
725 }
726 }
727 if(ok){
728 GList *rcpt_node;
729 rcpt_accept = 0;
731 for(rcpt_node = g_list_first(rcpt_list);
732 rcpt_node != NULL;
733 rcpt_node = g_list_next(rcpt_node)){
734 address *rcpt = (address *)(rcpt_node->data);
735 smtp_cmd_rcptto(psb, rcpt);
736 if(!psb->use_pipelining){
737 if((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
738 if(check_response(psb, FALSE)){
739 rcpt_accept++;
740 addr_mark_delivered(rcpt);
741 }
742 else{
743 /* if server returned an error for one recp. we
744 may still try the others. But if it is a timeout, eof
745 or unexpected response, it is more serious and we should
746 give up. */
747 if((psb->error != smtp_trylater) &&
748 (psb->error != smtp_fail)){
749 ok = FALSE;
750 break;
751 }else{
752 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s",
753 msg->uid, addr_string(rcpt),
754 psb->remote_host, psb->buffer);
755 if(psb->error == smtp_trylater){
756 addr_mark_defered(rcpt);
757 }else{
758 addr_mark_failed(rcpt);
759 }
760 }
761 }
762 else
763 break;
764 }
765 }
767 /* There is no point in going on if no recp.s were accpted.
768 But we can check that at this point only if not pipelining: */
769 ok = (ok && (psb->use_pipelining || (rcpt_accept > 0)));
770 if(ok){
772 fprintf(psb->out, "DATA\r\n"); fflush(psb->out);
774 DEBUG(4) debugf("DATA\r\n");
776 if(psb->use_pipelining){
777 /* the first pl'ed command was MAIL FROM
778 the last was DATA, whose response can be handled by the 'normal' code
779 all in between were RCPT TO:
780 */
781 /* response to MAIL FROM: */
782 if((ok = read_response(psb, SMTP_CMD_TIMEOUT))){
783 if((ok = check_response(psb, FALSE))){
785 /* response(s) to RCPT TO:
786 this is very similar to the sequence above for no pipeline
787 */
788 for(i = 0; i < rcpt_cnt; i++){
789 if((ok = read_response(psb, SMTP_CMD_TIMEOUT))){
790 address *rcpt = g_list_nth_data(rcpt_list, i);
791 if(check_response(psb, FALSE)){
792 rcpt_accept++;
793 addr_mark_delivered(rcpt);
794 }
795 else{
796 /* if server returned an error 4xx or 5xx for one recp. we
797 may still try the others. But if it is a timeout, eof
798 or unexpected response, it is more serious and we
799 should give up. */
800 if((psb->error != smtp_trylater) &&
801 (psb->error != smtp_fail)){
802 ok = FALSE;
803 break;
804 }else{
805 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s",
806 msg->uid, addr_string(rcpt),
807 psb->remote_host, psb->buffer);
808 if(psb->error == smtp_trylater){
809 addr_mark_defered(rcpt);
810 }else{
811 addr_mark_failed(rcpt);
812 }
813 }
814 }
815 }else{
816 DEBUG(5) debugf("check_response failed after RCPT TO\n");
817 break;
818 }
819 }
820 if(rcpt_accept == 0)
821 ok = FALSE;
822 }else{
823 DEBUG(5) debugf("check_response failed after MAIL FROM\n");
824 }
825 }else{
826 DEBUG(5) debugf("read_response failed after MAIL FROM\n");
827 }
828 } /* if(psb->use_pipelining) */
830 /* response to the DATA cmd */
831 if(ok){
832 if(read_response(psb, SMTP_DATA_TIMEOUT)){
833 if(check_response(psb, TRUE)){
834 send_header(psb, hdr_list);
835 send_data(psb, msg);
837 if(read_response(psb, SMTP_FINAL_TIMEOUT))
838 ok = check_response(psb, FALSE);
839 }
840 }
841 }
842 }
843 }
845 DEBUG(5){
846 debugf("psb->error = %d\n", psb->error);
847 debugf("ok = %d\n", ok);
848 debugf("rcpt_accept = %d\n", rcpt_accept);
849 }
851 if(psb->error == smtp_ok){
852 GList *rcpt_node;
853 for(rcpt_node = g_list_first(rcpt_list);
854 rcpt_node;
855 rcpt_node = g_list_next(rcpt_node)){
856 address *rcpt = (address *)(rcpt_node->data);
857 if(addr_is_delivered(rcpt))
858 logwrite(LOG_NOTICE, "%s => %s host=%s with %s\n",
859 msg->uid, addr_string(rcpt), psb->remote_host,
860 psb->use_esmtp ? "esmtp" : "smtp");
861 }
862 }else{
863 /* if something went wrong,
864 we have to unmark the rcpts prematurely marked as delivered
865 and mark the status */
866 smtp_out_mark_rcpts(psb, rcpt_list);
868 /* log the failure: */
869 smtp_out_log_failure(psb, msg);
870 }
871 return rcpt_accept;
872 }
874 gboolean smtp_out_quit(smtp_base *psb)
875 {
876 fprintf(psb->out, "QUIT\r\n"); fflush(psb->out);
878 DEBUG(4) debugf("QUIT\n");
880 signal(SIGALRM, SIG_DFL);
882 return TRUE;
883 }
885 gint smtp_deliver(gchar *host, gint port, GList *resolve_list,
886 message *msg,
887 address *return_path,
888 GList *rcpt_list)
889 {
890 smtp_base *psb;
891 smtp_error err;
893 DEBUG(5) debugf("smtp_deliver entered\n");
895 if(return_path == NULL)
896 return_path = msg->return_path;
898 if((psb = smtp_out_open(host, port, resolve_list))){
899 set_heloname(psb, return_path->domain, TRUE);
900 /* initiate connection, send message and quit: */
901 if(smtp_out_init(psb)){
902 smtp_out_msg(psb, msg, return_path, rcpt_list, NULL);
903 if(psb->error == smtp_ok ||
904 (psb->error == smtp_fail) ||
905 (psb->error == smtp_trylater) ||
906 (psb->error == smtp_syntax) ||
907 (psb->error == smtp_cancel))
909 smtp_out_quit(psb);
910 }
912 err = psb->error;
913 destroy_smtpbase(psb);
915 return err;
916 }
917 return -1;
918 }