Commit 814b9791 814b97914c8ac0177af4688e934511912733c314 by Sergey Poznyakoff

Add a framework for printing I/O transcripts; modify pop3d to use it.

* include/mailutils/stream.h (MU_STREAM_RDTHRU)
(MU_STREAM_WRTHRU,MU_IOCTL_SET_TRANSPORT): New flags.
(mu_xscript_stream_create, mu_iostream_create)
(mu_dbgstream_create): New prototypes.
* include/mailutils/sys/dbgstream.h: New header.
* include/mailutils/sys/iostream.h: New header.
* include/mailutils/sys/xscript-stream.h: New header.
* include/mailutils/sys/Makefile.am (sysinclude_HEADERS): Add
dbgstream.h, iostream.h and xscript-stream.h
* mailbox/dbgstream.c: New file.
* mailbox/iostream.c: New file.
* mailbox/xscript-stream.c: New file.
* mailbox/Makefile.am (libmailutils_la_SOURCES): Add dbgstream.c,
iostream.c and xscript-stream.c
* mailbox/filter_iconv.c (_icvt_ioctl): Simplify the declaration
of ptrans.
* mailbox/mapfile_stream.c (_mapfile_ioctl): Likewise.
* mailbox/memory_stream.c (_memory_ioctl): Likewise.
* mailbox/prog_stream.c (_prog_ioctl): Likewise.
* mailbox/tcp.c (_tcp_ioctl): Likewise.
* mailbox/fltstream.c (filter_ctl): Likewise.
(filter_read_through, filter_write_through): New methods.
(mu_filter_stream_create): Allow for use of MU_STREAM_RDTHRU
and MU_STREAM_WRTHRU to create two-way filters (writing
triggers filtering while reading is transparent or vice versa).
* pop3d/extra.c (istream, ostream): Remove globals.
(iostream): New variable.
(real_istream, real_ostream): New variables.
(pop3d_setio): Set transcript stream on top of the I/O one,
if required.
(pop3d_init_tls_server): Rewrite. Revert the meaning of the
return code to match the usual convention (0 - success).
(transcript): Removed.
(pop3d_outf): Remove calls to transcript.
* pop3d/pop3d.h (istream, ostream): Remove externs.
(iostream): New extern.
* pop3d/retr.c: Use iostream, instear of ostream.
* pop3d/top.c: Likewise.
* pop3d/stls.c: Update the call to pop3d_init_tls_server.

