comparison src/smtp_out.c @ 10:26e34ae9a3e3

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