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
#define MU_IOCTL_LEVEL 8
#define MU_IOCTL_GET_TRANSPORT_BUFFER 9
#define MU_IOCTL_SET_TRANSPORT_BUFFER 10
#define MU_TRANSPORT_INPUT 0
#define MU_TRANSPORT_OUTPUT 1
#define MU_TRANSPORT_VALID_TYPE(n) \
((n) == MU_TRANSPORT_INPUT || (n) == MU_TRANSPORT_OUTPUT)
struct mu_buffer_query
{
int type; /* One of MU_TRANSPORT_ defines */
enum mu_buffer_type buftype; /* Buffer type */
size_t bufsize; /* Buffer size */
};
#define MU_STREAM_DEFBUFSIZ 8192
extern size_t mu_stream_default_buffer_size;
void mu_stream_ref (mu_stream_t stream);
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,
int mu_stream_set_buffer (mu_stream_t stream, enum mu_buffer_type type,
size_t size);
int mu_stream_get_buffer (mu_stream_t stream,
struct mu_buffer_query *qry);
int mu_stream_read (mu_stream_t stream, void *buf, size_t size, size_t *pread);
int mu_stream_readdelim (mu_stream_t stream, char *buf, size_t size,
int delim, size_t *pread);
......
......@@ -279,7 +279,7 @@ _tls_io_ioctl (struct _mu_stream *stream, int op, void *arg)
break;
default:
return EINVAL;
return ENOSYS;
}
return 0;
}
......@@ -507,20 +507,49 @@ static int
_tls_ioctl (struct _mu_stream *stream, int op, void *arg)
{
struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream;
mu_transport_t *ptrans, trans[2];
switch (op)
{
case MU_IOCTL_GET_TRANSPORT:
if (!arg)
return EINVAL;
else
{
mu_transport_t *ptrans, trans[2];
ptrans = arg;
mu_stream_ioctl (sp->transport[0], MU_IOCTL_GET_TRANSPORT, trans);
ptrans[0] = trans[0];
mu_stream_ioctl (sp->transport[1], MU_IOCTL_GET_TRANSPORT, trans);
ptrans[1] = trans[0];
}
break;
case MU_IOCTL_GET_TRANSPORT_BUFFER:
if (!arg)
return EINVAL;
else
{
struct mu_buffer_query *qp = arg;
if (!MU_TRANSPORT_VALID_TYPE (qp->type) ||
!sp->transport[qp->type])
return EINVAL;
return mu_stream_get_buffer (sp->transport[qp->type], qp);
}
case MU_IOCTL_SET_TRANSPORT_BUFFER:
if (!arg)
return EINVAL;
else
{
struct mu_buffer_query *qp = arg;
if (!MU_TRANSPORT_VALID_TYPE (qp->type) ||
!sp->transport[qp->type])
return EINVAL;
return mu_stream_set_buffer (sp->transport[qp->type],
qp->buftype, qp->bufsize);
}
default:
return EINVAL;
}
......
......@@ -99,6 +99,7 @@ mbox_open (mu_mailbox_t mailbox, int flags)
if (status)
return status;
mu_stream_set_buffer (mailbox->stream, mu_buffer_full, 0);
status = mu_stream_open (mailbox->stream);
if (status)
......
......@@ -568,24 +568,30 @@ pop_header_fill (void *data, char **pbuf, size_t *plen)
int status;
if (mpm->flags & _POP3_MSG_SCANNED)
{
status = _pop_message_get_stream (mpm, &stream);
if (status == 0)
{
status = pop_header_blurb (stream, mpm->header_lines, pbuf, plen);
mu_stream_destroy (&stream);
}
}
else
{
status = mu_pop3_top (mpd->pop3, mpm->num, 0, &stream);
if (status)
status = _pop_message_get_stream (mpm, &stream);
if (status == 0)
{
status = pop_header_blurb (stream, 0, pbuf, plen);
if (!mu_stream_eof (stream))
pop_stream_drain (stream);
mu_stream_destroy (&stream);
return status;
}
else
status = _pop_message_get_stream (mpm, &stream);
return status;
}
status = pop_header_blurb (stream, mpm->header_lines, pbuf, plen);
mu_stream_destroy (&stream);
return status;
}
......
......@@ -29,11 +29,16 @@
#include <mailutils/sys/pop3.h>
/* Implementation of the stream for TOP and RETR. */
#define _POP3F_DONE 0x01
#define _POP3F_CHBUF 0x02
struct mu_pop3_stream
{
struct _mu_stream stream;
mu_pop3_t pop3;
int done;
int flags;
struct mu_buffer_query oldbuf;
};
enum pop3_decode_state
......@@ -187,6 +192,13 @@ _pop3_event_cb (mu_stream_t str, int ev, int flags)
struct mu_pop3_stream *sp = (struct mu_pop3_stream *) trans[0];
_mu_pop3_xscript_level (sp->pop3, MU_XSCRIPT_NORMAL);
sp->pop3->state = MU_POP3_NO_STATE;
if (sp->flags & _POP3F_CHBUF)
{
mu_stream_ioctl (str, MU_IOCTL_SET_TRANSPORT_BUFFER,
&sp->oldbuf);
sp->flags = _POP3F_DONE;
}
}
}
}
......@@ -205,8 +217,27 @@ mu_pop3_filter_create (mu_stream_t *pstream, mu_stream_t stream)
if (rc == 0)
{
mu_stream_t str = *pstream;
mu_transport_t trans[2];
str->event_cb = _pop3_event_cb;
str->event_mask = _MU_STR_EOF;
if (mu_stream_ioctl (str, MU_IOCTL_GET_TRANSPORT, trans) == 0)
{
struct mu_pop3_stream *sp = (struct mu_pop3_stream *) trans[0];
if (mu_stream_ioctl (stream, MU_IOCTL_GET_TRANSPORT_BUFFER,
&sp->oldbuf) == 0)
{
struct mu_buffer_query newbuf;
sp->flags |= _POP3F_CHBUF;
newbuf.type = MU_TRANSPORT_OUTPUT;
newbuf.buftype = mu_buffer_full;
newbuf.bufsize = 64*1024;
mu_stream_ioctl (str, MU_IOCTL_SET_TRANSPORT_BUFFER,
&newbuf);
}
}
}
return rc;
}
......@@ -221,7 +252,7 @@ _mu_pop3_read (struct _mu_stream *str, char *buf, size_t bufsize,
size_t nread;
int status = 0;
if (sp->done)
if (sp->flags & _POP3F_DONE)
nread = 0;
else
{
......@@ -229,7 +260,7 @@ _mu_pop3_read (struct _mu_stream *str, char *buf, size_t bufsize,
if (status == 0 && nread == 0)
{
pop3->state = MU_POP3_NO_STATE;
sp->done = 1;
sp->flags |= _POP3F_DONE;
}
}
*pnread = nread;
......@@ -245,7 +276,7 @@ _mu_pop3_readdelim (struct _mu_stream *str, char *buf, size_t bufsize,
size_t nread;
int status = 0;
if (sp->done)
if (sp->flags & _POP3F_DONE)
nread = 0;
else
{
......@@ -254,7 +285,7 @@ _mu_pop3_readdelim (struct _mu_stream *str, char *buf, size_t bufsize,
if (status == 0 && nread == 0)
{
pop3->state = MU_POP3_NO_STATE;
sp->done = 1;
sp->flags |= _POP3F_DONE;
}
}
*pnread = nread;
......@@ -294,7 +325,7 @@ mu_pop3_stream_create (mu_pop3_t pop3, mu_stream_t *pstream)
sp->stream.wait = _mu_pop3_wait;
sp->pop3 = pop3;
sp->done = 0;
sp->flags = 0;
str = (mu_stream_t) sp;
mu_stream_set_buffer (str, mu_buffer_line, 1024);
......
......@@ -231,7 +231,8 @@ hdr_from (struct header_call_args *args, void *data)
{
mu_header_t hdr;
mu_message_get_header (args->msg, &hdr);
if (mu_message_get_header (args->msg, &hdr))
abort ();
if (mu_header_aget_value_unfold (hdr, MU_HEADER_FROM, &from) == 0)
{
mu_address_t address = NULL;
......
......@@ -321,10 +321,18 @@ mail_diag_stderr_printer (void *data, mu_log_level_t level, const char *buf)
return 0;
}
static void
do_and_quit (const char *command)
{
int rc = util_do_command (command);
mu_mailbox_close (mbox);
exit (rc != 0);
}
int
main (int argc, char **argv)
{
char *mode = NULL, *prompt = NULL;
char *mode = NULL, *prompt = NULL, *p;
struct arguments args;
int i, rc;
......@@ -376,13 +384,9 @@ main (int argc, char **argv)
util_do_command ("set columns=%d", util_getcols ());
/* Set the default mailer to sendmail. */
{
char *mailer_name = alloca (strlen ("sendmail:")
+ strlen (PATH_SENDMAIL) + 1);
sprintf (mailer_name, "sendmail:%s", PATH_SENDMAIL);
mailvar_set ("sendmail", mailer_name, mailvar_type_string,
mailvar_set ("sendmail",
xstrdup ("sendmail:" PATH_SENDMAIL), mailvar_type_string,
MOPTF_OVERWRITE);
}
args.argc = 0;
args.argv = NULL;
......@@ -401,6 +405,7 @@ main (int argc, char **argv)
/* read system-wide mail.rc and user's .mailrc */
if (mailvar_get (NULL, "rc", mailvar_type_boolean, 0) == 0)
util_do_command ("source %s", SITE_MAIL_RC);
if ((p = getenv ("MAILRC")) && *p)
util_do_command ("source %s", getenv ("MAILRC"));
util_run_cached_commands (&command_list);
......@@ -476,11 +481,14 @@ main (int argc, char **argv)
}
if (strcmp (mode, "exist") == 0)
{
mu_mailbox_close (mbox);
return (total < 1) ? 1 : 0;
}
else if (strcmp (mode, "print") == 0)
return util_do_command ("print *");
do_and_quit ("print *");
else if (strcmp (mode, "headers") == 0)
return util_do_command ("from *");
do_and_quit ("from *");
else if (strcmp (mode, "read"))
{
util_error (_("Unknown mode `%s'"), mode);
......
......@@ -217,8 +217,20 @@ fd_ioctl (struct _mu_stream *str, int code, void *ptr)
fstr->fd = (int) ptrans[0];
break;
case MU_IOCTL_GET_TRANSPORT_BUFFER:
{
struct mu_buffer_query *qp = ptr;
return mu_stream_get_buffer (str, qp);
}
case MU_IOCTL_SET_TRANSPORT_BUFFER:
{
struct mu_buffer_query *qp = ptr;
return mu_stream_set_buffer (str, qp->buftype, qp->bufsize);
}
default:
return EINVAL;
return ENOSYS;
}
return 0;
}
......
......@@ -401,10 +401,12 @@ _icvt_ioctl (mu_stream_t stream, int code, void *ptr)
break;
case MU_IOCTL_SWAP_STREAM:
case MU_IOCTL_GET_TRANSPORT_BUFFER:
case MU_IOCTL_SET_TRANSPORT_BUFFER:
return mu_stream_ioctl (s->transport, code, ptr);
default:
return EINVAL;
return ENOSYS;
}
return 0;
}
......
......@@ -344,7 +344,11 @@ header_parse (mu_header_t header, const char *blurb, int len)
{
header_end = memchr (header_start2, '\n', len);
if (header_end == NULL)
{
header_end = header_start2 + len;
len = 0;
break;
}
else
{
len -= (header_end - header_start2 + 1);
......
......@@ -154,8 +154,20 @@ _iostream_ctl (struct _mu_stream *str, int op, void *arg)
return EINVAL;
return _mu_stream_swap_streams (str, sp->transport, arg, 0);
default:
case MU_IOCTL_GET_TRANSPORT_BUFFER:
case MU_IOCTL_SET_TRANSPORT_BUFFER:
if (!arg)
return EINVAL;
else
{
struct mu_buffer_query *qp = arg;
if (!MU_TRANSPORT_VALID_TYPE (qp->type) || !sp->transport[qp->type])
return EINVAL;
return mu_stream_ioctl (sp->transport[qp->type], op, arg);
}
default:
return ENOSYS;
}
return 0;
}
......
......@@ -218,8 +218,20 @@ _mapfile_ioctl (struct _mu_stream *str, int code, void *ptr)
ptrans[1] = NULL;
break;
case MU_IOCTL_GET_TRANSPORT_BUFFER:
{
struct mu_buffer_query *qp = ptr;
return mu_stream_get_buffer (str, qp);
}
case MU_IOCTL_SET_TRANSPORT_BUFFER:
{
struct mu_buffer_query *qp = ptr;
return mu_stream_set_buffer (str, qp->buftype, qp->bufsize);
}
default:
return EINVAL;
return ENOSYS;
}
return 0;
}
......
......@@ -159,8 +159,20 @@ _memory_ioctl (struct _mu_stream *stream, int code, void *ptr)
ptrans[1] = NULL;
break;
case MU_IOCTL_GET_TRANSPORT_BUFFER:
{
struct mu_buffer_query *qp = ptr;
return mu_stream_get_buffer (stream, qp);
}
case MU_IOCTL_SET_TRANSPORT_BUFFER:
{
struct mu_buffer_query *qp = ptr;
return mu_stream_set_buffer (stream, qp->buftype, qp->bufsize);
}
default:
return EINVAL;
return ENOSYS;
}
return 0;
}
......
......@@ -579,6 +579,17 @@ _mime_body_stream_size (mu_stream_t stream, mu_off_t *psize)
return rc;
}
static void
mime_reset_state (mu_mime_t mime)
{ /* reset message */
mime->cur_offset = 0;
mime->cur_part = 0;
mime->part_offset = 0;
if (mime->nmtp_parts > 1)
mime->flags |= MIME_INSERT_BOUNDARY;
}
/* FIXME: The seek method is defective */
static int
_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)
mu_mime_t mime = mstr->mime;
if (off == 0)
{ /* reset message */
mime->cur_offset = 0;
mime->cur_part = 0;
mime->part_offset = 0;
if (mime->nmtp_parts > 1)
mime->flags |= MIME_INSERT_BOUNDARY;
}
mime_reset_state (mime);
if (off != mime->cur_offset)
return ESPIPE;
......@@ -767,7 +771,7 @@ _mime_body_stream_ioctl (mu_stream_t stream, int code, void *arg)
break;
default:
rc = EINVAL;
rc = ENOSYS;
}
return rc;
}
......@@ -785,6 +789,7 @@ create_mime_body_stream (mu_stream_t *pstr, mu_mime_t mime)
sp->stream.ctl = _mime_body_stream_ioctl;
sp->stream.size = _mime_body_stream_size;
sp->mime = mime;
mime_reset_state (mime);
*pstr = (mu_stream_t) sp;
return 0;
}
......
......@@ -393,7 +393,7 @@ _prog_ioctl (struct _mu_stream *str, int code, void *ptr)
break;
default:
return EINVAL;
return ENOSYS;
}
return 0;
}
......
......@@ -131,8 +131,20 @@ rdcache_ioctl (struct _mu_stream *str, int op, void *arg)
ptrans[1] = NULL;
break;
default:
case MU_IOCTL_GET_TRANSPORT_BUFFER:
case MU_IOCTL_SET_TRANSPORT_BUFFER:
if (!arg)
return EINVAL;
else
{
struct mu_buffer_query *qp = arg;
if (qp->type != MU_TRANSPORT_INPUT || !sp->transport)
return EINVAL;
return mu_stream_ioctl (sp->transport, op, arg);
}
default:
return ENOSYS;
}
return 0;
}
......
......@@ -32,6 +32,8 @@
#include <mailutils/stream.h>
#include <mailutils/sys/stream.h>
size_t mu_stream_default_buffer_size = MU_STREAM_DEFBUFSIZ;
static void
_stream_setflag (struct _mu_stream *stream, int flag)
{
......@@ -351,7 +353,7 @@ mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence,
return mu_stream_seterr (stream, EINVAL, 1);
}
if (stream->buftype == mu_buffer_none
if ((stream->buftype == mu_buffer_none && offset != stream->offset)
|| offset < stream->offset
|| offset > stream->offset + _stream_buffer_offset (stream))
{
......@@ -442,7 +444,7 @@ mu_stream_set_buffer (mu_stream_t stream, enum mu_buffer_type type,
size_t size)
{
if (size == 0)
type = mu_buffer_none;
size = mu_stream_default_buffer_size;
if (stream->buffer)
{
......@@ -471,6 +473,14 @@ mu_stream_set_buffer (mu_stream_t stream, enum mu_buffer_type type,
}
int
mu_stream_get_buffer (mu_stream_t stream, struct mu_buffer_query *qry)
{
qry->buftype = stream->buftype;
qry->bufsize = stream->bufsize;
return 0;
}
int
mu_stream_read_unbuffered (mu_stream_t stream, void *buf, size_t size,
int full_read,
size_t *pnread)
......@@ -953,7 +963,13 @@ int
mu_stream_truncate (mu_stream_t stream, mu_off_t size)
{
if (stream->truncate)
{
int rc;
if ((rc = _stream_flush_buffer (stream, 1)))
return rc;
return stream->truncate (stream, size);
}
return ENOSYS;
}
......
......@@ -209,7 +209,7 @@ _tcp_ioctl (mu_stream_t stream, int code, void *ptr)
break;
default:
return EINVAL;
return ENOSYS;
}
return 0;
}
......
......@@ -315,6 +315,15 @@ _xscript_ctl (struct _mu_stream *str, int op, void *arg)
}
break;
case MU_IOCTL_GET_TRANSPORT_BUFFER:
case MU_IOCTL_SET_TRANSPORT_BUFFER:
{
struct mu_transport_buffer_query *qp = arg;
if (!sp->transport)
return EINVAL;
return mu_stream_ioctl (sp->transport, op, arg);
}
case MU_IOCTL_LEVEL:
if (!arg)
return EINVAL;
......
......@@ -115,6 +115,8 @@ static struct mu_cfg_param pop3d_cfg_param[] = {
N_("Set the bulletin database file name."),
N_("file") },
#endif
{ "output-buffer-size", mu_cfg_size, &pop3d_output_bufsize, 0, NULL,
N_("Size of the output buffer.") },
{ ".server", mu_cfg_section, NULL, 0, NULL,
N_("Server configuration.") },
{ "transcript", mu_cfg_bool, &pop3d_transcript, 0, NULL,
......
......@@ -201,6 +201,7 @@ extern int undelete_on_startup;
extern struct mu_auth_data *auth_data;
extern unsigned int idle_timeout;
extern int pop3d_transcript;
extern size_t pop3d_output_bufsize;
extern pop3d_command_handler_t pop3d_find_command (const char *name);
......
......@@ -17,6 +17,31 @@
#include "pop3d.h"
size_t pop3d_output_bufsize = 64 * 1024;
void
pop3d_send_payload (mu_stream_t stream)
{
struct mu_buffer_query oldbuf, newbuf;
int xscript_level = set_xscript_level (MU_XSCRIPT_PAYLOAD);
oldbuf.type = MU_TRANSPORT_OUTPUT;
mu_stream_ioctl (iostream, MU_IOCTL_GET_TRANSPORT_BUFFER,
&oldbuf);
newbuf.type = MU_TRANSPORT_OUTPUT;
newbuf.buftype = mu_buffer_full;
newbuf.bufsize = pop3d_output_bufsize;
mu_stream_ioctl (iostream, MU_IOCTL_SET_TRANSPORT_BUFFER,
&newbuf);
mu_stream_copy (iostream, stream, 0, NULL);
pop3d_outf (".\n");
mu_stream_ioctl (iostream, MU_IOCTL_SET_TRANSPORT_BUFFER,
&oldbuf);
set_xscript_level (xscript_level);
}
/* Prints out the specified message */
int
......@@ -26,7 +51,6 @@ pop3d_retr (char *arg)
mu_message_t msg = NULL;
mu_attribute_t attr = NULL;
mu_stream_t stream;
int xscript_level;
if ((strlen (arg) == 0) || (strchr (arg, ' ') != NULL))
return ERR_BAD_ARGS;
......@@ -47,8 +71,7 @@ pop3d_retr (char *arg)
return ERR_UNKNOWN;
pop3d_outf ("+OK\n");
xscript_level = set_xscript_level (MU_XSCRIPT_PAYLOAD);
mu_stream_copy (iostream, stream, 0, NULL);
pop3d_send_payload (stream);
mu_stream_destroy (&stream);
if (!mu_attribute_is_read (attr))
......@@ -56,9 +79,6 @@ pop3d_retr (char *arg)
pop3d_mark_retr (attr);
pop3d_outf (".\n");
set_xscript_level (xscript_level);
return OK;
}
......
......@@ -31,6 +31,7 @@ pop3d_top (char *arg)
mu_stream_t stream;
char *mesgc, *linesc, *p;
int xscript_level;
struct mu_buffer_query oldbuf, newbuf;
if (strlen (arg) == 0)
return ERR_BAD_ARGS;
......@@ -64,6 +65,14 @@ pop3d_top (char *arg)
pop3d_outf ("+OK\n");
xscript_level = set_xscript_level (MU_XSCRIPT_PAYLOAD);
oldbuf.type = MU_TRANSPORT_OUTPUT;
mu_stream_ioctl (iostream, MU_IOCTL_GET_TRANSPORT_BUFFER,
&oldbuf);
newbuf.type = MU_TRANSPORT_OUTPUT;
newbuf.buftype = mu_buffer_full;
newbuf.bufsize = pop3d_output_bufsize;
mu_stream_ioctl (iostream, MU_IOCTL_SET_TRANSPORT_BUFFER,
&newbuf);
mu_stream_copy (iostream, stream, 0, NULL);
pop3d_outf ("\n");
......@@ -88,6 +97,9 @@ pop3d_top (char *arg)
pop3d_outf (".\n");
mu_stream_ioctl (iostream, MU_IOCTL_SET_TRANSPORT_BUFFER,
&oldbuf);
set_xscript_level (xscript_level);
return OK;
......