Mercurial > masqmail
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 } |