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.
Showing
23 changed files
with
289 additions
and
63 deletions
... | @@ -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; | ... | ... |
-
Please register or sign in to post a comment