Commit 906499db 906499db53aea7333a11a87955c5c41ccbe45310 by Sergey Poznyakoff

Optimize I/O bufferization.

New ioctls MU_IOCTL_GET_TRANSPORT_BUFFER and
MU_IOCTL_SET_TRANSPORT_BUFFER return and modify bufferization
mode in the lowest level transport stream.  Both server and
client programs use this to switch to full buffering before
sending large amounts of data. This has a particular impact
on the output speed and CPU usage when TLS is in use.

* include/mailutils/stream.h (MU_IOCTL_GET_TRANSPORT_BUFFER)
(MU_IOCTL_SET_TRANSPORT_BUFFER): New ioctls.
(MU_TRANSPORT_INPUT, MU_TRANSPORT_OUTPUT): New constants.
(MU_TRANSPORT_VALID_TYPE): New macro.
(mu_buffer_query): New struct.
(mu_stream_get_buffer): New proto.

* libmu_auth/tls.c (_tls_io_ioctl): Return ENOSYS
if op is not supported.
(_tls_ioctl): Support MU_IOCTL_[GS]ET_TRANSPORT_BUFFER.
* mailbox/file_stream.c (fd_ioctl): Support MU_IOCTL_[GS]ET_TRANSPORT_BUFFER.
Return ENOSYS if op is not supported.
* mailbox/filter_iconv.c (_icvt_ioctl): Likewise.
* mailbox/iostream.c (_iostream_ctl): Likewise.
* mailbox/mapfile_stream.c (_mapfile_ioctl): Likewise.
* mailbox/memory_stream.c (_memory_ioctl): Likewise.
* mailbox/rdcache_stream.c (rdcache_ioctl): Likewise.
* mailbox/xscript-stream.c (_xscript_ctl): Likewise.
* mailbox/prog_stream.c (_prog_ioctl): Return ENOSYS if op is not
supported.
* mailbox/tcp.c (_tcp_ioctl): Likewise.

* mailbox/stream.c (mu_stream_default_buffer_size): New global.
(mu_stream_seek): Do not call seek method if the requested offset
is the same as the current one.
(mu_stream_set_buffer): Size==0 means use the default value.
(mu_stream_get_buffer): New function.
(mu_stream_truncate): Flush the buffer before truncating.

