Commit 08dbbe2a 08dbbe2a422ee12fc9b80f2b7bd5d209b0812272 by Sergey Poznyakoff

Improve transcript stream.

* include/mailutils/stream.h (MU_IOCTL_LEVEL): New ioctl op.
(XSCRIPT_NORMAL, XSCRIPT_SECURE, XSCRIPT_PAYLOAD): New constants.
* include/mailutils/sys/xscript-stream.h (_mu_xscript_stream)
<level>: New member.
* mailbox/xscript-stream.c (TRANS_DISABLED): New flag.
(print_transcript): Amount of output varies depending on the
current output level.  For secure data, try to recognize passwords
and to replace them with *** on output.
(_xscript_ctl): Support MU_IOCTL_LEVEL.
* pop3d/extra.c (set_xscript_level): New function.
* pop3d/pop3d.h (set_xscript_level): New proto.
* pop3d/retr.c (pop3d_retr): Set XSCRIPT_PAYLOAD level before
sending actual data and reset it to XSCRIPT_NORMAL afterwards.
* pop3d/top.c (pop3d_top): Likewise.
* pop3d/user.c: Set XSCRIPT_SECURE level while expecting the
PASS command.

* imap4d/fetch.c (imap4d_fetch): Run imap4d_fetch0 in XSCRIPT_PAYLOAD
level.
* imap4d/uid.c (imap4d_uid): Likewise.
* imap4d/imap4d.c (imap4d_mainloop): Unless started in preauth mode,
select XSCRIPT_SECURE mode until authentication has been passed.
* imap4d/imap4d.h (set_xscript_level): New proto.
* imap4d/io.c (io_format_completion_response): Switch to XSCRIPT_NORMAL
level when changing to the authenticated state.
(imap4d_readline): Read literals in XSCRIPT_PAYLOAD level.
* imap4d/util.c (set_xscript_level): New function.

* include/mailutils/pop3.h (mu_pop3_trace_mask): New prototype.
(MU_POP3_XSCRIPT_MASK): New macro.
(_mu_pop3_xscript_level): New proto.
* libproto/pop/pop3_pass.c (mu_pop3_pass): Set XSCRIPT_SECURE
while sending the password.
* libproto/pop/pop3_retr.c (mu_pop3_retr): Set XSCRIPT_PAYLOAD before
going to MU_POP3_RETR_RX state.
* libproto/pop/pop3_stream.c (_pop3_event_cb): Set XSCRIPT_NORMAL.
* libproto/pop/pop3_top.c (mu_pop3_top): Set XSCRIPT_PAYLOAD before
going to MU_POP3_TOP_RX state.
* libproto/pop/pop3_trace.c (mu_pop3_trace_mask)
(_mu_pop3_xscript_level): New functions.
* libproto/pop/mbox.c (pop_open): Set trace masks depending on the
trace6 and trace7 debug levels.

