Implemented correct semantics for sending mail to bcc'ed addresses.
Showing
2 changed files
with
512 additions
and
286 deletions
... | @@ -70,16 +70,18 @@ struct _mailer | ... | @@ -70,16 +70,18 @@ struct _mailer |
70 | if (mailer->observer) observer_notify (mailer->observer, type) | 70 | if (mailer->observer) observer_notify (mailer->observer, type) |
71 | 71 | ||
72 | /* Moro(?)ic kluge. */ | 72 | /* Moro(?)ic kluge. */ |
73 | #define MAILER_DEBUGV(mailer, type, format, av) \ | ||
74 | if (mailer->debug) mu_debug_print (mailer->debug, type, format, av) | ||
73 | #define MAILER_DEBUG0(mailer, type, format) \ | 75 | #define MAILER_DEBUG0(mailer, type, format) \ |
74 | if (mailer->debug) mu_debug_print (mailer->debug, type, format) | 76 | if (mailer->debug) mu_debug_print (mailer->debug, type, format) |
75 | #define MAILER_DEBUG1(mailer, type, format, arg1) \ | 77 | #define MAILER_DEBUG1(mailer, type, format, arg1) \ |
76 | if (mailer->debug) mu_debug_print (mailer->debug, type, format, arg1) | 78 | if (mailer->debug) mu_debug_print (mailer->debug, type, format, arg1) |
77 | #define MAILER_DEBUG2(mailer, type, format, arg1, arg2) \ | 79 | #define MAILER_DEBUG2(mailer, type, format, arg1, arg2) \ |
78 | if (mailer->debug) mu_debug_print (mailer->debug, type, format, arg1, arg2) | 80 | if (mailer->debug) mu_debug_print (mailer->debug, type, format, arg1, arg2) |
79 | #define MAILER_DEBUG3(mailer, type, format, arg1, arg2, arg3) \ | 81 | #define MAILER_DEBUG3(mailer, type, format, arg1, arg2, arg3) \ |
80 | if (mailer->debug) mu_debug_print (mailer->debug, type, format, arg1, arg2, arg3) | 82 | if (mailer->debug) mu_debug_print (mailer->debug, type, format, arg1, arg2, arg3) |
81 | #define MAILER_DEBUG4(mailer, type, format, arg1, arg2, arg3, arg4) \ | 83 | #define MAILER_DEBUG4(mailer, type, format, arg1, arg2, arg3, arg4) \ |
82 | if (mailer->debug) mu_debug_print (mailer->debug, type, format, arg1, arg2, arg3, arg4) | 84 | if (mailer->debug) mu_debug_print (mailer->debug, type, format, arg1, arg2, arg3, arg4) |
83 | 85 | ||
84 | #ifdef __cplusplus | 86 | #ifdef __cplusplus |
85 | } | 87 | } | ... | ... |
... | @@ -19,7 +19,9 @@ | ... | @@ -19,7 +19,9 @@ |
19 | # include <config.h> | 19 | # include <config.h> |
20 | #endif | 20 | #endif |
21 | 21 | ||
22 | #include <assert.h> | ||
22 | #include <errno.h> | 23 | #include <errno.h> |
24 | #include <ctype.h> | ||
23 | #include <netdb.h> | 25 | #include <netdb.h> |
24 | #include <pwd.h> | 26 | #include <pwd.h> |
25 | #include <stdarg.h> | 27 | #include <stdarg.h> |
... | @@ -30,6 +32,7 @@ | ... | @@ -30,6 +32,7 @@ |
30 | 32 | ||
31 | #include <mailutils/address.h> | 33 | #include <mailutils/address.h> |
32 | #include <mailutils/debug.h> | 34 | #include <mailutils/debug.h> |
35 | #include <mailutils/errno.h> | ||
33 | #include <mailutils/header.h> | 36 | #include <mailutils/header.h> |
34 | #include <mailutils/message.h> | 37 | #include <mailutils/message.h> |
35 | #include <mailutils/mutil.h> | 38 | #include <mailutils/mutil.h> |
... | @@ -65,11 +68,12 @@ struct _smtp | ... | @@ -65,11 +68,12 @@ struct _smtp |
65 | char *mailhost; | 68 | char *mailhost; |
66 | char *localhost; | 69 | char *localhost; |
67 | 70 | ||
68 | /* Buffered the IO. */ | 71 | /* IO buffering. */ |
72 | char *buffer; /* Must be freed. */ | ||
73 | size_t buflen; | ||
74 | |||
69 | char *ptr; | 75 | char *ptr; |
70 | char *nl; | 76 | char *nl; |
71 | char *buffer; | ||
72 | size_t buflen; | ||
73 | off_t s_offset; | 77 | off_t s_offset; |
74 | 78 | ||
75 | enum smtp_state | 79 | enum smtp_state |
... | @@ -83,22 +87,95 @@ struct _smtp | ... | @@ -83,22 +87,95 @@ struct _smtp |
83 | 87 | ||
84 | int extended; | 88 | int extended; |
85 | 89 | ||
86 | address_t mail_from; | 90 | char* mail_from; |
87 | address_t rcpt_to; | 91 | address_t rcpt_to; /* Destroy this if not the same as TO below. */ |
92 | address_t rcpt_bcc; | ||
93 | size_t rcpt_to_count; | ||
94 | size_t rcpt_bcc_count; | ||
88 | size_t rcpt_index; | 95 | size_t rcpt_index; |
96 | size_t rcpt_count; | ||
97 | int bccing; | ||
98 | message_t msg; | ||
89 | 99 | ||
90 | off_t offset; | 100 | off_t offset; |
91 | int dsn; | 101 | |
92 | message_t message; | 102 | /* The mailer_send_message() args. */ |
103 | message_t argmsg; | ||
104 | address_t argfrom; | ||
105 | address_t argto; | ||
93 | }; | 106 | }; |
94 | 107 | ||
95 | typedef struct _smtp * smtp_t; | 108 | typedef struct _smtp * smtp_t; |
96 | 109 | ||
97 | /* Usefull little Macros, since these are very repetitive. */ | 110 | /* Useful little macros, since these are very repetitive. */ |
98 | #define CLEAR_STATE(smtp) \ | 111 | |
99 | smtp->state = SMTP_NO_STATE | 112 | static void |
113 | CLEAR_STATE (smtp_t smtp) | ||
114 | { | ||
115 | smtp->ptr = NULL; | ||
116 | smtp->nl = NULL; | ||
117 | smtp->s_offset = 0; | ||
118 | smtp->extended = 0; | ||
119 | |||
120 | smtp->msg = NULL; | ||
121 | |||
122 | if (smtp->mail_from) | ||
123 | { | ||
124 | free (smtp->mail_from); | ||
125 | smtp->mail_from = NULL; | ||
126 | } | ||
127 | |||
128 | smtp->argfrom = NULL; | ||
129 | |||
130 | if (smtp->rcpt_to != smtp->argto) | ||
131 | address_destroy (&smtp->rcpt_to); | ||
132 | |||
133 | address_destroy (&smtp->rcpt_bcc); | ||
134 | |||
135 | if (smtp->msg != smtp->argmsg) | ||
136 | message_destroy (&smtp->msg, NULL); | ||
137 | |||
138 | smtp->argmsg = smtp->msg = NULL; | ||
139 | |||
140 | smtp->rcpt_to = smtp->argto = NULL; | ||
100 | 141 | ||
101 | /* Clear the state and close the stream. */ | 142 | smtp->rcpt_index = 0; |
143 | |||
144 | smtp->offset = 0; | ||
145 | |||
146 | smtp->state = SMTP_NO_STATE; | ||
147 | } | ||
148 | |||
149 | /* If we are resuming, we should be resuming the SAME operation | ||
150 | as that which is ongoing. Check this. */ | ||
151 | static int | ||
152 | smtp_check_send_resumption (smtp_t smtp, | ||
153 | message_t msg, address_t from, address_t to) | ||
154 | { | ||
155 | if(smtp->state == SMTP_NO_STATE) | ||
156 | return 0; | ||
157 | |||
158 | /* FIXME: state should be one of the "send" states if its not | ||
159 | "no state" */ | ||
160 | if (msg != smtp->argmsg) | ||
161 | return MU_ERR_BAD_RESUMPTION; | ||
162 | |||
163 | if (from != smtp->argfrom) | ||
164 | return MU_ERR_BAD_RESUMPTION; | ||
165 | |||
166 | if (to != smtp->argto) | ||
167 | return MU_ERR_BAD_RESUMPTION; | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | #define CHECK_SEND_RESUME(smtp, msg, from, to) \ | ||
173 | do { \ | ||
174 | if((status = smtp_check_send_resumption(smtp, msg, from, to)) != 0) \ | ||
175 | return status; \ | ||
176 | } while (0) | ||
177 | |||
178 | /* Clear the state and close the stream. */ | ||
102 | #define CHECK_ERROR_CLOSE(mailer, smtp, status) \ | 179 | #define CHECK_ERROR_CLOSE(mailer, smtp, status) \ |
103 | do \ | 180 | do \ |
104 | { \ | 181 | { \ |
... | @@ -111,7 +188,7 @@ do \ | ... | @@ -111,7 +188,7 @@ do \ |
111 | } \ | 188 | } \ |
112 | while (0) | 189 | while (0) |
113 | 190 | ||
114 | /* Clear the state. */ | 191 | /* Clear the state. */ |
115 | #define CHECK_ERROR(smtp, status) \ | 192 | #define CHECK_ERROR(smtp, status) \ |
116 | do \ | 193 | do \ |
117 | { \ | 194 | { \ |
... | @@ -147,8 +224,8 @@ static int smtp_readline (smtp_t); | ... | @@ -147,8 +224,8 @@ static int smtp_readline (smtp_t); |
147 | static int smtp_read_ack (smtp_t); | 224 | static int smtp_read_ack (smtp_t); |
148 | static int smtp_write (smtp_t); | 225 | static int smtp_write (smtp_t); |
149 | 226 | ||
150 | static int get_rcpt (message_t , address_t *); | 227 | static int _smtp_set_from (smtp_t, message_t , address_t); |
151 | static int get_from (message_t , char *, address_t *); | 228 | static int _smtp_set_rcpt (smtp_t, message_t , address_t); |
152 | 229 | ||
153 | int | 230 | int |
154 | _mailer_smtp_init (mailer_t mailer) | 231 | _mailer_smtp_init (mailer_t mailer) |
... | @@ -182,19 +259,20 @@ static void | ... | @@ -182,19 +259,20 @@ static void |
182 | smtp_destroy(mailer_t mailer) | 259 | smtp_destroy(mailer_t mailer) |
183 | { | 260 | { |
184 | smtp_t smtp = mailer->data; | 261 | smtp_t smtp = mailer->data; |
262 | |||
263 | CLEAR_STATE(smtp); | ||
264 | |||
185 | /* Not our responsability to close. */ | 265 | /* Not our responsability to close. */ |
186 | /* smtp_close (mailer); */ | 266 | |
187 | if (smtp->mailhost) | 267 | if (smtp->mailhost) |
188 | free (smtp->mailhost); | 268 | free (smtp->mailhost); |
189 | if (smtp->localhost) | 269 | if (smtp->localhost) |
190 | free (smtp->localhost); | 270 | free (smtp->localhost); |
191 | if (smtp->buffer) | 271 | if (smtp->buffer) |
192 | free (smtp->buffer); | 272 | free (smtp->buffer); |
193 | if (smtp->mail_from) | 273 | |
194 | address_destroy (&(smtp->mail_from)); | ||
195 | if (smtp->rcpt_to) | ||
196 | address_destroy (&(smtp->rcpt_to)); | ||
197 | free (smtp); | 274 | free (smtp); |
275 | |||
198 | mailer->data = NULL; | 276 | mailer->data = NULL; |
199 | } | 277 | } |
200 | 278 | ||
... | @@ -207,8 +285,7 @@ smtp_open (mailer_t mailer, int flags) | ... | @@ -207,8 +285,7 @@ smtp_open (mailer_t mailer, int flags) |
207 | size_t buf_len = 0; | 285 | size_t buf_len = 0; |
208 | 286 | ||
209 | /* Sanity checks. */ | 287 | /* Sanity checks. */ |
210 | if (smtp == NULL) | 288 | assert (smtp); |
211 | return EINVAL; | ||
212 | 289 | ||
213 | mailer->flags = flags; | 290 | mailer->flags = flags; |
214 | 291 | ||
... | @@ -220,6 +297,7 @@ smtp_open (mailer_t mailer, int flags) | ... | @@ -220,6 +297,7 @@ smtp_open (mailer_t mailer, int flags) |
220 | switch (smtp->state) | 297 | switch (smtp->state) |
221 | { | 298 | { |
222 | case SMTP_NO_STATE: | 299 | case SMTP_NO_STATE: |
300 | /* Set up the mailer, open the stream, etc. */ | ||
223 | /* Get the mailhost. */ | 301 | /* Get the mailhost. */ |
224 | if (smtp->mailhost) | 302 | if (smtp->mailhost) |
225 | { | 303 | { |
... | @@ -227,8 +305,10 @@ smtp_open (mailer_t mailer, int flags) | ... | @@ -227,8 +305,10 @@ smtp_open (mailer_t mailer, int flags) |
227 | smtp->mailhost = NULL; | 305 | smtp->mailhost = NULL; |
228 | } | 306 | } |
229 | smtp->mailhost = calloc (buf_len + 1, sizeof (char)); | 307 | smtp->mailhost = calloc (buf_len + 1, sizeof (char)); |
308 | |||
230 | if (smtp->mailhost == NULL) | 309 | if (smtp->mailhost == NULL) |
231 | return ENOMEM; | 310 | return ENOMEM; |
311 | |||
232 | url_get_host (mailer->url, smtp->mailhost, buf_len + 1, NULL); | 312 | url_get_host (mailer->url, smtp->mailhost, buf_len + 1, NULL); |
233 | 313 | ||
234 | if (smtp->localhost) | 314 | if (smtp->localhost) |
... | @@ -236,63 +316,16 @@ smtp_open (mailer_t mailer, int flags) | ... | @@ -236,63 +316,16 @@ smtp_open (mailer_t mailer, int flags) |
236 | free (smtp->localhost); | 316 | free (smtp->localhost); |
237 | smtp->localhost = NULL; | 317 | smtp->localhost = NULL; |
238 | } | 318 | } |
239 | /* Fetch our localhost name. */ | 319 | /* Fetch our local host name. */ |
240 | buf_len = 64; | 320 | |
241 | do | 321 | status = mu_get_host_name(&smtp->localhost); |
242 | { | 322 | |
243 | char *tmp; | 323 | if (status != 0) |
244 | errno = 0; | ||
245 | buf_len *= 2; /* Initial guess */ | ||
246 | tmp = realloc (smtp->localhost, buf_len); | ||
247 | if (tmp == NULL) | ||
248 | { | ||
249 | if (smtp->localhost) | ||
250 | free (smtp->localhost); | ||
251 | smtp->localhost = NULL; | ||
252 | free (smtp->mailhost); | ||
253 | smtp->mailhost = NULL; | ||
254 | return ENOMEM; | ||
255 | } | ||
256 | smtp->localhost = tmp; | ||
257 | } | ||
258 | while (((status = gethostname(smtp->localhost, buf_len)) == 0 | ||
259 | && !memchr (smtp->localhost, '\0', buf_len)) | ||
260 | #ifdef ENAMETOOLONG | ||
261 | || errno == ENAMETOOLONG | ||
262 | #endif | ||
263 | ); | ||
264 | if (status != 0 && errno != 0) | ||
265 | { | 324 | { |
266 | /* gethostname failed, abort. */ | 325 | /* gethostname failed, abort. */ |
267 | free (smtp->localhost); | ||
268 | smtp->localhost = NULL; | ||
269 | free (smtp->mailhost); | 326 | free (smtp->mailhost); |
270 | smtp->mailhost = NULL; | 327 | smtp->mailhost = NULL; |
271 | return EINVAL; | 328 | return status; |
272 | } | ||
273 | |||
274 | /* Many SMTP servers prefer a FQDN. */ | ||
275 | if (strchr (smtp->localhost, '.') == NULL) | ||
276 | { | ||
277 | struct hostent *hp = gethostbyname (smtp->localhost); | ||
278 | if (hp == NULL) | ||
279 | { | ||
280 | /* Don't flag it as an error some SMTP servers can get the FQDN | ||
281 | by themselves even if the client is lying, probably | ||
282 | with getpeername(). */ | ||
283 | /* return EINVAL; */ | ||
284 | } | ||
285 | else | ||
286 | { | ||
287 | free (smtp->localhost); | ||
288 | smtp->localhost = strdup (hp->h_name); | ||
289 | if (smtp->localhost == NULL) | ||
290 | { | ||
291 | free (smtp->mailhost); | ||
292 | smtp->mailhost = NULL; | ||
293 | return ENOMEM; | ||
294 | } | ||
295 | } | ||
296 | } | 329 | } |
297 | 330 | ||
298 | /* allocate a working io buffer. */ | 331 | /* allocate a working io buffer. */ |
... | @@ -318,7 +351,7 @@ smtp_open (mailer_t mailer, int flags) | ... | @@ -318,7 +351,7 @@ smtp_open (mailer_t mailer, int flags) |
318 | smtp->state = SMTP_OPEN; | 351 | smtp->state = SMTP_OPEN; |
319 | 352 | ||
320 | case SMTP_OPEN: | 353 | case SMTP_OPEN: |
321 | MAILER_DEBUG2 (mailer, MU_DEBUG_PROT, "smtp_open (%s:%d)\n", | 354 | MAILER_DEBUG2 (mailer, MU_DEBUG_PROT, "smtp_open (host: %s port: %d)\n", |
322 | smtp->mailhost, port); | 355 | smtp->mailhost, port); |
323 | status = stream_open (mailer->stream); | 356 | status = stream_open (mailer->stream); |
324 | CHECK_EAGAIN (smtp, status); | 357 | CHECK_EAGAIN (smtp, status); |
... | @@ -328,7 +361,7 @@ smtp_open (mailer_t mailer, int flags) | ... | @@ -328,7 +361,7 @@ smtp_open (mailer_t mailer, int flags) |
328 | /* Swallow the greetings. */ | 361 | /* Swallow the greetings. */ |
329 | status = smtp_read_ack (smtp); | 362 | status = smtp_read_ack (smtp); |
330 | CHECK_EAGAIN (smtp, status); | 363 | CHECK_EAGAIN (smtp, status); |
331 | MAILER_DEBUG0 (mailer, MU_DEBUG_PROT, smtp->buffer); | 364 | |
332 | if (smtp->buffer[0] != '2') | 365 | if (smtp->buffer[0] != '2') |
333 | { | 366 | { |
334 | stream_close (mailer->stream); | 367 | stream_close (mailer->stream); |
... | @@ -336,7 +369,7 @@ smtp_open (mailer_t mailer, int flags) | ... | @@ -336,7 +369,7 @@ smtp_open (mailer_t mailer, int flags) |
336 | } | 369 | } |
337 | status = smtp_writeline (smtp, "EHLO %s\r\n", smtp->localhost); | 370 | status = smtp_writeline (smtp, "EHLO %s\r\n", smtp->localhost); |
338 | CHECK_ERROR (smtp, status); | 371 | CHECK_ERROR (smtp, status); |
339 | MAILER_DEBUG0 (mailer, MU_DEBUG_PROT, smtp->buffer); | 372 | |
340 | smtp->state = SMTP_EHLO; | 373 | smtp->state = SMTP_EHLO; |
341 | 374 | ||
342 | case SMTP_EHLO: | 375 | case SMTP_EHLO: |
... | @@ -348,7 +381,7 @@ smtp_open (mailer_t mailer, int flags) | ... | @@ -348,7 +381,7 @@ smtp_open (mailer_t mailer, int flags) |
348 | case SMTP_EHLO_ACK: | 381 | case SMTP_EHLO_ACK: |
349 | status = smtp_read_ack (smtp); | 382 | status = smtp_read_ack (smtp); |
350 | CHECK_EAGAIN (smtp, status); | 383 | CHECK_EAGAIN (smtp, status); |
351 | MAILER_DEBUG0 (mailer, MU_DEBUG_PROT, smtp->buffer); | 384 | |
352 | if (smtp->buffer[0] != '2') | 385 | if (smtp->buffer[0] != '2') |
353 | { | 386 | { |
354 | smtp->extended = 0; | 387 | smtp->extended = 0; |
... | @@ -363,7 +396,7 @@ smtp_open (mailer_t mailer, int flags) | ... | @@ -363,7 +396,7 @@ smtp_open (mailer_t mailer, int flags) |
363 | } | 396 | } |
364 | 397 | ||
365 | case SMTP_HELO: | 398 | case SMTP_HELO: |
366 | if (!smtp->extended) | 399 | if (!smtp->extended) /* FIXME: this will always be false! */ |
367 | { | 400 | { |
368 | status = smtp_write (smtp); | 401 | status = smtp_write (smtp); |
369 | CHECK_EAGAIN (smtp, status); | 402 | CHECK_EAGAIN (smtp, status); |
... | @@ -375,7 +408,7 @@ smtp_open (mailer_t mailer, int flags) | ... | @@ -375,7 +408,7 @@ smtp_open (mailer_t mailer, int flags) |
375 | { | 408 | { |
376 | status = smtp_read_ack (smtp); | 409 | status = smtp_read_ack (smtp); |
377 | CHECK_EAGAIN (smtp, status); | 410 | CHECK_EAGAIN (smtp, status); |
378 | MAILER_DEBUG0 (mailer, MU_DEBUG_PROT, smtp->buffer); | 411 | |
379 | if (smtp->buffer[0] != '2') | 412 | if (smtp->buffer[0] != '2') |
380 | { | 413 | { |
381 | stream_close (mailer->stream); | 414 | stream_close (mailer->stream); |
... | @@ -399,9 +432,9 @@ smtp_close (mailer_t mailer) | ... | @@ -399,9 +432,9 @@ smtp_close (mailer_t mailer) |
399 | switch (smtp->state) | 432 | switch (smtp->state) |
400 | { | 433 | { |
401 | case SMTP_NO_STATE: | 434 | case SMTP_NO_STATE: |
402 | status = smtp_writeline (smtp, "Quit\r\n"); | 435 | status = smtp_writeline (smtp, "QUIT\r\n"); |
403 | CHECK_ERROR (smtp, status); | 436 | CHECK_ERROR (smtp, status); |
404 | MAILER_DEBUG0 (mailer, MU_DEBUG_PROT, smtp->buffer); | 437 | |
405 | smtp->state = SMTP_QUIT; | 438 | smtp->state = SMTP_QUIT; |
406 | 439 | ||
407 | case SMTP_QUIT: | 440 | case SMTP_QUIT: |
... | @@ -412,7 +445,6 @@ smtp_close (mailer_t mailer) | ... | @@ -412,7 +445,6 @@ smtp_close (mailer_t mailer) |
412 | case SMTP_QUIT_ACK: | 445 | case SMTP_QUIT_ACK: |
413 | status = smtp_read_ack (smtp); | 446 | status = smtp_read_ack (smtp); |
414 | CHECK_EAGAIN (smtp, status); | 447 | CHECK_EAGAIN (smtp, status); |
415 | MAILER_DEBUG0 (mailer, MU_DEBUG_PROT, smtp->buffer); | ||
416 | 448 | ||
417 | default: | 449 | default: |
418 | break; | 450 | break; |
... | @@ -421,46 +453,119 @@ smtp_close (mailer_t mailer) | ... | @@ -421,46 +453,119 @@ smtp_close (mailer_t mailer) |
421 | } | 453 | } |
422 | 454 | ||
423 | static int | 455 | static int |
424 | smtp_send_message(mailer_t mailer, message_t msg, address_t from, address_t to) | 456 | message_set_header_value (message_t msg, const char *field, const char *value) |
425 | { | 457 | { |
426 | smtp_t smtp = mailer->data; | 458 | int status = 0; |
459 | header_t hdr = NULL; | ||
460 | |||
461 | if ((status = message_get_header (msg, &hdr))) | ||
462 | return status; | ||
463 | |||
464 | if ((status = header_set_value (hdr, field, value, 1))) | ||
465 | return status; | ||
466 | |||
467 | return status; | ||
468 | } | ||
469 | |||
470 | /* | ||
471 | |||
472 | The smtp mailer doesn't deal with mail like: | ||
473 | |||
474 | To: public@com, pub2@com | ||
475 | Bcc: hidden@there, two@there | ||
476 | |||
477 | It just sends the message to all the addresses, making the | ||
478 | "blind" cc not particularly blind. | ||
479 | |||
480 | The correct algorithm is | ||
481 | |||
482 | - open smtp connection | ||
483 | - look as msg, figure out addrto&cc, and addrbcc | ||
484 | - deliver to the to & cc addresses: | ||
485 | - if there are bcc addrs, remove the bcc field | ||
486 | - send the message to to & cc addrs: | ||
487 | mail from: me | ||
488 | rcpt to: public@com | ||
489 | rcpt to: pub2@com | ||
490 | data | ||
491 | ... | ||
492 | |||
493 | - deliver to the bcc addrs: | ||
494 | |||
495 | for a in (bccaddrs) | ||
496 | do | ||
497 | - add header field to msg, bcc: $a | ||
498 | - send the msg: | ||
499 | mail from: me | ||
500 | rcpt to: $a | ||
501 | data | ||
502 | ... | ||
503 | done | ||
504 | |||
505 | - quit smtp connection | ||
506 | |||
507 | */ | ||
508 | |||
509 | static int | ||
510 | smtp_send_message (mailer_t mailer, message_t argmsg, address_t argfrom, | ||
511 | address_t argto) | ||
512 | { | ||
513 | smtp_t smtp = NULL; | ||
427 | int status; | 514 | int status; |
428 | 515 | ||
429 | if (smtp == NULL || msg == NULL) | 516 | if(mailer == NULL) |
430 | return EINVAL; | 517 | return EINVAL; |
431 | 518 | ||
432 | /* FIXME: implement the from and to */ | 519 | smtp = mailer->data; |
433 | if(from || to) | 520 | assert (smtp); |
434 | return ENOSYS; | 521 | |
522 | CHECK_SEND_RESUME (smtp, argmsg, argfrom, argto); | ||
435 | 523 | ||
436 | switch (smtp->state) | 524 | switch (smtp->state) |
437 | { | 525 | { |
438 | case SMTP_NO_STATE: | 526 | case SMTP_NO_STATE: |
439 | smtp->state = SMTP_ENV_FROM; | 527 | if (argmsg == NULL) |
440 | status = get_from (msg, smtp->localhost, &smtp->mail_from); | 528 | return EINVAL; |
529 | |||
530 | smtp->argmsg = smtp->msg = argmsg; | ||
531 | smtp->argfrom = argfrom; | ||
532 | smtp->argto = argto; | ||
533 | |||
534 | status = _smtp_set_from (smtp, smtp->argmsg, smtp->argfrom); | ||
441 | CHECK_ERROR (smtp, status); | 535 | CHECK_ERROR (smtp, status); |
442 | status = get_rcpt (msg, &smtp->rcpt_to); | 536 | |
537 | status = _smtp_set_rcpt (smtp, smtp->argmsg, smtp->argto); | ||
443 | CHECK_ERROR (smtp, status); | 538 | CHECK_ERROR (smtp, status); |
444 | 539 | ||
540 | /* Clear the Bcc: field if we found one. */ | ||
541 | if (smtp->rcpt_bcc) | ||
542 | { | ||
543 | smtp->msg = NULL; | ||
544 | status = message_create_copy (&smtp->msg, smtp->argmsg); | ||
545 | CHECK_ERROR (smtp, status); | ||
546 | |||
547 | status = message_set_header_value (smtp->msg, MU_HEADER_BCC, NULL); | ||
548 | CHECK_ERROR (smtp, status); | ||
549 | } | ||
550 | |||
551 | /* Begin bccing if there are not To: recipients. */ | ||
552 | if (smtp->rcpt_to_count == 0) | ||
553 | smtp->bccing = 1; | ||
554 | |||
555 | smtp->rcpt_index = 1; | ||
556 | |||
557 | smtp->state = SMTP_ENV_FROM; | ||
558 | |||
445 | case SMTP_ENV_FROM: | 559 | case SMTP_ENV_FROM: |
560 | ENV_FROM: | ||
446 | { | 561 | { |
447 | size_t len = 0; | 562 | status = smtp_writeline (smtp, "MAIL FROM: %s\r\n", smtp->mail_from); |
448 | char *frm; | ||
449 | address_get_email (smtp->mail_from, 1, NULL, 0, &len); | ||
450 | if (len == 0) | ||
451 | CHECK_ERROR (smtp, EINVAL); | ||
452 | frm = calloc (len + 1, sizeof (char)); | ||
453 | if (frm == NULL) | ||
454 | CHECK_ERROR (smtp, ENOMEM); | ||
455 | address_get_email (smtp->mail_from, 1, frm, len + 1, NULL); | ||
456 | status = smtp_writeline (smtp, "MAIL FROM: %s\r\n", frm); | ||
457 | free (frm); | ||
458 | address_destroy (&smtp->mail_from); | ||
459 | CHECK_ERROR (smtp, status); | 563 | CHECK_ERROR (smtp, status); |
460 | MAILER_DEBUG0 (mailer, MU_DEBUG_PROT, smtp->buffer); | ||
461 | smtp->state = SMTP_MAIL_FROM; | 564 | smtp->state = SMTP_MAIL_FROM; |
462 | } | 565 | } |
463 | 566 | ||
567 | /* We use a goto, since we may have multiple messages, | ||
568 | we come back here and doit all over again ... Not pretty. */ | ||
464 | case SMTP_MAIL_FROM: | 569 | case SMTP_MAIL_FROM: |
465 | status = smtp_write (smtp); | 570 | status = smtp_write (smtp); |
466 | CHECK_EAGAIN (smtp, status); | 571 | CHECK_EAGAIN (smtp, status); |
... | @@ -469,7 +574,6 @@ smtp_send_message(mailer_t mailer, message_t msg, address_t from, address_t to) | ... | @@ -469,7 +574,6 @@ smtp_send_message(mailer_t mailer, message_t msg, address_t from, address_t to) |
469 | case SMTP_MAIL_FROM_ACK: | 574 | case SMTP_MAIL_FROM_ACK: |
470 | status = smtp_read_ack (smtp); | 575 | status = smtp_read_ack (smtp); |
471 | CHECK_EAGAIN (smtp, status); | 576 | CHECK_EAGAIN (smtp, status); |
472 | MAILER_DEBUG0 (mailer, MU_DEBUG_PROT, smtp->buffer); | ||
473 | if (smtp->buffer[0] != '2') | 577 | if (smtp->buffer[0] != '2') |
474 | { | 578 | { |
475 | stream_close (mailer->stream); | 579 | stream_close (mailer->stream); |
... | @@ -478,64 +582,58 @@ smtp_send_message(mailer_t mailer, message_t msg, address_t from, address_t to) | ... | @@ -478,64 +582,58 @@ smtp_send_message(mailer_t mailer, message_t msg, address_t from, address_t to) |
478 | } | 582 | } |
479 | 583 | ||
480 | /* We use a goto, since we may have multiple recipients, | 584 | /* We use a goto, since we may have multiple recipients, |
481 | we come back here and doit all over again ... Not pretty. */ | 585 | we come back here and do it all over again ... Not pretty. */ |
482 | case SMTP_ENV_RCPT: | 586 | case SMTP_ENV_RCPT: |
483 | RCPT_TO: | 587 | ENV_RCPT: |
484 | { | 588 | { |
485 | size_t i = 0; | 589 | address_t addr = smtp->rcpt_to; |
590 | char *to = NULL; | ||
591 | |||
592 | if (smtp->bccing) | ||
593 | addr = smtp->rcpt_bcc; | ||
594 | |||
595 | status = address_aget_email (addr, smtp->rcpt_index, &to); | ||
596 | |||
597 | CHECK_ERROR (smtp, status); | ||
598 | |||
599 | /* Add the Bcc: field back in for recipient. */ | ||
600 | if(smtp->bccing) | ||
601 | { | ||
602 | status = message_set_header_value (smtp->msg, MU_HEADER_BCC, to); | ||
603 | CHECK_ERROR (smtp, status); | ||
604 | } | ||
605 | |||
606 | status = smtp_writeline (smtp, "RCPT TO: %s\r\n", to); | ||
607 | |||
608 | free (to); | ||
609 | |||
610 | CHECK_ERROR (smtp, status); | ||
611 | |||
612 | smtp->state = SMTP_RCPT_TO; | ||
486 | smtp->rcpt_index++; | 613 | smtp->rcpt_index++; |
487 | address_get_count (smtp->rcpt_to, &i); | ||
488 | if (smtp->rcpt_index <= i) | ||
489 | { | ||
490 | size_t len = 0; | ||
491 | char *To; | ||
492 | address_get_email (smtp->rcpt_to, smtp->rcpt_index, NULL, 0, &len); | ||
493 | if (len == 0) | ||
494 | CHECK_ERROR (smtp, EINVAL); | ||
495 | To = calloc (len + 1, sizeof (char)); | ||
496 | if (To == NULL) | ||
497 | CHECK_ERROR (smtp, ENOMEM); | ||
498 | address_get_email (smtp->rcpt_to, smtp->rcpt_index, To, len + 1, NULL); | ||
499 | status = smtp_writeline (smtp, "RCPT TO: %s\r\n", To); | ||
500 | free (To); | ||
501 | CHECK_ERROR (smtp, status); | ||
502 | MAILER_DEBUG0 (mailer, MU_DEBUG_PROT, smtp->buffer); | ||
503 | smtp->state = SMTP_RCPT_TO; | ||
504 | } | ||
505 | else | ||
506 | { | ||
507 | address_destroy (&(smtp->rcpt_to)); | ||
508 | smtp->rcpt_index = 0; | ||
509 | smtp->state = SMTP_DATA; | ||
510 | } | ||
511 | } | 614 | } |
512 | 615 | ||
513 | case SMTP_RCPT_TO: | 616 | case SMTP_RCPT_TO: |
514 | if (smtp->rcpt_to) | 617 | status = smtp_write (smtp); |
515 | { | 618 | CHECK_EAGAIN (smtp, status); |
516 | status = smtp_write (smtp); | 619 | smtp->state = SMTP_RCPT_TO_ACK; |
517 | CHECK_EAGAIN (smtp, status); | ||
518 | smtp->state = SMTP_RCPT_TO_ACK; | ||
519 | } | ||
520 | 620 | ||
521 | case SMTP_RCPT_TO_ACK: | 621 | case SMTP_RCPT_TO_ACK: |
522 | if (smtp->rcpt_to) | 622 | status = smtp_read_ack (smtp); |
623 | CHECK_EAGAIN (smtp, status); | ||
624 | if (smtp->buffer[0] != '2') | ||
523 | { | 625 | { |
524 | status = smtp_read_ack (smtp); | 626 | stream_close (mailer->stream); |
525 | CHECK_EAGAIN (smtp, status); | 627 | CLEAR_STATE (smtp); |
526 | MAILER_DEBUG0 (mailer, MU_DEBUG_PROT, smtp->buffer); | 628 | return MU_ERR_SMTP_RCPT_FAILED; |
527 | if (smtp->buffer[0] != '2') | ||
528 | { | ||
529 | stream_close (mailer->stream); | ||
530 | CLEAR_STATE (smtp); | ||
531 | return EACCES; | ||
532 | } | ||
533 | goto RCPT_TO; | ||
534 | } | 629 | } |
535 | /* We are done with the rcpt. */ | 630 | /* Redo the receipt sequence for every To: and Cc: recipient. */ |
631 | if (!smtp->bccing && smtp->rcpt_index <= smtp->rcpt_to_count) | ||
632 | goto ENV_RCPT; | ||
633 | |||
634 | /* We are done with the rcpt. */ | ||
536 | status = smtp_writeline (smtp, "DATA\r\n"); | 635 | status = smtp_writeline (smtp, "DATA\r\n"); |
537 | CHECK_ERROR (smtp, status); | 636 | CHECK_ERROR (smtp, status); |
538 | MAILER_DEBUG0 (mailer, MU_DEBUG_PROT, smtp->buffer); | ||
539 | smtp->state = SMTP_DATA; | 637 | smtp->state = SMTP_DATA; |
540 | 638 | ||
541 | case SMTP_DATA: | 639 | case SMTP_DATA: |
... | @@ -546,7 +644,6 @@ smtp_send_message(mailer_t mailer, message_t msg, address_t from, address_t to) | ... | @@ -546,7 +644,6 @@ smtp_send_message(mailer_t mailer, message_t msg, address_t from, address_t to) |
546 | case SMTP_DATA_ACK: | 644 | case SMTP_DATA_ACK: |
547 | status = smtp_read_ack (smtp); | 645 | status = smtp_read_ack (smtp); |
548 | CHECK_EAGAIN (smtp, status); | 646 | CHECK_EAGAIN (smtp, status); |
549 | MAILER_DEBUG0 (mailer, MU_DEBUG_PROT, smtp->buffer); | ||
550 | if (smtp->buffer[0] != '3') | 647 | if (smtp->buffer[0] != '3') |
551 | { | 648 | { |
552 | stream_close (mailer->stream); | 649 | stream_close (mailer->stream); |
... | @@ -565,12 +662,12 @@ smtp_send_message(mailer_t mailer, message_t msg, address_t from, address_t to) | ... | @@ -565,12 +662,12 @@ smtp_send_message(mailer_t mailer, message_t msg, address_t from, address_t to) |
565 | in the buffer and flush it. */ | 662 | in the buffer and flush it. */ |
566 | status = smtp_write (smtp); | 663 | status = smtp_write (smtp); |
567 | CHECK_EAGAIN (smtp, status); | 664 | CHECK_EAGAIN (smtp, status); |
568 | message_get_stream (msg, &stream); | 665 | message_get_stream (smtp->msg, &stream); |
569 | while ((status = stream_readline (stream, data, sizeof (data) - 1, | 666 | while ((status = stream_readline (stream, data, sizeof (data) - 1, |
570 | smtp->offset, &n)) == 0 && n > 0) | 667 | smtp->offset, &n)) == 0 && n > 0) |
571 | { | 668 | { |
572 | if (data [n - 1] == '\n') | 669 | if (data[n - 1] == '\n') |
573 | data [n -1] = '\0'; | 670 | data[n - 1] = '\0'; |
574 | if (data[0] == '.') | 671 | if (data[0] == '.') |
575 | { | 672 | { |
576 | status = smtp_writeline (smtp, ".%s\r\n", data); | 673 | status = smtp_writeline (smtp, ".%s\r\n", data); |
... | @@ -582,8 +679,7 @@ smtp_send_message(mailer_t mailer, message_t msg, address_t from, address_t to) | ... | @@ -582,8 +679,7 @@ smtp_send_message(mailer_t mailer, message_t msg, address_t from, address_t to) |
582 | CHECK_ERROR (smtp, status); | 679 | CHECK_ERROR (smtp, status); |
583 | } | 680 | } |
584 | smtp->offset += n; | 681 | smtp->offset += n; |
585 | MAILER_DEBUG0 (mailer, MU_DEBUG_PROT, smtp->buffer); | 682 | status = smtp_write (smtp); |
586 | status = smtp_write (smtp); | ||
587 | CHECK_EAGAIN (smtp, status); | 683 | CHECK_EAGAIN (smtp, status); |
588 | } | 684 | } |
589 | smtp->offset = 0; | 685 | smtp->offset = 0; |
... | @@ -600,8 +696,6 @@ smtp_send_message(mailer_t mailer, message_t msg, address_t from, address_t to) | ... | @@ -600,8 +696,6 @@ smtp_send_message(mailer_t mailer, message_t msg, address_t from, address_t to) |
600 | case SMTP_SEND_ACK: | 696 | case SMTP_SEND_ACK: |
601 | status = smtp_read_ack (smtp); | 697 | status = smtp_read_ack (smtp); |
602 | CHECK_EAGAIN (smtp, status); | 698 | CHECK_EAGAIN (smtp, status); |
603 | MAILER_DEBUG0 (mailer, MU_DEBUG_PROT, smtp->buffer); | ||
604 | observable_notify (mailer->observable, MU_EVT_MAILER_MESSAGE_SENT); | ||
605 | if (smtp->buffer[0] != '2') | 699 | if (smtp->buffer[0] != '2') |
606 | { | 700 | { |
607 | stream_close (mailer->stream); | 701 | stream_close (mailer->stream); |
... | @@ -609,6 +703,18 @@ smtp_send_message(mailer_t mailer, message_t msg, address_t from, address_t to) | ... | @@ -609,6 +703,18 @@ smtp_send_message(mailer_t mailer, message_t msg, address_t from, address_t to) |
609 | return EACCES; | 703 | return EACCES; |
610 | } | 704 | } |
611 | 705 | ||
706 | /* Decide whether we need to loop again, to deliver to Bcc: | ||
707 | recipients. */ | ||
708 | if (!smtp->bccing) | ||
709 | { | ||
710 | smtp->bccing = 1; | ||
711 | smtp->rcpt_index = 1; | ||
712 | } | ||
713 | if (smtp->rcpt_index <= smtp->rcpt_bcc_count) | ||
714 | goto ENV_FROM; | ||
715 | |||
716 | observable_notify (mailer->observable, MU_EVT_MAILER_MESSAGE_SENT); | ||
717 | |||
612 | default: | 718 | default: |
613 | break; | 719 | break; |
614 | } | 720 | } |
... | @@ -617,125 +723,229 @@ smtp_send_message(mailer_t mailer, message_t msg, address_t from, address_t to) | ... | @@ -617,125 +723,229 @@ smtp_send_message(mailer_t mailer, message_t msg, address_t from, address_t to) |
617 | } | 723 | } |
618 | 724 | ||
619 | static int | 725 | static int |
620 | get_from (message_t msg, char *localhost, address_t *pmail_from) | 726 | _smtp_set_from (smtp_t smtp, message_t msg, address_t from) |
621 | { | 727 | { |
622 | int status; | 728 | int status = 0; |
623 | size_t size = 0; | 729 | char *mail_from; |
624 | char *from; | ||
625 | header_t header = NULL; | 730 | header_t header = NULL; |
626 | 731 | ||
627 | message_get_header (msg, &header); | 732 | /* Get MAIL_FROM from FROM, the message, or the environment. */ |
628 | status = header_get_value (header, MU_HEADER_FROM, NULL, 0, &size); | 733 | if (from) |
629 | /* If it's not in the header create one form the passwd. */ | ||
630 | if (status != 0 || size == 0) | ||
631 | { | 734 | { |
632 | struct passwd *pwd = mu_getpwuid (getuid ()); | 735 | /* Use the specified address_t. */ |
633 | /* Not in the passwd ???? We have a problem. */ | 736 | if ((status = mailer_check_from (from)) != 0) |
634 | if (pwd == 0 || pwd->pw_name == NULL) | ||
635 | { | ||
636 | size = 10 + strlen (localhost) + 1; | ||
637 | from = calloc (size, sizeof (char)); | ||
638 | if (from == NULL) | ||
639 | return ENOMEM; | ||
640 | snprintf (from, size, "%d@%s", getuid(), localhost); | ||
641 | } | ||
642 | else | ||
643 | { | 737 | { |
644 | from = calloc (strlen (pwd->pw_name) + 1 | 738 | MAILER_DEBUG0 (smtp->mailer, MU_DEBUG_ERROR, |
645 | + strlen (localhost) + 1, sizeof (char)); | 739 | "mailer_send_message(): explicit from not valid\n"); |
646 | if (from == NULL) | 740 | return status; |
647 | return ENOMEM; | ||
648 | sprintf(from, "%s@%s", pwd->pw_name, localhost); | ||
649 | } | 741 | } |
742 | |||
743 | if ((status = address_aget_email (from, 1, &mail_from)) != 0) | ||
744 | return status; | ||
650 | } | 745 | } |
651 | else | 746 | else |
652 | { | 747 | { |
653 | from = calloc (size + 1, sizeof (char)); | 748 | char *from_hdr = NULL; |
654 | if (from == NULL) | 749 | |
655 | return ENOMEM; | 750 | if ((status = message_get_header (msg, &header)) != 0) |
656 | header_get_value (header, MU_HEADER_FROM, from, size + 1, NULL); | 751 | return status; |
657 | } | 752 | |
658 | /* Check if a Fully Qualified Name, some smtp servers | 753 | status = header_aget_value (header, MU_HEADER_FROM, &from_hdr); |
659 | notably sendmail insists on it, for good reasons. */ | 754 | |
660 | if (strchr (from, '@') == NULL) | 755 | switch (status) |
661 | { | ||
662 | char *tmp; | ||
663 | tmp = malloc (strlen (from) + 1 +strlen (localhost) + 1); | ||
664 | if (tmp == NULL) | ||
665 | { | 756 | { |
666 | free (from); | 757 | default: |
667 | return ENOMEM; | 758 | return status; |
759 | |||
760 | /* Use the From: header. */ | ||
761 | case 0: | ||
762 | { | ||
763 | address_t fromaddr = NULL; | ||
764 | |||
765 | MAILER_DEBUG1 (smtp->mailer, MU_DEBUG_TRACE, | ||
766 | "mailer_send_message(): using From: %s\n", | ||
767 | from_hdr); | ||
768 | |||
769 | if ((status = address_create (&fromaddr, from_hdr)) != 0) | ||
770 | { | ||
771 | free (from_hdr); | ||
772 | return status; | ||
773 | } | ||
774 | if ((status = mailer_check_from (fromaddr)) != 0) | ||
775 | { | ||
776 | free (from_hdr); | ||
777 | address_destroy (&fromaddr); | ||
778 | MAILER_DEBUG1 (smtp->mailer, MU_DEBUG_ERROR, | ||
779 | "mailer_send_message(): from field %s not valid\n", | ||
780 | from_hdr); | ||
781 | return status; | ||
782 | } | ||
783 | if ((status = address_aget_email (fromaddr, 1, &mail_from)) != 0) | ||
784 | { | ||
785 | free (from_hdr); | ||
786 | address_destroy (&fromaddr); | ||
787 | return status; | ||
788 | } | ||
789 | free (from_hdr); | ||
790 | address_destroy (&fromaddr); | ||
791 | } | ||
792 | break; | ||
793 | |||
794 | case ENOENT: | ||
795 | /* Use the environment. */ | ||
796 | mail_from = mu_get_user_email (NULL); | ||
797 | |||
798 | if (mail_from) | ||
799 | { | ||
800 | MAILER_DEBUG1 (smtp->mailer, MU_DEBUG_TRACE, | ||
801 | "mailer_send_message(): using user's address: %s\n", | ||
802 | mail_from); | ||
803 | } | ||
804 | else | ||
805 | { | ||
806 | MAILER_DEBUG0 (smtp->mailer, MU_DEBUG_TRACE, | ||
807 | "mailer_send_message(): no user's address, failing\n"); | ||
808 | } | ||
809 | |||
810 | if (!mail_from) | ||
811 | return errno; | ||
812 | |||
813 | status = 0; | ||
814 | |||
815 | /* FIXME: should we add the From: header? */ | ||
816 | |||
817 | break; | ||
818 | |||
668 | } | 819 | } |
669 | sprintf (tmp, "%s@%s", from, localhost); | ||
670 | free (from); | ||
671 | from = tmp; | ||
672 | } | 820 | } |
673 | status = address_create (pmail_from, from); | 821 | |
674 | free (from); | 822 | assert (mail_from); |
823 | |||
824 | smtp->mail_from = mail_from; | ||
825 | |||
675 | return status; | 826 | return status; |
676 | } | 827 | } |
677 | 828 | ||
678 | static int | 829 | static int |
679 | get_rcpt (message_t msg, address_t *prcpt_to) | 830 | _smtp_set_rcpt (smtp_t smtp, message_t msg, address_t to) |
680 | { | 831 | { |
681 | char *rcpt; | 832 | int status = 0; |
682 | int status; | ||
683 | size_t size = 0; | ||
684 | header_t header = NULL; | 833 | header_t header = NULL; |
834 | char *toaddrv[3] = { NULL, NULL }; | ||
835 | char *bccaddr = NULL; | ||
836 | address_t rcpt_to = NULL; | ||
837 | address_t rcpt_bcc = NULL; | ||
685 | 838 | ||
686 | message_get_header (msg, &header); | 839 | /* Get RCPT_TO from TO, or the message. */ |
687 | status = header_get_value (header, MU_HEADER_TO, NULL, 0, &size); | ||
688 | if (status == 0 && size != 0) | ||
689 | { | ||
690 | char *tmp; | ||
691 | size_t len; | ||
692 | rcpt = calloc (size + 1, sizeof (char)); | ||
693 | if (rcpt == NULL) | ||
694 | return ENOMEM; | ||
695 | header_get_value (header, MU_HEADER_TO, rcpt, size + 1, NULL); | ||
696 | 840 | ||
697 | size = 0; | 841 | if (to) |
698 | status = header_get_value (header, MU_HEADER_CC, NULL, 0, &size); | 842 | { |
699 | if (status == 0 && size != 0) | 843 | /* Use the specified address_t. */ |
844 | if ((status = mailer_check_to (to)) != 0) | ||
700 | { | 845 | { |
701 | len = strlen (rcpt); | 846 | MAILER_DEBUG0 (smtp->mailer, MU_DEBUG_ERROR, |
702 | tmp = realloc (rcpt, (len + 1 + size + 1) * sizeof (char)); | 847 | "mailer_send_message(): explicit to not valid\n"); |
703 | if (tmp == NULL) | 848 | return status; |
704 | { | ||
705 | free (rcpt); | ||
706 | return ENOMEM; | ||
707 | } | ||
708 | else | ||
709 | rcpt = tmp; | ||
710 | rcpt[len] = ','; | ||
711 | header_get_value (header, MU_HEADER_CC, rcpt + len + 1, | ||
712 | size + 1, NULL); | ||
713 | |||
714 | size = 0; | ||
715 | status = header_get_value (header, MU_HEADER_BCC, NULL, 0, &size); | ||
716 | if (status == 0 && size != 0) | ||
717 | { | ||
718 | len = strlen (rcpt); | ||
719 | tmp = realloc (rcpt, (len + 1 + size + 1) * sizeof (char)); | ||
720 | if (tmp == NULL) | ||
721 | { | ||
722 | free (rcpt); | ||
723 | return ENOMEM; | ||
724 | } | ||
725 | else | ||
726 | rcpt = tmp; | ||
727 | rcpt[len] = ','; | ||
728 | header_get_value (header, MU_HEADER_BCC, rcpt + len + 1, | ||
729 | size + 1, NULL); | ||
730 | } | ||
731 | } | 849 | } |
732 | status = address_create (prcpt_to, rcpt); | 850 | smtp->rcpt_to = to; |
733 | free (rcpt); | 851 | |
734 | return status; | 852 | return status; |
735 | } | 853 | } |
736 | return EINVAL; | ||
737 | } | ||
738 | 854 | ||
855 | if ((status = message_get_header (msg, &header))) | ||
856 | return status; | ||
857 | |||
858 | status = header_aget_value (header, MU_HEADER_TO, toaddrv + 0); | ||
859 | |||
860 | if (status && status != ENOENT) | ||
861 | goto end; | ||
862 | |||
863 | status = header_aget_value (header, MU_HEADER_CC, toaddrv + 1); | ||
864 | |||
865 | if (status && status != ENOENT) | ||
866 | goto end; | ||
867 | |||
868 | status = header_aget_value (header, MU_HEADER_BCC, &bccaddr); | ||
869 | |||
870 | if (status && status != ENOENT) | ||
871 | goto end; | ||
872 | |||
873 | status = 0; | ||
874 | |||
875 | { | ||
876 | const char **av = (const char **) toaddrv; | ||
877 | int tostatus = address_createv (&rcpt_to, av, 2); | ||
878 | |||
879 | /* Any error other than EMPTY_ADDRESS is fatal */ | ||
880 | if (tostatus) | ||
881 | { | ||
882 | if (tostatus == MU_ERR_EMPTY_ADDRESS) | ||
883 | tostatus = MU_ERR_MAILER_NO_RCPT_TO; | ||
884 | else | ||
885 | goto end; | ||
886 | } | ||
887 | |||
888 | if (!bccaddr) | ||
889 | status = MU_ERR_EMPTY_ADDRESS; | ||
890 | else | ||
891 | { | ||
892 | status = address_create (&rcpt_bcc, bccaddr); | ||
893 | |||
894 | if (status) | ||
895 | { | ||
896 | if (status == MU_ERR_EMPTY_ADDRESS) | ||
897 | status = MU_ERR_MAILER_NO_RCPT_TO; | ||
898 | else | ||
899 | goto end; | ||
900 | } | ||
901 | } | ||
902 | |||
903 | /* If both to and bcc are empty, it is fatal */ | ||
904 | if (status == MU_ERR_EMPTY_ADDRESS && tostatus == status) | ||
905 | goto end; | ||
906 | |||
907 | /* otherwise, at least rcpt_to or rcpt_bcc is defined */ | ||
908 | status = 0; | ||
909 | } | ||
910 | |||
911 | /* If to or bcc is present, the must be OK. */ | ||
912 | if (rcpt_to && (status = mailer_check_to (rcpt_to))) | ||
913 | goto end; | ||
914 | |||
915 | if (rcpt_bcc && (status = mailer_check_to (rcpt_bcc))) | ||
916 | goto end; | ||
917 | |||
918 | end: | ||
919 | |||
920 | if (toaddrv[0]) | ||
921 | free (toaddrv[0]); | ||
922 | |||
923 | if (toaddrv[1]) | ||
924 | free (toaddrv[1]); | ||
925 | |||
926 | if (bccaddr) | ||
927 | free (bccaddr); | ||
928 | |||
929 | if (status) | ||
930 | { | ||
931 | address_destroy (&rcpt_to); | ||
932 | address_destroy (&rcpt_bcc); | ||
933 | } | ||
934 | else | ||
935 | { | ||
936 | smtp->rcpt_to = rcpt_to; | ||
937 | |||
938 | if (smtp->rcpt_to) | ||
939 | address_get_count (smtp->rcpt_to, &smtp->rcpt_to_count); | ||
940 | |||
941 | smtp->rcpt_bcc = rcpt_bcc; | ||
942 | |||
943 | if (smtp->rcpt_bcc) | ||
944 | address_get_count (smtp->rcpt_bcc, &smtp->rcpt_bcc_count); | ||
945 | } | ||
946 | |||
947 | return status; | ||
948 | } | ||
739 | /* C99 says that a conforming implementations of snprintf () | 949 | /* C99 says that a conforming implementations of snprintf () |
740 | should return the number of char that would have been call | 950 | should return the number of char that would have been call |
741 | but many GNU/Linux && BSD implementations return -1 on error. | 951 | but many GNU/Linux && BSD implementations return -1 on error. |
... | @@ -748,25 +958,36 @@ smtp_writeline (smtp_t smtp, const char *format, ...) | ... | @@ -748,25 +958,36 @@ smtp_writeline (smtp_t smtp, const char *format, ...) |
748 | va_list ap; | 958 | va_list ap; |
749 | int done = 1; | 959 | int done = 1; |
750 | 960 | ||
751 | va_start(ap, format); | 961 | va_start (ap, format); |
752 | do | 962 | do |
753 | { | 963 | { |
754 | len = vsnprintf (smtp->buffer, smtp->buflen - 1, format, ap); | 964 | len = vsnprintf (smtp->buffer, smtp->buflen - 1, format, ap); |
755 | if (len < 0 || (len >= (int)smtp->buflen) | 965 | if (len < 0 || (len >= (int) smtp->buflen) |
756 | || !memchr (smtp->buffer, '\0', len + 1)) | 966 | || !memchr (smtp->buffer, '\0', len + 1)) |
757 | { | 967 | { |
758 | smtp->buflen *= 2; | 968 | char *buffer = NULL; |
759 | smtp->buffer = realloc (smtp->buffer, smtp->buflen); | 969 | size_t buflen = smtp->buflen * 2; |
760 | if (smtp->buffer == NULL) | 970 | buffer = realloc (smtp->buffer, buflen); |
761 | return ENOMEM; | 971 | if (smtp->buffer == NULL) |
972 | return ENOMEM; | ||
973 | smtp->buffer = buffer; | ||
974 | smtp->buflen = buflen; | ||
762 | done = 0; | 975 | done = 0; |
763 | } | 976 | } |
764 | else | 977 | else |
765 | done = 1; | 978 | done = 1; |
766 | } | 979 | } |
767 | while (!done); | 980 | while (!done); |
768 | va_end(ap); | 981 | |
982 | va_end (ap); | ||
983 | |||
769 | smtp->ptr = smtp->buffer + len; | 984 | smtp->ptr = smtp->buffer + len; |
985 | |||
986 | while (len > 0 && isspace (smtp->buffer[len-1])) | ||
987 | len--; | ||
988 | |||
989 | MAILER_DEBUG2 (smtp->mailer, MU_DEBUG_PROT, "> %.*s\n", len, smtp->buffer); | ||
990 | |||
770 | return 0; | 991 | return 0; |
771 | } | 992 | } |
772 | 993 | ||
... | @@ -781,10 +1002,10 @@ smtp_write (smtp_t smtp) | ... | @@ -781,10 +1002,10 @@ smtp_write (smtp_t smtp) |
781 | status = stream_write (smtp->mailer->stream, smtp->buffer, len, | 1002 | status = stream_write (smtp->mailer->stream, smtp->buffer, len, |
782 | 0, &len); | 1003 | 0, &len); |
783 | if (status == 0) | 1004 | if (status == 0) |
784 | { | 1005 | { |
785 | memmove (smtp->buffer, smtp->buffer + len, len); | 1006 | memmove (smtp->buffer, smtp->buffer + len, len); |
786 | smtp->ptr -= len; | 1007 | smtp->ptr -= len; |
787 | } | 1008 | } |
788 | } | 1009 | } |
789 | else | 1010 | else |
790 | { | 1011 | { |
... | @@ -804,8 +1025,7 @@ smtp_read_ack (smtp_t smtp) | ... | @@ -804,8 +1025,7 @@ smtp_read_ack (smtp_t smtp) |
804 | { | 1025 | { |
805 | multi = 0; | 1026 | multi = 0; |
806 | status = smtp_readline (smtp); | 1027 | status = smtp_readline (smtp); |
807 | if ((smtp->ptr - smtp->buffer) > 4 | 1028 | if ((smtp->ptr - smtp->buffer) > 4 && smtp->buffer[3] == '-') |
808 | && smtp->buffer[3] == '-') | ||
809 | multi = 1; | 1029 | multi = 1; |
810 | if (status == 0) | 1030 | if (status == 0) |
811 | smtp->ptr = smtp->buffer; | 1031 | smtp->ptr = smtp->buffer; |
... | @@ -832,7 +1052,7 @@ smtp_readline (smtp_t smtp) | ... | @@ -832,7 +1052,7 @@ smtp_readline (smtp_t smtp) |
832 | status = stream_readline (smtp->mailer->stream, smtp->buffer + total, | 1052 | status = stream_readline (smtp->mailer->stream, smtp->buffer + total, |
833 | smtp->buflen - total, smtp->s_offset, &n); | 1053 | smtp->buflen - total, smtp->s_offset, &n); |
834 | if (status != 0) | 1054 | if (status != 0) |
835 | return status; | 1055 | return status; |
836 | 1056 | ||
837 | /* Server went away, consider this like an error. */ | 1057 | /* Server went away, consider this like an error. */ |
838 | if (n == 0) | 1058 | if (n == 0) |
... | @@ -841,17 +1061,17 @@ smtp_readline (smtp_t smtp) | ... | @@ -841,17 +1061,17 @@ smtp_readline (smtp_t smtp) |
841 | total += n; | 1061 | total += n; |
842 | smtp->s_offset += n; | 1062 | smtp->s_offset += n; |
843 | smtp->nl = memchr (smtp->buffer, '\n', total); | 1063 | smtp->nl = memchr (smtp->buffer, '\n', total); |
844 | if (smtp->nl == NULL) /* Do we have a full line. */ | 1064 | if (smtp->nl == NULL) /* Do we have a full line. */ |
845 | { | 1065 | { |
846 | /* Allocate a bigger buffer ? */ | 1066 | /* Allocate a bigger buffer ? */ |
847 | if (total >= smtp->buflen -1) | 1067 | if (total >= smtp->buflen - 1) |
848 | { | 1068 | { |
849 | smtp->buflen *= 2; | 1069 | smtp->buflen *= 2; |
850 | smtp->buffer = realloc (smtp->buffer, smtp->buflen + 1); | 1070 | smtp->buffer = realloc (smtp->buffer, smtp->buflen + 1); |
851 | if (smtp->buffer == NULL) | 1071 | if (smtp->buffer == NULL) |
852 | return ENOMEM; | 1072 | return ENOMEM; |
853 | } | 1073 | } |
854 | } | 1074 | } |
855 | smtp->ptr = smtp->buffer + total; | 1075 | smtp->ptr = smtp->buffer + total; |
856 | } | 1076 | } |
857 | while (smtp->nl == NULL); | 1077 | while (smtp->nl == NULL); |
... | @@ -863,5 +1083,9 @@ smtp_readline (smtp_t smtp) | ... | @@ -863,5 +1083,9 @@ smtp_readline (smtp_t smtp) |
863 | *(smtp->nl) = '\0'; | 1083 | *(smtp->nl) = '\0'; |
864 | smtp->ptr = smtp->nl; | 1084 | smtp->ptr = smtp->nl; |
865 | } | 1085 | } |
1086 | |||
1087 | MAILER_DEBUG1 (smtp->mailer, MU_DEBUG_PROT, "< %s", smtp->buffer); | ||
1088 | |||
866 | return 0; | 1089 | return 0; |
867 | } | 1090 | } |
1091 | ... | ... |
-
Please register or sign in to post a comment