* mailbox/mime.c (mime_reset_state): New function.
(_mime_body_stream_seek): Rewrite using mime_reset_state.
(_mime_body_stream_ioctl): Return ENOSYS if op is not
supported.
(create_mime_body_stream): Reset mime state (_mime_body_stream_seek
may not be called due to the optimization in mu_stream_seek.

* mailbox/header.c (header_parse): Exit correctly if the buffer is
not terminated with a \n.

* libproto/mbox/mbox.c (mbox_open): Enforce full buffering on the
mailbox stream.
* libproto/pop/mbox.c (pop_header_fill): Minor fix.
* libproto/pop/pop3_stream.c (_POP3F_DONE)
(_POP3F_CHBUF): New constants.
(mu_pop3_stream)<done>: Remove. Replaced with flags.
<oldbuf>: New member.
(_pop3_event_cb): If _POP3F_CHBUF flag is set, restore
the initial buffering mode on the transport stream.
(mu_pop3_filter_create): Save away current buffering mode
and enforce full buffering while transferring bulk data.

* mail/from.c (hdr_from): Check return value from mu_message_get_header.
* mail/mail.c (main): Allow for MAILRC having empty value.
Always close the mailbox before exiting.

* pop3d/pop3d.c (pop3d_cfg_param): New statement output-buffer-size.
* pop3d/pop3d.h (pop3d_output_bufsize): New global.
* pop3d/retr.c (pop3d_send_payload): New function.
(pop3d_retr): Rewrite using pop3d_send_payload. Save away
current buffering mode and enforce full buffering while
transferring bulk data.
* pop3d/top.c (pop3d_top_: Likewise.
1 parent 1c398929
...@@ -65,6 +65,23 @@ enum mu_buffer_type ...@@ -65,6 +65,23 @@ enum mu_buffer_type
65 65
66 #define MU_IOCTL_LEVEL 8 66 #define MU_IOCTL_LEVEL 8
67 67
68 #define MU_IOCTL_GET_TRANSPORT_BUFFER 9
69 #define MU_IOCTL_SET_TRANSPORT_BUFFER 10
70
71 #define MU_TRANSPORT_INPUT 0
72 #define MU_TRANSPORT_OUTPUT 1
73 #define MU_TRANSPORT_VALID_TYPE(n) \
74 ((n) == MU_TRANSPORT_INPUT || (n) == MU_TRANSPORT_OUTPUT)
75
76 struct mu_buffer_query
77 {
78 int type; /* One of MU_TRANSPORT_ defines */
79 enum mu_buffer_type buftype; /* Buffer type */
80 size_t bufsize; /* Buffer size */
81 };
82
83 #define MU_STREAM_DEFBUFSIZ 8192
84 extern size_t mu_stream_default_buffer_size;
68 85
69 void mu_stream_ref (mu_stream_t stream); 86 void mu_stream_ref (mu_stream_t stream);
70 void mu_stream_unref (mu_stream_t stream); 87 void mu_stream_unref (mu_stream_t stream);
...@@ -84,6 +101,8 @@ int mu_stream_skip_input_bytes (mu_stream_t stream, mu_off_t count, ...@@ -84,6 +101,8 @@ int mu_stream_skip_input_bytes (mu_stream_t stream, mu_off_t count,
84 101
85 int mu_stream_set_buffer (mu_stream_t stream, enum mu_buffer_type type, 102 int mu_stream_set_buffer (mu_stream_t stream, enum mu_buffer_type type,
86 size_t size); 103 size_t size);
104 int mu_stream_get_buffer (mu_stream_t stream,
105 struct mu_buffer_query *qry);
87 int mu_stream_read (mu_stream_t stream, void *buf, size_t size, size_t *pread); 106 int mu_stream_read (mu_stream_t stream, void *buf, size_t size, size_t *pread);
88 int mu_stream_readdelim (mu_stream_t stream, char *buf, size_t size, 107 int mu_stream_readdelim (mu_stream_t stream, char *buf, size_t size,
89 int delim, size_t *pread); 108 int delim, size_t *pread);
......
...@@ -279,7 +279,7 @@ _tls_io_ioctl (struct _mu_stream *stream, int op, void *arg) ...@@ -279,7 +279,7 @@ _tls_io_ioctl (struct _mu_stream *stream, int op, void *arg)
279 break; 279 break;
280 280
281 default: 281 default:
282 return EINVAL; 282 return ENOSYS;
283 } 283 }
284 return 0; 284 return 0;
285 } 285 }
...@@ -507,20 +507,49 @@ static int ...@@ -507,20 +507,49 @@ static int
507 _tls_ioctl (struct _mu_stream *stream, int op, void *arg) 507 _tls_ioctl (struct _mu_stream *stream, int op, void *arg)
508 { 508 {
509 struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream; 509 struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream;
510 mu_transport_t *ptrans, trans[2];
511 510
512 switch (op) 511 switch (op)
513 { 512 {
514 case MU_IOCTL_GET_TRANSPORT: 513 case MU_IOCTL_GET_TRANSPORT:
515 if (!arg) 514 if (!arg)
516 return EINVAL; 515 return EINVAL;
517 ptrans = arg; 516 else
518 mu_stream_ioctl (sp->transport[0], MU_IOCTL_GET_TRANSPORT, trans); 517 {
519 ptrans[0] = trans[0]; 518 mu_transport_t *ptrans, trans[2];
520 mu_stream_ioctl (sp->transport[1], MU_IOCTL_GET_TRANSPORT, trans); 519
521 ptrans[1] = trans[0]; 520 ptrans = arg;
521 mu_stream_ioctl (sp->transport[0], MU_IOCTL_GET_TRANSPORT, trans);
522 ptrans[0] = trans[0];
523 mu_stream_ioctl (sp->transport[1], MU_IOCTL_GET_TRANSPORT, trans);
524 ptrans[1] = trans[0];
525 }
522 break; 526 break;
523 527
528 case MU_IOCTL_GET_TRANSPORT_BUFFER:
529 if (!arg)
530 return EINVAL;
531 else
532 {
533 struct mu_buffer_query *qp = arg;
534 if (!MU_TRANSPORT_VALID_TYPE (qp->type) ||
535 !sp->transport[qp->type])
536 return EINVAL;
537 return mu_stream_get_buffer (sp->transport[qp->type], qp);
538 }
539
540 case MU_IOCTL_SET_TRANSPORT_BUFFER:
541 if (!arg)
542 return EINVAL;
543 else
544 {
545 struct mu_buffer_query *qp = arg;
546 if (!MU_TRANSPORT_VALID_TYPE (qp->type) ||
547 !sp->transport[qp->type])
548 return EINVAL;
549 return mu_stream_set_buffer (sp->transport[qp->type],
550 qp->buftype, qp->bufsize);
551 }
552
524 default: 553 default:
525 return EINVAL; 554 return EINVAL;
526 } 555 }
......
...@@ -99,7 +99,8 @@ mbox_open (mu_mailbox_t mailbox, int flags) ...@@ -99,7 +99,8 @@ mbox_open (mu_mailbox_t mailbox, int flags)
99 99
100 if (status) 100 if (status)
101 return status; 101 return status;
102 102 mu_stream_set_buffer (mailbox->stream, mu_buffer_full, 0);
103
103 status = mu_stream_open (mailbox->stream); 104 status = mu_stream_open (mailbox->stream);
104 if (status) 105 if (status)
105 { 106 {
......
...@@ -568,24 +568,30 @@ pop_header_fill (void *data, char **pbuf, size_t *plen) ...@@ -568,24 +568,30 @@ pop_header_fill (void *data, char **pbuf, size_t *plen)
568 int status; 568 int status;
569 569
570 if (mpm->flags & _POP3_MSG_SCANNED) 570 if (mpm->flags & _POP3_MSG_SCANNED)
571 status = _pop_message_get_stream (mpm, &stream); 571 {
572 status = _pop_message_get_stream (mpm, &stream);
573 if (status == 0)
574 {
575 status = pop_header_blurb (stream, mpm->header_lines, pbuf, plen);
576 mu_stream_destroy (&stream);
577 }
578 }
572 else 579 else
573 { 580 {
574 status = mu_pop3_top (mpd->pop3, mpm->num, 0, &stream); 581 status = mu_pop3_top (mpd->pop3, mpm->num, 0, &stream);
582 if (status)
583 status = _pop_message_get_stream (mpm, &stream);
584
575 if (status == 0) 585 if (status == 0)
576 { 586 {
577 status = pop_header_blurb (stream, 0, pbuf, plen); 587 status = pop_header_blurb (stream, 0, pbuf, plen);
578 if (!mu_stream_eof (stream)) 588 if (!mu_stream_eof (stream))
579 pop_stream_drain (stream); 589 pop_stream_drain (stream);
580 mu_stream_destroy (&stream); 590 mu_stream_destroy (&stream);
581 return status;
582 } 591 }
583 else 592 return status;
584 status = _pop_message_get_stream (mpm, &stream);
585 } 593 }
586 594
587 status = pop_header_blurb (stream, mpm->header_lines, pbuf, plen);
588 mu_stream_destroy (&stream);
589 return status; 595 return status;
590 } 596 }
591 597
......
...@@ -29,11 +29,16 @@ ...@@ -29,11 +29,16 @@
29 #include <mailutils/sys/pop3.h> 29 #include <mailutils/sys/pop3.h>
30 30
31 /* Implementation of the stream for TOP and RETR. */ 31 /* Implementation of the stream for TOP and RETR. */
32
33 #define _POP3F_DONE 0x01
34 #define _POP3F_CHBUF 0x02
35
32 struct mu_pop3_stream 36 struct mu_pop3_stream
33 { 37 {
34 struct _mu_stream stream; 38 struct _mu_stream stream;
35 mu_pop3_t pop3; 39 mu_pop3_t pop3;
36 int done; 40 int flags;
41 struct mu_buffer_query oldbuf;
37 }; 42 };
38 43
39 enum pop3_decode_state 44 enum pop3_decode_state
...@@ -187,6 +192,13 @@ _pop3_event_cb (mu_stream_t str, int ev, int flags) ...@@ -187,6 +192,13 @@ _pop3_event_cb (mu_stream_t str, int ev, int flags)
187 struct mu_pop3_stream *sp = (struct mu_pop3_stream *) trans[0]; 192 struct mu_pop3_stream *sp = (struct mu_pop3_stream *) trans[0];
188 _mu_pop3_xscript_level (sp->pop3, MU_XSCRIPT_NORMAL); 193 _mu_pop3_xscript_level (sp->pop3, MU_XSCRIPT_NORMAL);
189 sp->pop3->state = MU_POP3_NO_STATE; 194 sp->pop3->state = MU_POP3_NO_STATE;
195
196 if (sp->flags & _POP3F_CHBUF)
197 {
198 mu_stream_ioctl (str, MU_IOCTL_SET_TRANSPORT_BUFFER,
199 &sp->oldbuf);
200 sp->flags = _POP3F_DONE;
201 }
190 } 202 }
191 } 203 }
192 } 204 }
...@@ -205,8 +217,27 @@ mu_pop3_filter_create (mu_stream_t *pstream, mu_stream_t stream) ...@@ -205,8 +217,27 @@ mu_pop3_filter_create (mu_stream_t *pstream, mu_stream_t stream)
205 if (rc == 0) 217 if (rc == 0)
206 { 218 {
207 mu_stream_t str = *pstream; 219 mu_stream_t str = *pstream;
220 mu_transport_t trans[2];
221
208 str->event_cb = _pop3_event_cb; 222 str->event_cb = _pop3_event_cb;
209 str->event_mask = _MU_STR_EOF; 223 str->event_mask = _MU_STR_EOF;
224
225 if (mu_stream_ioctl (str, MU_IOCTL_GET_TRANSPORT, trans) == 0)
226 {
227 struct mu_pop3_stream *sp = (struct mu_pop3_stream *) trans[0];
228 if (mu_stream_ioctl (stream, MU_IOCTL_GET_TRANSPORT_BUFFER,
229 &sp->oldbuf) == 0)
230 {
231 struct mu_buffer_query newbuf;
232
233 sp->flags |= _POP3F_CHBUF;
234 newbuf.type = MU_TRANSPORT_OUTPUT;
235 newbuf.buftype = mu_buffer_full;
236 newbuf.bufsize = 64*1024;
237 mu_stream_ioctl (str, MU_IOCTL_SET_TRANSPORT_BUFFER,
238 &newbuf);
239 }
240 }
210 } 241 }
211 return rc; 242 return rc;
212 } 243 }
...@@ -221,7 +252,7 @@ _mu_pop3_read (struct _mu_stream *str, char *buf, size_t bufsize, ...@@ -221,7 +252,7 @@ _mu_pop3_read (struct _mu_stream *str, char *buf, size_t bufsize,
221 size_t nread; 252 size_t nread;
222 int status = 0; 253 int status = 0;
223 254
224 if (sp->done) 255 if (sp->flags & _POP3F_DONE)
225 nread = 0; 256 nread = 0;
226 else 257 else
227 { 258 {
...@@ -229,7 +260,7 @@ _mu_pop3_read (struct _mu_stream *str, char *buf, size_t bufsize, ...@@ -229,7 +260,7 @@ _mu_pop3_read (struct _mu_stream *str, char *buf, size_t bufsize,
229 if (status == 0 && nread == 0) 260 if (status == 0 && nread == 0)
230 { 261 {
231 pop3->state = MU_POP3_NO_STATE; 262 pop3->state = MU_POP3_NO_STATE;
232 sp->done = 1; 263 sp->flags |= _POP3F_DONE;
233 } 264 }
234 } 265 }
235 *pnread = nread; 266 *pnread = nread;
...@@ -245,7 +276,7 @@ _mu_pop3_readdelim (struct _mu_stream *str, char *buf, size_t bufsize, ...@@ -245,7 +276,7 @@ _mu_pop3_readdelim (struct _mu_stream *str, char *buf, size_t bufsize,
245 size_t nread; 276 size_t nread;
246 int status = 0; 277 int status = 0;
247 278
248 if (sp->done) 279 if (sp->flags & _POP3F_DONE)
249 nread = 0; 280 nread = 0;
250 else 281 else
251 { 282 {
...@@ -254,7 +285,7 @@ _mu_pop3_readdelim (struct _mu_stream *str, char *buf, size_t bufsize, ...@@ -254,7 +285,7 @@ _mu_pop3_readdelim (struct _mu_stream *str, char *buf, size_t bufsize,
254 if (status == 0 && nread == 0) 285 if (status == 0 && nread == 0)
255 { 286 {
256 pop3->state = MU_POP3_NO_STATE; 287 pop3->state = MU_POP3_NO_STATE;
257 sp->done = 1; 288 sp->flags |= _POP3F_DONE;
258 } 289 }
259 } 290 }
260 *pnread = nread; 291 *pnread = nread;
...@@ -294,7 +325,7 @@ mu_pop3_stream_create (mu_pop3_t pop3, mu_stream_t *pstream) ...@@ -294,7 +325,7 @@ mu_pop3_stream_create (mu_pop3_t pop3, mu_stream_t *pstream)
294 sp->stream.wait = _mu_pop3_wait; 325 sp->stream.wait = _mu_pop3_wait;
295 326
296 sp->pop3 = pop3; 327 sp->pop3 = pop3;
297 sp->done = 0; 328 sp->flags = 0;
298 str = (mu_stream_t) sp; 329 str = (mu_stream_t) sp;
299 mu_stream_set_buffer (str, mu_buffer_line, 1024); 330 mu_stream_set_buffer (str, mu_buffer_line, 1024);
300 331
......
...@@ -231,7 +231,8 @@ hdr_from (struct header_call_args *args, void *data) ...@@ -231,7 +231,8 @@ hdr_from (struct header_call_args *args, void *data)
231 { 231 {
232 mu_header_t hdr; 232 mu_header_t hdr;
233 233
234 mu_message_get_header (args->msg, &hdr); 234 if (mu_message_get_header (args->msg, &hdr))
235 abort ();
235 if (mu_header_aget_value_unfold (hdr, MU_HEADER_FROM, &from) == 0) 236 if (mu_header_aget_value_unfold (hdr, MU_HEADER_FROM, &from) == 0)
236 { 237 {
237 mu_address_t address = NULL; 238 mu_address_t address = NULL;
......
...@@ -321,10 +321,18 @@ mail_diag_stderr_printer (void *data, mu_log_level_t level, const char *buf) ...@@ -321,10 +321,18 @@ mail_diag_stderr_printer (void *data, mu_log_level_t level, const char *buf)
321 return 0; 321 return 0;
322 } 322 }
323 323
324 static void
325 do_and_quit (const char *command)
326 {
327 int rc = util_do_command (command);
328 mu_mailbox_close (mbox);
329 exit (rc != 0);
330 }
331
324 int 332 int
325 main (int argc, char **argv) 333 main (int argc, char **argv)
326 { 334 {
327 char *mode = NULL, *prompt = NULL; 335 char *mode = NULL, *prompt = NULL, *p;
328 struct arguments args; 336 struct arguments args;
329 int i, rc; 337 int i, rc;
330 338
...@@ -376,13 +384,9 @@ main (int argc, char **argv) ...@@ -376,13 +384,9 @@ main (int argc, char **argv)
376 util_do_command ("set columns=%d", util_getcols ()); 384 util_do_command ("set columns=%d", util_getcols ());
377 385
378 /* Set the default mailer to sendmail. */ 386 /* Set the default mailer to sendmail. */
379 { 387 mailvar_set ("sendmail",
380 char *mailer_name = alloca (strlen ("sendmail:") 388 xstrdup ("sendmail:" PATH_SENDMAIL), mailvar_type_string,
381 + strlen (PATH_SENDMAIL) + 1); 389 MOPTF_OVERWRITE);
382 sprintf (mailer_name, "sendmail:%s", PATH_SENDMAIL);
383 mailvar_set ("sendmail", mailer_name, mailvar_type_string,
384 MOPTF_OVERWRITE);
385 }
386 390
387 args.argc = 0; 391 args.argc = 0;
388 args.argv = NULL; 392 args.argv = NULL;
...@@ -401,7 +405,8 @@ main (int argc, char **argv) ...@@ -401,7 +405,8 @@ main (int argc, char **argv)
401 /* read system-wide mail.rc and user's .mailrc */ 405 /* read system-wide mail.rc and user's .mailrc */
402 if (mailvar_get (NULL, "rc", mailvar_type_boolean, 0) == 0) 406 if (mailvar_get (NULL, "rc", mailvar_type_boolean, 0) == 0)
403 util_do_command ("source %s", SITE_MAIL_RC); 407 util_do_command ("source %s", SITE_MAIL_RC);
404 util_do_command ("source %s", getenv ("MAILRC")); 408 if ((p = getenv ("MAILRC")) && *p)
409 util_do_command ("source %s", getenv ("MAILRC"));
405 410
406 util_run_cached_commands (&command_list); 411 util_run_cached_commands (&command_list);
407 412
...@@ -476,11 +481,14 @@ main (int argc, char **argv) ...@@ -476,11 +481,14 @@ main (int argc, char **argv)
476 } 481 }
477 482
478 if (strcmp (mode, "exist") == 0) 483 if (strcmp (mode, "exist") == 0)
479 return (total < 1) ? 1 : 0; 484 {
485 mu_mailbox_close (mbox);
486 return (total < 1) ? 1 : 0;
487 }
480 else if (strcmp (mode, "print") == 0) 488 else if (strcmp (mode, "print") == 0)
481 return util_do_command ("print *"); 489 do_and_quit ("print *");
482 else if (strcmp (mode, "headers") == 0) 490 else if (strcmp (mode, "headers") == 0)
483 return util_do_command ("from *"); 491 do_and_quit ("from *");
484 else if (strcmp (mode, "read")) 492 else if (strcmp (mode, "read"))
485 { 493 {
486 util_error (_("Unknown mode `%s'"), mode); 494 util_error (_("Unknown mode `%s'"), mode);
......
...@@ -217,8 +217,20 @@ fd_ioctl (struct _mu_stream *str, int code, void *ptr) ...@@ -217,8 +217,20 @@ fd_ioctl (struct _mu_stream *str, int code, void *ptr)
217 fstr->fd = (int) ptrans[0]; 217 fstr->fd = (int) ptrans[0];
218 break; 218 break;
219 219
220 case MU_IOCTL_GET_TRANSPORT_BUFFER:
221 {
222 struct mu_buffer_query *qp = ptr;
223 return mu_stream_get_buffer (str, qp);
224 }
225
226 case MU_IOCTL_SET_TRANSPORT_BUFFER:
227 {
228 struct mu_buffer_query *qp = ptr;
229 return mu_stream_set_buffer (str, qp->buftype, qp->bufsize);
230 }
231
220 default: 232 default:
221 return EINVAL; 233 return ENOSYS;
222 } 234 }
223 return 0; 235 return 0;
224 } 236 }
......
...@@ -401,10 +401,12 @@ _icvt_ioctl (mu_stream_t stream, int code, void *ptr) ...@@ -401,10 +401,12 @@ _icvt_ioctl (mu_stream_t stream, int code, void *ptr)
401 break; 401 break;
402 402
403 case MU_IOCTL_SWAP_STREAM: 403 case MU_IOCTL_SWAP_STREAM:
404 case MU_IOCTL_GET_TRANSPORT_BUFFER:
405 case MU_IOCTL_SET_TRANSPORT_BUFFER:
404 return mu_stream_ioctl (s->transport, code, ptr); 406 return mu_stream_ioctl (s->transport, code, ptr);
405 407
406 default: 408 default:
407 return EINVAL; 409 return ENOSYS;
408 } 410 }
409 return 0; 411 return 0;
410 } 412 }
......
...@@ -344,7 +344,11 @@ header_parse (mu_header_t header, const char *blurb, int len) ...@@ -344,7 +344,11 @@ header_parse (mu_header_t header, const char *blurb, int len)
344 { 344 {
345 header_end = memchr (header_start2, '\n', len); 345 header_end = memchr (header_start2, '\n', len);
346 if (header_end == NULL) 346 if (header_end == NULL)
347 break; 347 {
348 header_end = header_start2 + len;
349 len = 0;
350 break;
351 }
348 else 352 else
349 { 353 {
350 len -= (header_end - header_start2 + 1); 354 len -= (header_end - header_start2 + 1);
...@@ -431,7 +435,7 @@ mu_header_create (mu_header_t *ph, const char *blurb, size_t len) ...@@ -431,7 +435,7 @@ mu_header_create (mu_header_t *ph, const char *blurb, size_t len)
431 { 435 {
432 mu_header_t header; 436 mu_header_t header;
433 int status = 0; 437 int status = 0;
434 438
435 header = calloc (1, sizeof (*header)); 439 header = calloc (1, sizeof (*header));
436 if (header == NULL) 440 if (header == NULL)
437 return ENOMEM; 441 return ENOMEM;
......
...@@ -153,9 +153,21 @@ _iostream_ctl (struct _mu_stream *str, int op, void *arg) ...@@ -153,9 +153,21 @@ _iostream_ctl (struct _mu_stream *str, int op, void *arg)
153 if (!arg) 153 if (!arg)
154 return EINVAL; 154 return EINVAL;
155 return _mu_stream_swap_streams (str, sp->transport, arg, 0); 155 return _mu_stream_swap_streams (str, sp->transport, arg, 0);
156
157 case MU_IOCTL_GET_TRANSPORT_BUFFER:
158 case MU_IOCTL_SET_TRANSPORT_BUFFER:
159 if (!arg)
160 return EINVAL;
161 else
162 {
163 struct mu_buffer_query *qp = arg;
164 if (!MU_TRANSPORT_VALID_TYPE (qp->type) || !sp->transport[qp->type])
165 return EINVAL;
166 return mu_stream_ioctl (sp->transport[qp->type], op, arg);
167 }
156 168
157 default: 169 default:
158 return EINVAL; 170 return ENOSYS;
159 } 171 }
160 return 0; 172 return 0;
161 } 173 }
......
...@@ -218,8 +218,20 @@ _mapfile_ioctl (struct _mu_stream *str, int code, void *ptr) ...@@ -218,8 +218,20 @@ _mapfile_ioctl (struct _mu_stream *str, int code, void *ptr)
218 ptrans[1] = NULL; 218 ptrans[1] = NULL;
219 break; 219 break;
220 220
221 case MU_IOCTL_GET_TRANSPORT_BUFFER:
222 {
223 struct mu_buffer_query *qp = ptr;
224 return mu_stream_get_buffer (str, qp);
225 }
226
227 case MU_IOCTL_SET_TRANSPORT_BUFFER:
228 {
229 struct mu_buffer_query *qp = ptr;
230 return mu_stream_set_buffer (str, qp->buftype, qp->bufsize);
231 }
232
221 default: 233 default:
222 return EINVAL; 234 return ENOSYS;
223 } 235 }
224 return 0; 236 return 0;
225 } 237 }
......
...@@ -159,8 +159,20 @@ _memory_ioctl (struct _mu_stream *stream, int code, void *ptr) ...@@ -159,8 +159,20 @@ _memory_ioctl (struct _mu_stream *stream, int code, void *ptr)
159 ptrans[1] = NULL; 159 ptrans[1] = NULL;
160 break; 160 break;
161 161
162 case MU_IOCTL_GET_TRANSPORT_BUFFER:
163 {
164 struct mu_buffer_query *qp = ptr;
165 return mu_stream_get_buffer (stream, qp);
166 }
167
168 case MU_IOCTL_SET_TRANSPORT_BUFFER:
169 {
170 struct mu_buffer_query *qp = ptr;
171 return mu_stream_set_buffer (stream, qp->buftype, qp->bufsize);
172 }
173
162 default: 174 default:
163 return EINVAL; 175 return ENOSYS;
164 } 176 }
165 return 0; 177 return 0;
166 } 178 }
......
...@@ -579,6 +579,17 @@ _mime_body_stream_size (mu_stream_t stream, mu_off_t *psize) ...@@ -579,6 +579,17 @@ _mime_body_stream_size (mu_stream_t stream, mu_off_t *psize)
579 return rc; 579 return rc;
580 } 580 }
581 581
582 static void
583 mime_reset_state (mu_mime_t mime)
584 { /* reset message */
585 mime->cur_offset = 0;
586 mime->cur_part = 0;
587 mime->part_offset = 0;
588
589 if (mime->nmtp_parts > 1)
590 mime->flags |= MIME_INSERT_BOUNDARY;
591 }
592
582 /* FIXME: The seek method is defective */ 593 /* FIXME: The seek method is defective */
583 static int 594 static int
584 _mime_body_stream_seek (mu_stream_t stream, mu_off_t off, mu_off_t *presult) 595 _mime_body_stream_seek (mu_stream_t stream, mu_off_t off, mu_off_t *presult)
...@@ -587,14 +598,7 @@ _mime_body_stream_seek (mu_stream_t stream, mu_off_t off, mu_off_t *presult) ...@@ -587,14 +598,7 @@ _mime_body_stream_seek (mu_stream_t stream, mu_off_t off, mu_off_t *presult)
587 mu_mime_t mime = mstr->mime; 598 mu_mime_t mime = mstr->mime;
588 599
589 if (off == 0) 600 if (off == 0)
590 { /* reset message */ 601 mime_reset_state (mime);
591 mime->cur_offset = 0;
592 mime->cur_part = 0;
593 mime->part_offset = 0;
594
595 if (mime->nmtp_parts > 1)
596 mime->flags |= MIME_INSERT_BOUNDARY;
597 }
598 602
599 if (off != mime->cur_offset) 603 if (off != mime->cur_offset)
600 return ESPIPE; 604 return ESPIPE;
...@@ -767,7 +771,7 @@ _mime_body_stream_ioctl (mu_stream_t stream, int code, void *arg) ...@@ -767,7 +771,7 @@ _mime_body_stream_ioctl (mu_stream_t stream, int code, void *arg)
767 break; 771 break;
768 772
769 default: 773 default:
770 rc = EINVAL; 774 rc = ENOSYS;
771 } 775 }
772 return rc; 776 return rc;
773 } 777 }
...@@ -785,6 +789,7 @@ create_mime_body_stream (mu_stream_t *pstr, mu_mime_t mime) ...@@ -785,6 +789,7 @@ create_mime_body_stream (mu_stream_t *pstr, mu_mime_t mime)
785 sp->stream.ctl = _mime_body_stream_ioctl; 789 sp->stream.ctl = _mime_body_stream_ioctl;
786 sp->stream.size = _mime_body_stream_size; 790 sp->stream.size = _mime_body_stream_size;
787 sp->mime = mime; 791 sp->mime = mime;
792 mime_reset_state (mime);
788 *pstr = (mu_stream_t) sp; 793 *pstr = (mu_stream_t) sp;
789 return 0; 794 return 0;
790 } 795 }
......
...@@ -393,7 +393,7 @@ _prog_ioctl (struct _mu_stream *str, int code, void *ptr) ...@@ -393,7 +393,7 @@ _prog_ioctl (struct _mu_stream *str, int code, void *ptr)
393 break; 393 break;
394 394
395 default: 395 default:
396 return EINVAL; 396 return ENOSYS;
397 } 397 }
398 return 0; 398 return 0;
399 } 399 }
......
...@@ -131,8 +131,20 @@ rdcache_ioctl (struct _mu_stream *str, int op, void *arg) ...@@ -131,8 +131,20 @@ rdcache_ioctl (struct _mu_stream *str, int op, void *arg)
131 ptrans[1] = NULL; 131 ptrans[1] = NULL;
132 break; 132 break;
133 133
134 case MU_IOCTL_GET_TRANSPORT_BUFFER:
135 case MU_IOCTL_SET_TRANSPORT_BUFFER:
136 if (!arg)
137 return EINVAL;
138 else
139 {
140 struct mu_buffer_query *qp = arg;
141 if (qp->type != MU_TRANSPORT_INPUT || !sp->transport)
142 return EINVAL;
143 return mu_stream_ioctl (sp->transport, op, arg);
144 }
145
134 default: 146 default:
135 return EINVAL; 147 return ENOSYS;
136 } 148 }
137 return 0; 149 return 0;
138 } 150 }
......
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
32 #include <mailutils/stream.h> 32 #include <mailutils/stream.h>
33 #include <mailutils/sys/stream.h> 33 #include <mailutils/sys/stream.h>
34 34
35 size_t mu_stream_default_buffer_size = MU_STREAM_DEFBUFSIZ;
36
35 static void 37 static void
36 _stream_setflag (struct _mu_stream *stream, int flag) 38 _stream_setflag (struct _mu_stream *stream, int flag)
37 { 39 {
...@@ -351,7 +353,7 @@ mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence, ...@@ -351,7 +353,7 @@ mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence,
351 return mu_stream_seterr (stream, EINVAL, 1); 353 return mu_stream_seterr (stream, EINVAL, 1);
352 } 354 }
353 355
354 if (stream->buftype == mu_buffer_none 356 if ((stream->buftype == mu_buffer_none && offset != stream->offset)
355 || offset < stream->offset 357 || offset < stream->offset
356 || offset > stream->offset + _stream_buffer_offset (stream)) 358 || offset > stream->offset + _stream_buffer_offset (stream))
357 { 359 {
...@@ -442,7 +444,7 @@ mu_stream_set_buffer (mu_stream_t stream, enum mu_buffer_type type, ...@@ -442,7 +444,7 @@ mu_stream_set_buffer (mu_stream_t stream, enum mu_buffer_type type,
442 size_t size) 444 size_t size)
443 { 445 {
444 if (size == 0) 446 if (size == 0)
445 type = mu_buffer_none; 447 size = mu_stream_default_buffer_size;
446 448
447 if (stream->buffer) 449 if (stream->buffer)
448 { 450 {
...@@ -471,6 +473,14 @@ mu_stream_set_buffer (mu_stream_t stream, enum mu_buffer_type type, ...@@ -471,6 +473,14 @@ mu_stream_set_buffer (mu_stream_t stream, enum mu_buffer_type type,
471 } 473 }
472 474
473 int 475 int
476 mu_stream_get_buffer (mu_stream_t stream, struct mu_buffer_query *qry)
477 {
478 qry->buftype = stream->buftype;
479 qry->bufsize = stream->bufsize;
480 return 0;
481 }
482
483 int
474 mu_stream_read_unbuffered (mu_stream_t stream, void *buf, size_t size, 484 mu_stream_read_unbuffered (mu_stream_t stream, void *buf, size_t size,
475 int full_read, 485 int full_read,
476 size_t *pnread) 486 size_t *pnread)
...@@ -953,7 +963,13 @@ int ...@@ -953,7 +963,13 @@ int
953 mu_stream_truncate (mu_stream_t stream, mu_off_t size) 963 mu_stream_truncate (mu_stream_t stream, mu_off_t size)
954 { 964 {
955 if (stream->truncate) 965 if (stream->truncate)
956 return stream->truncate (stream, size); 966 {
967 int rc;
968
969 if ((rc = _stream_flush_buffer (stream, 1)))
970 return rc;
971 return stream->truncate (stream, size);
972 }
957 return ENOSYS; 973 return ENOSYS;
958 } 974 }
959 975
......
...@@ -209,7 +209,7 @@ _tcp_ioctl (mu_stream_t stream, int code, void *ptr) ...@@ -209,7 +209,7 @@ _tcp_ioctl (mu_stream_t stream, int code, void *ptr)
209 break; 209 break;
210 210
211 default: 211 default:
212 return EINVAL; 212 return ENOSYS;
213 } 213 }
214 return 0; 214 return 0;
215 } 215 }
......
...@@ -315,6 +315,15 @@ _xscript_ctl (struct _mu_stream *str, int op, void *arg) ...@@ -315,6 +315,15 @@ _xscript_ctl (struct _mu_stream *str, int op, void *arg)
315 } 315 }
316 break; 316 break;
317 317
318 case MU_IOCTL_GET_TRANSPORT_BUFFER:
319 case MU_IOCTL_SET_TRANSPORT_BUFFER:
320 {
321 struct mu_transport_buffer_query *qp = arg;
322 if (!sp->transport)
323 return EINVAL;
324 return mu_stream_ioctl (sp->transport, op, arg);
325 }
326
318 case MU_IOCTL_LEVEL: 327 case MU_IOCTL_LEVEL:
319 if (!arg) 328 if (!arg)
320 return EINVAL; 329 return EINVAL;
......
...@@ -115,6 +115,8 @@ static struct mu_cfg_param pop3d_cfg_param[] = { ...@@ -115,6 +115,8 @@ static struct mu_cfg_param pop3d_cfg_param[] = {
115 N_("Set the bulletin database file name."), 115 N_("Set the bulletin database file name."),
116 N_("file") }, 116 N_("file") },
117 #endif 117 #endif
118 { "output-buffer-size", mu_cfg_size, &pop3d_output_bufsize, 0, NULL,
119 N_("Size of the output buffer.") },
118 { ".server", mu_cfg_section, NULL, 0, NULL, 120 { ".server", mu_cfg_section, NULL, 0, NULL,
119 N_("Server configuration.") }, 121 N_("Server configuration.") },
120 { "transcript", mu_cfg_bool, &pop3d_transcript, 0, NULL, 122 { "transcript", mu_cfg_bool, &pop3d_transcript, 0, NULL,
......
...@@ -201,6 +201,7 @@ extern int undelete_on_startup; ...@@ -201,6 +201,7 @@ extern int undelete_on_startup;
201 extern struct mu_auth_data *auth_data; 201 extern struct mu_auth_data *auth_data;
202 extern unsigned int idle_timeout; 202 extern unsigned int idle_timeout;
203 extern int pop3d_transcript; 203 extern int pop3d_transcript;
204 extern size_t pop3d_output_bufsize;
204 205
205 extern pop3d_command_handler_t pop3d_find_command (const char *name); 206 extern pop3d_command_handler_t pop3d_find_command (const char *name);
206 207
......
...@@ -17,6 +17,31 @@ ...@@ -17,6 +17,31 @@
17 17
18 #include "pop3d.h" 18 #include "pop3d.h"
19 19
20 size_t pop3d_output_bufsize = 64 * 1024;
21
22 void
23 pop3d_send_payload (mu_stream_t stream)
24 {
25 struct mu_buffer_query oldbuf, newbuf;
26 int xscript_level = set_xscript_level (MU_XSCRIPT_PAYLOAD);
27
28 oldbuf.type = MU_TRANSPORT_OUTPUT;
29 mu_stream_ioctl (iostream, MU_IOCTL_GET_TRANSPORT_BUFFER,
30 &oldbuf);
31 newbuf.type = MU_TRANSPORT_OUTPUT;
32 newbuf.buftype = mu_buffer_full;
33 newbuf.bufsize = pop3d_output_bufsize;
34 mu_stream_ioctl (iostream, MU_IOCTL_SET_TRANSPORT_BUFFER,
35 &newbuf);
36
37 mu_stream_copy (iostream, stream, 0, NULL);
38 pop3d_outf (".\n");
39
40 mu_stream_ioctl (iostream, MU_IOCTL_SET_TRANSPORT_BUFFER,
41 &oldbuf);
42 set_xscript_level (xscript_level);
43 }
44
20 /* Prints out the specified message */ 45 /* Prints out the specified message */
21 46
22 int 47 int
...@@ -26,7 +51,6 @@ pop3d_retr (char *arg) ...@@ -26,7 +51,6 @@ pop3d_retr (char *arg)
26 mu_message_t msg = NULL; 51 mu_message_t msg = NULL;
27 mu_attribute_t attr = NULL; 52 mu_attribute_t attr = NULL;
28 mu_stream_t stream; 53 mu_stream_t stream;
29 int xscript_level;
30 54
31 if ((strlen (arg) == 0) || (strchr (arg, ' ') != NULL)) 55 if ((strlen (arg) == 0) || (strchr (arg, ' ') != NULL))
32 return ERR_BAD_ARGS; 56 return ERR_BAD_ARGS;
...@@ -47,18 +71,14 @@ pop3d_retr (char *arg) ...@@ -47,18 +71,14 @@ pop3d_retr (char *arg)
47 return ERR_UNKNOWN; 71 return ERR_UNKNOWN;
48 72
49 pop3d_outf ("+OK\n"); 73 pop3d_outf ("+OK\n");
50 xscript_level = set_xscript_level (MU_XSCRIPT_PAYLOAD); 74 pop3d_send_payload (stream);
51 mu_stream_copy (iostream, stream, 0, NULL);
52 mu_stream_destroy (&stream); 75 mu_stream_destroy (&stream);
53 76
54 if (!mu_attribute_is_read (attr)) 77 if (!mu_attribute_is_read (attr))
55 mu_attribute_set_read (attr); 78 mu_attribute_set_read (attr);
56 79
57 pop3d_mark_retr (attr); 80 pop3d_mark_retr (attr);
58 81
59 pop3d_outf (".\n"); 82
60
61 set_xscript_level (xscript_level);
62
63 return OK; 83 return OK;
64 } 84 }
......
...@@ -31,6 +31,7 @@ pop3d_top (char *arg) ...@@ -31,6 +31,7 @@ pop3d_top (char *arg)
31 mu_stream_t stream; 31 mu_stream_t stream;
32 char *mesgc, *linesc, *p; 32 char *mesgc, *linesc, *p;
33 int xscript_level; 33 int xscript_level;
34 struct mu_buffer_query oldbuf, newbuf;
34 35
35 if (strlen (arg) == 0) 36 if (strlen (arg) == 0)
36 return ERR_BAD_ARGS; 37 return ERR_BAD_ARGS;
...@@ -64,6 +65,14 @@ pop3d_top (char *arg) ...@@ -64,6 +65,14 @@ pop3d_top (char *arg)
64 pop3d_outf ("+OK\n"); 65 pop3d_outf ("+OK\n");
65 66
66 xscript_level = set_xscript_level (MU_XSCRIPT_PAYLOAD); 67 xscript_level = set_xscript_level (MU_XSCRIPT_PAYLOAD);
68 oldbuf.type = MU_TRANSPORT_OUTPUT;
69 mu_stream_ioctl (iostream, MU_IOCTL_GET_TRANSPORT_BUFFER,
70 &oldbuf);
71 newbuf.type = MU_TRANSPORT_OUTPUT;
72 newbuf.buftype = mu_buffer_full;
73 newbuf.bufsize = pop3d_output_bufsize;
74 mu_stream_ioctl (iostream, MU_IOCTL_SET_TRANSPORT_BUFFER,
75 &newbuf);
67 76
68 mu_stream_copy (iostream, stream, 0, NULL); 77 mu_stream_copy (iostream, stream, 0, NULL);
69 pop3d_outf ("\n"); 78 pop3d_outf ("\n");
...@@ -88,6 +97,9 @@ pop3d_top (char *arg) ...@@ -88,6 +97,9 @@ pop3d_top (char *arg)
88 97
89 pop3d_outf (".\n"); 98 pop3d_outf (".\n");
90 99
100 mu_stream_ioctl (iostream, MU_IOCTL_SET_TRANSPORT_BUFFER,
101 &oldbuf);
102
91 set_xscript_level (xscript_level); 103 set_xscript_level (xscript_level);
92 104
93 return OK; 105 return OK;
......