masqmail-0.2
diff src/smtp_out.c @ 0:08114f7dcc23
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 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/smtp_out.c Fri Sep 26 17:05:23 2008 +0200 1.3 @@ -0,0 +1,918 @@ 1.4 +/* smtp_out.c, Copyright (C) 1999-2001 Oliver Kurth, 1.5 + * 1.6 + * This program is free software; you can redistribute it and/or modify 1.7 + * it under the terms of the GNU General Public License as published by 1.8 + * the Free Software Foundation; either version 2 of the License, or 1.9 + * (at your option) any later version. 1.10 + * 1.11 + * This program is distributed in the hope that it will be useful, 1.12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 1.13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.14 + * GNU General Public License for more details. 1.15 + * 1.16 + * You should have received a copy of the GNU General Public License 1.17 + * along with this program; if not, write to the Free Software 1.18 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 1.19 + */ 1.20 + 1.21 +/* 1.22 + send bugs to: kurth@innominate.de 1.23 +*/ 1.24 + 1.25 +/* 1.26 + I always forget these rfc numbers: 1.27 + RFC 821 (SMTP) 1.28 + RFC 1869 (ESMTP) 1.29 + RFC 1870 (ESMTP SIZE) 1.30 + RFC 2197 (ESMTP PIPELINE) 1.31 + RFC 2554 (ESMTP AUTH) 1.32 +*/ 1.33 + 1.34 +#include "masqmail.h" 1.35 +#include "smtp_out.h" 1.36 +#include "readsock.h" 1.37 + 1.38 +#ifdef ENABLE_AUTH 1.39 + 1.40 +#ifdef USE_LIB_CRYPTO 1.41 +#include <openssl/hmac.h> 1.42 +#include <openssl/md5.h> 1.43 +#include <openssl/evp.h> 1.44 +#else 1.45 +#include "md5/global.h" 1.46 +#include "md5/md5.h" 1.47 +#include "md5/hmac_md5.h" 1.48 +#endif 1.49 + 1.50 +#include "base64/base64.h" 1.51 +#endif 1.52 + 1.53 +void destroy_smtpbase(smtp_base *psb) 1.54 +{ 1.55 + fclose(psb->in); 1.56 + fclose(psb->out); 1.57 + 1.58 + close(psb->sock); 1.59 + 1.60 + if(psb->helo_name) g_free(psb->helo_name); 1.61 + if(psb->buffer) g_free(psb->buffer); 1.62 + if(psb->auth_names) g_strfreev(psb->auth_names); 1.63 + 1.64 + if(psb->auth_name) g_free(psb->auth_name); 1.65 + if(psb->auth_login) g_free(psb->auth_login); 1.66 + if(psb->auth_secret) g_free(psb->auth_secret); 1.67 +} 1.68 + 1.69 +gchar *set_heloname(smtp_base *psb, gchar *default_name, gboolean do_correct) 1.70 +{ 1.71 + struct sockaddr_in sname; 1.72 + int len = sizeof(struct sockaddr_in); 1.73 + struct hostent *host_entry; 1.74 + 1.75 + if(do_correct){ 1.76 + getsockname(psb->sock, (struct sockaddr *)(&sname), &len); 1.77 + DEBUG(5) debugf("socket: name.sin_addr = %s\n", inet_ntoa(sname.sin_addr)); 1.78 + host_entry = 1.79 + gethostbyaddr((const char *)&(sname.sin_addr), 1.80 + sizeof(sname.sin_addr), AF_INET); 1.81 + if(host_entry){ 1.82 + psb->helo_name = g_strdup(host_entry->h_name); 1.83 + }else{ 1.84 + /* we failed to look up our own name. Instead of giving our local hostname, 1.85 + we may give our IP number to show the server that we are at least 1.86 + willing to be honest. For the really picky ones.*/ 1.87 + DEBUG(5) debugf("failed to look up own host name.\n"); 1.88 + psb->helo_name = g_strdup_printf("[%s]", inet_ntoa(sname.sin_addr)); 1.89 + } 1.90 + DEBUG(5) debugf("helo_name = %s\n", psb->helo_name); 1.91 + } 1.92 + if(psb->helo_name == NULL){ 1.93 + psb->helo_name = g_strdup(default_name); 1.94 + } 1.95 + return psb->helo_name; 1.96 +} 1.97 + 1.98 +#ifdef ENABLE_AUTH 1.99 + 1.100 +gboolean set_auth(smtp_base *psb, gchar *name, gchar *login, gchar *secret) 1.101 +{ 1.102 + if((strcasecmp(name, "CRAM-MD5") == 0) || 1.103 + (strcasecmp(name, "LOGIN") == 0)) { 1.104 + psb->auth_name = g_strdup(name); 1.105 + psb->auth_login = g_strdup(login); 1.106 + psb->auth_secret = g_strdup(secret); 1.107 + 1.108 + return TRUE; 1.109 + } 1.110 + return FALSE; 1.111 +} 1.112 + 1.113 +#endif 1.114 + 1.115 +static 1.116 +smtp_base *create_smtpbase(gint sock) 1.117 +{ 1.118 + gint dup_sock; 1.119 + 1.120 + smtp_base *psb = (smtp_base *)g_malloc(sizeof(smtp_base)); 1.121 + 1.122 + psb->sock = sock; 1.123 + 1.124 + psb->use_esmtp = FALSE; 1.125 + psb->use_size = FALSE; 1.126 + psb->use_pipelining = FALSE; 1.127 + psb->use_auth = FALSE; 1.128 + 1.129 + psb->max_size = 0; 1.130 + psb->auth_names = NULL; 1.131 + 1.132 + psb->buffer = (gchar *)g_malloc(SMTP_BUF_LEN); 1.133 + 1.134 + dup_sock = dup(sock); 1.135 + psb->out = fdopen(sock, "w"); 1.136 + psb->in = fdopen(dup_sock, "r"); 1.137 + 1.138 + psb->error = smtp_ok; 1.139 + 1.140 + psb->helo_name = NULL; 1.141 + 1.142 + psb->auth_name = psb->auth_login = psb->auth_secret = NULL; 1.143 + 1.144 + return psb; 1.145 +} 1.146 + 1.147 +static 1.148 +gboolean read_response(smtp_base *psb, int timeout) 1.149 +{ 1.150 + gint buf_pos = 0; 1.151 + gchar code[5]; 1.152 + gint i, len; 1.153 + 1.154 + do{ 1.155 + len = read_sockline(psb->in, &(psb->buffer[buf_pos]), 1.156 + SMTP_BUF_LEN - buf_pos, timeout, READSOCKL_CHUG); 1.157 + if(len == -3){ 1.158 + psb->error = smtp_timeout; 1.159 + return FALSE; 1.160 + } 1.161 + else if(len == -2){ 1.162 + psb->error = smtp_syntax; 1.163 + return FALSE; 1.164 + } 1.165 + else if(len == -1){ 1.166 + psb->error = smtp_eof; 1.167 + return FALSE; 1.168 + } 1.169 + for(i = 0; i < 4; i++) 1.170 + code[i] = psb->buffer[buf_pos+i]; 1.171 + code[i] = 0; 1.172 + psb->last_code = atoi(code); 1.173 + 1.174 + buf_pos += len; 1.175 + 1.176 + }while(code[3] == '-'); 1.177 + 1.178 + return TRUE; 1.179 +} 1.180 + 1.181 +static 1.182 +gboolean check_response(smtp_base *psb, gboolean after_data) 1.183 +{ 1.184 + char c = psb->buffer[0]; 1.185 + 1.186 + if(((c == '2') && !after_data) || ((c == '3') && after_data)){ 1.187 + psb->error = smtp_ok; 1.188 + DEBUG(6) debugf("response OK:'%s' after_date = %d\n", psb->buffer, (int)after_data); 1.189 + return TRUE; 1.190 + }else{ 1.191 + if(c == '4') 1.192 + psb->error = smtp_trylater; 1.193 + else if(c == '5') 1.194 + psb->error = smtp_fail; 1.195 + else 1.196 + psb->error = smtp_syntax; 1.197 + DEBUG(6) debugf("response failure:'%s' after_date = %d\n", psb->buffer, (int)after_data); 1.198 + return FALSE; 1.199 + } 1.200 +} 1.201 + 1.202 +static 1.203 +gboolean check_init_response(smtp_base *psb) 1.204 +{ 1.205 + if(check_response(psb, FALSE)){ 1.206 + psb->use_esmtp = (strstr(psb->buffer, "ESMTP") != NULL); 1.207 + 1.208 + DEBUG(4) debugf(psb->use_esmtp ? "uses esmtp\n" : "no esmtp\n"); 1.209 + 1.210 + return TRUE; 1.211 + } 1.212 + return FALSE; 1.213 +} 1.214 + 1.215 +static 1.216 +gchar *get_response_arg(gchar *response) 1.217 +{ 1.218 + gchar buf[SMTP_BUF_LEN]; 1.219 + gchar *p = response, *q = buf; 1.220 + 1.221 + while(*p && (*p != '\n') && isspace(*p)) p++; 1.222 + if(*p && (*p != '\n')){ 1.223 + while(*p && (*p != '\n') && (*p != '\r') && (q < buf+SMTP_BUF_LEN-1)) *(q++) = *(p++); 1.224 + *q = 0; 1.225 + return g_strdup(buf); 1.226 + } 1.227 + return NULL; 1.228 +} 1.229 + 1.230 +static 1.231 +gboolean check_helo_response(smtp_base *psb) 1.232 +{ 1.233 + gchar *ptr = psb->buffer; 1.234 + 1.235 + if(!check_response(psb, FALSE)) 1.236 + return FALSE; 1.237 + 1.238 + while(*ptr){ 1.239 + if(strncasecmp(&(ptr[4]), "SIZE", 4) == 0){ 1.240 + gchar *arg; 1.241 + psb->use_size = TRUE; 1.242 + arg = get_response_arg(&(ptr[8])); 1.243 + if(arg){ 1.244 + psb->max_size = atoi(arg); 1.245 + g_free(arg); 1.246 + } 1.247 + } 1.248 + 1.249 + if(strncasecmp(&(ptr[4]), "PIPELINING", 10) == 0) 1.250 + psb->use_pipelining = TRUE; 1.251 + 1.252 + if(strncasecmp(&(ptr[4]), "AUTH", 4) == 0){ 1.253 + if((ptr[8] == ' ') || (ptr[8] == '=') || (ptr[8] == '\t')){ /* not sure about '\t' */ 1.254 + gchar *arg; 1.255 + psb->use_auth = TRUE; 1.256 + arg = get_response_arg(&(ptr[9])); /* after several years I finally learnt to count */ 1.257 + if(arg){ 1.258 + psb->auth_names = g_strsplit(arg, " " , 0); 1.259 + g_free(arg); 1.260 + 1.261 + DEBUG(4){ 1.262 + gint i = 0; 1.263 + while(psb->auth_names[i]){ 1.264 + debugf("offered AUTH %s\n", psb->auth_names[i]); 1.265 + i++; 1.266 + } 1.267 + } 1.268 + } 1.269 + } 1.270 + } 1.271 + 1.272 + while(*ptr != '\n') ptr++; 1.273 + ptr++; 1.274 + } 1.275 + 1.276 + DEBUG(4){ 1.277 + debugf(psb->use_size ? "uses SIZE\n" : "no size\n"); 1.278 + debugf(psb->use_pipelining ? "uses PIPELINING\n" : "no pipelining\n"); 1.279 + debugf(psb->use_auth ? "uses AUTH\n" : "no auth\n"); 1.280 + } 1.281 + 1.282 + return TRUE; 1.283 +} 1.284 + 1.285 +static 1.286 +gboolean smtp_helo(smtp_base *psb, gchar *helo) 1.287 +{ 1.288 + while(TRUE){ 1.289 + if(psb->use_esmtp){ 1.290 + fprintf(psb->out, "EHLO %s\r\n", helo); fflush(psb->out); 1.291 + 1.292 + DEBUG(4) debugf("EHLO %s\r\n", helo); 1.293 + 1.294 + }else{ 1.295 + fprintf(psb->out, "HELO %s\r\n", helo); fflush(psb->out); 1.296 + 1.297 + DEBUG(4) debugf("HELO %s\r\n", helo); 1.298 + 1.299 + } 1.300 + 1.301 + if(!read_response(psb, SMTP_CMD_TIMEOUT)) 1.302 + return FALSE; 1.303 + 1.304 + if(check_helo_response(psb)) 1.305 + return TRUE; 1.306 + else{ 1.307 + if(psb->error == smtp_fail){ 1.308 + if(psb->use_esmtp){ 1.309 + /* our guess that server understands EHLO was wrong, 1.310 + try again with HELO 1.311 + */ 1.312 + psb->use_esmtp = FALSE; 1.313 + }else{ 1.314 + /* what sort of server ist THAT ?! 1.315 + give up... 1.316 + */ 1.317 + return FALSE; 1.318 + } 1.319 + }else 1.320 + return FALSE; 1.321 + } 1.322 + } 1.323 +} 1.324 + 1.325 +static 1.326 +void smtp_cmd_mailfrom(smtp_base *psb, address *return_path, guint size) 1.327 +{ 1.328 + if(psb->use_size){ 1.329 + fprintf(psb->out, "MAIL FROM:%s SIZE=%d\r\n", 1.330 + addr_string(return_path), size); 1.331 + fflush(psb->out); 1.332 + 1.333 + DEBUG(4) debugf("MAIL FROM:%s SIZE=%d\r\n", 1.334 + addr_string(return_path), size); 1.335 + 1.336 + }else{ 1.337 + fprintf(psb->out, "MAIL FROM:%s\r\n", addr_string(return_path)); 1.338 + fflush(psb->out); 1.339 + 1.340 + DEBUG(4) debugf("MAIL FROM:%s\r\n", addr_string(return_path)); 1.341 + } 1.342 +} 1.343 + 1.344 +static 1.345 +void smtp_cmd_rcptto(smtp_base *psb, address *rcpt) 1.346 +{ 1.347 + fprintf(psb->out, "RCPT TO:%s\r\n", addr_string(rcpt)); 1.348 + fflush(psb->out); 1.349 + DEBUG(4) debugf("RCPT TO:%s\n", addr_string(rcpt)); 1.350 +} 1.351 + 1.352 +static 1.353 +void send_data_line(smtp_base *psb, gchar *data) 1.354 +{ 1.355 + /* According to RFC 821 each line should be terminated with CRLF. 1.356 + Since a dot on a line itself marks the end of data, each line 1.357 + beginning with a dot is prepended with another dot. 1.358 + */ 1.359 + gchar *ptr; 1.360 + gboolean new_line = TRUE; /* previous versions assumed that each item was 1.361 + exactly one line. This is no longer the case */ 1.362 + 1.363 + ptr = data; 1.364 + while(*ptr){ 1.365 + int c = (int)(*ptr); 1.366 + if(c == '.') 1.367 + if(new_line) 1.368 + putc('.', psb->out); 1.369 + if(c == '\n'){ 1.370 + putc('\r', psb->out); 1.371 + putc('\n', psb->out); 1.372 + new_line = TRUE; 1.373 + }else{ 1.374 + putc(c, psb->out); 1.375 + new_line = FALSE; 1.376 + } 1.377 + ptr++; 1.378 + } 1.379 +} 1.380 + 1.381 +static 1.382 +void send_header(smtp_base *psb, GList *hdr_list) 1.383 +{ 1.384 + GList *node; 1.385 + gint num_hdrs = 0; 1.386 + 1.387 + /* header */ 1.388 + if(hdr_list){ 1.389 + foreach(hdr_list, node){ 1.390 + if(node->data){ 1.391 + header *hdr = (header *)(node->data); 1.392 + if(hdr->header){ 1.393 + send_data_line(psb, hdr->header); 1.394 + num_hdrs++; 1.395 + } 1.396 + } 1.397 + } 1.398 + } 1.399 + 1.400 + /* empty line separating headers from data: */ 1.401 + putc('\r', psb->out); 1.402 + putc('\n', psb->out); 1.403 + 1.404 + DEBUG(4) debugf("sent %d headers\n", num_hdrs); 1.405 +} 1.406 + 1.407 +static 1.408 +void send_data(smtp_base *psb, message *msg) 1.409 +{ 1.410 + GList *node; 1.411 + gint num_lines = 0; 1.412 + 1.413 + /* data */ 1.414 + if(msg->data_list){ 1.415 + for(node = g_list_first(msg->data_list); node; node = g_list_next(node)){ 1.416 + if(node->data){ 1.417 + send_data_line(psb, node->data); 1.418 + num_lines++; 1.419 + } 1.420 + } 1.421 + } 1.422 + 1.423 + DEBUG(4) debugf("sent %d lines of data\n", num_lines); 1.424 + 1.425 + fprintf(psb->out, ".\r\n"); 1.426 + fflush(psb->out); 1.427 +} 1.428 + 1.429 +void smtp_out_mark_rcpts(smtp_base *psb, GList *rcpt_list) 1.430 +{ 1.431 + GList *rcpt_node; 1.432 + for(rcpt_node = g_list_first(rcpt_list); 1.433 + rcpt_node; 1.434 + rcpt_node = g_list_next(rcpt_node)){ 1.435 + address *rcpt = (address *)(rcpt_node->data); 1.436 + 1.437 + addr_unmark_delivered(rcpt); 1.438 + 1.439 + if((psb->error == smtp_trylater) || (psb->error == smtp_timeout) || 1.440 + (psb->error == smtp_eof)){ 1.441 + addr_mark_defered(rcpt); 1.442 + }else{ 1.443 + addr_mark_failed(rcpt); 1.444 + } 1.445 + } 1.446 +} 1.447 + 1.448 +void smtp_out_log_failure(smtp_base *psb, message *msg) 1.449 +{ 1.450 + gchar *err_str; 1.451 + 1.452 + if(psb->error == smtp_timeout) 1.453 + err_str = g_strdup("connection timed out."); 1.454 + else if(psb->error == smtp_eof) 1.455 + err_str = g_strdup("connection terminated prematurely."); 1.456 + else if(psb->error == smtp_syntax) 1.457 + err_str = g_strdup_printf("got unexpected response: %s", psb->buffer); 1.458 + else if(psb->error == smtp_cancel) 1.459 + err_str = g_strdup("delivery was canceled.\n"); 1.460 + else 1.461 + /* error message should still be in the buffer */ 1.462 + err_str = g_strdup_printf("failed: %s\n", psb->buffer); 1.463 + 1.464 + if(msg == NULL) 1.465 + logwrite(LOG_NOTICE, "host=%s %s\n", 1.466 + psb->remote_host, err_str); 1.467 + else 1.468 + logwrite(LOG_NOTICE, "%s == host=%s %s\n", 1.469 + msg->uid, psb->remote_host, err_str); 1.470 + 1.471 + g_free(err_str); 1.472 +} 1.473 + 1.474 +smtp_base *smtp_out_open(gchar *host, gint port, GList *resolve_list) 1.475 +{ 1.476 + smtp_base *psb; 1.477 + gint sock; 1.478 + mxip_addr *addr; 1.479 + 1.480 + DEBUG(5) debugf("smtp_out_open entered, host = %s\n", host); 1.481 + 1.482 + if((addr = connect_resolvelist(&sock, host, port, resolve_list))){ 1.483 + /* create structure to hold status data: */ 1.484 + psb = create_smtpbase(sock); 1.485 + psb->remote_host = addr->name; 1.486 + 1.487 + DEBUG(5){ 1.488 + struct sockaddr_in name; 1.489 + int len = sizeof(struct sockaddr); 1.490 + getsockname(sock, (struct sockaddr *)(&name), &len); 1.491 + debugf("socket: name.sin_addr = %s\n", inet_ntoa(name.sin_addr)); 1.492 + } 1.493 + return psb; 1.494 + }else{ 1.495 + DEBUG(5) debugf("connect_resolvelist failed: %s %s\n", strerror(errno), hstrerror(h_errno)); 1.496 + } 1.497 + 1.498 + return NULL; 1.499 +} 1.500 + 1.501 +smtp_base *smtp_out_open_child(gchar *cmd) 1.502 +{ 1.503 + smtp_base *psb; 1.504 + gint sock; 1.505 + 1.506 + DEBUG(5) debugf("smtp_out_open_child entered, cmd = %s\n", cmd); 1.507 + 1.508 + sock = child(cmd); 1.509 + 1.510 + if(sock > 0){ 1.511 + psb = create_smtpbase(sock); 1.512 + psb->remote_host = NULL; 1.513 + 1.514 + return psb; 1.515 + } 1.516 + 1.517 + return NULL; 1.518 +} 1.519 + 1.520 +gboolean smtp_out_rset(smtp_base *psb) 1.521 +{ 1.522 + gboolean ok; 1.523 + 1.524 + fprintf(psb->out, "RSET\r\n"); fflush(psb->out); 1.525 + DEBUG(4) debugf("RSET\n"); 1.526 + 1.527 + if((ok = read_response(psb, SMTP_CMD_TIMEOUT))) 1.528 + if(check_response(psb, FALSE)) 1.529 + return TRUE; 1.530 + 1.531 + smtp_out_log_failure(psb, NULL); 1.532 + 1.533 + return FALSE; 1.534 +} 1.535 + 1.536 +#ifdef ENABLE_AUTH 1.537 + 1.538 +static 1.539 +gboolean smtp_out_auth_cram_md5(smtp_base *psb) 1.540 +{ 1.541 + gboolean ok = FALSE; 1.542 + 1.543 + fprintf(psb->out, "AUTH CRAM-MD5\r\n"); fflush(psb->out); 1.544 + DEBUG(4) debugf("AUTH CRAM-MD5\n"); 1.545 + if((ok = read_response(psb, SMTP_CMD_TIMEOUT))){ 1.546 + if((ok = check_response(psb, TRUE))){ 1.547 + gchar *chall64 = get_response_arg(&(psb->buffer[4])); 1.548 + gint chall_size; 1.549 + gchar *chall = base64_decode(chall64, &chall_size); 1.550 + guchar digest[16], *reply64, *reply; 1.551 + gchar digest_string[33]; 1.552 + gint i; 1.553 +#ifdef USE_LIB_CRYPTO 1.554 + unsigned int digest_len; 1.555 +#endif 1.556 + 1.557 + DEBUG(5) debugf("encoded challenge = %s\n", chall64); 1.558 + DEBUG(5) debugf("decoded challenge = %s, size = %d\n", chall, chall_size); 1.559 + 1.560 + DEBUG(5) debugf("secret = %s\n", psb->auth_secret); 1.561 + 1.562 +#ifdef USE_LIB_CRYPTO 1.563 + HMAC(EVP_md5(), psb->auth_secret, strlen(psb->auth_secret), chall, chall_size, digest, &digest_len); 1.564 +#else 1.565 + hmac_md5(chall, chall_size, psb->auth_secret, strlen(psb->auth_secret), digest); 1.566 +#endif 1.567 + 1.568 + for(i = 0; i < 16; i++) 1.569 + sprintf(&(digest_string[i+i]), "%02x", (unsigned int)(digest[i])); 1.570 + digest_string[32] = 0; 1.571 + 1.572 + DEBUG(5) debugf("digest = %s\n", digest_string); 1.573 + 1.574 + reply = g_strdup_printf("%s %s", psb->auth_login, digest_string); 1.575 + DEBUG(5) debugf("unencoded reply = %s\n", reply); 1.576 + 1.577 + reply64 = base64_encode(reply, strlen(reply)); 1.578 + DEBUG(5) debugf("encoded reply = %s\n", reply64); 1.579 + 1.580 + fprintf(psb->out, "%s\r\n", reply64); fflush(psb->out); 1.581 + DEBUG(4) debugf("%s\n", reply64); 1.582 + 1.583 + if((ok = read_response(psb, SMTP_CMD_TIMEOUT))) 1.584 + ok = check_response(psb, FALSE); 1.585 + 1.586 + g_free(reply64); 1.587 + g_free(reply); 1.588 + g_free(chall); 1.589 + g_free(chall64); 1.590 + } 1.591 + } 1.592 + return ok; 1.593 +} 1.594 + 1.595 +static 1.596 +gboolean smtp_out_auth_login(smtp_base *psb) 1.597 +{ 1.598 + gboolean ok = FALSE; 1.599 + fprintf(psb->out, "AUTH LOGIN\r\n"); fflush(psb->out); 1.600 + if((ok = read_response(psb, SMTP_CMD_TIMEOUT))){ 1.601 + if((ok = check_response(psb, TRUE))){ 1.602 + gchar *resp64; 1.603 + guchar *resp; 1.604 + gint resp_size; 1.605 + gchar *reply64; 1.606 + 1.607 + resp64 = get_response_arg(&(psb->buffer[4])); 1.608 + DEBUG(5) debugf("encoded response = %s\n", resp64); 1.609 + resp = base64_decode(resp64, &resp_size); 1.610 + g_free(resp64); 1.611 + DEBUG(5) debugf("decoded response = %s, size = %d\n", 1.612 + resp, resp_size); 1.613 + g_free(resp); 1.614 + reply64 = base64_encode(psb->auth_login, 1.615 + strlen(psb->auth_login)); 1.616 + fprintf(psb->out, "%s\r\n", reply64); fflush(psb->out); 1.617 + g_free(reply64); 1.618 + if((ok = read_response(psb, SMTP_CMD_TIMEOUT))) { 1.619 + if ((ok = check_response(psb, TRUE))) { 1.620 + resp64 = get_response_arg(&(psb->buffer[4])); 1.621 + DEBUG(5) debugf("encoded response = %s\n", resp64); 1.622 + resp = base64_decode(resp64, &resp_size); 1.623 + g_free(resp64); 1.624 + DEBUG(5) debugf("decoded response = %s, size = %d\n", 1.625 + resp, resp_size); 1.626 + g_free(resp); 1.627 + reply64 = base64_encode(psb->auth_secret, 1.628 + strlen(psb->auth_secret)); 1.629 + fprintf(psb->out, "%s\r\n", reply64); fflush(psb->out); 1.630 + g_free(reply64); 1.631 + if((ok = read_response(psb, SMTP_CMD_TIMEOUT))) 1.632 + ok = check_response(psb, FALSE); 1.633 + } 1.634 + } 1.635 + } 1.636 + } 1.637 + return ok; 1.638 +} 1.639 + 1.640 +gboolean smtp_out_auth(smtp_base *psb) 1.641 +{ 1.642 + gboolean ok = FALSE; 1.643 + gint i = 0; 1.644 + while(psb->auth_names[i]){ 1.645 + if(strcasecmp(psb->auth_names[i], psb->auth_name) == 0) 1.646 + break; 1.647 + i++; 1.648 + } 1.649 + if(psb->auth_names[i]){ 1.650 + if(strcasecmp(psb->auth_name, "cram-md5") == 0){ 1.651 + smtp_out_auth_cram_md5(psb); 1.652 + }else if(strcasecmp(psb->auth_name, "login") == 0){ 1.653 + smtp_out_auth_login(psb); 1.654 + }else{ 1.655 + logwrite(LOG_ERR, "auth method %s not supported\n", psb->auth_name); 1.656 + } 1.657 + }else{ 1.658 + logwrite(LOG_ERR, "no auth method %s found.\n", psb->auth_name); 1.659 + } 1.660 + return ok; 1.661 +} 1.662 + 1.663 +#endif 1.664 + 1.665 +gboolean smtp_out_init(smtp_base *psb) 1.666 +{ 1.667 + gboolean ok; 1.668 + 1.669 + if((ok = read_response(psb, SMTP_INITIAL_TIMEOUT))){ 1.670 + if((ok = check_init_response(psb))){ 1.671 + 1.672 + if((ok = smtp_helo(psb, psb->helo_name))){ 1.673 +#ifdef ENABLE_AUTH 1.674 + if(psb->auth_name && psb->use_auth){ 1.675 + /* we completely disregard the response of server here. If 1.676 + authentication fails, the server will complain later 1.677 + anyway. I know, this is not polite... */ 1.678 + smtp_out_auth(psb); 1.679 + } 1.680 +#endif 1.681 + } 1.682 + } 1.683 + } 1.684 + if(!ok) 1.685 + smtp_out_log_failure(psb, NULL); 1.686 + return ok; 1.687 +} 1.688 + 1.689 +gint smtp_out_msg(smtp_base *psb, 1.690 + message *msg, address *return_path, GList *rcpt_list, 1.691 + GList *hdr_list) 1.692 +{ 1.693 + gint i, size; 1.694 + gboolean ok = TRUE; 1.695 + int rcpt_cnt; 1.696 + int rcpt_accept = 0; 1.697 + 1.698 + DEBUG(5) debugf("smtp_out_msg entered\n"); 1.699 + 1.700 + /* defaults: */ 1.701 + if(return_path == NULL) 1.702 + return_path = msg->return_path; 1.703 + if(hdr_list == NULL) 1.704 + hdr_list = msg->hdr_list; 1.705 + if(rcpt_list == NULL) 1.706 + rcpt_list = msg->rcpt_list; 1.707 + rcpt_cnt = g_list_length(rcpt_list); 1.708 + 1.709 + size = msg_calc_size(msg, TRUE); 1.710 + 1.711 + /* respect maximum size given by server: */ 1.712 + if((psb->max_size > 0) && (size > psb->max_size)){ 1.713 + logwrite(LOG_WARNING, 1.714 + "%s == host=%s message size (%d) > fixed maximum message size of server (%d)", 1.715 + msg->uid, psb->remote_host, size, psb->max_size); 1.716 + psb->error = smtp_cancel; 1.717 + ok = FALSE; 1.718 + } 1.719 + 1.720 + if(ok){ 1.721 + smtp_cmd_mailfrom(psb, return_path, 1.722 + psb->use_size ? 1.723 + size + SMTP_SIZE_ADD : 0); 1.724 + 1.725 + if(!psb->use_pipelining){ 1.726 + if((ok = read_response(psb, SMTP_CMD_TIMEOUT))) 1.727 + ok = check_response(psb, FALSE); 1.728 + } 1.729 + } 1.730 + if(ok){ 1.731 + GList *rcpt_node; 1.732 + rcpt_accept = 0; 1.733 + 1.734 + for(rcpt_node = g_list_first(rcpt_list); 1.735 + rcpt_node != NULL; 1.736 + rcpt_node = g_list_next(rcpt_node)){ 1.737 + address *rcpt = (address *)(rcpt_node->data); 1.738 + smtp_cmd_rcptto(psb, rcpt); 1.739 + if(!psb->use_pipelining){ 1.740 + if((ok = read_response(psb, SMTP_CMD_TIMEOUT))) 1.741 + if(check_response(psb, FALSE)){ 1.742 + rcpt_accept++; 1.743 + addr_mark_delivered(rcpt); 1.744 + } 1.745 + else{ 1.746 + /* if server returned an error for one recp. we 1.747 + may still try the others. But if it is a timeout, eof 1.748 + or unexpected response, it is more serious and we should 1.749 + give up. */ 1.750 + if((psb->error != smtp_trylater) && 1.751 + (psb->error != smtp_fail)){ 1.752 + ok = FALSE; 1.753 + break; 1.754 + }else{ 1.755 + logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s", 1.756 + msg->uid, addr_string(rcpt), 1.757 + psb->remote_host, psb->buffer); 1.758 + if(psb->error == smtp_trylater){ 1.759 + addr_mark_defered(rcpt); 1.760 + }else{ 1.761 + addr_mark_failed(rcpt); 1.762 + } 1.763 + } 1.764 + } 1.765 + else 1.766 + break; 1.767 + } 1.768 + } 1.769 + 1.770 + /* There is no point in going on if no recp.s were accpted. 1.771 + But we can check that at this point only if not pipelining: */ 1.772 + ok = (ok && (psb->use_pipelining || (rcpt_accept > 0))); 1.773 + if(ok){ 1.774 + 1.775 + fprintf(psb->out, "DATA\r\n"); fflush(psb->out); 1.776 + 1.777 + DEBUG(4) debugf("DATA\r\n"); 1.778 + 1.779 + if(psb->use_pipelining){ 1.780 + /* the first pl'ed command was MAIL FROM 1.781 + the last was DATA, whose response can be handled by the 'normal' code 1.782 + all in between were RCPT TO: 1.783 + */ 1.784 + /* response to MAIL FROM: */ 1.785 + if((ok = read_response(psb, SMTP_CMD_TIMEOUT))){ 1.786 + if((ok = check_response(psb, FALSE))){ 1.787 + 1.788 + /* response(s) to RCPT TO: 1.789 + this is very similar to the sequence above for no pipeline 1.790 + */ 1.791 + for(i = 0; i < rcpt_cnt; i++){ 1.792 + if((ok = read_response(psb, SMTP_CMD_TIMEOUT))){ 1.793 + address *rcpt = g_list_nth_data(rcpt_list, i); 1.794 + if(check_response(psb, FALSE)){ 1.795 + rcpt_accept++; 1.796 + addr_mark_delivered(rcpt); 1.797 + } 1.798 + else{ 1.799 + /* if server returned an error 4xx or 5xx for one recp. we 1.800 + may still try the others. But if it is a timeout, eof 1.801 + or unexpected response, it is more serious and we 1.802 + should give up. */ 1.803 + if((psb->error != smtp_trylater) && 1.804 + (psb->error != smtp_fail)){ 1.805 + ok = FALSE; 1.806 + break; 1.807 + }else{ 1.808 + logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s", 1.809 + msg->uid, addr_string(rcpt), 1.810 + psb->remote_host, psb->buffer); 1.811 + if(psb->error == smtp_trylater){ 1.812 + addr_mark_defered(rcpt); 1.813 + }else{ 1.814 + addr_mark_failed(rcpt); 1.815 + } 1.816 + } 1.817 + } 1.818 + }else{ 1.819 + DEBUG(5) debugf("check_response failed after RCPT TO\n"); 1.820 + break; 1.821 + } 1.822 + } 1.823 + if(rcpt_accept == 0) 1.824 + ok = FALSE; 1.825 + }else{ 1.826 + DEBUG(5) debugf("check_response failed after MAIL FROM\n"); 1.827 + } 1.828 + }else{ 1.829 + DEBUG(5) debugf("read_response failed after MAIL FROM\n"); 1.830 + } 1.831 + } /* if(psb->use_pipelining) */ 1.832 + 1.833 + /* response to the DATA cmd */ 1.834 + if(ok){ 1.835 + if(read_response(psb, SMTP_DATA_TIMEOUT)){ 1.836 + if(check_response(psb, TRUE)){ 1.837 + send_header(psb, hdr_list); 1.838 + send_data(psb, msg); 1.839 + 1.840 + if(read_response(psb, SMTP_FINAL_TIMEOUT)) 1.841 + ok = check_response(psb, FALSE); 1.842 + } 1.843 + } 1.844 + } 1.845 + } 1.846 + } 1.847 + 1.848 + DEBUG(5){ 1.849 + debugf("psb->error = %d\n", psb->error); 1.850 + debugf("ok = %d\n", ok); 1.851 + debugf("rcpt_accept = %d\n", rcpt_accept); 1.852 + } 1.853 + 1.854 + if(psb->error == smtp_ok){ 1.855 + GList *rcpt_node; 1.856 + for(rcpt_node = g_list_first(rcpt_list); 1.857 + rcpt_node; 1.858 + rcpt_node = g_list_next(rcpt_node)){ 1.859 + address *rcpt = (address *)(rcpt_node->data); 1.860 + if(addr_is_delivered(rcpt)) 1.861 + logwrite(LOG_NOTICE, "%s => %s host=%s with %s\n", 1.862 + msg->uid, addr_string(rcpt), psb->remote_host, 1.863 + psb->use_esmtp ? "esmtp" : "smtp"); 1.864 + } 1.865 + }else{ 1.866 + /* if something went wrong, 1.867 + we have to unmark the rcpts prematurely marked as delivered 1.868 + and mark the status */ 1.869 + smtp_out_mark_rcpts(psb, rcpt_list); 1.870 + 1.871 + /* log the failure: */ 1.872 + smtp_out_log_failure(psb, msg); 1.873 + } 1.874 + return rcpt_accept; 1.875 +} 1.876 + 1.877 +gboolean smtp_out_quit(smtp_base *psb) 1.878 +{ 1.879 + fprintf(psb->out, "QUIT\r\n"); fflush(psb->out); 1.880 + 1.881 + DEBUG(4) debugf("QUIT\n"); 1.882 + 1.883 + signal(SIGALRM, SIG_DFL); 1.884 + 1.885 + return TRUE; 1.886 +} 1.887 + 1.888 +gint smtp_deliver(gchar *host, gint port, GList *resolve_list, 1.889 + message *msg, 1.890 + address *return_path, 1.891 + GList *rcpt_list) 1.892 +{ 1.893 + smtp_base *psb; 1.894 + smtp_error err; 1.895 + 1.896 + DEBUG(5) debugf("smtp_deliver entered\n"); 1.897 + 1.898 + if(return_path == NULL) 1.899 + return_path = msg->return_path; 1.900 + 1.901 + if((psb = smtp_out_open(host, port, resolve_list))){ 1.902 + set_heloname(psb, return_path->domain, TRUE); 1.903 + /* initiate connection, send message and quit: */ 1.904 + if(smtp_out_init(psb)){ 1.905 + smtp_out_msg(psb, msg, return_path, rcpt_list, NULL); 1.906 + if(psb->error == smtp_ok || 1.907 + (psb->error == smtp_fail) || 1.908 + (psb->error == smtp_trylater) || 1.909 + (psb->error == smtp_syntax) || 1.910 + (psb->error == smtp_cancel)) 1.911 + 1.912 + smtp_out_quit(psb); 1.913 + } 1.914 + 1.915 + err = psb->error; 1.916 + destroy_smtpbase(psb); 1.917 + 1.918 + return err; 1.919 + } 1.920 + return -1; 1.921 +}