* examples/pop3client.c (com_verbose): Allow to mask/unmask transcript
levels.
1 parent 7bfe0ed9
......@@ -131,8 +131,8 @@ COMMAND commands[] = {
"Get the unique id of message: UIDL [msgno]" },
{ "user", 2, 2, com_user,
"send login: USER user" },
{ "verbose", 1, 2, com_verbose,
"Enable Protocol tracing: verbose [on|off]" },
{ "verbose", 1, 4, com_verbose,
"Enable Protocol tracing: verbose [on|off|mask|unmask] [x1 [x2]]" },
#ifdef WITH_READLINE
{ "history", 1, 1, com_history,
"Show command history" },
......@@ -145,6 +145,14 @@ mu_pop3_t pop3;
/* Flag if verbosity is needed. */
int verbose;
#define VERBOSE_MASK(n) (1<<((n)+1))
#define SET_VERBOSE_MASK(n) (verbose |= VERBOSE_MASK (n))
#define CLR_VERBOSE_MASK(n) (verbose &= VERBOSE_MASK (n))
#define QRY_VERBOSE_MASK(n) (verbose & VERBOSE_MASK (n))
#define HAS_VERBOSE_MASK(n) (verbose & ~1)
#define SET_VERBOSE() (verbose |= 1)
#define CLR_VERBOSE() (verbose &= ~1)
#define QRY_VERBOSE() (verbose & 1)
/* When non-zero, this global means the user is done using this program. */
int done;
......@@ -408,10 +416,8 @@ get_bool (const char *str, int *pb)
|| mu_c_strcasecmp (str, "false") == 0)
*pb = 0;
else
{
mu_error ("not a boolean: %s", str);
return 1;
}
return 0;
}
......@@ -509,13 +515,91 @@ find_command (char *name)
return NULL;
}
static int
string_to_xlev (const char *name, int *pv)
{
if (strcmp (name, "secure") == 0)
*pv = XSCRIPT_SECURE;
else if (strcmp (name, "payload") == 0)
*pv = XSCRIPT_PAYLOAD;
else
return 1;
return 0;
}
static int
change_verbose_mask (int set, int argc, char **argv)
{
int i;
for (i = 0; i < argc; i++)
{
int lev;
if (string_to_xlev (argv[i], &lev))
{
mu_error ("unknown level: %s", argv[i]);
return 1;
}
if (set)
SET_VERBOSE_MASK (lev);
else
CLR_VERBOSE_MASK (lev);
}
return 0;
}
void
set_verbose (mu_pop3_t p)
{
if (p)
{
if (QRY_VERBOSE ())
{
mu_pop3_trace (p, MU_POP3_TRACE_SET);
}
else
mu_pop3_trace (p, MU_POP3_TRACE_CLR);
}
}
void
set_verbose_mask (mu_pop3_t p)
{
if (p)
{
mu_pop3_trace_mask (p, QRY_VERBOSE_MASK (XSCRIPT_SECURE)
? MU_POP3_TRACE_SET : MU_POP3_TRACE_CLR,
XSCRIPT_SECURE);
mu_pop3_trace_mask (p, QRY_VERBOSE_MASK (XSCRIPT_PAYLOAD)
? MU_POP3_TRACE_SET : MU_POP3_TRACE_CLR,
XSCRIPT_PAYLOAD);
}
}
int
com_verbose (int argc, char **argv)
{
if (argc == 1)
{
if (verbose)
printf ("verbose is on\n");
if (QRY_VERBOSE ())
{
printf ("verbose is on");
if (HAS_VERBOSE_MASK ())
{
char *delim = " (";
if (QRY_VERBOSE_MASK (XSCRIPT_SECURE))
{
printf("%ssecure", delim);
delim = ", ";
}
if (QRY_VERBOSE_MASK (XSCRIPT_PAYLOAD))
printf("%spayload", delim);
printf (")");
}
printf ("\n");
}
else
printf ("verbose is off\n");
}
......@@ -525,16 +609,20 @@ com_verbose (int argc, char **argv)
if (get_bool (argv[1], &bv) == 0)
{
verbose = bv;
if (pop3 != NULL)
{
if (verbose == 1)
mu_pop3_trace (pop3, MU_POP3_TRACE_SET);
else
mu_pop3_trace (pop3, MU_POP3_TRACE_CLR);
}
verbose |= bv;
if (argc > 2)
change_verbose_mask (verbose, argc - 2, argv + 2);
set_verbose (pop3);
}
else if (strcmp (argv[1], "mask") == 0)
change_verbose_mask (1, argc - 2, argv + 2);
else if (strcmp (argv[1], "unmask") == 0)
change_verbose_mask (0, argc - 2, argv + 2);
else
mu_error ("unknown subcommand");
set_verbose_mask (pop3);
}
return 0;
}
......@@ -929,8 +1017,11 @@ com_connect (int argc, char **argv)
{
mu_stream_t tcp;
if (verbose)
mu_pop3_trace (pop3, MU_POP3_TRACE_SET);
if (QRY_VERBOSE ())
{
set_verbose (pop3);
set_verbose_mask (pop3);
}
status = mu_tcp_stream_create (&tcp, argv[0], n, MU_STREAM_READ);
if (status == 0)
{
......
......@@ -1679,7 +1679,8 @@ imap4d_fetch (struct imap4d_command *command, imap4d_tokbuf_t tok)
{
int rc;
char *err_text = "Completed";
int xlev = set_xscript_level (XSCRIPT_PAYLOAD);
rc = imap4d_fetch0 (tok, 0, &err_text);
set_xscript_level (xlev);
return io_completion_response (command, rc, "%s", err_text);
}
......
......@@ -422,6 +422,8 @@ imap4d_mainloop (int fd, FILE *infile, FILE *outfile)
RESP_PREAUTH : RESP_OK, "%s", text);
io_flush ();
set_xscript_level ((state == STATE_AUTH) ? XSCRIPT_NORMAL : XSCRIPT_SECURE);
tokp = imap4d_tokbuf_init ();
while (1)
{
......
......@@ -382,6 +382,8 @@ int is_atom (const char *s);
int util_isdelim (const char *str);
int util_trim_nl (char *s, size_t len);
int set_xscript_level (int xlev);
#ifdef WITH_TLS
int imap4d_init_tls_server (void);
#endif /* WITH_TLS */
......
......@@ -241,7 +241,11 @@ io_format_completion_response (mu_stream_t str,
new_state = STATE_NONE;
if (new_state != STATE_NONE)
{
if (new_state == STATE_AUTH)
set_xscript_level (XSCRIPT_NORMAL);
state = new_state;
}
return status;
}
......@@ -570,6 +574,7 @@ imap4d_readline (struct imap4d_tokbuf *tok)
char *sp = NULL;
char *buf;
size_t len;
int xlev = set_xscript_level (XSCRIPT_PAYLOAD);
number = strtoul (last_arg + 1, &sp, 10);
/* Client can ask for non-synchronised literal,
......@@ -595,6 +600,7 @@ imap4d_readline (struct imap4d_tokbuf *tok)
tok->level += len;
tok->buffer[tok->level++] = 0;
tok->argp[tok->argc - 1] = off;
set_xscript_level (xlev);
}
else
break;
......
......@@ -37,7 +37,11 @@ imap4d_uid (struct imap4d_command *command, imap4d_tokbuf_t tok)
cmd = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
if (mu_c_strcasecmp (cmd, "FETCH") == 0)
{
int xlev = set_xscript_level (XSCRIPT_PAYLOAD);
rc = imap4d_fetch0 (tok, 1, &err_text);
set_xscript_level (xlev);
}
else if (mu_c_strcasecmp (cmd, "COPY") == 0)
rc = imap4d_copy0 (tok, 1, &err_text);
else if (mu_c_strcasecmp (cmd, "STORE") == 0)
......
......@@ -672,3 +672,22 @@ is_atom (const char *s)
return 1;
}
int
set_xscript_level (int xlev)
{
if (imap4d_transcript)
{
if (xlev != XSCRIPT_NORMAL)
{
mu_log_level_t n = xlev == XSCRIPT_SECURE ?
MU_DEBUG_TRACE6 : MU_DEBUG_TRACE7;
if (mu_global_debug_level ("imap4") & MU_DEBUG_LEVEL_MASK (n))
return XSCRIPT_NORMAL;
}
if (mu_stream_ioctl (iostream, MU_IOCTL_LEVEL, &xlev) == 0)
return xlev;
}
return 0;
}
......
......@@ -50,6 +50,7 @@ int mu_pop3_get_timeout (mu_pop3_t pop3, int *timeout);
#define MU_POP3_TRACE_SET 1
#define MU_POP3_TRACE_QRY 2
int mu_pop3_trace (mu_pop3_t pop3, int op);
int mu_pop3_trace_mask (mu_pop3_t pop3, int op, int lev);
int mu_pop3_apop (mu_pop3_t pop3, const char *name, const char *digest);
......
......@@ -63,6 +63,9 @@ enum mu_buffer_type
#define MU_IOCTL_SET_TRANSPORT 6
#define MU_IOCTL_SWAP_STREAM 7
#define MU_IOCTL_LEVEL 8
void mu_stream_ref (mu_stream_t stream);
void mu_stream_unref (mu_stream_t stream);
void mu_stream_destroy (mu_stream_t *pstream);
......@@ -153,9 +156,15 @@ 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);
/* Transcript output levels */
#define XSCRIPT_NORMAL 0 /* Normal transcript */
#define XSCRIPT_SECURE 1 /* Security-related data are being sent/received */
#define XSCRIPT_PAYLOAD 2 /* Actual payload (may be copious) */
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 mu_dbgstream_create(mu_stream_t *pref, mu_debug_t debug,
mu_log_level_t level, int flags);
......
......@@ -59,6 +59,7 @@ enum mu_pop3_state
#define MU_POP3_ACK 0x01
#define MU_POP3_TRACE 0x02
#define MU_POP3_XSCRIPT_MASK(n) (1<<((n)+1))
/* Structure to hold things general to POP3 mailbox, like its state, etc ... */
struct _mu_pop3
......@@ -90,6 +91,8 @@ extern int mu_pop3_stream_create (mu_pop3_t pop3, mu_stream_t *pstream);
extern int mu_pop3_carrier_is_ready (mu_stream_t carrier, int flag,
int timeout);
int _mu_pop3_xscript_level (mu_pop3_t pop3, int xlev);
int _mu_pop3_trace_enable (mu_pop3_t pop3);
int _mu_pop3_trace_disable (mu_pop3_t pop3);
......
......@@ -27,6 +27,7 @@ struct _mu_xscript_stream
mu_stream_t transport;
mu_stream_t logstr;
int flags;
int level;
char *prefix[2];
};
......
......@@ -161,6 +161,10 @@ pop_open (mu_mailbox_t mbox, int flags)
if (mu_debug_check_level (mbox->debug, MU_DEBUG_PROT))
mu_pop3_trace (mpd->pop3, MU_POP3_TRACE_SET);
if (mu_debug_check_level (mbox->debug, MU_DEBUG_TRACE6))
mu_pop3_trace_mask (mpd->pop3, MU_POP3_TRACE_SET, XSCRIPT_SECURE);
if (mu_debug_check_level (mbox->debug, MU_DEBUG_TRACE7))
mu_pop3_trace_mask (mpd->pop3, MU_POP3_TRACE_SET, XSCRIPT_PAYLOAD);
do
{
......@@ -214,7 +218,7 @@ pop_destroy (mu_mailbox_t mbox)
{
size_t i;
mu_monitor_wrlock (mbox->monitor);
/* Destroy the pop messages and ressources associated to them. */
/* Destroy the pop messages and resources associated to them. */
for (i = 0; i < mpd->msg_count; i++)
{
if (mpd->msg[i])
......@@ -291,7 +295,7 @@ pop_scan (mu_mailbox_t mbox, size_t msgno, size_t *pcount)
if (mu_observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD,
&tmp) != 0)
break;
if (((i +1) % 10) == 0)
if (((i + 1) % 10) == 0)
{
mu_observable_notify (mbox->observable, MU_EVT_MAILBOX_PROGRESS,
NULL);
......
......@@ -35,7 +35,10 @@ mu_pop3_pass (mu_pop3_t pop3, const char *passwd)
switch (pop3->state)
{
case MU_POP3_NO_STATE:
if (mu_pop3_trace_mask (pop3, MU_POP3_TRACE_QRY, XSCRIPT_SECURE))
_mu_pop3_xscript_level (pop3, XSCRIPT_SECURE);
status = mu_pop3_writeline (pop3, "PASS %s\r\n", passwd);
_mu_pop3_xscript_level (pop3, XSCRIPT_NORMAL);
MU_POP3_CHECK_ERROR (pop3, status);
/* FIXME: how to obscure the passwd in the stream buffer? */
MU_POP3_FCLR (pop3, MU_POP3_ACK);
......
......@@ -50,6 +50,8 @@ mu_pop3_retr (mu_pop3_t pop3, unsigned int msgno, mu_stream_t *pstream)
MU_POP3_CHECK_OK (pop3);
status = mu_pop3_stream_create (pop3, pstream);
MU_POP3_CHECK_ERROR (pop3, status);
if (mu_pop3_trace_mask (pop3, MU_POP3_TRACE_QRY, XSCRIPT_PAYLOAD))
_mu_pop3_xscript_level (pop3, XSCRIPT_PAYLOAD);
pop3->state = MU_POP3_RETR_RX;
case MU_POP3_RETR_RX:
......
......@@ -185,6 +185,7 @@ _pop3_event_cb (mu_stream_t str, int ev, int flags)
if (mu_stream_ioctl (str, MU_IOCTL_GET_TRANSPORT, trans) == 0)
{
struct mu_pop3_stream *sp = (struct mu_pop3_stream *) trans[0];
_mu_pop3_xscript_level (sp->pop3, XSCRIPT_NORMAL);
sp->pop3->state = MU_POP3_NO_STATE;
}
}
......
......@@ -50,6 +50,8 @@ mu_pop3_top (mu_pop3_t pop3, unsigned msgno, unsigned int lines,
MU_POP3_CHECK_OK (pop3);
status = mu_pop3_stream_create (pop3, pstream);
MU_POP3_CHECK_ERROR (pop3, status);
if (mu_pop3_trace_mask (pop3, MU_POP3_TRACE_QRY, XSCRIPT_PAYLOAD))
_mu_pop3_xscript_level (pop3, XSCRIPT_PAYLOAD);
pop3->state = MU_POP3_TOP_RX;
case MU_POP3_TOP_RX:
......
......@@ -115,4 +115,36 @@ mu_pop3_trace (mu_pop3_t pop3, int op)
return EINVAL;
}
int
mu_pop3_trace_mask (mu_pop3_t pop3, int op, int lev)
{
switch (op)
{
case MU_POP3_TRACE_SET:
pop3->flags |= MU_POP3_XSCRIPT_MASK(lev);
break;
case MU_POP3_TRACE_CLR:
pop3->flags &= ~MU_POP3_XSCRIPT_MASK(lev);
break;
case MU_POP3_TRACE_QRY:
if (pop3->flags & MU_POP3_XSCRIPT_MASK(lev))
break;
return MU_ERR_NOENT;
default:
return EINVAL;
}
return 0;
}
int
_mu_pop3_xscript_level (mu_pop3_t pop3, int xlev)
{
if (mu_stream_ioctl (pop3->carrier, MU_IOCTL_LEVEL, &xlev) == 0)
return xlev;
return XSCRIPT_NORMAL;
}
......
......@@ -30,6 +30,8 @@
#include <mailutils/stream.h>
#include <mailutils/sys/stream.h>
#include <mailutils/sys/xscript-stream.h>
#include <mailutils/cctype.h>
#include <mailutils/cstr.h>
/* A "transcript stream" transparently writes data to and reads data from
an underlying transport stream, writing each lineful of data to a "log
......@@ -40,8 +42,50 @@
#define TRANS_READ 0x1
#define TRANS_WRITE 0x2
#define TRANS_DISABLED 0x4
#define FLAG_TO_PFX(c) ((c) - 1)
static int
word_match (const char *buf, size_t len, int n, const char *word,
size_t *pos)
{
size_t i = 0;
size_t wl = strlen (word);
for (;; n--)
{
/* Skip whitespace separator */
for (; i < len && mu_isspace (buf[i]); i++)
;
if (n == 0)
break;
/* Skip the argument */
if (buf[i] == '"')
{
for (i++; i < len && buf[i] != '"'; i++)
if (buf[i] == '\'')
i++;
}
else
{
for (; i < len && !mu_isspace (buf[i]); i++)
;
}
}
if (i + wl <= len &&
mu_c_strncasecmp (buf + i, word, wl) == 0 &&
mu_isblank (buf[i + wl]))
{
*pos = i + wl;
return 1;
}
return 0;
}
static void
print_transcript (struct _mu_xscript_stream *str, int flag,
const char *buf, size_t size)
......@@ -57,14 +101,56 @@ print_transcript (struct _mu_xscript_stream *str, int flag,
str->prefix[FLAG_TO_PFX(flag)],
strlen (str->prefix[FLAG_TO_PFX (flag)]),
NULL);
str->flags &= ~flag;
str->flags &= ~(flag | TRANS_DISABLED);
}
if (str->flags & TRANS_DISABLED)
return;
if (str->level == XSCRIPT_PAYLOAD)
{
mu_stream_printf (str->logstr, "(data...)\n");
str->flags |= TRANS_DISABLED;
return;
}
p = memchr (buf, '\n', size);
if (p)
{
len = p - buf;
if (p > buf && p[-1] == '\r')
len--;
if (str->level == XSCRIPT_SECURE)
{
size_t i;
if (word_match (buf, len, 0, "PASS", &i))
mu_stream_printf (str->logstr, "PASS ***");
else if (word_match (buf, len, 1, "LOGIN", &i))
{
/* Skip the whitespace separator */
for (; i < len && mu_isspace (buf[i]); i++)
;
/* Skip the first argument (presumably the user name) */
if (buf[i] == '"')
{
for (i++; i < len && buf[i] != '"'; i++)
if (buf[i] == '\'')
i++;
}
else
{
for (; i < len && !mu_isspace (buf[i]); i++)
;
}
mu_stream_write (str->logstr, buf, i, NULL);
mu_stream_write (str->logstr, " \"***\"", 6, NULL);
}
else
mu_stream_write (str->logstr, buf, len, NULL);
}
else
mu_stream_write (str->logstr, buf, len, NULL);
mu_stream_write (str->logstr, "\n", 1, NULL);
str->flags |= flag;
......@@ -229,6 +315,18 @@ _xscript_ctl (struct _mu_stream *str, int op, void *arg)
}
break;
case MU_IOCTL_LEVEL:
if (!arg)
return EINVAL;
else
{
int oldlev = sp->level;
sp->level = *(int*)arg;
sp->flags = TRANS_READ | TRANS_WRITE;
*(int*)arg = oldlev;
}
break;
default:
return mu_stream_ioctl (sp->transport, op, arg);
}
......
......@@ -338,3 +338,23 @@ pop3d_undelete_all ()
mu_attribute_unset_deleted (attr);
}
}
int
set_xscript_level (int xlev)
{
if (pop3d_transcript)
{
if (xlev != XSCRIPT_NORMAL)
{
mu_log_level_t n = xlev == XSCRIPT_SECURE ?
MU_DEBUG_TRACE6 : MU_DEBUG_TRACE7;
if (mu_global_debug_level ("pop3") & MU_DEBUG_LEVEL_MASK (n))
return XSCRIPT_NORMAL;
}
if (mu_stream_ioctl (iostream, MU_IOCTL_LEVEL, &xlev) == 0)
return xlev;
}
return 0;
}
......
......@@ -265,4 +265,6 @@ extern int set_bulletin_source (const char *source);
extern int pop3d_begin_session (void);
extern const char *pop3d_error_string (int code);
extern int set_xscript_level (int xlev);
#endif /* _POP3D_H */
......
......@@ -26,6 +26,7 @@ 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;
......@@ -46,6 +47,7 @@ pop3d_retr (char *arg)
return ERR_UNKNOWN;
pop3d_outf ("+OK\n");
xscript_level = set_xscript_level (XSCRIPT_PAYLOAD);
mu_stream_copy (iostream, stream, 0, NULL);
mu_stream_destroy (&stream);
......@@ -56,5 +58,7 @@ pop3d_retr (char *arg)
pop3d_outf (".\n");
set_xscript_level (xscript_level);
return OK;
}
......
......@@ -30,6 +30,7 @@ pop3d_top (char *arg)
mu_body_t body;
mu_stream_t stream;
char *mesgc, *linesc, *p;
int xscript_level;
if (strlen (arg) == 0)
return ERR_BAD_ARGS;
......@@ -62,6 +63,8 @@ pop3d_top (char *arg)
return ERR_UNKNOWN;
pop3d_outf ("+OK\n");
xscript_level = set_xscript_level (XSCRIPT_PAYLOAD);
mu_stream_copy (iostream, stream, 0, NULL);
pop3d_outf ("\n");
mu_stream_destroy (&stream);
......@@ -85,5 +88,7 @@ pop3d_top (char *arg)
pop3d_outf (".\n");
set_xscript_level (xscript_level);
return OK;
}
......
......@@ -91,6 +91,7 @@ pop3d_user (char *arg)
{
char *buf, *pass, *cmd;
char buffer[512];
int xscript_level;
if (state != AUTHORIZATION)
return ERR_WRONG_STATE;
......@@ -101,8 +102,10 @@ pop3d_user (char *arg)
pop3d_outf ("+OK\n");
pop3d_flush_output ();
xscript_level = set_xscript_level (XSCRIPT_SECURE);
buf = pop3d_readline (buffer, sizeof (buffer));
pop3d_parse_command (buf, &cmd, &pass);
set_xscript_level (xscript_level);
if (mu_c_strcasecmp (cmd, "PASS") == 0)
{
......