Commit f24df125 f24df125b4a5f7e29eee39e89127871a38856281 by Sergey Poznyakoff

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.
1 parent 6b7badca
...@@ -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 }
......
...@@ -26,7 +26,6 @@ maidag_SOURCES=\ ...@@ -26,7 +26,6 @@ maidag_SOURCES=\
26 lmtp.c\ 26 lmtp.c\
27 maidag.c\ 27 maidag.c\
28 maidag.h\ 28 maidag.h\
29 mailtmp.c\
30 mailquota.c\ 29 mailquota.c\
31 python.c\ 30 python.c\
32 sieve.c\ 31 sieve.c\
......
...@@ -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,
......
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
...@@ -90,7 +90,6 @@ maidag/deliver.c ...@@ -90,7 +90,6 @@ maidag/deliver.c
90 maidag/lmtp.c 90 maidag/lmtp.c
91 maidag/maidag.c 91 maidag/maidag.c
92 maidag/mailquota.c 92 maidag/mailquota.c
93 maidag/mailtmp.c
94 maidag/script.c 93 maidag/script.c
95 94
96 mail/alias.c 95 mail/alias.c
......