Fixes in stream subsystem. Rewrite and optimize maidag lmtp mode using streams.
* libmailutils/file_stream.c (mu_fd_stream_create): Mark stream as open, do not call mu_stream_open explicitly. * libmailutils/message_stream.c (mu_stream_to_message): Bugfixes, wrong owner given to mu_envelope_set_ calls. * libmailutils/stream.c (_MU_STR_FLUSH_ALL) (_MU_STR_FLUSH_KEEP): New macros for _stream_flush_buffer. (_stream_flush_buffer): Change the meaning of the last argument. All callers updated. (mu_stream_seek): Fix operation with MU_SEEK_END. Call _mu_stream_cleareof on success. (mu_stream_read): Call _stream_flush_buffer in buffered mode. (mu_stream_getdelim, mu_stream_readdelim): Call _stream_flush_buffer. * libmailutils/streamcpy.c (mu_stream_copy): Reset size if mu_stream_seek fails. * libmailutils/temp_file_stream.c (mu_temp_file_stream_create): Set full buffering mode by default. * maidag/mailtmp.c: Remove. * maidag/Makefile.am (maidag_SOURCES): Remove mailtmp.c * po/POTFILES.in: Likewise. * maidag/deliver.c (make_tmp): Rewrite. Return mu_mailbox_t. All callers changed. * maidag/lmtp.c (lmtp_transcript): Remove static. (lmpt_transcript): New function. (lmtp_reply): Use mu_stream_t instead of FILE. (xlatnl): Remove. Superseded by mu_rtrim_cset and family. (mtmp, mbox): Remove globals. (mesg): New global. (cfun_unknown, cfun_mail_from, cfun_rcpt_to) (dot_temp_fail, dot_deliver, cfun_rset) (cfun_lhlo, cfun_quit, cfun_help): Use mu_stream_t instead of FILE. (cfun_data): Rewrite. (cfun_dot): Remove. (to_fgets): Rewrite using mu_stream_t. (lmtp_loop): Change signature. Rewrite using mu_stream_t. (lmtp_connection, maidag_lmtp_server): Update accordingly. * maidag/maidag.c (maidag_transcript): New global. (options, parse_opt): New option --transcript. * maidag/maidag.h (maidag_transcript): New extern. (mail_tmp_begin, mail_tmp_add_line, mail_tmp_finish) (mail_tmp_destroy): Remove.
Showing
12 changed files
with
366 additions
and
382 deletions
... | @@ -390,15 +390,11 @@ mu_fd_stream_create (mu_stream_t *pstream, char *filename, int fd, int flags) | ... | @@ -390,15 +390,11 @@ mu_fd_stream_create (mu_stream_t *pstream, char *filename, int fd, int flags) |
390 | struct _mu_file_stream *fstr; | 390 | struct _mu_file_stream *fstr; |
391 | int rc = _mu_file_stream_create (&fstr, | 391 | int rc = _mu_file_stream_create (&fstr, |
392 | sizeof (struct _mu_file_stream), | 392 | sizeof (struct _mu_file_stream), |
393 | filename, fd, flags); | 393 | filename, fd, flags|_MU_STR_OPEN); |
394 | if (rc == 0) | 394 | if (rc == 0) |
395 | { | 395 | { |
396 | mu_stream_t stream = (mu_stream_t) fstr; | 396 | mu_stream_t stream = (mu_stream_t) fstr; |
397 | mu_stream_set_buffer (stream, mu_buffer_full, 0); | 397 | mu_stream_set_buffer (stream, mu_buffer_full, 0); |
398 | rc = mu_stream_open (stream); | ||
399 | if (rc) | ||
400 | mu_stream_unref (stream); | ||
401 | else | ||
402 | *pstream = stream; | 398 | *pstream = stream; |
403 | } | 399 | } |
404 | return rc; | 400 | return rc; | ... | ... |
... | @@ -414,8 +414,8 @@ mu_stream_to_message (mu_stream_t instream, mu_message_t *pmsg) | ... | @@ -414,8 +414,8 @@ mu_stream_to_message (mu_stream_t instream, mu_message_t *pmsg) |
414 | return rc; | 414 | return rc; |
415 | } | 415 | } |
416 | 416 | ||
417 | mu_envelope_set_date (env, _env_msg_date, msg); | 417 | mu_envelope_set_date (env, _env_msg_date, draftstream); |
418 | mu_envelope_set_sender (env, _env_msg_sender, msg); | 418 | mu_envelope_set_sender (env, _env_msg_sender, draftstream); |
419 | mu_message_set_envelope (msg, env, draftstream); | 419 | mu_message_set_envelope (msg, env, draftstream); |
420 | 420 | ||
421 | mu_body_create (&body, msg); | 421 | mu_body_create (&body, msg); | ... | ... |
... | @@ -34,6 +34,9 @@ | ... | @@ -34,6 +34,9 @@ |
34 | 34 | ||
35 | size_t mu_stream_default_buffer_size = MU_STREAM_DEFBUFSIZ; | 35 | size_t mu_stream_default_buffer_size = MU_STREAM_DEFBUFSIZ; |
36 | 36 | ||
37 | #define _MU_STR_FLUSH_ALL 0x01 | ||
38 | #define _MU_STR_FLUSH_KEEP 0x02 | ||
39 | |||
37 | #define _stream_event(stream, code, n, p) \ | 40 | #define _stream_event(stream, code, n, p) \ |
38 | do \ | 41 | do \ |
39 | { \ | 42 | { \ |
... | @@ -167,7 +170,7 @@ _stream_buffer_full_p (struct _mu_stream *stream) | ... | @@ -167,7 +170,7 @@ _stream_buffer_full_p (struct _mu_stream *stream) |
167 | } | 170 | } |
168 | 171 | ||
169 | static int | 172 | static int |
170 | _stream_flush_buffer (struct _mu_stream *stream, int all) | 173 | _stream_flush_buffer (struct _mu_stream *stream, int flags) |
171 | { | 174 | { |
172 | int rc; | 175 | int rc; |
173 | char *start, *end; | 176 | char *start, *end; |
... | @@ -215,7 +218,8 @@ _stream_flush_buffer (struct _mu_stream *stream, int all) | ... | @@ -215,7 +218,8 @@ _stream_flush_buffer (struct _mu_stream *stream, int all) |
215 | if (wrsize == 0) | 218 | if (wrsize == 0) |
216 | break; | 219 | break; |
217 | } | 220 | } |
218 | if ((all && wrsize) || wrsize == stream->level) | 221 | if (((flags & _MU_STR_FLUSH_ALL) && wrsize) || |
222 | wrsize == stream->level) | ||
219 | { | 223 | { |
220 | rc = _stream_write_unbuffered (stream, | 224 | rc = _stream_write_unbuffered (stream, |
221 | stream->buffer, | 225 | stream->buffer, |
... | @@ -234,9 +238,10 @@ _stream_flush_buffer (struct _mu_stream *stream, int all) | ... | @@ -234,9 +238,10 @@ _stream_flush_buffer (struct _mu_stream *stream, int all) |
234 | stream->level = stream->pos = wrsize; | 238 | stream->level = stream->pos = wrsize; |
235 | return 0; | 239 | return 0; |
236 | } | 240 | } |
241 | _stream_clrflag (stream, _MU_STR_DIRTY); | ||
237 | } | 242 | } |
238 | 243 | ||
239 | _stream_clrflag (stream, _MU_STR_DIRTY); | 244 | if (!(flags & _MU_STR_FLUSH_KEEP)) |
240 | stream->pos = stream->level = 0; | 245 | stream->pos = stream->level = 0; |
241 | return 0; | 246 | return 0; |
242 | } | 247 | } |
... | @@ -400,8 +405,8 @@ mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence, | ... | @@ -400,8 +405,8 @@ mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence, |
400 | case MU_SEEK_END: | 405 | case MU_SEEK_END: |
401 | rc = mu_stream_size (stream, &size); | 406 | rc = mu_stream_size (stream, &size); |
402 | if (rc) | 407 | if (rc) |
403 | return mu_stream_seterr (stream, rc, 1); | 408 | return rc; |
404 | offset += size + stream->pos; | 409 | offset += size; |
405 | break; | 410 | break; |
406 | 411 | ||
407 | default: | 412 | default: |
... | @@ -414,7 +419,7 @@ mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence, | ... | @@ -414,7 +419,7 @@ mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence, |
414 | || offset < stream->offset | 419 | || offset < stream->offset |
415 | || offset > stream->offset + stream->level)) | 420 | || offset > stream->offset + stream->level)) |
416 | { | 421 | { |
417 | if ((rc = _stream_flush_buffer (stream, 1))) | 422 | if ((rc = _stream_flush_buffer (stream, _MU_STR_FLUSH_ALL))) |
418 | return rc; | 423 | return rc; |
419 | rc = stream->seek (stream, offset, &stream->offset); | 424 | rc = stream->seek (stream, offset, &stream->offset); |
420 | if (rc == ESPIPE) | 425 | if (rc == ESPIPE) |
... | @@ -426,6 +431,8 @@ mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence, | ... | @@ -426,6 +431,8 @@ mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence, |
426 | else if (stream->buftype != mu_buffer_none) | 431 | else if (stream->buftype != mu_buffer_none) |
427 | stream->pos = offset - stream->offset; | 432 | stream->pos = offset - stream->offset; |
428 | 433 | ||
434 | _mu_stream_cleareof (stream); | ||
435 | |||
429 | if (pres) | 436 | if (pres) |
430 | *pres = stream->offset + stream->pos; | 437 | *pres = stream->offset + stream->pos; |
431 | return 0; | 438 | return 0; |
... | @@ -469,7 +476,7 @@ _stream_skip_input_bytes (mu_stream_t stream, mu_off_t count, mu_off_t *pres) | ... | @@ -469,7 +476,7 @@ _stream_skip_input_bytes (mu_stream_t stream, mu_off_t count, mu_off_t *pres) |
469 | { | 476 | { |
470 | for (pos = 0;;) | 477 | for (pos = 0;;) |
471 | { | 478 | { |
472 | if ((rc = _stream_flush_buffer (stream, 1))) | 479 | if ((rc = _stream_flush_buffer (stream, _MU_STR_FLUSH_ALL))) |
473 | return rc; | 480 | return rc; |
474 | if (stream->pos == stream->level) | 481 | if (stream->pos == stream->level) |
475 | { | 482 | { |
... | @@ -693,10 +700,15 @@ mu_stream_read (mu_stream_t stream, void *buf, size_t size, size_t *pread) | ... | @@ -693,10 +700,15 @@ mu_stream_read (mu_stream_t stream, void *buf, size_t size, size_t *pread) |
693 | { | 700 | { |
694 | char *bufp = buf; | 701 | char *bufp = buf; |
695 | size_t nbytes = 0; | 702 | size_t nbytes = 0; |
703 | int rc; | ||
704 | |||
705 | if ((rc = _stream_flush_buffer (stream, | ||
706 | _MU_STR_FLUSH_ALL|_MU_STR_FLUSH_KEEP))) | ||
707 | return rc; | ||
708 | |||
696 | while (size) | 709 | while (size) |
697 | { | 710 | { |
698 | size_t n; | 711 | size_t n; |
699 | int rc; | ||
700 | 712 | ||
701 | if (stream->pos == stream->level) | 713 | if (stream->pos == stream->level) |
702 | { | 714 | { |
... | @@ -824,7 +836,12 @@ mu_stream_readdelim (mu_stream_t stream, char *buf, size_t size, | ... | @@ -824,7 +836,12 @@ mu_stream_readdelim (mu_stream_t stream, char *buf, size_t size, |
824 | rc = _stream_readdelim (stream, buf, size, delim, pread); | 836 | rc = _stream_readdelim (stream, buf, size, delim, pread); |
825 | } | 837 | } |
826 | else | 838 | else |
839 | { | ||
840 | if ((rc = _stream_flush_buffer (stream, | ||
841 | _MU_STR_FLUSH_ALL|_MU_STR_FLUSH_KEEP))) | ||
842 | return rc; | ||
827 | rc = _stream_scandelim (stream, buf, size, delim, pread); | 843 | rc = _stream_scandelim (stream, buf, size, delim, pread); |
844 | } | ||
828 | return rc; | 845 | return rc; |
829 | } | 846 | } |
830 | 847 | ||
... | @@ -850,6 +867,10 @@ mu_stream_getdelim (mu_stream_t stream, char **pbuf, size_t *psize, | ... | @@ -850,6 +867,10 @@ mu_stream_getdelim (mu_stream_t stream, char **pbuf, size_t *psize, |
850 | _stream_init (stream); | 867 | _stream_init (stream); |
851 | } | 868 | } |
852 | 869 | ||
870 | if ((rc = _stream_flush_buffer (stream, | ||
871 | _MU_STR_FLUSH_ALL|_MU_STR_FLUSH_KEEP))) | ||
872 | return rc; | ||
873 | |||
853 | if (lineptr == NULL || n == 0) | 874 | if (lineptr == NULL || n == 0) |
854 | { | 875 | { |
855 | char *new_lineptr; | 876 | char *new_lineptr; |
... | @@ -997,7 +1018,7 @@ mu_stream_flush (mu_stream_t stream) | ... | @@ -997,7 +1018,7 @@ mu_stream_flush (mu_stream_t stream) |
997 | return MU_ERR_NOT_OPEN; | 1018 | return MU_ERR_NOT_OPEN; |
998 | _stream_init (stream); | 1019 | _stream_init (stream); |
999 | } | 1020 | } |
1000 | rc = _stream_flush_buffer (stream, 1); | 1021 | rc = _stream_flush_buffer (stream, _MU_STR_FLUSH_ALL); |
1001 | if (rc) | 1022 | if (rc) |
1002 | return rc; | 1023 | return rc; |
1003 | if ((stream->flags & _MU_STR_WRT) && stream->flush) | 1024 | if ((stream->flags & _MU_STR_WRT) && stream->flush) |
... | @@ -1031,6 +1052,7 @@ int | ... | @@ -1031,6 +1052,7 @@ int |
1031 | mu_stream_size (mu_stream_t stream, mu_off_t *psize) | 1052 | mu_stream_size (mu_stream_t stream, mu_off_t *psize) |
1032 | { | 1053 | { |
1033 | int rc; | 1054 | int rc; |
1055 | mu_off_t size; | ||
1034 | 1056 | ||
1035 | if (!(stream->flags & _MU_STR_OPEN)) | 1057 | if (!(stream->flags & _MU_STR_OPEN)) |
1036 | { | 1058 | { |
... | @@ -1040,7 +1062,13 @@ mu_stream_size (mu_stream_t stream, mu_off_t *psize) | ... | @@ -1040,7 +1062,13 @@ mu_stream_size (mu_stream_t stream, mu_off_t *psize) |
1040 | } | 1062 | } |
1041 | if (!stream->size) | 1063 | if (!stream->size) |
1042 | return mu_stream_seterr (stream, ENOSYS, 0); | 1064 | return mu_stream_seterr (stream, ENOSYS, 0); |
1043 | rc = stream->size (stream, psize); | 1065 | rc = stream->size (stream, &size); |
1066 | if (rc == 0) | ||
1067 | { | ||
1068 | if (stream->buftype != mu_buffer_none && stream->offset == size) | ||
1069 | size += stream->level; | ||
1070 | *psize = size; | ||
1071 | } | ||
1044 | return mu_stream_seterr (stream, rc, rc != 0); | 1072 | return mu_stream_seterr (stream, rc, rc != 0); |
1045 | } | 1073 | } |
1046 | 1074 | ||
... | @@ -1118,7 +1146,7 @@ mu_stream_truncate (mu_stream_t stream, mu_off_t size) | ... | @@ -1118,7 +1146,7 @@ mu_stream_truncate (mu_stream_t stream, mu_off_t size) |
1118 | { | 1146 | { |
1119 | int rc; | 1147 | int rc; |
1120 | 1148 | ||
1121 | if ((rc = _stream_flush_buffer (stream, 1))) | 1149 | if ((rc = _stream_flush_buffer (stream, _MU_STR_FLUSH_ALL))) |
1122 | return rc; | 1150 | return rc; |
1123 | return stream->truncate (stream, size); | 1151 | return stream->truncate (stream, size); |
1124 | } | 1152 | } | ... | ... |
... | @@ -72,6 +72,7 @@ mu_stream_copy (mu_stream_t dst, mu_stream_t src, mu_off_t size, | ... | @@ -72,6 +72,7 @@ mu_stream_copy (mu_stream_t dst, mu_stream_t src, mu_off_t size, |
72 | case EACCES: | 72 | case EACCES: |
73 | mu_stream_clearerr (src); | 73 | mu_stream_clearerr (src); |
74 | case ENOSYS: | 74 | case ENOSYS: |
75 | size = 0; | ||
75 | break; | 76 | break; |
76 | 77 | ||
77 | default: | 78 | default: | ... | ... |
... | @@ -66,7 +66,10 @@ mu_temp_file_stream_create (mu_stream_t *pstream, const char *dir) | ... | @@ -66,7 +66,10 @@ mu_temp_file_stream_create (mu_stream_t *pstream, const char *dir) |
66 | if (rc) | 66 | if (rc) |
67 | mu_stream_unref (stream); | 67 | mu_stream_unref (stream); |
68 | else | 68 | else |
69 | { | ||
70 | mu_stream_set_buffer (stream, mu_buffer_full, 0); | ||
69 | *pstream = stream; | 71 | *pstream = stream; |
70 | } | 72 | } |
73 | } | ||
71 | return 0; | 74 | return 0; |
72 | } | 75 | } | ... | ... |
... | @@ -19,26 +19,110 @@ | ... | @@ -19,26 +19,110 @@ |
19 | 19 | ||
20 | #include "maidag.h" | 20 | #include "maidag.h" |
21 | 21 | ||
22 | void | 22 | static mu_mailbox_t |
23 | make_tmp (const char *from, mu_mailbox_t *mbox) | 23 | make_tmp (const char *from) |
24 | { | 24 | { |
25 | struct mail_tmp *mtmp; | ||
26 | char *buf = NULL; | ||
27 | size_t n = 0; | ||
28 | int rc; | 25 | int rc; |
26 | mu_stream_t in, out; | ||
27 | char *buf = NULL; | ||
28 | size_t size = 0, n; | ||
29 | mu_mailbox_t mbox; | ||
29 | 30 | ||
30 | if (mail_tmp_begin (&mtmp, from)) | 31 | rc = mu_stdio_stream_create (&in, MU_STDIN_FD, MU_STREAM_READ); |
32 | if (rc) | ||
33 | { | ||
34 | mu_diag_funcall (MU_DIAG_ERROR, "mu_stdio_stream_create", | ||
35 | "MU_STDIN_FD", rc); | ||
31 | exit (EX_TEMPFAIL); | 36 | exit (EX_TEMPFAIL); |
37 | } | ||
32 | 38 | ||
33 | while (getline (&buf, &n, stdin) > 0) | 39 | rc = mu_temp_file_stream_create (&out, NULL); |
34 | if ((rc = mail_tmp_add_line (mtmp, buf, strlen (buf)))) | 40 | if (rc) |
35 | break; | 41 | { |
42 | maidag_error (_("unable to open temporary file: %s"), mu_strerror (rc)); | ||
43 | exit (EX_TEMPFAIL); | ||
44 | } | ||
45 | |||
46 | rc = mu_stream_getline (in, &buf, &size, &n); | ||
47 | if (rc) | ||
48 | { | ||
49 | maidag_error (_("read error: %s"), mu_strerror (rc)); | ||
50 | mu_stream_destroy (&in); | ||
51 | mu_stream_destroy (&out); | ||
52 | exit (EX_TEMPFAIL); | ||
53 | } | ||
54 | if (n == 0) | ||
55 | { | ||
56 | maidag_error (_("unexpected EOF on input")); | ||
57 | mu_stream_destroy (&in); | ||
58 | mu_stream_destroy (&out); | ||
59 | exit (EX_TEMPFAIL); | ||
60 | } | ||
61 | |||
62 | if (n >= 5 && memcmp (buf, "From ", 5)) | ||
63 | { | ||
64 | struct mu_auth_data *auth = NULL; | ||
65 | if (!from) | ||
66 | { | ||
67 | auth = mu_get_auth_by_uid (getuid ()); | ||
68 | if (auth) | ||
69 | from = auth->name; | ||
70 | } | ||
71 | if (from) | ||
72 | { | ||
73 | time_t t; | ||
74 | |||
75 | time (&t); | ||
76 | mu_stream_printf (out, "From %s %s", from, ctime (&t)); | ||
77 | } | ||
78 | else | ||
79 | { | ||
80 | maidag_error (_("cannot determine sender address")); | ||
81 | mu_stream_destroy (&in); | ||
82 | mu_stream_destroy (&out); | ||
83 | exit (EX_TEMPFAIL); | ||
84 | } | ||
85 | if (auth) | ||
86 | mu_auth_data_free (auth); | ||
87 | } | ||
88 | |||
89 | mu_stream_write (out, buf, n, NULL); | ||
36 | free (buf); | 90 | free (buf); |
37 | if (rc == 0) | 91 | |
38 | rc = mail_tmp_finish (mtmp, mbox); | 92 | rc = mu_stream_copy (out, in, 0, NULL); |
39 | mail_tmp_destroy (&mtmp); | 93 | |
94 | mu_stream_destroy (&in); | ||
95 | if (rc) | ||
96 | { | ||
97 | maidag_error (_("copy error: %s"), mu_strerror (rc)); | ||
98 | mu_stream_destroy (&out); | ||
99 | exit (EX_TEMPFAIL); | ||
100 | } | ||
101 | |||
102 | mu_stream_flush (out); | ||
103 | if ((rc = mu_mailbox_create (&mbox, "mbox:/dev/null")) | ||
104 | || (rc = mu_mailbox_open (mbox, MU_STREAM_READ)) | ||
105 | || (rc = mu_mailbox_set_stream (mbox, out))) | ||
106 | { | ||
107 | maidag_error (_("error opening temporary file: %s"), | ||
108 | mu_strerror (rc)); | ||
109 | mu_stream_destroy (&out); | ||
110 | exit (EX_TEMPFAIL); | ||
111 | } | ||
112 | |||
113 | rc = mu_mailbox_messages_count (mbox, &n); | ||
40 | if (rc) | 114 | if (rc) |
115 | { | ||
116 | errno = rc; | ||
117 | maidag_error (_("error creating temporary message: %s"), | ||
118 | mu_strerror (rc)); | ||
119 | mu_stream_destroy (&out); | ||
41 | exit (EX_TEMPFAIL); | 120 | exit (EX_TEMPFAIL); |
121 | } | ||
122 | |||
123 | /* FIXME: mu_stream_unref (out); But mu_mailbox_set_stream | ||
124 | steals the reference */ | ||
125 | return mbox; | ||
42 | } | 126 | } |
43 | 127 | ||
44 | int | 128 | int |
... | @@ -65,9 +149,7 @@ mda (mu_mailbox_t mbx, char *username) | ... | @@ -65,9 +149,7 @@ mda (mu_mailbox_t mbx, char *username) |
65 | int | 149 | int |
66 | maidag_stdio_delivery (int argc, char **argv) | 150 | maidag_stdio_delivery (int argc, char **argv) |
67 | { | 151 | { |
68 | mu_mailbox_t mbox; | 152 | mu_mailbox_t mbox = make_tmp (sender_address); |
69 | |||
70 | make_tmp (sender_address, &mbox); | ||
71 | 153 | ||
72 | if (multiple_delivery) | 154 | if (multiple_delivery) |
73 | multiple_delivery = argc > 1; | 155 | multiple_delivery = argc > 1; | ... | ... |
... | @@ -26,10 +26,39 @@ | ... | @@ -26,10 +26,39 @@ |
26 | #include <mu_umaxtostr.h> | 26 | #include <mu_umaxtostr.h> |
27 | 27 | ||
28 | mu_list_t lmtp_groups; | 28 | mu_list_t lmtp_groups; |
29 | static int lmtp_transcript; | 29 | |
30 | static mu_stream_t | ||
31 | lmpt_transcript (mu_stream_t iostream) | ||
32 | { | ||
33 | int rc; | ||
34 | mu_debug_t debug; | ||
35 | mu_stream_t dstr, xstr; | ||
36 | |||
37 | mu_diag_get_debug (&debug); | ||
38 | |||
39 | rc = mu_dbgstream_create (&dstr, debug, MU_DIAG_DEBUG, 0); | ||
40 | if (rc) | ||
41 | mu_error (_("cannot create debug stream; transcript disabled: %s"), | ||
42 | mu_strerror (rc)); | ||
43 | else | ||
44 | { | ||
45 | rc = mu_xscript_stream_create (&xstr, iostream, dstr, NULL); | ||
46 | if (rc) | ||
47 | mu_error (_("cannot create transcript stream: %s"), | ||
48 | mu_strerror (rc)); | ||
49 | else | ||
50 | { | ||
51 | /* FIXME: Would do a mu_stream_unref (iostream) here, | ||
52 | however mu_xscript_stream_create *may* steal the reference. | ||
53 | This should be fixed in mu_xscript_stream_create. */ | ||
54 | iostream = xstr; | ||
55 | } | ||
56 | } | ||
57 | return iostream; | ||
58 | } | ||
30 | 59 | ||
31 | void | 60 | void |
32 | lmtp_reply (FILE *fp, char *code, char *enh, char *fmt, ...) | 61 | lmtp_reply (mu_stream_t iostr, char *code, char *enh, char *fmt, ...) |
33 | { | 62 | { |
34 | va_list ap; | 63 | va_list ap; |
35 | char *str; | 64 | char *str; |
... | @@ -38,14 +67,6 @@ lmtp_reply (FILE *fp, char *code, char *enh, char *fmt, ...) | ... | @@ -38,14 +67,6 @@ lmtp_reply (FILE *fp, char *code, char *enh, char *fmt, ...) |
38 | vasprintf (&str, fmt, ap); | 67 | vasprintf (&str, fmt, ap); |
39 | va_end (ap); | 68 | va_end (ap); |
40 | 69 | ||
41 | if (lmtp_transcript) | ||
42 | { | ||
43 | if (enh) | ||
44 | mu_diag_output (MU_DIAG_INFO, "LMTP reply: %s %s %s", code, enh, str); | ||
45 | else | ||
46 | mu_diag_output (MU_DIAG_INFO, "LMTP reply: %s %s", code, str); | ||
47 | } | ||
48 | |||
49 | if (!str) | 70 | if (!str) |
50 | { | 71 | { |
51 | mu_error (_("not enough memory")); | 72 | mu_error (_("not enough memory")); |
... | @@ -59,39 +80,23 @@ lmtp_reply (FILE *fp, char *code, char *enh, char *fmt, ...) | ... | @@ -59,39 +80,23 @@ lmtp_reply (FILE *fp, char *code, char *enh, char *fmt, ...) |
59 | if (end) | 80 | if (end) |
60 | { | 81 | { |
61 | size_t len = end - str; | 82 | size_t len = end - str; |
62 | fprintf (fp, "%s-", code); | 83 | mu_stream_printf (iostr, "%s-", code); |
63 | if (enh) | 84 | if (enh) |
64 | fprintf (fp, "%s ", enh); | 85 | mu_stream_printf (iostr, "%s ", enh); |
65 | fprintf (fp, "%.*s\r\n", (int) len, str); | 86 | mu_stream_printf (iostr, "%.*s\r\n", (int) len, str); |
66 | for (str = end; *str && *str == '\n'; str++); | 87 | for (str = end; *str && *str == '\n'; str++); |
67 | } | 88 | } |
68 | else | 89 | else |
69 | { | 90 | { |
70 | fprintf (fp, "%s ", code); | 91 | mu_stream_printf (iostr, "%s ", code); |
71 | if (enh) | 92 | if (enh) |
72 | fprintf (fp, "%s ", enh); | 93 | mu_stream_printf (iostr, "%s ", enh); |
73 | fprintf (fp, "%s\r\n", str); | 94 | mu_stream_printf (iostr, "%s\r\n", str); |
74 | str += strlen (str); | 95 | str += strlen (str); |
75 | } | 96 | } |
76 | } | 97 | } |
77 | } | 98 | } |
78 | 99 | ||
79 | void | ||
80 | xlatnl (char *arg) | ||
81 | { | ||
82 | size_t len = strlen (arg); | ||
83 | if (len > 0 && arg[len-1] == '\n') | ||
84 | { | ||
85 | len--; | ||
86 | if (len > 0 && arg[len-1] == '\r') | ||
87 | { | ||
88 | arg[len-1] = '\n'; | ||
89 | arg[len] = 0; | ||
90 | } | ||
91 | } | ||
92 | } | ||
93 | |||
94 | |||
95 | enum lmtp_state | 100 | enum lmtp_state |
96 | { | 101 | { |
97 | state_none, | 102 | state_none, |
... | @@ -152,14 +157,13 @@ int transtab[NCMD][NSTATE] = { | ... | @@ -152,14 +157,13 @@ int transtab[NCMD][NSTATE] = { |
152 | char *lhlo_domain; /* Sender domain */ | 157 | char *lhlo_domain; /* Sender domain */ |
153 | char *mail_from; /* Sender address */ | 158 | char *mail_from; /* Sender address */ |
154 | mu_list_t rcpt_list; /* Recipient addresses */ | 159 | mu_list_t rcpt_list; /* Recipient addresses */ |
155 | struct mail_tmp *mtmp; /* Temporary mail storage */ | 160 | mu_message_t mesg; /* Collected message */ |
156 | mu_mailbox_t mbox; /* Collected mail body */ | ||
157 | 161 | ||
158 | 162 | ||
159 | int | 163 | int |
160 | cfun_unknown (FILE *out, char *arg) | 164 | cfun_unknown (mu_stream_t iostr, char *arg) |
161 | { | 165 | { |
162 | lmtp_reply (out, "500", "5.5.1", "Command unrecognized"); | 166 | lmtp_reply (iostr, "500", "5.5.1", "Command unrecognized"); |
163 | return 0; | 167 | return 0; |
164 | } | 168 | } |
165 | 169 | ||
... | @@ -242,46 +246,46 @@ check_address (char *arg, int with_domain, char **pret) | ... | @@ -242,46 +246,46 @@ check_address (char *arg, int with_domain, char **pret) |
242 | 246 | ||
243 | 247 | ||
244 | int | 248 | int |
245 | cfun_mail_from (FILE *out, char *arg) | 249 | cfun_mail_from (mu_stream_t iostr, char *arg) |
246 | { | 250 | { |
247 | if (*arg == 0) | 251 | if (*arg == 0) |
248 | { | 252 | { |
249 | lmtp_reply (out, "501", "5.5.2", "Syntax error"); | 253 | lmtp_reply (iostr, "501", "5.5.2", "Syntax error"); |
250 | return 1; | 254 | return 1; |
251 | } | 255 | } |
252 | 256 | ||
253 | if (check_address (arg, 1, &mail_from)) | 257 | if (check_address (arg, 1, &mail_from)) |
254 | { | 258 | { |
255 | lmtp_reply (out, "553", "5.1.8", "Address format error"); | 259 | lmtp_reply (iostr, "553", "5.1.8", "Address format error"); |
256 | return 1; | 260 | return 1; |
257 | } | 261 | } |
258 | lmtp_reply (out, "250", "2.1.0", "Go ahead"); | 262 | lmtp_reply (iostr, "250", "2.1.0", "Go ahead"); |
259 | return 0; | 263 | return 0; |
260 | } | 264 | } |
261 | 265 | ||
262 | 266 | ||
263 | int | 267 | int |
264 | cfun_rcpt_to (FILE *out, char *arg) | 268 | cfun_rcpt_to (mu_stream_t iostr, char *arg) |
265 | { | 269 | { |
266 | char *user; | 270 | char *user; |
267 | struct mu_auth_data *auth; | 271 | struct mu_auth_data *auth; |
268 | 272 | ||
269 | if (*arg == 0) | 273 | if (*arg == 0) |
270 | { | 274 | { |
271 | lmtp_reply (out, "501", "5.5.2", "Syntax error"); | 275 | lmtp_reply (iostr, "501", "5.5.2", "Syntax error"); |
272 | return 1; | 276 | return 1; |
273 | } | 277 | } |
274 | 278 | ||
275 | /* FIXME: Check if domain is OK */ | 279 | /* FIXME: Check if domain is OK */ |
276 | if (check_address (arg, 0, &user)) | 280 | if (check_address (arg, 0, &user)) |
277 | { | 281 | { |
278 | lmtp_reply (out, "553", "5.1.8", "Address format error"); | 282 | lmtp_reply (iostr, "553", "5.1.8", "Address format error"); |
279 | return 1; | 283 | return 1; |
280 | } | 284 | } |
281 | auth = mu_get_auth_by_name (user); | 285 | auth = mu_get_auth_by_name (user); |
282 | if (!auth) | 286 | if (!auth) |
283 | { | 287 | { |
284 | lmtp_reply (out, "550", "5.1.1", "User unknown"); | 288 | lmtp_reply (iostr, "550", "5.1.1", "User unknown"); |
285 | free (user); | 289 | free (user); |
286 | return 1; | 290 | return 1; |
287 | } | 291 | } |
... | @@ -292,27 +296,7 @@ cfun_rcpt_to (FILE *out, char *arg) | ... | @@ -292,27 +296,7 @@ cfun_rcpt_to (FILE *out, char *arg) |
292 | mu_list_set_destroy_item (rcpt_list, mu_list_free_item); | 296 | mu_list_set_destroy_item (rcpt_list, mu_list_free_item); |
293 | } | 297 | } |
294 | mu_list_append (rcpt_list, user); | 298 | mu_list_append (rcpt_list, user); |
295 | lmtp_reply (out, "250", "2.1.5", "Go ahead"); | 299 | lmtp_reply (iostr, "250", "2.1.5", "Go ahead"); |
296 | return 0; | ||
297 | } | ||
298 | |||
299 | |||
300 | int | ||
301 | cfun_data (FILE *out, char *arg) | ||
302 | { | ||
303 | if (*arg) | ||
304 | { | ||
305 | lmtp_reply (out, "501", "5.5.2", "Syntax error"); | ||
306 | return 1; | ||
307 | } | ||
308 | |||
309 | if (mail_tmp_begin (&mtmp, mail_from)) | ||
310 | { | ||
311 | /* FIXME: codes */ | ||
312 | lmtp_reply (out, "450", "4.1.0", "Temporary failure, try again later"); | ||
313 | return 1; | ||
314 | } | ||
315 | lmtp_reply (out, "354", NULL, "Go ahead"); | ||
316 | return 0; | 300 | return 0; |
317 | } | 301 | } |
318 | 302 | ||
... | @@ -321,8 +305,8 @@ int | ... | @@ -321,8 +305,8 @@ int |
321 | dot_temp_fail (void *item, void *cbdata) | 305 | dot_temp_fail (void *item, void *cbdata) |
322 | { | 306 | { |
323 | char *name = item; | 307 | char *name = item; |
324 | FILE *out = cbdata; | 308 | mu_stream_t iostr = cbdata; |
325 | lmtp_reply (out, "450", "4.1.0", "%s: temporary failure", name); | 309 | lmtp_reply (iostr, "450", "4.1.0", "%s: temporary failure", name); |
326 | return 0; | 310 | return 0; |
327 | } | 311 | } |
328 | 312 | ||
... | @@ -330,39 +314,27 @@ int | ... | @@ -330,39 +314,27 @@ int |
330 | dot_deliver (void *item, void *cbdata) | 314 | dot_deliver (void *item, void *cbdata) |
331 | { | 315 | { |
332 | char *name = item; | 316 | char *name = item; |
333 | FILE *out = cbdata; | 317 | mu_stream_t iostr = cbdata; |
334 | char *errp = NULL; | 318 | char *errp = NULL; |
335 | mu_message_t msg; | ||
336 | int status; | ||
337 | |||
338 | if ((status = mu_mailbox_get_message (mbox, 1, &msg)) != 0) | ||
339 | { | ||
340 | mu_error (_("cannot get message from the temporary mailbox: %s"), | ||
341 | mu_strerror (status)); | ||
342 | lmtp_reply (out, "450", "4.1.0", | ||
343 | "%s: temporary failure, try again later", | ||
344 | name); | ||
345 | return 0; | ||
346 | } | ||
347 | 319 | ||
348 | switch (deliver (msg, name, &errp)) | 320 | switch (deliver (mesg, name, &errp)) |
349 | { | 321 | { |
350 | case 0: | 322 | case 0: |
351 | lmtp_reply (out, "250", "2.0.0", "%s: delivered", name); | 323 | lmtp_reply (iostr, "250", "2.0.0", "%s: delivered", name); |
352 | break; | 324 | break; |
353 | 325 | ||
354 | case EX_UNAVAILABLE: | 326 | case EX_UNAVAILABLE: |
355 | if (errp) | 327 | if (errp) |
356 | lmtp_reply (out, "553", "5.1.8", "%s", errp); | 328 | lmtp_reply (iostr, "553", "5.1.8", "%s", errp); |
357 | else | 329 | else |
358 | lmtp_reply (out, "553", "5.1.8", "%s: delivery failed", name); | 330 | lmtp_reply (iostr, "553", "5.1.8", "%s: delivery failed", name); |
359 | break; | 331 | break; |
360 | 332 | ||
361 | default: | 333 | default: |
362 | if (errp) | 334 | if (errp) |
363 | lmtp_reply (out, "450", "4.1.0", "%s", errp); | 335 | lmtp_reply (iostr, "450", "4.1.0", "%s", errp); |
364 | else | 336 | else |
365 | lmtp_reply (out, "450", "4.1.0", | 337 | lmtp_reply (iostr, "450", "4.1.0", |
366 | "%s: temporary failure, try again later", | 338 | "%s: temporary failure, try again later", |
367 | name); | 339 | name); |
368 | break; | 340 | break; |
... | @@ -372,37 +344,103 @@ dot_deliver (void *item, void *cbdata) | ... | @@ -372,37 +344,103 @@ dot_deliver (void *item, void *cbdata) |
372 | } | 344 | } |
373 | 345 | ||
374 | int | 346 | int |
375 | cfun_dot (FILE *out, char *arg) | 347 | cfun_data (mu_stream_t iostr, char *arg) |
376 | { | 348 | { |
377 | if (!mtmp) | 349 | int rc; |
378 | mu_list_do (rcpt_list, dot_temp_fail, out); | 350 | mu_stream_t flt, tempstr; |
379 | else | 351 | time_t t; |
352 | int xlev = MU_XSCRIPT_PAYLOAD, xlev_switch = 0, buf_switch = 0; | ||
353 | struct mu_buffer_query oldbuf; | ||
354 | |||
355 | if (*arg) | ||
380 | { | 356 | { |
381 | int rc = mail_tmp_finish (mtmp, &mbox); | 357 | lmtp_reply (iostr, "501", "5.5.2", "Syntax error"); |
358 | return 1; | ||
359 | } | ||
360 | |||
361 | rc = mu_filter_create (&flt, iostr, "CRLFDOT", MU_FILTER_DECODE, | ||
362 | MU_STREAM_READ|MU_STREAM_WRTHRU); | ||
382 | if (rc) | 363 | if (rc) |
383 | mu_list_do (rcpt_list, dot_temp_fail, out); | ||
384 | else | ||
385 | { | 364 | { |
386 | mu_list_do (rcpt_list, dot_deliver, out); | 365 | maidag_error (_("unable to open filter: %s"), |
387 | mail_tmp_destroy (&mtmp); | 366 | mu_strerror (rc)); |
388 | mu_mailbox_destroy (&mbox); | 367 | lmtp_reply (iostr, "450", "4.1.0", "Temporary failure, try again later"); |
368 | return 1; | ||
389 | } | 369 | } |
370 | |||
371 | rc = mu_temp_file_stream_create (&tempstr, NULL); | ||
372 | if (rc) | ||
373 | { | ||
374 | maidag_error (_("unable to open temporary file: %s"), mu_strerror (rc)); | ||
375 | mu_stream_destroy (&flt); | ||
376 | return 1; | ||
390 | } | 377 | } |
391 | free (mail_from); | 378 | |
392 | mu_list_destroy (&rcpt_list); | 379 | /* Write out envelope */ |
380 | time (&t); | ||
381 | rc = mu_stream_printf (tempstr, "From %s %s", mail_from, ctime (&t)); | ||
382 | if (rc) | ||
383 | { | ||
384 | maidag_error (_("copy error: %s"), mu_strerror (rc)); | ||
385 | mu_stream_destroy (&flt); | ||
386 | mu_stream_destroy (&tempstr); | ||
387 | mu_list_do (rcpt_list, dot_temp_fail, iostr); | ||
388 | } | ||
389 | |||
390 | lmtp_reply (iostr, "354", NULL, "Go ahead"); | ||
391 | |||
392 | if (mu_stream_ioctl (iostr, MU_IOCTL_GET_TRANSPORT_BUFFER, &oldbuf) == 0) | ||
393 | { | ||
394 | struct mu_buffer_query newbuf; | ||
395 | |||
396 | newbuf.type = MU_TRANSPORT_OUTPUT; | ||
397 | newbuf.buftype = mu_buffer_full; | ||
398 | newbuf.bufsize = 64*1024; | ||
399 | if (mu_stream_ioctl (iostr, MU_IOCTL_SET_TRANSPORT_BUFFER, &newbuf)) | ||
400 | buf_switch = 1; | ||
401 | } | ||
402 | |||
403 | if (mu_stream_ioctl (iostr, MU_IOCTL_LEVEL, &xlev) == 0) | ||
404 | xlev_switch = 1; | ||
405 | rc = mu_stream_copy (tempstr, flt, 0, NULL); | ||
406 | mu_stream_destroy (&flt); | ||
407 | if (xlev_switch) | ||
408 | mu_stream_ioctl (iostr, MU_IOCTL_LEVEL, &xlev); | ||
409 | if (buf_switch) | ||
410 | mu_stream_ioctl (iostr, MU_IOCTL_SET_TRANSPORT_BUFFER, &oldbuf); | ||
411 | if (rc) | ||
412 | { | ||
413 | maidag_error (_("copy error: %s"), mu_strerror (rc)); | ||
414 | mu_list_do (rcpt_list, dot_temp_fail, iostr); | ||
415 | } | ||
416 | |||
417 | rc = mu_stream_to_message (tempstr, &mesg); | ||
418 | if (rc) | ||
419 | { | ||
420 | maidag_error (_("error creating temporary message: %s"), | ||
421 | mu_strerror (rc)); | ||
422 | mu_list_do (rcpt_list, dot_temp_fail, iostr); | ||
423 | } | ||
424 | |||
425 | rc = mu_list_do (rcpt_list, dot_deliver, iostr); | ||
426 | |||
427 | mu_stream_destroy (&tempstr); | ||
428 | mu_message_destroy (&mesg, mu_message_get_owner (mesg)); | ||
429 | if (rc) | ||
430 | mu_list_do (rcpt_list, dot_temp_fail, iostr); | ||
431 | |||
393 | return 0; | 432 | return 0; |
394 | } | 433 | } |
395 | 434 | ||
396 | 435 | ||
397 | int | 436 | int |
398 | cfun_rset (FILE *out, char *arg) | 437 | cfun_rset (mu_stream_t iostr, char *arg) |
399 | { | 438 | { |
400 | free (lhlo_domain); | 439 | free (lhlo_domain); |
401 | free (mail_from); | 440 | free (mail_from); |
402 | mu_list_destroy (&rcpt_list); | 441 | mu_list_destroy (&rcpt_list); |
403 | mail_tmp_destroy (&mtmp); | 442 | mu_message_destroy (&mesg, mu_message_get_owner (mesg)); |
404 | mu_mailbox_destroy (&mbox); | 443 | lmtp_reply (iostr, "250", "2.0.0", "OK, forgotten"); |
405 | lmtp_reply (out, "250", "2.0.0", "OK, forgotten"); | ||
406 | return 0; | 444 | return 0; |
407 | } | 445 | } |
408 | 446 | ||
... | @@ -413,32 +451,32 @@ PIPELINING\n\ | ... | @@ -413,32 +451,32 @@ PIPELINING\n\ |
413 | HELP"; | 451 | HELP"; |
414 | 452 | ||
415 | int | 453 | int |
416 | cfun_lhlo (FILE *out, char *arg) | 454 | cfun_lhlo (mu_stream_t iostr, char *arg) |
417 | { | 455 | { |
418 | if (*arg == 0) | 456 | if (*arg == 0) |
419 | { | 457 | { |
420 | lmtp_reply (out, "501", "5.0.0", "Syntax error"); | 458 | lmtp_reply (iostr, "501", "5.0.0", "Syntax error"); |
421 | return 1; | 459 | return 1; |
422 | } | 460 | } |
423 | lhlo_domain = strdup (arg); | 461 | lhlo_domain = strdup (arg); |
424 | lmtp_reply (out, "250", NULL, "Hello\n"); | 462 | lmtp_reply (iostr, "250", NULL, "Hello\n"); |
425 | lmtp_reply (out, "250", NULL, capa_str); | 463 | lmtp_reply (iostr, "250", NULL, capa_str); |
426 | return 0; | 464 | return 0; |
427 | } | 465 | } |
428 | 466 | ||
429 | 467 | ||
430 | int | 468 | int |
431 | cfun_quit (FILE *out, char *arg) | 469 | cfun_quit (mu_stream_t iostr, char *arg) |
432 | { | 470 | { |
433 | lmtp_reply (out, "221", "2.0.0", "Bye"); | 471 | lmtp_reply (iostr, "221", "2.0.0", "Bye"); |
434 | return 0; | 472 | return 0; |
435 | } | 473 | } |
436 | 474 | ||
437 | 475 | ||
438 | int | 476 | int |
439 | cfun_help (FILE *out, char *arg) | 477 | cfun_help (mu_stream_t iostr, char *arg) |
440 | { | 478 | { |
441 | lmtp_reply (out, "200", "2.0.0", "Man, help yourself"); | 479 | lmtp_reply (iostr, "200", "2.0.0", "Man, help yourself"); |
442 | return 0; | 480 | return 0; |
443 | } | 481 | } |
444 | 482 | ||
... | @@ -448,7 +486,7 @@ struct command_tab | ... | @@ -448,7 +486,7 @@ struct command_tab |
448 | char *cmd_verb; | 486 | char *cmd_verb; |
449 | int cmd_len; | 487 | int cmd_len; |
450 | enum lmtp_command cmd_code; | 488 | enum lmtp_command cmd_code; |
451 | int (*cmd_fun) (FILE *, char *); | 489 | int (*cmd_fun) (mu_stream_t, char *); |
452 | } command_tab[] = { | 490 | } command_tab[] = { |
453 | #define S(s) #s, (sizeof #s - 1) | 491 | #define S(s) #s, (sizeof #s - 1) |
454 | { S(lhlo), cmd_lhlo, cfun_lhlo }, | 492 | { S(lhlo), cmd_lhlo, cfun_lhlo }, |
... | @@ -458,7 +496,6 @@ struct command_tab | ... | @@ -458,7 +496,6 @@ struct command_tab |
458 | { S(quit), cmd_quit, cfun_quit }, | 496 | { S(quit), cmd_quit, cfun_quit }, |
459 | { S(rset), cmd_rset, cfun_rset }, | 497 | { S(rset), cmd_rset, cfun_rset }, |
460 | { S(help), cmd_help, cfun_help }, | 498 | { S(help), cmd_help, cfun_help }, |
461 | { S(.), cmd_dot, cfun_dot }, | ||
462 | { NULL, 0, cmd_unknown, cfun_unknown } | 499 | { NULL, 0, cmd_unknown, cfun_unknown } |
463 | }; | 500 | }; |
464 | 501 | ||
... | @@ -479,48 +516,27 @@ getcmd (char *buf, char **sp) | ... | @@ -479,48 +516,27 @@ getcmd (char *buf, char **sp) |
479 | return cp; | 516 | return cp; |
480 | } | 517 | } |
481 | 518 | ||
482 | static char * | 519 | static int |
483 | to_fgets (char *buf, size_t size, FILE *fp, unsigned int timeout) | 520 | to_fgets (mu_stream_t iostr, char **pbuf, size_t *psize, size_t *pnread, |
521 | unsigned int timeout) | ||
484 | { | 522 | { |
485 | char *p; | 523 | int rc; |
524 | |||
486 | alarm (timeout); | 525 | alarm (timeout); |
487 | p = fgets (buf, size, fp); | 526 | rc = mu_stream_getline (iostr, pbuf, psize, pnread); |
488 | alarm (0); | 527 | alarm (0); |
489 | return p; | 528 | return rc; |
490 | } | 529 | } |
491 | 530 | ||
492 | int | 531 | int |
493 | lmtp_loop (FILE *in, FILE *out, unsigned int timeout) | 532 | lmtp_loop (mu_stream_t iostr, unsigned int timeout) |
494 | { | 533 | { |
495 | char buf[1024]; | 534 | size_t size = 0, n; |
535 | char *buf = NULL; | ||
496 | enum lmtp_state state = state_init; | 536 | enum lmtp_state state = state_init; |
497 | 537 | ||
498 | setvbuf (in, NULL, _IOLBF, 0); | 538 | lmtp_reply (iostr, "220", NULL, "At your service"); |
499 | setvbuf (out, NULL, _IOLBF, 0); | 539 | while (to_fgets (iostr, &buf, &size, &n, timeout) == 0 && n) |
500 | |||
501 | lmtp_reply (out, "220", NULL, "At your service"); | ||
502 | while (to_fgets (buf, sizeof buf, in, timeout)) | ||
503 | { | ||
504 | if (state == state_data | ||
505 | && !(buf[0] == '.' | ||
506 | && (buf[1] == '\n' || (buf[1] == '\r' && buf[2] == '\n')))) | ||
507 | { | ||
508 | /* This is a special case */ | ||
509 | if (mtmp) | ||
510 | { | ||
511 | size_t len; | ||
512 | int rc; | ||
513 | |||
514 | xlatnl (buf); | ||
515 | len = strlen (buf); | ||
516 | if ((rc = mail_tmp_add_line (mtmp, buf, len))) | ||
517 | { | ||
518 | mail_tmp_destroy (&mtmp); | ||
519 | /* Wait the dot to report the error */ | ||
520 | } | ||
521 | } | ||
522 | } | ||
523 | else | ||
524 | { | 540 | { |
525 | char *sp; | 541 | char *sp; |
526 | struct command_tab *cp = getcmd (buf, &sp); | 542 | struct command_tab *cp = getcmd (buf, &sp); |
... | @@ -529,22 +545,18 @@ lmtp_loop (FILE *in, FILE *out, unsigned int timeout) | ... | @@ -529,22 +545,18 @@ lmtp_loop (FILE *in, FILE *out, unsigned int timeout) |
529 | 545 | ||
530 | mu_rtrim_cset (sp, "\r\n"); | 546 | mu_rtrim_cset (sp, "\r\n"); |
531 | 547 | ||
532 | if (lmtp_transcript) | ||
533 | mu_diag_output (MU_DIAG_INFO, "LMTP receive: %s", buf); | ||
534 | |||
535 | if (next_state != state_none) | 548 | if (next_state != state_none) |
536 | { | 549 | { |
537 | if (cp->cmd_fun) | 550 | if (cp->cmd_fun) |
538 | { | 551 | { |
539 | sp = mu_str_skip_class (sp, MU_CTYPE_SPACE); | 552 | sp = mu_str_skip_class (sp, MU_CTYPE_SPACE); |
540 | if (cp->cmd_fun (out, sp)) | 553 | if (cp->cmd_fun (iostr, sp)) |
541 | continue; | 554 | continue; |
542 | } | 555 | } |
543 | state = next_state; | 556 | state = next_state; |
544 | } | 557 | } |
545 | else | 558 | else |
546 | lmtp_reply (out, "503", "5.0.0", "Syntax error"); | 559 | lmtp_reply (iostr, "503", "5.0.0", "Syntax error"); |
547 | } | ||
548 | 560 | ||
549 | if (state == state_end) | 561 | if (state == state_end) |
550 | break; | 562 | break; |
... | @@ -563,8 +575,22 @@ int | ... | @@ -563,8 +575,22 @@ int |
563 | lmtp_connection (int fd, struct sockaddr *sa, int salen, void *data, | 575 | lmtp_connection (int fd, struct sockaddr *sa, int salen, void *data, |
564 | mu_ip_server_t srv, time_t timeout, int transcript) | 576 | mu_ip_server_t srv, time_t timeout, int transcript) |
565 | { | 577 | { |
566 | lmtp_transcript = transcript; | 578 | mu_stream_t str; |
567 | lmtp_loop (fdopen (fd, "r"), fdopen (fd, "w"), timeout); | 579 | int rc; |
580 | |||
581 | rc = mu_fd_stream_create (&str, NULL, fd, | ||
582 | MU_STREAM_RDWR|MU_STREAM_AUTOCLOSE); | ||
583 | if (rc) | ||
584 | { | ||
585 | mu_diag_funcall (MU_DIAG_ERROR, "mu_fd_stream_create", NULL, rc); | ||
586 | return rc; | ||
587 | } | ||
588 | mu_stream_set_buffer (str, mu_buffer_line, 0); | ||
589 | |||
590 | if (transcript || maidag_transcript) | ||
591 | str = lmpt_transcript (str); | ||
592 | lmtp_loop (str, timeout); | ||
593 | mu_stream_destroy (&str); | ||
568 | return 0; | 594 | return 0; |
569 | } | 595 | } |
570 | 596 | ||
... | @@ -641,5 +667,39 @@ maidag_lmtp_server () | ... | @@ -641,5 +667,39 @@ maidag_lmtp_server () |
641 | return EX_CONFIG; | 667 | return EX_CONFIG; |
642 | } | 668 | } |
643 | else | 669 | else |
644 | return lmtp_loop (stdin, stdout, 0); | 670 | { |
671 | mu_stream_t str, istream, ostream; | ||
672 | |||
673 | rc = mu_stdio_stream_create (&istream, MU_STDIN_FD, MU_STREAM_READ); | ||
674 | if (rc) | ||
675 | { | ||
676 | mu_diag_funcall (MU_DIAG_ERROR, "mu_stdio_stream_create", | ||
677 | "MU_STDIN_FD", rc); | ||
678 | return EX_UNAVAILABLE; | ||
679 | } | ||
680 | |||
681 | rc = mu_stdio_stream_create (&ostream, MU_STDOUT_FD, MU_STREAM_WRITE); | ||
682 | if (rc) | ||
683 | { | ||
684 | mu_diag_funcall (MU_DIAG_ERROR, "mu_stdio_stream_create", | ||
685 | "MU_STDOUT_FD", rc); | ||
686 | return 1; | ||
687 | } | ||
688 | |||
689 | rc = mu_iostream_create (&str, istream, ostream); | ||
690 | mu_stream_unref (istream); | ||
691 | mu_stream_unref (ostream); | ||
692 | if (rc) | ||
693 | { | ||
694 | mu_diag_funcall (MU_DIAG_ERROR, "mu_iostream_create", NULL, rc); | ||
695 | return 1; | ||
696 | } | ||
697 | |||
698 | if (maidag_transcript) | ||
699 | str = lmpt_transcript (str); | ||
700 | |||
701 | rc = lmtp_loop (str, 0); | ||
702 | mu_stream_destroy (&str); | ||
703 | return rc; | ||
704 | } | ||
645 | } | 705 | } | ... | ... |
... | @@ -53,6 +53,7 @@ int lmtp_mode; | ... | @@ -53,6 +53,7 @@ int lmtp_mode; |
53 | int url_option; | 53 | int url_option; |
54 | char *lmtp_url_string; | 54 | char *lmtp_url_string; |
55 | int reuse_lmtp_address = 1; | 55 | int reuse_lmtp_address = 1; |
56 | int maidag_transcript; | ||
56 | 57 | ||
57 | const char *program_version = "maidag (" PACKAGE_STRING ")"; | 58 | const char *program_version = "maidag (" PACKAGE_STRING ")"; |
58 | static char doc[] = | 59 | static char doc[] = |
... | @@ -72,6 +73,7 @@ static char args_doc[] = N_("[recipient...]"); | ... | @@ -72,6 +73,7 @@ static char args_doc[] = N_("[recipient...]"); |
72 | #define LMTP_OPTION 258 | 73 | #define LMTP_OPTION 258 |
73 | #define FOREGROUND_OPTION 260 | 74 | #define FOREGROUND_OPTION 260 |
74 | #define URL_OPTION 261 | 75 | #define URL_OPTION 261 |
76 | #define TRANSCRIPT_OPTION 262 | ||
75 | 77 | ||
76 | static struct argp_option options[] = | 78 | static struct argp_option options[] = |
77 | { | 79 | { |
... | @@ -94,6 +96,8 @@ static struct argp_option options[] = | ... | @@ -94,6 +96,8 @@ static struct argp_option options[] = |
94 | N_("enable debugging"), GRID + 1 }, | 96 | N_("enable debugging"), GRID + 1 }, |
95 | { "stderr", STDERR_OPTION, NULL, 0, | 97 | { "stderr", STDERR_OPTION, NULL, 0, |
96 | N_("log to standard error"), GRID + 1 }, | 98 | N_("log to standard error"), GRID + 1 }, |
99 | { "transcript", TRANSCRIPT_OPTION, NULL, 0, | ||
100 | N_("enable session transcript"), GRID + 1 }, | ||
97 | #undef GRID | 101 | #undef GRID |
98 | 102 | ||
99 | #define GRID 2 | 103 | #define GRID 2 |
... | @@ -212,6 +216,10 @@ parse_opt (int key, char *arg, struct argp_state *state) | ... | @@ -212,6 +216,10 @@ parse_opt (int key, char *arg, struct argp_state *state) |
212 | mu_argp_node_list_new (lst, "listen", arg); | 216 | mu_argp_node_list_new (lst, "listen", arg); |
213 | break; | 217 | break; |
214 | 218 | ||
219 | case TRANSCRIPT_OPTION: | ||
220 | maidag_transcript = 1; | ||
221 | break; | ||
222 | |||
215 | case 'r': | 223 | case 'r': |
216 | case 'f': | 224 | case 'f': |
217 | if (sender_address != NULL) | 225 | if (sender_address != NULL) | ... | ... |
... | @@ -142,6 +142,7 @@ extern char *lmtp_url_string; | ... | @@ -142,6 +142,7 @@ extern char *lmtp_url_string; |
142 | extern int reuse_lmtp_address; | 142 | extern int reuse_lmtp_address; |
143 | extern mu_list_t lmtp_groups; | 143 | extern mu_list_t lmtp_groups; |
144 | extern mu_acl_t maidag_acl; | 144 | extern mu_acl_t maidag_acl; |
145 | extern int maidag_transcript; | ||
145 | 146 | ||
146 | void close_fds (void); | 147 | void close_fds (void); |
147 | int switch_user_id (struct mu_auth_data *auth, int user); | 148 | int switch_user_id (struct mu_auth_data *auth, int user); |
... | @@ -160,12 +161,6 @@ int deliver (mu_message_t msg, char *name, char **errp); | ... | @@ -160,12 +161,6 @@ int deliver (mu_message_t msg, char *name, char **errp); |
160 | int sieve_test (struct mu_auth_data *auth, mu_message_t msg); | 161 | int sieve_test (struct mu_auth_data *auth, mu_message_t msg); |
161 | int check_quota (struct mu_auth_data *auth, mu_off_t size, mu_off_t *rest); | 162 | int check_quota (struct mu_auth_data *auth, mu_off_t size, mu_off_t *rest); |
162 | 163 | ||
163 | struct mail_tmp; | ||
164 | int mail_tmp_begin (struct mail_tmp **pmtmp, const char *from); | ||
165 | int mail_tmp_add_line (struct mail_tmp *mtmp, char *buf, size_t buflen); | ||
166 | int mail_tmp_finish (struct mail_tmp *mtmp, mu_mailbox_t *mbox); | ||
167 | void mail_tmp_destroy (struct mail_tmp **pmtmp); | ||
168 | |||
169 | enum maidag_forward_result | 164 | enum maidag_forward_result |
170 | { | 165 | { |
171 | maidag_forward_none, | 166 | maidag_forward_none, | ... | ... |
maidag/mailtmp.c
deleted
100644 → 0
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 1999, 2000, 2001, 2002, 2005, 2007, 2009, 2010 Free | ||
3 | Software Foundation, Inc. | ||
4 | |||
5 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 3, or (at your option) | ||
8 | any later version. | ||
9 | |||
10 | GNU Mailutils is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNU Mailutils; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | ||
18 | MA 02110-1301 USA */ | ||
19 | |||
20 | #include "maidag.h" | ||
21 | |||
22 | struct mail_tmp | ||
23 | { | ||
24 | mu_stream_t stream; | ||
25 | size_t line; | ||
26 | char *tempfile; | ||
27 | const char *from; | ||
28 | int had_nl; | ||
29 | }; | ||
30 | |||
31 | int | ||
32 | mail_tmp_begin (struct mail_tmp **pmtmp, const char *from) | ||
33 | { | ||
34 | int status; | ||
35 | struct mail_tmp *mtmp = malloc (sizeof *mtmp); | ||
36 | |||
37 | if (!mtmp) | ||
38 | return ENOMEM; | ||
39 | |||
40 | memset (mtmp, 0, sizeof *mtmp); | ||
41 | |||
42 | mtmp->tempfile = mu_tempname (NULL); | ||
43 | if ((status = mu_file_stream_create (&mtmp->stream, mtmp->tempfile, | ||
44 | MU_STREAM_RDWR))) | ||
45 | { | ||
46 | free (mtmp); | ||
47 | maidag_error (_("unable to open temporary file: %s"), | ||
48 | mu_strerror (status)); | ||
49 | return status; | ||
50 | } | ||
51 | |||
52 | mtmp->from = from; | ||
53 | *pmtmp = mtmp; | ||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | int | ||
58 | mail_tmp_add_line (struct mail_tmp *mtmp, char *buf, size_t buflen) | ||
59 | { | ||
60 | int status = 0; | ||
61 | |||
62 | mtmp->line++; | ||
63 | if (mtmp->line == 1) | ||
64 | { | ||
65 | const char *from = mtmp->from; | ||
66 | |||
67 | if (buflen >= 5 && memcmp (buf, "From ", 5)) | ||
68 | { | ||
69 | struct mu_auth_data *auth = NULL; | ||
70 | if (!from) | ||
71 | { | ||
72 | auth = mu_get_auth_by_uid (getuid ()); | ||
73 | if (auth) | ||
74 | from = auth->name; | ||
75 | } | ||
76 | if (from) | ||
77 | { | ||
78 | time_t t; | ||
79 | char *envs; | ||
80 | |||
81 | time (&t); | ||
82 | asprintf (&envs, "From %s %s", from, ctime (&t)); | ||
83 | status = mu_stream_write (mtmp->stream, | ||
84 | envs, | ||
85 | strlen (envs), NULL); | ||
86 | free (envs); | ||
87 | } | ||
88 | else | ||
89 | { | ||
90 | maidag_error (_("cannot determine sender address")); | ||
91 | return EINVAL; | ||
92 | } | ||
93 | if (auth) | ||
94 | mu_auth_data_free (auth); | ||
95 | } | ||
96 | } | ||
97 | else if (buflen >= 5 && !memcmp (buf, "From ", 5)) | ||
98 | { | ||
99 | static char *escape = ">"; | ||
100 | status = mu_stream_write (mtmp->stream, escape, 1, NULL); | ||
101 | } | ||
102 | |||
103 | if (!status) | ||
104 | status = mu_stream_write (mtmp->stream, buf, buflen, NULL); | ||
105 | |||
106 | if (status) | ||
107 | { | ||
108 | maidag_error (_("error writing temporary file: %s"), | ||
109 | mu_strerror (status)); | ||
110 | mu_stream_destroy (&mtmp->stream); | ||
111 | } | ||
112 | mtmp->had_nl = buf[buflen-1] == '\n'; | ||
113 | return status; | ||
114 | } | ||
115 | |||
116 | int | ||
117 | mail_tmp_finish (struct mail_tmp *mtmp, mu_mailbox_t *mbox) | ||
118 | { | ||
119 | int status; | ||
120 | static char *newline = "\n"; | ||
121 | size_t n; | ||
122 | |||
123 | if (!mtmp->had_nl) | ||
124 | status = mu_stream_write (mtmp->stream, newline, 1, NULL); | ||
125 | |||
126 | status = mu_stream_write (mtmp->stream, newline, 1, NULL); | ||
127 | unlink (mtmp->tempfile); | ||
128 | free (mtmp->tempfile); | ||
129 | mtmp->tempfile = NULL; | ||
130 | |||
131 | if (status) | ||
132 | { | ||
133 | errno = status; | ||
134 | maidag_error (_("error writing temporary file: %s"), | ||
135 | mu_strerror (status)); | ||
136 | mu_stream_destroy (&mtmp->stream); | ||
137 | return status; | ||
138 | } | ||
139 | |||
140 | mu_stream_flush (mtmp->stream); | ||
141 | if ((status = mu_mailbox_create (mbox, "mbox:/dev/null")) | ||
142 | || (status = mu_mailbox_open (*mbox, MU_STREAM_READ)) | ||
143 | || (status = mu_mailbox_set_stream (*mbox, mtmp->stream))) | ||
144 | { | ||
145 | maidag_error (_("error opening temporary file: %s"), | ||
146 | mu_strerror (status)); | ||
147 | mu_stream_destroy (&mtmp->stream); | ||
148 | return status; | ||
149 | } | ||
150 | |||
151 | status = mu_mailbox_messages_count (*mbox, &n); | ||
152 | if (status) | ||
153 | { | ||
154 | errno = status; | ||
155 | maidag_error (_("error creating temporary message: %s"), | ||
156 | mu_strerror (status)); | ||
157 | mu_stream_destroy (&mtmp->stream); | ||
158 | return status; | ||
159 | } | ||
160 | |||
161 | mtmp->stream = NULL; | ||
162 | mtmp->line = 0; | ||
163 | |||
164 | return status; | ||
165 | |||
166 | } | ||
167 | |||
168 | void | ||
169 | mail_tmp_destroy (struct mail_tmp **pmtmp) | ||
170 | { | ||
171 | struct mail_tmp *mtmp = *pmtmp; | ||
172 | |||
173 | if (mtmp) | ||
174 | { | ||
175 | if (mtmp->tempfile) | ||
176 | { | ||
177 | unlink (mtmp->tempfile); | ||
178 | free (mtmp->tempfile); | ||
179 | } | ||
180 | mu_stream_destroy (&mtmp->stream); | ||
181 | free (*pmtmp); | ||
182 | *pmtmp = NULL; | ||
183 | } | ||
184 | } | ||
185 | |||
186 | |||
187 |
-
Please register or sign in to post a comment