Commit 1c21c97f 1c21c97fb9b01a50a5d812a55345787045f73f91 by Sam Roberts

Implemented correct semantics for sending mail to bcc'ed addresses.

1 parent 026e47c0
...@@ -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,20 +87,93 @@ struct _smtp ...@@ -83,20 +87,93 @@ 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;
141
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)
100 177
101 /* Clear the state and close the stream. */ 178 /* Clear the state and close the stream. */
102 #define CHECK_ERROR_CLOSE(mailer, smtp, status) \ 179 #define CHECK_ERROR_CLOSE(mailer, smtp, status) \
...@@ -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;
241 do
242 {
243 char *tmp;
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 {
266 /* gethostname failed, abort. */
267 free (smtp->localhost);
268 smtp->localhost = NULL;
269 free (smtp->mailhost);
270 smtp->mailhost = NULL;
271 return EINVAL;
272 }
273 320
274 /* Many SMTP servers prefer a FQDN. */ 321 status = mu_get_host_name(&smtp->localhost);
275 if (strchr (smtp->localhost, '.') == NULL) 322
276 { 323 if (status != 0)
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 { 324 {
325 /* gethostname failed, abort. */
291 free (smtp->mailhost); 326 free (smtp->mailhost);
292 smtp->mailhost = NULL; 327 smtp->mailhost = NULL;
293 return ENOMEM; 328 return status;
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;
486 smtp->rcpt_index++; 590 char *to = NULL;
487 address_get_count (smtp->rcpt_to, &i); 591
488 if (smtp->rcpt_index <= i) 592 if (smtp->bccing)
489 { 593 addr = smtp->rcpt_bcc;
490 size_t len = 0; 594
491 char *To; 595 status = address_aget_email (addr, smtp->rcpt_index, &to);
492 address_get_email (smtp->rcpt_to, smtp->rcpt_index, NULL, 0, &len); 596
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); 597 CHECK_ERROR (smtp, status);
502 MAILER_DEBUG0 (mailer, MU_DEBUG_PROT, smtp->buffer); 598
503 smtp->state = SMTP_RCPT_TO; 599 /* Add the Bcc: field back in for recipient. */
504 } 600 if(smtp->bccing)
505 else
506 { 601 {
507 address_destroy (&(smtp->rcpt_to)); 602 status = message_set_header_value (smtp->msg, MU_HEADER_BCC, to);
508 smtp->rcpt_index = 0; 603 CHECK_ERROR (smtp, status);
509 smtp->state = SMTP_DATA;
510 } 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;
613 smtp->rcpt_index++;
511 } 614 }
512 615
513 case SMTP_RCPT_TO: 616 case SMTP_RCPT_TO:
514 if (smtp->rcpt_to)
515 {
516 status = smtp_write (smtp); 617 status = smtp_write (smtp);
517 CHECK_EAGAIN (smtp, status); 618 CHECK_EAGAIN (smtp, status);
518 smtp->state = SMTP_RCPT_TO_ACK; 619 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)
523 {
524 status = smtp_read_ack (smtp); 622 status = smtp_read_ack (smtp);
525 CHECK_EAGAIN (smtp, status); 623 CHECK_EAGAIN (smtp, status);
526 MAILER_DEBUG0 (mailer, MU_DEBUG_PROT, smtp->buffer);
527 if (smtp->buffer[0] != '2') 624 if (smtp->buffer[0] != '2')
528 { 625 {
529 stream_close (mailer->stream); 626 stream_close (mailer->stream);
530 CLEAR_STATE (smtp); 627 CLEAR_STATE (smtp);
531 return EACCES; 628 return MU_ERR_SMTP_RCPT_FAILED;
532 }
533 goto RCPT_TO;
534 } 629 }
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
535 /* We are done with the rcpt. */ 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,7 +679,6 @@ smtp_send_message(mailer_t mailer, message_t msg, address_t from, address_t to) ...@@ -582,7 +679,6 @@ 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);
586 status = smtp_write (smtp); 682 status = smtp_write (smtp);
587 CHECK_EAGAIN (smtp, status); 683 CHECK_EAGAIN (smtp, status);
588 } 684 }
...@@ -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 { 737 {
636 size = 10 + strlen (localhost) + 1; 738 MAILER_DEBUG0 (smtp->mailer, MU_DEBUG_ERROR,
637 from = calloc (size, sizeof (char)); 739 "mailer_send_message(): explicit from not valid\n");
638 if (from == NULL) 740 return status;
639 return ENOMEM; 741 }
640 snprintf (from, size, "%d@%s", getuid(), localhost); 742
743 if ((status = address_aget_email (from, 1, &mail_from)) != 0)
744 return status;
641 } 745 }
642 else 746 else
643 { 747 {
644 from = calloc (strlen (pwd->pw_name) + 1 748 char *from_hdr = NULL;
645 + strlen (localhost) + 1, sizeof (char)); 749
646 if (from == NULL) 750 if ((status = message_get_header (msg, &header)) != 0)
647 return ENOMEM; 751 return status;
648 sprintf(from, "%s@%s", pwd->pw_name, localhost); 752
753 status = header_aget_value (header, MU_HEADER_FROM, &from_hdr);
754
755 switch (status)
756 {
757 default:
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;
649 } 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;
650 } 782 }
651 else 783 if ((status = address_aget_email (fromaddr, 1, &mail_from)) != 0)
652 { 784 {
653 from = calloc (size + 1, sizeof (char)); 785 free (from_hdr);
654 if (from == NULL) 786 address_destroy (&fromaddr);
655 return ENOMEM; 787 return status;
656 header_get_value (header, MU_HEADER_FROM, from, size + 1, NULL);
657 } 788 }
658 /* Check if a Fully Qualified Name, some smtp servers 789 free (from_hdr);
659 notably sendmail insists on it, for good reasons. */ 790 address_destroy (&fromaddr);
660 if (strchr (from, '@') == NULL) 791 }
792 break;
793
794 case ENOENT:
795 /* Use the environment. */
796 mail_from = mu_get_user_email (NULL);
797
798 if (mail_from)
661 { 799 {
662 char *tmp; 800 MAILER_DEBUG1 (smtp->mailer, MU_DEBUG_TRACE,
663 tmp = malloc (strlen (from) + 1 +strlen (localhost) + 1); 801 "mailer_send_message(): using user's address: %s\n",
664 if (tmp == NULL) 802 mail_from);
803 }
804 else
665 { 805 {
666 free (from); 806 MAILER_DEBUG0 (smtp->mailer, MU_DEBUG_TRACE,
667 return ENOMEM; 807 "mailer_send_message(): no user's address, failing\n");
668 } 808 }
669 sprintf (tmp, "%s@%s", from, localhost); 809
670 free (from); 810 if (!mail_from)
671 from = tmp; 811 return errno;
812
813 status = 0;
814
815 /* FIXME: should we add the From: header? */
816
817 break;
818
672 } 819 }
673 status = address_create (pmail_from, from); 820 }
674 free (from); 821
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); 840
688 if (status == 0 && size != 0) 841 if (to)
689 { 842 {
690 char *tmp; 843 /* Use the specified address_t. */
691 size_t len; 844 if ((status = mailer_check_to (to)) != 0)
692 rcpt = calloc (size + 1, sizeof (char)); 845 {
693 if (rcpt == NULL) 846 MAILER_DEBUG0 (smtp->mailer, MU_DEBUG_ERROR,
694 return ENOMEM; 847 "mailer_send_message(): explicit to not valid\n");
695 header_get_value (header, MU_HEADER_TO, rcpt, size + 1, NULL); 848 return status;
849 }
850 smtp->rcpt_to = to;
851
852 return status;
853 }
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;
696 874
697 size = 0;
698 status = header_get_value (header, MU_HEADER_CC, NULL, 0, &size);
699 if (status == 0 && size != 0)
700 { 875 {
701 len = strlen (rcpt); 876 const char **av = (const char **) toaddrv;
702 tmp = realloc (rcpt, (len + 1 + size + 1) * sizeof (char)); 877 int tostatus = address_createv (&rcpt_to, av, 2);
703 if (tmp == NULL) 878
879 /* Any error other than EMPTY_ADDRESS is fatal */
880 if (tostatus)
704 { 881 {
705 free (rcpt); 882 if (tostatus == MU_ERR_EMPTY_ADDRESS)
706 return ENOMEM; 883 tostatus = MU_ERR_MAILER_NO_RCPT_TO;
884 else
885 goto end;
707 } 886 }
887
888 if (!bccaddr)
889 status = MU_ERR_EMPTY_ADDRESS;
708 else 890 else
709 rcpt = tmp; 891 {
710 rcpt[len] = ','; 892 status = address_create (&rcpt_bcc, bccaddr);
711 header_get_value (header, MU_HEADER_CC, rcpt + len + 1,
712 size + 1, NULL);
713 893
714 size = 0; 894 if (status)
715 status = header_get_value (header, MU_HEADER_BCC, NULL, 0, &size);
716 if (status == 0 && size != 0)
717 { 895 {
718 len = strlen (rcpt); 896 if (status == MU_ERR_EMPTY_ADDRESS)
719 tmp = realloc (rcpt, (len + 1 + size + 1) * sizeof (char)); 897 status = MU_ERR_MAILER_NO_RCPT_TO;
720 if (tmp == NULL) 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)
721 { 930 {
722 free (rcpt); 931 address_destroy (&rcpt_to);
723 return ENOMEM; 932 address_destroy (&rcpt_bcc);
724 } 933 }
725 else 934 else
726 rcpt = tmp; 935 {
727 rcpt[len] = ','; 936 smtp->rcpt_to = rcpt_to;
728 header_get_value (header, MU_HEADER_BCC, rcpt + len + 1, 937
729 size + 1, NULL); 938 if (smtp->rcpt_to)
730 } 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);
731 } 945 }
732 status = address_create (prcpt_to, rcpt); 946
733 free (rcpt);
734 return status; 947 return status;
735 }
736 return EINVAL;
737 } 948 }
738
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;
970 buffer = realloc (smtp->buffer, buflen);
760 if (smtp->buffer == NULL) 971 if (smtp->buffer == NULL)
761 return ENOMEM; 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
...@@ -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;
...@@ -844,7 +1064,7 @@ smtp_readline (smtp_t smtp) ...@@ -844,7 +1064,7 @@ smtp_readline (smtp_t smtp)
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);
...@@ -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
......