Commit e4648a8d e4648a8d1dcdfc40547e160d77d753e46e1c57ca by Sergey Poznyakoff

examples/mta.c: use streams instead of FILE; exit with codes from sysexits.h

1 parent db1ee5e0
Showing 1 changed file with 137 additions and 154 deletions
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
57 #endif 57 #endif
58 #include <string.h> 58 #include <string.h>
59 #include <pwd.h> 59 #include <pwd.h>
60 #include <sysexits.h>
60 #include <sys/stat.h> 61 #include <sys/stat.h>
61 #include <sys/time.h> 62 #include <sys/time.h>
62 #include <sys/socket.h> 63 #include <sys/socket.h>
...@@ -141,7 +142,7 @@ main (int argc, char **argv) ...@@ -141,7 +142,7 @@ main (int argc, char **argv)
141 break; 142 break;
142 143
143 default: 144 default:
144 exit (1); 145 exit (EX_USAGE);
145 } 146 }
146 } 147 }
147 148
...@@ -190,73 +191,71 @@ from_address () ...@@ -190,73 +191,71 @@ from_address ()
190 return strdup (from_person); 191 return strdup (from_person);
191 } 192 }
192 193
193 void 194 static mu_message_t
194 make_tmp (FILE *input, const char *from, char **tempfile) 195 make_tmp (mu_stream_t in)
195 { 196 {
196 time_t t; 197 int rc;
197 int fd = mu_tempfile (NULL, tempfile); 198 mu_stream_t out;
198 FILE *fp;
199 char *buf = NULL; 199 char *buf = NULL;
200 size_t n = 0; 200 size_t size = 0, n;
201 int line; 201 mu_message_t mesg;
202 202
203 if (fd == -1 || (fp = fdopen (fd, "w+")) == NULL) 203 rc = mu_temp_file_stream_create (&out, NULL);
204 if (rc)
204 { 205 {
205 mu_error ("%s: unable to open temporary file", progname); 206 mu_error (_("unable to open temporary file: %s"), mu_strerror (rc));
206 exit (1); 207 exit (EX_UNAVAILABLE);
207 } 208 }
208 209
209 line = 0; 210 rc = mu_stream_getline (in, &buf, &size, &n);
210 while (getline (&buf, &n, input) > 0) 211 if (rc)
211 { 212 {
212 int len = strlen (buf); 213 mu_error (_("read error: %s"), mu_strerror (rc));
213 if (len >= 2 && buf[len - 2] == '\r') 214 mu_stream_destroy (&out);
214 { 215 exit (EX_UNAVAILABLE);
215 buf[len - 2] = '\n'; 216 }
216 buf[len - 1] = 0; 217 if (n == 0)
217 } 218 {
218 219 mu_error (_("unexpected EOF on input"));
219 line++; 220 mu_stream_destroy (&out);
220 if (line == 1) 221 exit (EX_DATAERR);
221 { 222 }
222 if (memcmp (buf, "From ", 5))
223 {
224 char *from = from_address ();
225 if (from)
226 {
227 time (&t);
228 fprintf (fp, "From %s %s", from, ctime (&t));
229 free (from);
230 }
231 else
232 {
233 mu_error ("%s: can't determine sender address", progname);
234 exit (1);
235 }
236 }
237 }
238 else if (!memcmp (buf, "From ", 5))
239 fputc ('>', fp);
240 223
241 if (dot && buf[0] == '.' && 224 if (n >= 5 && memcmp (buf, "From ", 5))
242 ((buf[1] == '\r' && buf[2] == '\n') || (buf[1] == '\n'))) 225 {
243 break; 226 time_t t;
244 227 const char *from = from_address ();
245 if (fputs (buf, fp) == EOF) 228 if (!from)
246 { 229 {
247 mu_error ("%s: temporary file write error", progname); 230 mu_error ("%s: can't determine sender address", progname);
248 fclose (fp); 231 exit (EX_NOUSER);
249 exit (1);
250 } 232 }
233
234 time (&t);
235 mu_stream_printf (out, "From %s %s", from, ctime (&t));
251 } 236 }
252
253 if (buf && strchr (buf, '\n') == NULL)
254 putc ('\n', fp);
255 237
256 putc ('\n', fp); 238 mu_stream_write (out, buf, n, NULL);
257 free (buf); 239 free (buf);
240
241 rc = mu_stream_copy (out, in, 0, NULL);
242 if (rc)
243 {
244 mu_error (_("copy error: %s"), mu_strerror (rc));
245 mu_stream_destroy (&out);
246 exit (EX_UNAVAILABLE);
247 }
248
249 rc = mu_stream_to_message (out, &mesg);
250 mu_stream_destroy (&out);
251 if (rc)
252 {
253 mu_error (_("error creating temporary message: %s"),
254 mu_strerror (rc));
255 exit (EX_UNAVAILABLE);
256 }
258 257
259 fclose (fp); 258 return mesg;
260 } 259 }
261 260
262 void 261 void
...@@ -462,9 +461,8 @@ message_finalize (mu_message_t msg, int warn) ...@@ -462,9 +461,8 @@ message_finalize (mu_message_t msg, int warn)
462 int 461 int
463 mta_stdin (int argc, char **argv) 462 mta_stdin (int argc, char **argv)
464 { 463 {
465 int c; 464 int c, rc;
466 char *tempfile; 465 mu_stream_t in;
467 mu_mailbox_t mbox;
468 mu_message_t msg = NULL; 466 mu_message_t msg = NULL;
469 467
470 for (c = 0; c < argc; c++) 468 for (c = 0; c < argc; c++)
...@@ -476,27 +474,19 @@ mta_stdin (int argc, char **argv) ...@@ -476,27 +474,19 @@ mta_stdin (int argc, char **argv)
476 } 474 }
477 } 475 }
478 476
479 make_tmp (stdin, from_person, &tempfile); 477 rc = mu_stdio_stream_create (&in, MU_STDIN_FD, MU_STREAM_READ);
480 if ((c = mu_mailbox_create_default (&mbox, tempfile)) != 0) 478 if (rc)
481 { 479 {
482 mu_error ("%s: can't create mailbox %s: %s", 480 mu_diag_funcall (MU_DIAG_ERROR, "mu_stdio_stream_create",
483 progname, tempfile, mu_strerror (c)); 481 "MU_STDIN_FD", rc);
484 unlink (tempfile); 482 exit (EX_UNAVAILABLE);
485 return 1; 483 }
486 }
487 484
488 if ((c = mu_mailbox_open (mbox, MU_STREAM_RDWR)) != 0) 485 msg = make_tmp (in);
489 { 486 mu_stream_destroy (&in);
490 mu_error ("%s: can't open mailbox %s: %s",
491 progname, tempfile, mu_strerror (c));
492 unlink (tempfile);
493 return 1;
494 }
495
496 mu_mailbox_get_message (mbox, 1, &msg);
497 if (message_finalize (msg, 1)) 487 if (message_finalize (msg, 1))
498 return 1; 488 return 1;
499 489
500 if (!recipients) 490 if (!recipients)
501 { 491 {
502 mu_error ("%s: Recipient names must be specified", progname); 492 mu_error ("%s: Recipient names must be specified", progname);
...@@ -504,24 +494,20 @@ mta_stdin (int argc, char **argv) ...@@ -504,24 +494,20 @@ mta_stdin (int argc, char **argv)
504 } 494 }
505 495
506 mta_send (msg); 496 mta_send (msg);
507 497 mu_message_destroy (&msg, mu_message_get_owner (msg));
508 unlink (tempfile);
509 free (tempfile);
510 return 0; 498 return 0;
511 } 499 }
512 500
513 FILE *in, *out;
514
515 void 501 void
516 smtp_reply (int code, char *fmt, ...) 502 smtp_reply (mu_stream_t str, int code, char *fmt, ...)
517 { 503 {
518 va_list ap; 504 va_list ap;
519 505
506 mu_stream_printf (str, "%d ", code);
520 va_start (ap, fmt); 507 va_start (ap, fmt);
521 fprintf (out, "%d ", code); 508 mu_stream_vprintf (str, fmt, ap);
522 vfprintf (out, fmt, ap);
523 va_end (ap); 509 va_end (ap);
524 fprintf (out, "\r\n"); 510 mu_stream_printf (str, "\r\n");
525 } 511 }
526 512
527 #define STATE_INIT 0 513 #define STATE_INIT 0
...@@ -575,42 +561,34 @@ check_prefix (char *str, const char *prefix) ...@@ -575,42 +561,34 @@ check_prefix (char *str, const char *prefix)
575 } 561 }
576 562
577 void 563 void
578 smtp (int fd) 564 smtp (mu_stream_t str)
579 { 565 {
580 int state, c; 566 int state;
581 char *buf = NULL; 567 char *buf = NULL;
582 size_t size = 0; 568 size_t size = 0;
583 mu_mailbox_t mbox;
584 mu_message_t msg;
585 char *tempfile;
586 char *rcpt_addr; 569 char *rcpt_addr;
587 570
588 in = fdopen (fd, "r"); 571 smtp_reply (str, 220, "Ready");
589 out = fdopen (fd, "w");
590 SETVBUF (in, NULL, _IOLBF, 0);
591 SETVBUF (out, NULL, _IOLBF, 0);
592
593 smtp_reply (220, "Ready");
594 for (state = STATE_INIT; state != STATE_QUIT; ) 572 for (state = STATE_INIT; state != STATE_QUIT; )
595 { 573 {
574 char *s;
596 int argc; 575 int argc;
597 char **argv; 576 char **argv;
598 int kw, len; 577 int kw;
578 size_t len;
599 579
600 if (getline (&buf, &size, in) == -1) 580 if (mu_stream_getline (str, &buf, &size, &len) || len == 0)
601 exit (1); 581 exit (EX_PROTOCOL);
602 len = strlen (buf); 582
603 while (len > 0 && (buf[len-1] == '\n' || buf[len-1] == '\r')) 583 s = mu_str_stripws (buf);
604 len --;
605 buf[len] = 0;
606 584
607 if (mu_argcv_get (buf, "", NULL, &argc, &argv)) 585 if (mu_argcv_get (s, "", NULL, &argc, &argv))
608 exit (1); 586 exit (EX_UNAVAILABLE);
609 587
610 kw = smtp_kw (argv[0]); 588 kw = smtp_kw (argv[0]);
611 if (kw == KW_QUIT) 589 if (kw == KW_QUIT)
612 { 590 {
613 smtp_reply (221, "Done"); 591 smtp_reply (str, 221, "Done");
614 state = STATE_QUIT; 592 state = STATE_QUIT;
615 mu_argcv_free (argc, argv); 593 mu_argcv_free (argc, argv);
616 continue; 594 continue;
...@@ -625,15 +603,15 @@ smtp (int fd) ...@@ -625,15 +603,15 @@ smtp (int fd)
625 case KW_HELO: 603 case KW_HELO:
626 if (argc == 2) 604 if (argc == 2)
627 { 605 {
628 smtp_reply (250, "pleased to meet you"); 606 smtp_reply (str, 250, "pleased to meet you");
629 state = STATE_EHLO; 607 state = STATE_EHLO;
630 } 608 }
631 else 609 else
632 smtp_reply (501, "%s requires domain address", argv[0]); 610 smtp_reply (str, 501, "%s requires domain address", argv[0]);
633 break; 611 break;
634 612
635 default: 613 default:
636 smtp_reply (503, "Polite people say HELO first"); 614 smtp_reply (str, 503, "Polite people say HELO first");
637 break; 615 break;
638 } 616 }
639 break; 617 break;
...@@ -652,15 +630,15 @@ smtp (int fd) ...@@ -652,15 +630,15 @@ smtp (int fd)
652 if (from_person) 630 if (from_person)
653 { 631 {
654 from_person = strdup (from_person); 632 from_person = strdup (from_person);
655 smtp_reply (250, "Sender OK"); 633 smtp_reply (str, 250, "Sender OK");
656 state = STATE_MAIL; 634 state = STATE_MAIL;
657 } 635 }
658 else 636 else
659 smtp_reply (501, "Syntax error"); 637 smtp_reply (str, 501, "Syntax error");
660 break; 638 break;
661 639
662 default: 640 default:
663 smtp_reply (503, "Need MAIL command"); 641 smtp_reply (str, 503, "Need MAIL command");
664 } 642 }
665 break; 643 break;
666 644
...@@ -678,19 +656,19 @@ smtp (int fd) ...@@ -678,19 +656,19 @@ smtp (int fd)
678 if (rcpt_addr) 656 if (rcpt_addr)
679 { 657 {
680 if (add_recipient (rcpt_addr)) 658 if (add_recipient (rcpt_addr))
681 smtp_reply (451, "Recipient not accepted"); 659 smtp_reply (str, 451, "Recipient not accepted");
682 else 660 else
683 { 661 {
684 smtp_reply (250, "Recipient OK"); 662 smtp_reply (str, 250, "Recipient OK");
685 state = STATE_RCPT; 663 state = STATE_RCPT;
686 } 664 }
687 } 665 }
688 else 666 else
689 smtp_reply (501, "Syntax error"); 667 smtp_reply (str, 501, "Syntax error");
690 break; 668 break;
691 669
692 default: 670 default:
693 smtp_reply (503, "Need RCPT command"); 671 smtp_reply (str, 503, "Need RCPT command");
694 } 672 }
695 break; 673 break;
696 674
...@@ -708,55 +686,51 @@ smtp (int fd) ...@@ -708,55 +686,51 @@ smtp (int fd)
708 if (rcpt_addr) 686 if (rcpt_addr)
709 { 687 {
710 if (add_recipient (rcpt_addr)) 688 if (add_recipient (rcpt_addr))
711 smtp_reply (451, "Recipient not accepted"); 689 smtp_reply (str, 451, "Recipient not accepted");
712 else 690 else
713 { 691 {
714 smtp_reply (250, "Recipient OK"); 692 smtp_reply (str, 250, "Recipient OK");
715 state = STATE_RCPT; 693 state = STATE_RCPT;
716 } 694 }
717 } 695 }
718 else 696 else
719 smtp_reply (501, "Syntax error"); 697 smtp_reply (str, 501, "Syntax error");
720 break; 698 break;
721 699
722 case KW_DATA: 700 case KW_DATA:
723 smtp_reply (354, 701 {
724 "Enter mail, end with \".\" on a line by itself"); 702 mu_stream_t flt;
725 make_tmp (in, from_person, &tempfile); 703 mu_message_t msg;
726 if ((c = mu_mailbox_create_default (&mbox, tempfile)) != 0) 704 int rc;
727 { 705
728 mu_error ("%s: can't create mailbox %s: %s", 706 rc = mu_filter_create (&flt, str, "CRLFDOT", MU_FILTER_DECODE,
729 progname, 707 MU_STREAM_READ|MU_STREAM_WRTHRU);
730 tempfile, mu_strerror (c)); 708 if (rc)
731 unlink (tempfile); 709 {
732 exit (1); 710 mu_diag_funcall (MU_DIAG_ERROR, "mu_filter_create",
733 } 711 "CRLFDOT", rc);
734 712 exit (EX_UNAVAILABLE);
735 if ((c = mu_mailbox_open (mbox, MU_STREAM_RDWR)) != 0) 713 }
736 { 714 smtp_reply (str, 354,
737 mu_error ("%s: can't open mailbox %s: %s", 715 "Enter mail, end with \".\" on a line by itself");
738 progname, 716
739 tempfile, mu_strerror (c)); 717 msg = make_tmp (flt);
740 unlink (tempfile); 718 mu_stream_destroy (&flt);
741 exit (1); 719 if (message_finalize (msg, 0) == 0)
742 } 720 mta_send (msg);
743 721 else
744 mu_mailbox_get_message (mbox, 1, &msg); 722 smtp_reply (str, 501, "can't send message"); /*FIXME: code?*/
745 if (message_finalize (msg, 0) == 0) 723 mu_message_destroy (&msg, mu_message_get_owner (msg));
746 mta_send (msg); 724 mu_address_destroy (&recipients);
747 else 725 from_person = NULL;
748 smtp_reply (501, "can't send message"); /*FIXME: code?*/
749 unlink (tempfile);
750
751 mu_address_destroy (&recipients);
752 from_person = NULL;
753 726
754 smtp_reply (250, "Message accepted for delivery"); 727 smtp_reply (str, 250, "Message accepted for delivery");
755 state = STATE_EHLO; 728 state = STATE_EHLO;
729 }
756 break; 730 break;
757 731
758 default: 732 default:
759 smtp_reply (503, "Invalid command"); 733 smtp_reply (str, 503, "Invalid command");
760 break; 734 break;
761 } 735 }
762 break; 736 break;
...@@ -764,8 +738,6 @@ smtp (int fd) ...@@ -764,8 +738,6 @@ smtp (int fd)
764 } 738 }
765 mu_argcv_free (argc, argv); 739 mu_argcv_free (argc, argv);
766 } 740 }
767
768 close (fd);
769 } 741 }
770 742
771 int 743 int
...@@ -826,7 +798,9 @@ mta_smtp (int argc, char **argv) ...@@ -826,7 +798,9 @@ mta_smtp (int argc, char **argv)
826 struct sockaddr_in his_addr; 798 struct sockaddr_in his_addr;
827 int sfd, status; 799 int sfd, status;
828 socklen_t len; 800 socklen_t len;
829 801 int rc;
802 mu_stream_t str;
803
830 FD_ZERO (&rfds); 804 FD_ZERO (&rfds);
831 FD_SET (fd, &rfds); 805 FD_SET (fd, &rfds);
832 806
...@@ -846,7 +820,16 @@ mta_smtp (int argc, char **argv) ...@@ -846,7 +820,16 @@ mta_smtp (int argc, char **argv)
846 return 1; 820 return 1;
847 } 821 }
848 822
849 smtp (sfd); 823 rc = mu_fd_stream_create (&str, NULL, sfd,
824 MU_STREAM_RDWR|MU_STREAM_AUTOCLOSE);
825 if (rc)
826 {
827 mu_diag_funcall (MU_DIAG_ERROR, "mu_fd_stream_create", NULL, rc);
828 break;
829 }
830 mu_stream_set_buffer (str, mu_buffer_line, 0);
831 smtp (str);
832 mu_stream_destroy (&str);
850 break; 833 break;
851 } 834 }
852 835
......