* mailbox/stream_vprintf.c (mu_stream_vprintf): Fix return
value to match the usual convention.
1 parent cab81060
......@@ -47,6 +47,9 @@ enum mu_buffer_type
/* FIXME: This one affects only mailboxes */
#define MU_STREAM_QACCESS 0x00000200
#define MU_STREAM_RDTHRU 0x00000400
#define MU_STREAM_WRTHRU 0x00000800
#define MU_STREAM_IRGRP 0x00001000
#define MU_STREAM_IWGRP 0x00002000
#define MU_STREAM_IROTH 0x00004000
......@@ -59,6 +62,7 @@ enum mu_buffer_type
#define MU_IOCTL_SET_SEEK_LIMITS 4
#define MU_IOCTL_ABRIDGE_SEEK MU_IOCTL_SET_SEEK_LIMITS
#define MU_IOCTL_GET_SEEK_LIMITS 5
#define MU_IOCTL_SET_TRANSPORT 6
void mu_stream_ref (mu_stream_t stream);
void mu_stream_unref (mu_stream_t stream);
......@@ -145,4 +149,12 @@ int mu_tcp_stream_create_with_source_host (mu_stream_t *stream,
int mu_tcp_stream_create (mu_stream_t *stream, const char *host, int port,
int flags);
int mu_xscript_stream_create(mu_stream_t *pref, mu_stream_t transport,
mu_stream_t logstr,
const char *prefix[]);
int mu_iostream_create (mu_stream_t *pref, mu_stream_t in, mu_stream_t out,
int flags);
int mu_dbgstream_create(mu_stream_t *pref, mu_debug_t debug,
mu_log_level_t level, int flags);
#endif
......
......@@ -19,10 +19,12 @@
sysincludedir=$(pkgincludedir)/sys
sysinclude_HEADERS = \
dbgstream.h\
file_stream.h\
filter.h\
header_stream.h\
header.h\
iostream.h\
mapfile_stream.h\
memory_stream.h\
message_stream.h\
......@@ -36,4 +38,5 @@ sysinclude_HEADERS = \
stream.h\
tls-stream.h\
pop3.h\
nntp.h
nntp.h\
xscript-stream.h
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2010 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#ifndef _MAILUTILS_SYS_DBGSTREAM_H
# define _MAILUTILS_SYS_DBGSTREAM_H
# include <mailutils/types.h>
# include <mailutils/stream.h>
# include <mailutils/sys/stream.h>
struct _mu_dbgstream
{
struct _mu_stream stream;
mu_debug_t debug;
mu_log_level_t level;
};
#endif
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2010 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#ifndef _MAILUTILS_SYS_IOSTREAM_H
# define _MAILUTILS_SYS_IOSTREAM_H
# include <mailutils/types.h>
# include <mailutils/stream.h>
# include <mailutils/sys/stream.h>
# define _MU_STREAM_INPUT 0
# define _MU_STREAM_OUTPUT 1
struct _mu_iostream
{
struct _mu_stream stream;
mu_stream_t transport[2];
int last_err_str;
};
#endif
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2010 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#ifndef _MAILUTILS_SYS_XSCRIPT_STREAM_H
# define _MAILUTILS_SYS_XSCRIPT_STREAM_H
# include <mailutils/types.h>
# include <mailutils/stream.h>
# include <mailutils/sys/stream.h>
struct _mu_xscript_stream
{
struct _mu_stream stream;
mu_stream_t transport;
mu_stream_t logstr;
int flags;
char *prefix[2];
};
#endif
......@@ -69,6 +69,7 @@ libmailutils_la_SOURCES = \
daemon.c\
date.c\
dbgstderr.c\
dbgstream.c\
dbgsyslog.c\
debug.c\
diag.c\
......@@ -84,6 +85,7 @@ libmailutils_la_SOURCES = \
gocs.c\
hdritr.c\
header.c\
iostream.c\
iterator.c\
ipsrv.c\
kwd.c\
......@@ -150,7 +152,8 @@ libmailutils_la_SOURCES = \
vartab.c\
vasnprintf.c\
version.c\
wicket.c
wicket.c\
xscript-stream.c
BUILT_SOURCES = parsedate.c muerrno.c cfg_parser.c cfg_parser.h cfg_lexer.c
MOSTLYCLEANFILES=
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2004,
2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <mailutils/types.h>
#include <mailutils/alloc.h>
#include <mailutils/errno.h>
#include <mailutils/nls.h>
#include <mailutils/stream.h>
#include <mailutils/sys/stream.h>
#include <mailutils/sys/dbgstream.h>
#include <mailutils/debug.h>
static int
_dbg_write (struct _mu_stream *str, const char *buf, size_t size,
size_t *pnwrite)
{
struct _mu_dbgstream *sp = (struct _mu_dbgstream *)str;
if (pnwrite)
*pnwrite = size;
while (size > 0 && (buf[size-1] == '\n' || buf[size-1] == '\r'))
size--;
if (size)
mu_debug_printf (sp->debug, sp->level, "%.*s\n", size, buf);
return 0;
}
static int
_dbg_flush (struct _mu_stream *str)
{
struct _mu_dbgstream *sp = (struct _mu_dbgstream *)str;
mu_debug_printf (sp->debug, sp->level, "\n");
return 0;
}
static void
_dbg_done (struct _mu_stream *str)
{
struct _mu_dbgstream *sp = (struct _mu_dbgstream *)str;
if (!(str->flags & MU_STREAM_NO_CLOSE))
mu_debug_destroy (&sp->debug, NULL);
}
int
mu_dbgstream_create(mu_stream_t *pref, mu_debug_t debug, mu_log_level_t level,
int flags)
{
struct _mu_dbgstream *sp;
sp = (struct _mu_dbgstream *)
_mu_stream_create (sizeof (*sp), MU_STREAM_WRITE |
(flags & MU_STREAM_NO_CLOSE));
if (!sp)
return ENOMEM;
sp->stream.write = _dbg_write;
sp->stream.flush = _dbg_flush;
sp->stream.done = _dbg_done;
sp->debug = debug;
sp->level = level;
mu_stream_set_buffer ((mu_stream_t) sp, mu_buffer_line, 1024);
*pref = (mu_stream_t) sp;
return 0;
}
......@@ -192,7 +192,7 @@ static int
fd_ioctl (struct _mu_stream *str, int code, void *ptr)
{
struct _mu_file_stream *fstr = (struct _mu_file_stream *) str;
mu_transport_t (*ptrans)[2];
mu_transport_t *ptrans;
switch (code)
{
......@@ -200,8 +200,8 @@ fd_ioctl (struct _mu_stream *str, int code, void *ptr)
if (!ptr)
return EINVAL;
ptrans = ptr;
(*ptrans)[0] = (mu_transport_t) fstr->fd;
(*ptrans)[1] = NULL;
ptrans[0] = (mu_transport_t) fstr->fd;
ptrans[1] = NULL;
break;
default:
......
......@@ -390,7 +390,7 @@ static int
_icvt_ioctl (mu_stream_t stream, int code, void *ptr)
{
struct icvt_stream *s = (struct icvt_stream *)stream;
mu_transport_t (*ptrans)[2];
mu_transport_t *ptrans;
switch (code)
{
......@@ -398,8 +398,8 @@ _icvt_ioctl (mu_stream_t stream, int code, void *ptr)
if (!ptr)
return EINVAL;
ptrans = ptr;
(*ptrans)[0] = (mu_transport_t) s->transport;
(*ptrans)[1] = NULL;
ptrans[0] = (mu_transport_t) s->transport;
ptrans[1] = NULL;
break;
default:
......
......@@ -335,7 +335,7 @@ static int
filter_ctl (struct _mu_stream *stream, int op, void *ptr)
{
struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream;
mu_transport_t (*ptrans)[2];
mu_transport_t *ptrans;
switch (op)
{
......@@ -343,8 +343,8 @@ filter_ctl (struct _mu_stream *stream, int op, void *ptr)
if (!ptr)
return EINVAL;
ptrans = ptr;
(*ptrans)[0] = (mu_transport_t) fs->transport;
(*ptrans)[1] = NULL;
ptrans[0] = (mu_transport_t) fs->transport;
ptrans[1] = NULL;
break;
default:
......@@ -390,6 +390,26 @@ filter_close (mu_stream_t stream)
return mu_stream_close (fs->transport);
}
static int
filter_read_through (struct _mu_stream *stream,
char *buf, size_t bufsize,
size_t *pnread)
{
struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream;
return mu_stream_read (fs->transport, buf, bufsize, pnread);
}
static int
filter_write_through (struct _mu_stream *stream,
const char *buf, size_t bufsize,
size_t *pnwrite)
{
struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream;
return mu_stream_write (fs->transport, buf, bufsize, pnwrite);
}
int
mu_filter_stream_create (mu_stream_t *pflt,
mu_stream_t str,
......@@ -402,7 +422,14 @@ mu_filter_stream_create (mu_stream_t *pflt,
if ((flags & MU_STREAM_RDWR) == MU_STREAM_RDWR
|| !(flags & MU_STREAM_RDWR)
|| (flags & (MU_STREAM_WRITE|MU_STREAM_SEEK)) == (MU_STREAM_WRITE|MU_STREAM_SEEK))
|| (flags & (MU_STREAM_WRITE|MU_STREAM_SEEK)) ==
(MU_STREAM_WRITE|MU_STREAM_SEEK)
|| (flags & (MU_STREAM_RDTHRU|MU_STREAM_WRTHRU)) ==
(MU_STREAM_RDTHRU|MU_STREAM_WRTHRU)
|| (flags & (MU_STREAM_READ|MU_STREAM_RDTHRU)) ==
(MU_STREAM_READ|MU_STREAM_RDTHRU)
|| (flags & (MU_STREAM_WRITE|MU_STREAM_WRTHRU)) ==
(MU_STREAM_WRITE|MU_STREAM_WRTHRU))
return EINVAL;
fs = (struct _mu_filter_stream *) _mu_stream_create (sizeof (*fs), flags);
......@@ -413,11 +440,21 @@ mu_filter_stream_create (mu_stream_t *pflt,
{
fs->stream.read = filter_read;
fs->stream.flush = filter_rd_flush;
if (flags & MU_STREAM_WRTHRU)
{
flags |= MU_STREAM_WRITE;
fs->stream.write = filter_write_through;
}
}
else
{
fs->stream.write = filter_write;
fs->stream.flush = filter_wr_flush;
if (flags & MU_STREAM_RDTHRU)
{
flags |= MU_STREAM_READ;
fs->stream.read = filter_read_through;
}
}
fs->stream.done = filter_done;
fs->stream.close = filter_close;
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2010 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <mailutils/types.h>
#include <mailutils/alloc.h>
#include <mailutils/errno.h>
#include <mailutils/nls.h>
#include <mailutils/stream.h>
#include <mailutils/sys/stream.h>
#include <mailutils/sys/iostream.h>
static int
_iostream_read (struct _mu_stream *str, char *buf, size_t bufsize,
size_t *pnread)
{
struct _mu_iostream *sp = (struct _mu_iostream *)str;
int rc = mu_stream_read (sp->transport[_MU_STREAM_INPUT], buf, bufsize,
pnread);
if (rc)
sp->last_err_str = _MU_STREAM_INPUT;
return rc;
}
static int
_iostream_readdelim (struct _mu_stream *str, char *buf, size_t bufsize,
int delim, size_t *pnread)
{
struct _mu_iostream *sp = (struct _mu_iostream *)str;
int rc = mu_stream_readdelim (sp->transport[_MU_STREAM_INPUT], buf,
bufsize, delim, pnread);
if (rc)
sp->last_err_str = _MU_STREAM_INPUT;
return rc;
}
static int
_iostream_write (struct _mu_stream *str, const char *buf, size_t bufsize,
size_t *pnwrite)
{
struct _mu_iostream *sp = (struct _mu_iostream *)str;
int rc = mu_stream_write (sp->transport[_MU_STREAM_OUTPUT], buf, bufsize,
pnwrite);
if (rc)
sp->last_err_str = _MU_STREAM_OUTPUT;
return rc;
}
static int
_iostream_flush (struct _mu_stream *str)
{
struct _mu_iostream *sp = (struct _mu_iostream *)str;
int rc = mu_stream_flush (sp->transport[_MU_STREAM_INPUT]);
if (rc)
{
sp->last_err_str = _MU_STREAM_INPUT;
return rc;
}
if (sp->transport[_MU_STREAM_INPUT] != sp->transport[_MU_STREAM_OUTPUT])
{
rc = mu_stream_flush (sp->transport[_MU_STREAM_OUTPUT]);
if (rc)
sp->last_err_str = _MU_STREAM_OUTPUT;
}
return rc;
}
static int
_iostream_open (struct _mu_stream *str)
{
struct _mu_iostream *sp = (struct _mu_iostream *)str;
int rc;
rc = mu_stream_open (sp->transport[_MU_STREAM_INPUT]);
if (rc)
{
sp->last_err_str = _MU_STREAM_INPUT;
return rc;
}
if (sp->transport[_MU_STREAM_INPUT] != sp->transport[_MU_STREAM_OUTPUT])
{
rc = mu_stream_open (sp->transport[_MU_STREAM_OUTPUT]);
if (rc)
{
sp->last_err_str = _MU_STREAM_OUTPUT;
mu_stream_close (sp->transport[_MU_STREAM_INPUT]);
}
}
return rc;
}
static int
_iostream_close (struct _mu_stream *str)
{
struct _mu_iostream *sp = (struct _mu_iostream *)str;
if (sp->stream.flags & MU_STREAM_NO_CLOSE)
return 0;
mu_stream_close (sp->transport[_MU_STREAM_INPUT]);
if (sp->transport[_MU_STREAM_INPUT] != sp->transport[_MU_STREAM_OUTPUT])
mu_stream_close (sp->transport[_MU_STREAM_OUTPUT]);
return 0;
}
static void
_iostream_done (struct _mu_stream *str)
{
struct _mu_iostream *sp = (struct _mu_iostream *)str;
mu_stream_unref (sp->transport[_MU_STREAM_INPUT]);
if (sp->transport[_MU_STREAM_INPUT] != sp->transport[_MU_STREAM_OUTPUT])
mu_stream_unref (sp->transport[_MU_STREAM_OUTPUT]);
}
static int
_iostream_ctl (struct _mu_stream *str, int op, void *arg)
{
struct _mu_iostream *sp = (struct _mu_iostream *)str;
mu_transport_t *ptrans;
switch (op)
{
case MU_IOCTL_GET_TRANSPORT:
if (!arg)
return EINVAL;
ptrans = arg;
ptrans[0] = (mu_transport_t) sp->transport[_MU_STREAM_INPUT];
ptrans[1] = (mu_transport_t) sp->transport[_MU_STREAM_OUTPUT];
break;
case MU_IOCTL_SET_TRANSPORT:
if (!arg)
return EINVAL;
ptrans = arg;
sp->transport[_MU_STREAM_INPUT] = (mu_stream_t) ptrans[0];
sp->transport[_MU_STREAM_OUTPUT] = (mu_stream_t) ptrans[1];
break;
default:
return EINVAL;
}
return 0;
}
static int
_iostream_wait (struct _mu_stream *str, int *pflags, struct timeval *tvp)
{
struct _mu_iostream *sp = (struct _mu_iostream *)str;
int rc = EINVAL;
if (*pflags == MU_STREAM_READY_RD)
{
rc = mu_stream_wait (sp->transport[_MU_STREAM_INPUT], pflags, tvp);
if (rc)
sp->last_err_str = _MU_STREAM_INPUT;
}
else if (*pflags == MU_STREAM_READY_WR)
{
rc = mu_stream_wait (sp->transport[_MU_STREAM_OUTPUT], pflags, tvp);
if (rc)
sp->last_err_str = _MU_STREAM_OUTPUT;
}
return rc;
}
static int
_iostream_shutdown (struct _mu_stream *str, int how)
{
struct _mu_iostream *sp = (struct _mu_iostream *)str;
int rc = EINVAL;
switch (how)
{
case MU_STREAM_READ:
rc = mu_stream_shutdown (sp->transport[_MU_STREAM_INPUT], how);
if (rc)
sp->last_err_str = _MU_STREAM_INPUT;
break;
case MU_STREAM_WRITE:
rc = mu_stream_shutdown (sp->transport[_MU_STREAM_OUTPUT], how);
if (rc)
sp->last_err_str = _MU_STREAM_OUTPUT;
}
return rc;
}
static const char *
_iostream_error_string (struct _mu_stream *str, int rc)
{
struct _mu_iostream *sp = (struct _mu_iostream *)str;
mu_stream_t transport = sp->transport[sp->last_err_str];
if (transport)
return mu_stream_strerror (transport, rc);
return mu_strerror (rc);
}
int
mu_iostream_create (mu_stream_t *pref, mu_stream_t in, mu_stream_t out,
int flags)
{
struct _mu_iostream *sp;
sp = (struct _mu_iostream *)
_mu_stream_create (sizeof (*sp),
MU_STREAM_READ | MU_STREAM_WRITE |
(flags & MU_STREAM_NO_CLOSE));
if (!sp)
return ENOMEM;
sp->stream.read = _iostream_read;
sp->stream.readdelim = _iostream_readdelim;
sp->stream.write = _iostream_write;
sp->stream.flush = _iostream_flush;
sp->stream.open = _iostream_open;
sp->stream.close = _iostream_close;
sp->stream.done = _iostream_done;
sp->stream.ctl = _iostream_ctl;
sp->stream.wait = _iostream_wait;
sp->stream.shutdown = _iostream_shutdown;
sp->stream.error_string = _iostream_error_string;
mu_stream_ref (in);
sp->transport[_MU_STREAM_INPUT] = in;
mu_stream_ref (out);
sp->transport[_MU_STREAM_OUTPUT] = out;
mu_stream_set_buffer ((mu_stream_t) sp, mu_buffer_line, 1024);
*pref = (mu_stream_t) sp;
return 0;
}
......@@ -209,13 +209,13 @@ static int
_mapfile_ioctl (struct _mu_stream *str, int code, void *ptr)
{
struct _mu_mapfile_stream *mfs = (struct _mu_mapfile_stream *) str;
mu_transport_t (*ptrans)[2];
mu_transport_t ptrans[2];
switch (code)
{
case MU_IOCTL_GET_TRANSPORT:
(*ptrans)[0] = (mu_transport_t) mfs->fd;
(*ptrans)[1] = NULL;
ptrans[0] = (mu_transport_t) mfs->fd;
ptrans[1] = NULL;
break;
default:
......
......@@ -147,7 +147,7 @@ static int
_memory_ioctl (struct _mu_stream *stream, int code, void *ptr)
{
struct _mu_memory_stream *mfs = (struct _mu_memory_stream *) stream;
mu_transport_t (*ptrans)[2];
mu_transport_t *ptrans;
switch (code)
{
......@@ -155,8 +155,8 @@ _memory_ioctl (struct _mu_stream *stream, int code, void *ptr)
if (!ptr)
return EINVAL;
ptrans = ptr;
(*ptrans)[0] = (mu_transport_t) mfs->ptr;
(*ptrans)[1] = NULL;
ptrans[0] = (mu_transport_t) mfs->ptr;
ptrans[1] = NULL;
break;
default:
......
......@@ -367,7 +367,7 @@ _prog_ioctl (struct _mu_stream *str, int code, void *ptr)
{
struct _mu_prog_stream *fstr = (struct _mu_prog_stream *) str;
mu_transport_t t[2];
mu_transport_t (*ptrans)[2];
mu_transport_t *ptrans;
switch (code)
{
......@@ -375,9 +375,9 @@ _prog_ioctl (struct _mu_stream *str, int code, void *ptr)
if (!ptr)
return EINVAL;
mu_stream_ioctl (fstr->in, MU_IOCTL_GET_TRANSPORT, t);
(*ptrans)[0] = t[0];
ptrans[0] = t[0];
mu_stream_ioctl (fstr->out, MU_IOCTL_GET_TRANSPORT, t);
(*ptrans)[1] = t[1];
ptrans[1] = t[1];
break;
case MU_IOCTL_GET_STATUS:
......
......@@ -37,6 +37,6 @@ mu_stream_vprintf (mu_stream_t str, const char *fmt, va_list ap)
n = strlen (buf);
rc = mu_stream_write (str, buf, n, NULL);
free (buf);
return rc == 0 ? n : -1;
return rc;
}
......
......@@ -196,7 +196,7 @@ static int
_tcp_ioctl (mu_stream_t stream, int code, void *ptr)
{
struct _tcp_instance *tcp = (struct _tcp_instance *)stream;
mu_transport_t (*ptrans)[2];
mu_transport_t *ptrans;
switch (code)
{
......@@ -204,8 +204,8 @@ _tcp_ioctl (mu_stream_t stream, int code, void *ptr)
if (!ptr)
return EINVAL;
ptrans = ptr;
(*ptrans)[0] = (mu_transport_t) tcp->fd;
(*ptrans)[1] = NULL;
ptrans[0] = (mu_transport_t) tcp->fd;
ptrans[1] = NULL;
break;
default:
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2004,
2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <mailutils/types.h>
#include <mailutils/alloc.h>
#include <mailutils/errno.h>
#include <mailutils/nls.h>
#include <mailutils/stream.h>
#include <mailutils/sys/stream.h>
#include <mailutils/sys/xscript-stream.h>
/* A "transcript stream" transparently writes data to and reads data from
an underlying transport stream, writing each lineful of data to a "log
stream". Writes to log stream are prefixed with a string indicating
direction of the data (read/write). Default prefixes are those used in
RFCs -- "S: ", for data written ("Server"), and "C: ", for data read
("Client"). */
#define TRANS_READ 0x1
#define TRANS_WRITE 0x2
#define FLAG_TO_PFX(c) ((c) - 1)
static void
print_transcript (struct _mu_xscript_stream *str, int flag,
const char *buf, size_t size)
{
while (size)
{
const char *p;
size_t len;
if (str->flags & flag)
{
mu_stream_write (str->logstr,
str->prefix[FLAG_TO_PFX(flag)],
strlen (str->prefix[FLAG_TO_PFX (flag)]),
NULL);
str->flags &= ~flag;
}
p = memchr (buf, '\n', size);
if (p)
{
len = p - buf;
if (p > buf && p[-1] == '\r')
len--;
mu_stream_write (str->logstr, buf, len, NULL);
mu_stream_write (str->logstr, "\n", 1, NULL);
str->flags |= flag;
len = p - buf + 1;
buf = p + 1;
size -= len;
}
else
{
mu_stream_write (str->logstr, buf, size, NULL);
break;
}
}
}
static int
_xscript_read (struct _mu_stream *str, char *buf, size_t bufsize,
size_t *pnread)
{
struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str;
size_t nbytes;
int rc = mu_stream_read (sp->transport, buf, bufsize, &nbytes);
if (rc == 0)
{
print_transcript (sp, TRANS_READ, buf, nbytes);
if (pnread)
*pnread = nbytes;
}
return rc;
}
static int
_xscript_readdelim (struct _mu_stream *str, char *buf, size_t bufsize,
int delim, size_t *pnread)
{
struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str;
size_t nread;
int rc = mu_stream_readdelim (sp->transport, buf, bufsize, delim, &nread);
if (rc == 0)
{
print_transcript (sp, TRANS_READ, buf, nread);
if (pnread)
*pnread = nread;
}
return rc;
}
static int
_xscript_write (struct _mu_stream *str, const char *buf, size_t bufsize,
size_t *pnwrite)
{
struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str;
int rc = mu_stream_write (sp->transport, buf, bufsize, pnwrite);
if (rc == 0)
print_transcript (sp, TRANS_WRITE, buf, pnwrite ? *pnwrite : bufsize);
return rc;
}
static int
_xscript_flush (struct _mu_stream *str)
{
struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str;
return mu_stream_flush (sp->transport);
}
static int
_xscript_open (struct _mu_stream *str)
{
struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str;
return mu_stream_open (sp->transport);
}
static int
_xscript_close (struct _mu_stream *str)
{
struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str;
if (sp->stream.flags & MU_STREAM_NO_CLOSE)
return 0;
return mu_stream_close (sp->transport);
}
static void
_xscript_done (struct _mu_stream *str)
{
struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str;
free (sp->prefix[0]);
free (sp->prefix[1]);
mu_stream_unref (sp->transport);
mu_stream_unref (sp->logstr);
}
static int
_xscript_seek (struct _mu_stream *str, mu_off_t off, mu_off_t *ppos)
{
struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str;
return mu_stream_seek (sp->transport, off, MU_SEEK_SET, ppos);
}
static int
_xscript_size (struct _mu_stream *str, mu_off_t *psize)
{
struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str;
return mu_stream_size (sp->transport, psize);
}
static int
_xscript_ctl (struct _mu_stream *str, int op, void *arg)
{
struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str;
mu_transport_t *ptrans;
switch (op)
{
case MU_IOCTL_GET_TRANSPORT:
if (!arg)
return EINVAL;
ptrans = arg;
ptrans[0] = (mu_transport_t) sp->transport;
ptrans[1] = (mu_transport_t) sp->logstr;
break;
case MU_IOCTL_SET_TRANSPORT:
if (!arg)
return EINVAL;
ptrans = arg;
if (ptrans[0])
sp->transport = (mu_stream_t) ptrans[0];
if (ptrans[1])
sp->logstr = (mu_stream_t) ptrans[1];
break;
default:
return mu_stream_ioctl (sp->transport, op, arg);
}
return 0;
}
static int
_xscript_wait (struct _mu_stream *str, int *pflags, struct timeval *tvp)
{
struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str;
return mu_stream_wait (sp->transport, pflags, tvp);
}
static int
_xscript_truncate (struct _mu_stream *str, mu_off_t size)
{
struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str;
return mu_stream_truncate (sp->transport, size);
}
static int
_xscript_shutdown (struct _mu_stream *str, int how)
{
struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str;
return mu_stream_shutdown (sp->transport, how);
}
static const char *
_xscript_error_string (struct _mu_stream *str, int rc)
{
struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str;
const char *p = mu_stream_strerror (sp->transport, rc);
if (!p)
p = mu_strerror (rc);
return p;
}
const char *default_prefix[2] = {
"C: ", "S: "
};
int
mu_xscript_stream_create(mu_stream_t *pref, mu_stream_t transport,
mu_stream_t logstr,
const char *prefix[])
{
int flags;
struct _mu_xscript_stream *sp;
mu_stream_get_flags (transport, &flags);
sp = (struct _mu_xscript_stream *) _mu_stream_create (sizeof (*sp), flags);
if (!sp)
return ENOMEM;
sp->stream.read = _xscript_read;
sp->stream.readdelim = _xscript_readdelim;
sp->stream.write = _xscript_write;
sp->stream.flush = _xscript_flush;
sp->stream.open = _xscript_open;
sp->stream.close = _xscript_close;
sp->stream.done = _xscript_done;
sp->stream.seek = _xscript_seek;
sp->stream.size = _xscript_size;
sp->stream.ctl = _xscript_ctl;
sp->stream.wait = _xscript_wait;
sp->stream.truncate = _xscript_truncate;
sp->stream.shutdown = _xscript_shutdown;
sp->stream.error_string = _xscript_error_string;
mu_stream_ref (transport);
sp->transport = transport;
mu_stream_ref (logstr);
sp->logstr = logstr;
sp->flags = TRANS_READ | TRANS_WRITE;
if (prefix)
{
sp->prefix[0] = strdup(prefix[0] ? prefix[0] : default_prefix[0]);
sp->prefix[1] = strdup(prefix[1] ? prefix[1] : default_prefix[1]);
}
else
{
sp->prefix[0] = strdup(default_prefix[0]);
sp->prefix[1] = strdup(default_prefix[1]);
}
if (sp->prefix[0] == NULL || sp->prefix[1] == 0)
{
free (sp->prefix[0]);
free (sp->prefix[1]);
free (sp);
return ENOMEM;
}
mu_stream_set_buffer ((mu_stream_t) sp, mu_buffer_line, 1024);
*pref = (mu_stream_t) sp;
return 0;
}
......@@ -20,7 +20,7 @@
#include "pop3d.h"
#include "mailutils/libargp.h"
mu_stream_t istream, ostream;
mu_stream_t iostream;
void
pop3d_parse_command (char *cmd, char **pcmd, char **parg)
......@@ -132,12 +132,12 @@ pop3d_abquit (int reason)
FIXME: This is sorta kludge: we could use MU_IOCTL_GET_TRANSPORT call
to retrieve the bottom-level stream, if filter streams supported it.
*/
static mu_stream_t real_ostream;
static mu_stream_t real_istream, real_ostream;
void
pop3d_setio (FILE *in, FILE *out)
{
mu_stream_t str;
mu_stream_t str, istream, ostream;
if (!in)
pop3d_abquit (ERR_NO_IFILE);
......@@ -147,6 +147,7 @@ pop3d_setio (FILE *in, FILE *out)
if (mu_stdio_stream_create (&istream, fileno (in),
MU_STREAM_READ | MU_STREAM_NO_CLOSE))
pop3d_abquit (ERR_NO_IFILE);
real_istream = istream;
mu_stream_set_buffer (istream, mu_buffer_line, 1024);
if (mu_stdio_stream_create (&str, fileno (out),
......@@ -157,6 +158,32 @@ pop3d_setio (FILE *in, FILE *out)
MU_STREAM_WRITE | MU_STREAM_NO_CLOSE))
pop3d_abquit (ERR_NO_IFILE);
mu_stream_set_buffer (ostream, mu_buffer_line, 1024);
if (mu_iostream_create (&iostream, istream, ostream, 0))
pop3d_abquit (ERR_FILE);
if (pop3d_transcript)
{
int rc;
mu_debug_t debug;
mu_stream_t dstr, xstr;
mu_diag_get_debug (&debug);
rc = mu_dbgstream_create (&dstr, debug, MU_DIAG_DEBUG,
MU_STREAM_NO_CLOSE);
if (rc)
mu_error (_("cannot create debug stream; transcript disabled: %s"),
mu_strerror (rc));
else
{
rc = mu_xscript_stream_create (&xstr, iostream, dstr, NULL);
if (rc)
mu_error (_("cannot create transcript stream: %s"),
mu_strerror (rc));
else
iostream = xstr;
}
}
}
#ifdef WITH_TLS
......@@ -166,37 +193,44 @@ pop3d_init_tls_server ()
mu_stream_t stream;
int rc;
rc = mu_tls_server_stream_create (&stream, istream, real_ostream, 0);
rc = mu_tls_server_stream_create (&stream, real_istream, real_ostream,
MU_STREAM_NO_CLOSE);
if (rc)
return 0;
return 1;
rc = mu_stream_open (stream);
if (rc)
{
mu_diag_output (MU_DIAG_ERROR, _("cannot open TLS stream: %s"),
mu_stream_strerror (stream, rc));
return 0;
mu_stream_destroy (&stream);
return 1;
}
istream = stream;
mu_stream_destroy (&ostream);
if (mu_filter_create (&ostream, stream, "rfc822", MU_FILTER_ENCODE,
MU_STREAM_WRITE | MU_STREAM_NO_CLOSE))
if (mu_filter_create (&stream, stream, "rfc822", MU_FILTER_ENCODE,
MU_STREAM_WRITE | MU_STREAM_RDTHRU |
MU_STREAM_NO_CLOSE))
pop3d_abquit (ERR_NO_IFILE);
mu_stream_set_buffer (ostream, mu_buffer_line, 1024);
return 1;
if (pop3d_transcript)
{
mu_transport_t trans[2];
trans[0] = (mu_transport_t) stream;
trans[1] = NULL;
mu_stream_ioctl (iostream, MU_IOCTL_SET_TRANSPORT, trans);
}
else
iostream = stream;
return 0;
}
#endif
void
pop3d_bye ()
{
if (istream == ostream)
{
mu_stream_close (istream);
mu_stream_destroy (&istream);
}
/* There's no reason closing in/out streams otherwise */
mu_stream_close (iostream);
mu_stream_destroy (&iostream);
#ifdef WITH_TLS
if (tls_available)
mu_deinit_tls_libs ();
......@@ -206,53 +240,28 @@ pop3d_bye ()
void
pop3d_flush_output ()
{
mu_stream_flush (ostream);
mu_stream_flush (iostream);
}
int
pop3d_is_master ()
{
return ostream == NULL;
}
static void
transcript (const char *pfx, const char *buf)
{
if (pop3d_transcript)
{
int len = strlen (buf);
if (len > 0 && buf[len-1] == '\n')
{
len--;
if (len > 0 && buf[len-1] == '\r')
len--;
}
mu_diag_output (MU_DIAG_DEBUG, "%s: %-.*s", pfx, len, buf);
}
return iostream == NULL;
}
void
pop3d_outf (const char *fmt, ...)
{
va_list ap;
char *buf;
int rc;
va_start (ap, fmt);
vasprintf (&buf, fmt, ap);
rc = mu_stream_vprintf (iostream, fmt, ap);
va_end (ap);
if (!buf)
pop3d_abquit (ERR_NO_MEM);
transcript ("sent", buf);
rc = mu_stream_write (ostream, buf, strlen (buf), NULL);
free (buf);
if (rc)
{
mu_diag_output (MU_DIAG_ERROR, _("Write failed: %s"),
mu_stream_strerror (ostream, rc));
mu_stream_strerror (iostream, rc));
pop3d_abquit (ERR_IO);
}
}
......@@ -265,13 +274,13 @@ pop3d_readline (char *buffer, size_t size)
size_t nbytes;
alarm (idle_timeout);
rc = mu_stream_readline (istream, buffer, size, &nbytes);
rc = mu_stream_readline (iostream, buffer, size, &nbytes);
alarm (0);
if (rc)
{
mu_diag_output (MU_DIAG_ERROR, _("Read failed: %s"),
mu_stream_strerror (ostream, rc));
mu_stream_strerror (iostream, rc));
pop3d_abquit (ERR_IO);
}
else if (nbytes == 0)
......@@ -285,8 +294,6 @@ pop3d_readline (char *buffer, size_t size)
pop3d_abquit (ERR_PROTO);
}
transcript ("recv", buffer);
return buffer;
}
......
......@@ -189,7 +189,7 @@ struct pop3d_command
pop3d_command_handler_t handler;
};
extern mu_stream_t istream, ostream;
extern mu_stream_t iostream;
extern mu_pop_server_t pop3srv;
extern mu_mailbox_t mbox;
extern int state;
......
......@@ -46,7 +46,7 @@ pop3d_retr (char *arg)
return ERR_UNKNOWN;
pop3d_outf ("+OK\n");
mu_stream_copy (ostream, stream, 0);
mu_stream_copy (iostream, stream, 0);
mu_stream_destroy (&stream);
if (!mu_attribute_is_read (attr))
......
......@@ -35,7 +35,7 @@ pop3d_stls (char *arg)
pop3d_outf ("+OK Begin TLS negotiation\n");
pop3d_flush_output ();
tls_done = pop3d_init_tls_server ();
tls_done = pop3d_init_tls_server () == 0;
if (!tls_done)
{
......
......@@ -62,7 +62,7 @@ pop3d_top (char *arg)
return ERR_UNKNOWN;
pop3d_outf ("+OK\n");
mu_stream_copy (ostream, stream, 0);
mu_stream_copy (iostream, stream, 0);
pop3d_outf ("\n");
mu_stream_destroy (&stream);
......