comparison src/smtp_out.c @ 0:08114f7dcc23 0.2.21

this is masqmail-0.2.21 from oliver kurth
author meillo@marmaro.de
date Fri, 26 Sep 2008 17:05:23 +0200
parents
children 26e34ae9a3e3
comparison
equal deleted inserted replaced
-1:000000000000 0:08114f7dcc23
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 */
17
18 /*
19 send bugs to: kurth@innominate.de
20 */
21
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 */
30
31 #include "masqmail.h"
32 #include "smtp_out.h"
33 #include "readsock.h"
34
35 #ifdef ENABLE_AUTH
36
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
46
47 #include "base64/base64.h"
48 #endif
49
50 void destroy_smtpbase(smtp_base *psb)
51 {
52 fclose(psb->in);
53 fclose(psb->out);
54
55 close(psb->sock);
56
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);
60
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 }
65
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;
71
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 }
94
95 #ifdef ENABLE_AUTH
96
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);
104
105 return TRUE;
106 }
107 return FALSE;
108 }
109
110 #endif
111
112 static
113 smtp_base *create_smtpbase(gint sock)
114 {
115 gint dup_sock;
116
117 smtp_base *psb = (smtp_base *)g_malloc(sizeof(smtp_base));
118
119 psb->sock = sock;
120
121 psb->use_esmtp = FALSE;
122 psb->use_size = FALSE;
123 psb->use_pipelining = FALSE;
124 psb->use_auth = FALSE;
125
126 psb->max_size = 0;
127 psb->auth_names = NULL;
128
129 psb->buffer = (gchar *)g_malloc(SMTP_BUF_LEN);
130
131 dup_sock = dup(sock);
132 psb->out = fdopen(sock, "w");
133 psb->in = fdopen(dup_sock, "r");
134
135 psb->error = smtp_ok;
136
137 psb->helo_name = NULL;
138
139 psb->auth_name = psb->auth_login = psb->auth_secret = NULL;
140
141 return psb;
142 }
143
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;
150
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);
170
171 buf_pos += len;
172
173 }while(code[3] == '-');
174
175 return TRUE;
176 }
177
178 static
179 gboolean check_response(smtp_base *psb, gboolean after_data)
180 {
181 char c = psb->buffer[0];
182
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 }
198
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);
204
205 DEBUG(4) debugf(psb->use_esmtp ? "uses esmtp\n" : "no esmtp\n");
206
207 return TRUE;
208 }
209 return FALSE;
210 }
211
212 static
213 gchar *get_response_arg(gchar *response)
214 {
215 gchar buf[SMTP_BUF_LEN];
216 gchar *p = response, *q = buf;
217
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 }
226
227 static
228 gboolean check_helo_response(smtp_base *psb)
229 {
230 gchar *ptr = psb->buffer;
231
232 if(!check_response(psb, FALSE))
233 return FALSE;
234
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 }
245
246 if(strncasecmp(&(ptr[4]), "PIPELINING", 10) == 0)
247 psb->use_pipelining = TRUE;
248
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);
257
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 }
268
269 while(*ptr != '\n') ptr++;
270 ptr++;
271 }
272
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 }
278
279 return TRUE;
280 }
281
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);
288
289 DEBUG(4) debugf("EHLO %s\r\n", helo);
290
291 }else{
292 fprintf(psb->out, "HELO %s\r\n", helo); fflush(psb->out);
293
294 DEBUG(4) debugf("HELO %s\r\n", helo);
295
296 }
297
298 if(!read_response(psb, SMTP_CMD_TIMEOUT))
299 return FALSE;
300
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 }
321
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);
329
330 DEBUG(4) debugf("MAIL FROM:%s SIZE=%d\r\n",
331 addr_string(return_path), size);
332
333 }else{
334 fprintf(psb->out, "MAIL FROM:%s\r\n", addr_string(return_path));
335 fflush(psb->out);
336
337 DEBUG(4) debugf("MAIL FROM:%s\r\n", addr_string(return_path));
338 }
339 }
340
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 }
348
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 */
359
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 }
377
378 static
379 void send_header(smtp_base *psb, GList *hdr_list)
380 {
381 GList *node;
382 gint num_hdrs = 0;
383
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 }
396
397 /* empty line separating headers from data: */
398 putc('\r', psb->out);
399 putc('\n', psb->out);
400
401 DEBUG(4) debugf("sent %d headers\n", num_hdrs);
402 }
403
404 static
405 void send_data(smtp_base *psb, message *msg)
406 {
407 GList *node;
408 gint num_lines = 0;
409
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 }
419
420 DEBUG(4) debugf("sent %d lines of data\n", num_lines);
421
422 fprintf(psb->out, ".\r\n");
423 fflush(psb->out);
424 }
425
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);
433
434 addr_unmark_delivered(rcpt);
435
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 }
444
445 void smtp_out_log_failure(smtp_base *psb, message *msg)
446 {
447 gchar *err_str;
448
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);
460
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);
467
468 g_free(err_str);
469 }
470
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;
476
477 DEBUG(5) debugf("smtp_out_open entered, host = %s\n", host);
478
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;
483
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 }
494
495 return NULL;
496 }
497
498 smtp_base *smtp_out_open_child(gchar *cmd)
499 {
500 smtp_base *psb;
501 gint sock;
502
503 DEBUG(5) debugf("smtp_out_open_child entered, cmd = %s\n", cmd);
504
505 sock = child(cmd);
506
507 if(sock > 0){
508 psb = create_smtpbase(sock);
509 psb->remote_host = NULL;
510
511 return psb;
512 }
513
514 return NULL;
515 }
516
517 gboolean smtp_out_rset(smtp_base *psb)
518 {
519 gboolean ok;
520
521 fprintf(psb->out, "RSET\r\n"); fflush(psb->out);
522 DEBUG(4) debugf("RSET\n");
523
524 if((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
525 if(check_response(psb, FALSE))
526 return TRUE;
527
528 smtp_out_log_failure(psb, NULL);
529
530 return FALSE;
531 }
532
533 #ifdef ENABLE_AUTH
534
535 static
536 gboolean smtp_out_auth_cram_md5(smtp_base *psb)
537 {
538 gboolean ok = FALSE;
539
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
553
554 DEBUG(5) debugf("encoded challenge = %s\n", chall64);
555 DEBUG(5) debugf("decoded challenge = %s, size = %d\n", chall, chall_size);
556
557 DEBUG(5) debugf("secret = %s\n", psb->auth_secret);
558
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
564
565 for(i = 0; i < 16; i++)
566 sprintf(&(digest_string[i+i]), "%02x", (unsigned int)(digest[i]));
567 digest_string[32] = 0;
568
569 DEBUG(5) debugf("digest = %s\n", digest_string);
570
571 reply = g_strdup_printf("%s %s", psb->auth_login, digest_string);
572 DEBUG(5) debugf("unencoded reply = %s\n", reply);
573
574 reply64 = base64_encode(reply, strlen(reply));
575 DEBUG(5) debugf("encoded reply = %s\n", reply64);
576
577 fprintf(psb->out, "%s\r\n", reply64); fflush(psb->out);
578 DEBUG(4) debugf("%s\n", reply64);
579
580 if((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
581 ok = check_response(psb, FALSE);
582
583 g_free(reply64);
584 g_free(reply);
585 g_free(chall);
586 g_free(chall64);
587 }
588 }
589 return ok;
590 }
591
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;
603
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 }
636
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 }
659
660 #endif
661
662 gboolean smtp_out_init(smtp_base *psb)
663 {
664 gboolean ok;
665
666 if((ok = read_response(psb, SMTP_INITIAL_TIMEOUT))){
667 if((ok = check_init_response(psb))){
668
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 }
685
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;
694
695 DEBUG(5) debugf("smtp_out_msg entered\n");
696
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);
705
706 size = msg_calc_size(msg, TRUE);
707
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 }
716
717 if(ok){
718 smtp_cmd_mailfrom(psb, return_path,
719 psb->use_size ?
720 size + SMTP_SIZE_ADD : 0);
721
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;
730
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 }
766
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){
771
772 fprintf(psb->out, "DATA\r\n"); fflush(psb->out);
773
774 DEBUG(4) debugf("DATA\r\n");
775
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))){
784
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) */
829
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);
836
837 if(read_response(psb, SMTP_FINAL_TIMEOUT))
838 ok = check_response(psb, FALSE);
839 }
840 }
841 }
842 }
843 }
844
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 }
850
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);
867
868 /* log the failure: */
869 smtp_out_log_failure(psb, msg);
870 }
871 return rcpt_accept;
872 }
873
874 gboolean smtp_out_quit(smtp_base *psb)
875 {
876 fprintf(psb->out, "QUIT\r\n"); fflush(psb->out);
877
878 DEBUG(4) debugf("QUIT\n");
879
880 signal(SIGALRM, SIG_DFL);
881
882 return TRUE;
883 }
884
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;
892
893 DEBUG(5) debugf("smtp_deliver entered\n");
894
895 if(return_path == NULL)
896 return_path = msg->return_path;
897
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))
908
909 smtp_out_quit(psb);
910 }
911
912 err = psb->error;
913 destroy_smtpbase(psb);
914
915 return err;
916 }
917 return -1;
918 }