Commit 0d5e2520 0d5e25206ad589442bc13ad1791bc150e2a597de by Sergey Poznyakoff

* auth/sql.c, libproto/mbox/folder.c: Rename MU_READ_ERROR to

MU_ERR_READ, for consistency.

* comsat/Makefile.am (comsatd_LDADD): Add all mailbox formats.
* comsat/cfg.c: Use mu_error instead of syslog.
* comsat/comsat.c (comsat_daemon): Implement test mode.
(notify_user): Use mailbox quick access mode instead of directly
fiddling with the UNIX mailbox stream.

* include/mailutils/stream.h (MU_STREAM_QACCESS): New define.
* libproto/mbox/mbox.c: Implement _quick_get_message method.
* libproto/mbox/mbox0.h (mbox_scan1): New function.
* libproto/mbox/mboxscan.c (mbox_scan0): Split into mbox_scan0
proper and mbox_scan_internal.
(mbox_scan1): New function.
Remove unused defines.
* libsieve/load.c: Do not deallocate loaded modules.
* mail.local/main.c (set_debug_flags): Fix typo.
* mailbox/amd.c: Implement get_qid method.
(amd_append_message) Singal MU_EVT_MESSAGE_APPEND.
* mailbox/errors (MU_ERR_BADOP): New error code.
(MU_READ_ERROR): Rename to MU_ERR_READ, for consistency.
* mailbox/file_stream.c (_prog_destroy,_prog_close): Fix waiting
for the children to terminate. Do not forcefully kill them.

* mailbox/mailbox.c: Control allowed operations, depending on
MU_STREAM_QACCESS bit.
1 parent df7db464
......@@ -417,7 +417,7 @@ get_field (mu_sql_connection_t conn, const char *id, char **ret, int mandatory)
{
mu_error (_("SQL field `%s' (`%s') has NULL value"),
id, name ? *name : id);
rc = MU_READ_ERROR;
rc = MU_ERR_READ;
}
return rc;
......
......@@ -26,6 +26,11 @@ comsatd_SOURCES = action.c cfg.c comsat.c comsat.h
comsatd_LDADD = \
../lib/libmuaux.la\
${MU_LIB_MBOX}\
${MU_LIB_IMAP}\
${MU_LIB_POP}\
${MU_LIB_NNTP}\
${MU_LIB_MH}\
${MU_LIB_MAILDIR}\
${MU_LIB_MAILUTILS}\
@MU_COMMON_LIBRARIES@
......
......@@ -110,7 +110,7 @@ netdef_parse (char *str)
netdef = malloc (sizeof *netdef);
if (!netdef)
{
syslog (LOG_ERR, _("Out of memory"));
mu_error (_("Out of memory"));
exit (1);
}
......@@ -135,7 +135,8 @@ read_config (const char *config_file)
fp = fopen (config_file, "r");
if (!fp)
{
syslog (LOG_ERR, _("Cannot open config file %s: %m"), config_file);
mu_error (_("Cannot open config file %s: %s"), config_file,
mu_strerror (errno));
return;
}
......@@ -162,7 +163,7 @@ read_config (const char *config_file)
mu_argcv_get (ptr, "", NULL, &argc, &argv);
if (argc < 2)
{
syslog (LOG_ERR, _("%s:%d: too few fields"), config_file, line);
mu_error (_("%s:%d: too few fields"), config_file, line);
mu_argcv_free (argc, argv);
continue;
}
......@@ -174,7 +175,7 @@ read_config (const char *config_file)
else if (strcmp (argv[1], "no") == 0)
allow_biffrc = 0;
else
syslog (LOG_ERR, _("%s:%d: yes or no expected"), config_file, line);
mu_error (_("%s:%d: yes or no expected"), config_file, line);
}
else if (strcmp (argv[0], "max-requests") == 0)
maxrequests = strtoul (argv[1], NULL, 0);
......@@ -194,7 +195,7 @@ read_config (const char *config_file)
action = ACT_DENY;
else
{
syslog (LOG_ERR, _("%s:%d: unknown keyword"), config_file, line);
mu_error (_("%s:%d: unknown keyword"), config_file, line);
mu_argcv_free (argc, argv);
continue;
}
......@@ -205,8 +206,8 @@ read_config (const char *config_file)
netdef_t *cur = netdef_parse (argv[i]);
if (!cur)
{
syslog (LOG_ERR, _("%s:%d: cannot parse netdef: %s"),
config_file, line, argv[i]);
mu_error (_("%s:%d: cannot parse netdef: %s"),
config_file, line, argv[i]);
continue;
}
if (!tail)
......@@ -221,7 +222,7 @@ read_config (const char *config_file)
acl = malloc (sizeof *acl);
if (!acl)
{
syslog (LOG_CRIT, _("Out of memory"));
mu_error (_("Out of memory"));
exit (1);
}
acl->next = NULL;
......
......@@ -57,7 +57,8 @@ static char doc[] = "GNU comsatd";
static struct argp_option options[] =
{
{"config", 'c', N_("FILE"), 0, N_("Read configuration from FILE"), 0},
{ "config", 'c', N_("FILE"), 0, N_("Read configuration from FILE"), 0 },
{ "test", 't', NULL, 0, N_("Run in test mode"), 0 },
{ NULL, 0, NULL, 0, NULL, 0 }
};
......@@ -104,7 +105,8 @@ static void comsat_init (void);
static void comsat_daemon_init (void);
static void comsat_daemon (int _port);
static int comsat_main (int fd);
static void notify_user (const char *user, const char *device, const char *path, off_t offset);
static void notify_user (const char *user, const char *device,
const char *path, mu_message_qid_t qid);
static int find_user (const char *name, char *tty);
static char *mailbox_path (const char *user);
static void change_user (const char *user);
......@@ -112,6 +114,7 @@ static void change_user (const char *user);
static int xargc;
static char **xargv;
char *config_file = NULL;
int test_mode;
static error_t
comsatd_parse_opt (int key, char *arg, struct argp_state *state)
......@@ -125,6 +128,10 @@ comsatd_parse_opt (int key, char *arg, struct argp_state *state)
case 'c':
config_file = arg;
break;
case 't':
test_mode = 1;
break;
default:
return ARGP_ERR_UNKNOWN;
......@@ -134,20 +141,59 @@ comsatd_parse_opt (int key, char *arg, struct argp_state *state)
int
main(int argc, char **argv)
main (int argc, char **argv)
{
int c;
int ind;
/* Native Language Support */
mu_init_nls ();
mu_argp_init (program_version, NULL);
mu_argp_parse (&argp, &argc, &argv, 0, comsat_argp_capa,
NULL, &daemon_param);
&ind, &daemon_param);
argc -= ind;
argv += ind;
if (test_mode)
{
char *user, *url, *qid;
comsat_init ();
if (config_file)
read_config (config_file);
if (argc == 0)
exit (0);
if (argc < 2 || argc > 2)
{
mu_error (_("Mailbox URL and message QID are required in test mode"));
exit (EXIT_FAILURE);
}
user = getenv ("LOGNAME");
if (!user)
{
user = getenv ("USER");
if (!user)
{
struct passwd *pw = getpwuid (getuid ());
if (!pw)
{
mu_error (_("Cannot determine user name"));
exit (EXIT_FAILURE);
}
user = pw->pw_name;
}
}
notify_user (user, "/dev/tty", argv[0], argv[1]);
exit (0);
}
if (daemon_param.timeout > 0 && daemon_param.mode == MODE_DAEMON)
{
fprintf (stderr, _("--timeout and --daemon are incompatible\n"));
mu_error (_("--timeout and --daemon are incompatible"));
exit (EXIT_FAILURE);
}
......@@ -194,7 +240,8 @@ sig_hup (int sig)
void
comsat_init ()
{
mu_registrar_record (mu_path_record);
/* Register mailbox formats */
mu_register_all_mbox_formats ();
gethostname (hostname, sizeof hostname);
......@@ -324,10 +371,10 @@ comsat_main (int fd)
char buffer[216]; /*FIXME: Arbitrary size */
pid_t pid;
char tty[MAX_TTY_SIZE];
char *p, *endp;
size_t offset;
char *p;
char *path = NULL;
mu_message_qid_t qid;
len = sizeof sin_from;
rdlen = recvfrom (fd, buffer, sizeof buffer, 0,
(struct sockaddr*)&sin_from, &len);
......@@ -362,19 +409,8 @@ comsat_main (int fd)
}
*p++ = 0;
offset = strtoul (p, &endp, 0);
switch (*endp)
{
case 0:
break;
case ':':
path = endp+1;
break;
default:
if (!isspace (*endp))
syslog (LOG_ERR, _("Malformed input: %s@%s (near %s)"), buffer, p, endp);
}
qid = p;
if (find_user (buffer, tty) != SUCCESS)
return 0;
......@@ -400,7 +436,7 @@ comsat_main (int fd)
}
/* Child: do actual I/O */
notify_user (buffer, tty, path, offset);
notify_user (buffer, tty, path, qid);
exit (0);
}
......@@ -423,17 +459,14 @@ get_newline_str (FILE *fp)
/* NOTE: Do not bother to free allocated memory, as the program exits
immediately after executing this */
static void
notify_user (const char *user, const char *device, const char *path, off_t offset)
notify_user (const char *user, const char *device, const char *path,
mu_message_qid_t qid)
{
FILE *fp;
const char *cr;
char *blurb;
mu_mailbox_t mbox = NULL, tmp = NULL;
mu_mailbox_t mbox = NULL;
mu_message_t msg;
mu_stream_t stream = NULL;
int status;
off_t size;
size_t count, n;
change_user (user);
if ((fp = fopen (device, "w")) == NULL)
......@@ -452,56 +485,21 @@ notify_user (const char *user, const char *device, const char *path, off_t offse
}
if ((status = mu_mailbox_create (&mbox, path)) != 0
|| (status = mu_mailbox_open (mbox, MU_STREAM_READ)) != 0)
|| (status = mu_mailbox_open (mbox, MU_STREAM_READ|MU_STREAM_QACCESS)) != 0)
{
syslog (LOG_ERR, _("Cannot open mailbox %s: %s"),
path, mu_strerror (status));
return;
}
if ((status = mu_mailbox_get_stream (mbox, &stream)))
{
syslog (LOG_ERR, _("Cannot get stream for mailbox %s: %s"),
path, mu_strerror (status));
return;
}
if ((status = mu_stream_size (stream, &size)))
{
syslog (LOG_ERR, _("Cannot get stream size (mailbox %s): %s"),
path, mu_strerror (status));
return;
}
/* Read headers */
size -= offset;
blurb = malloc (size + 1);
if (!blurb)
return;
mu_stream_read (stream, blurb, size, offset, &n);
blurb[size] = 0;
if ((status = mu_mailbox_create (&tmp, "/dev/null")) != 0
|| (status = mu_mailbox_open (tmp, MU_STREAM_READ)) != 0)
{
syslog (LOG_ERR, _("Cannot create temporary mailbox: %s"),
mu_strerror (status));
return;
}
if ((status = mu_memory_stream_create (&stream, 0, 0)))
status = mu_mailbox_quick_get_message (mbox, qid, &msg);
if (status)
{
syslog (LOG_ERR, _("Cannot create temporary stream: %s"),
mu_strerror (status));
return;
syslog (LOG_ERR, _("Cannot get message (mailbox %s, qid %s): %s"),
path, qid, mu_strerror (status));
return; /* FIXME: Notify the user, anyway */
}
mu_stream_write (stream, blurb, size, 0, &count);
mu_mailbox_set_stream (tmp, stream);
mu_mailbox_messages_count (tmp, &count);
mu_mailbox_get_message (tmp, 1, &msg);
run_user_action (fp, cr, msg);
fclose (fp);
}
......
......@@ -39,7 +39,9 @@ extern "C" { /*}*/
#define MU_STREAM_NO_CLOSE 0x00000100
#define MU_STREAM_ALLOW_LINKS 0x00000200
#define MU_STREAM_NONLOCK 0x00000400
/* This one affects only mailboxes */
#define MU_STREAM_QACCESS 0x00000800
/* Functions useful to users of the pre-defined stream types. */
extern int mu_file_stream_create (mu_stream_t *stream, const char* filename,
......
......@@ -358,7 +358,7 @@ list_helper (struct search_data *data,
break;
case GLOB_ABORTED:
status = MU_READ_ERROR;
status = MU_ERR_READ;
break;
case GLOB_NOMATCH:
......
......@@ -35,6 +35,9 @@ static void mbox_destroy (mu_mailbox_t);
static int mbox_open (mu_mailbox_t, int);
static int mbox_close (mu_mailbox_t);
static int mbox_get_message (mu_mailbox_t, size_t, mu_message_t *);
static int mbox_quick_get_message (mu_mailbox_t, mu_message_qid_t,
mu_message_t *);
/* static int mbox_get_message_by_uid (mu_mailbox_t, size_t, mu_message_t *); */
static int mbox_append_message (mu_mailbox_t, mu_message_t);
static int mbox_messages_count (mu_mailbox_t, size_t *);
......@@ -136,6 +139,7 @@ _mailbox_mbox_init (mu_mailbox_t mailbox)
mailbox->_sync = mbox_sync;
mailbox->_uidvalidity = mbox_uidvalidity;
mailbox->_uidnext = mbox_uidnext;
mailbox->_quick_get_message = mbox_quick_get_message;
mailbox->_scan = mbox_scan;
mailbox->_is_updated = mbox_is_updated;
......@@ -1065,45 +1069,10 @@ mbox_envelope_sender (mu_envelope_t envelope, char *buf, size_t len,
}
static int
mbox_get_message (mu_mailbox_t mailbox, size_t msgno, mu_message_t *pmsg)
new_message (mu_mailbox_t mailbox, mbox_message_t mum, mu_message_t *pmsg)
{
int status;
mbox_data_t mud = mailbox->data;
mbox_message_t mum;
mu_message_t msg = NULL;
/* Sanity checks. */
if (pmsg == NULL)
return MU_ERR_OUT_PTR_NULL;
if (mud == NULL)
return EINVAL;
/* If we did not start a scanning yet do it now. */
if (mud->messages_count == 0)
{
status = mbox_scan0 (mailbox, 1, NULL, 0);
if (status != 0)
return status;
}
/* Second sanity: check the message number. */
if (!(mud->messages_count > 0
&& msgno > 0
&& msgno <= mud->messages_count))
return EINVAL;
mum = mud->umessages[msgno - 1];
/* Check if we already have it. */
if (mum->message)
{
if (pmsg)
*pmsg = mum->message;
return 0;
}
MAILBOX_DEBUG2 (mailbox, MU_DEBUG_TRACE, "mbox_get_message (%s, %d)\n",
mud->name, msgno);
mu_message_t msg;
/* Get an empty message struct. */
status = mu_message_create (&msg, mum);
......@@ -1185,9 +1154,109 @@ mbox_get_message (mu_mailbox_t mailbox, size_t msgno, mu_message_t *pmsg)
mu_message_set_mailbox (msg, mailbox, mum);
*pmsg = msg;
return 0;
}
static int
mbox_get_message (mu_mailbox_t mailbox, size_t msgno, mu_message_t *pmsg)
{
int status;
mbox_data_t mud = mailbox->data;
mbox_message_t mum;
/* Sanity checks. */
if (pmsg == NULL)
return MU_ERR_OUT_PTR_NULL;
if (mud == NULL)
return EINVAL;
/* If we did not start a scanning yet do it now. */
if (mud->messages_count == 0)
{
status = mbox_scan0 (mailbox, 1, NULL, 0);
if (status != 0)
return status;
}
/* Second sanity: check the message number. */
if (!(mud->messages_count > 0
&& msgno > 0
&& msgno <= mud->messages_count))
return EINVAL;
mum = mud->umessages[msgno - 1];
/* Check if we already have it. */
if (mum->message)
{
if (pmsg)
*pmsg = mum->message;
return 0;
}
MAILBOX_DEBUG2 (mailbox, MU_DEBUG_TRACE, "mbox_get_message (%s, %d)\n",
mud->name, msgno);
return new_message (mailbox, mum, pmsg);
}
static int
qid2off (mu_message_qid_t qid, mu_off_t *pret)
{
mu_off_t ret = 0;
for (;*qid; qid++)
{
if (!('0' <= *qid && *qid <= '9'))
return 1;
ret = ret * 10 + *qid - '0';
}
*pret = ret;
return 0;
}
static int
mbox_quick_get_message (mu_mailbox_t mailbox, mu_message_qid_t qid,
mu_message_t *pmsg)
{
int status;
mbox_data_t mud = mailbox->data;
mbox_message_t mum;
mu_off_t offset;
if (mailbox == NULL || qid2off (qid, &offset)
|| !(mailbox->flags & MU_STREAM_QACCESS))
return EINVAL;
if (mud->messages_count == 0)
{
status = mbox_scan1 (mailbox, offset, 0);
if (status != 0)
return status;
}
/* Quick access mode retrieves only one message */
mum = mud->umessages[0];
/* Check if we already have it and verify if it is the right one. */
if (mum->message)
{
char *vqid;
status = mu_message_get_qid (mum->message, &vqid);
if (status)
return status;
status = strcmp (qid, vqid);
free (vqid);
if (status)
return MU_ERR_EXISTS;
if (pmsg)
*pmsg = mum->message;
return 0;
}
return new_message (mailbox, mum, pmsg);
}
static int
mbox_append_message (mu_mailbox_t mailbox, mu_message_t msg)
{
......
......@@ -124,6 +124,9 @@ struct _mbox_data
int mbox_scan0 (mu_mailbox_t mailbox, size_t msgno, size_t *pcount,
int do_notif);
int mbox_scan1 (mu_mailbox_t mailbox, mu_off_t offset, int do_notif);
#ifdef WITH_PTHREAD
void mbox_cleanup (void *arg);
#endif
......
......@@ -52,8 +52,6 @@
locks, flush the stream save the pointers etc ... hurry and wait...
I this point I'm pretty much ranting. */
/* From the C-Client, part of pine */
/* You are not expected to understand this macro, but read the next page if
* you are not faint of heart.
*
......@@ -181,6 +179,7 @@ h
} \
while (0)
#define ATTRIBUTE_SET(buf,mum,c0,c1,type) \
do \
{ \
......@@ -195,215 +194,6 @@ do \
} \
} while (0)
#define ISBCC(buf) ( \
(buf[0] == 'B' || buf[0] == 'b') \
&& (buf[1] == 'C' || buf[1] == 'c') \
&& (buf[2] == 'C' || buf[2] == 'c') \
&& (buf[3] == ':' || buf[3] == ' ' || buf[3] == '\t'))
#define ISCC(buf) ( \
(buf[0] == 'C' || buf[0] == 'c') \
&& (buf[1] == 'C' || buf[1] == 'c') \
&& (buf[2] == ':' || buf[2] == ' ' || buf[2] == '\t'))
#define ISCONTENT_LANGUAGE(buf) ( \
(buf[0] == 'C' || buf[0] == 'c') \
&& (buf[1] == 'O' || buf[1] == 'o') \
&& (buf[2] == 'N' || buf[2] == 'n') \
&& (buf[3] == 'T' || buf[3] == 't') \
&& (buf[4] == 'E' || buf[4] == 'e') \
&& (buf[5] == 'N' || buf[5] == 'n') \
&& (buf[6] == 'T' || buf[6] == 't') \
&& (buf[7] == '-') \
&& (buf[8] == 'L' || buf[8] == 'l') \
&& (buf[9] == 'A' || buf[9] == 'a') \
&& (buf[10] == 'N' || buf[10] == 'n') \
&& (buf[11] == 'G' || buf[11] == 'g') \
&& (buf[12] == 'U' || buf[12] == 'u') \
&& (buf[13] == 'A' || buf[13] == 'a') \
&& (buf[14] == 'G' || buf[14] == 'g') \
&& (buf[15] == 'E' || buf[15] == 'e') \
&& (buf[16] == ':' || buf[16] == ' ' || buf[16] == '\t'))
#define ISCONTENT_TRANSFER_ENCODING(buf) ( \
(buf[0] == 'C' || buf[0] == 'c') \
&& (buf[1] == 'O' || buf[1] == 'o') \
&& (buf[2] == 'N' || buf[2] == 'n') \
&& (buf[3] == 'T' || buf[3] == 't') \
&& (buf[4] == 'E' || buf[4] == 'e') \
&& (buf[5] == 'N' || buf[5] == 'n') \
&& (buf[6] == 'T' || buf[6] == 't') \
&& (buf[7] == '-') \
&& (buf[8] == 'T' || buf[8] == 't') \
&& (buf[9] == 'R' || buf[9] == 'r') \
&& (buf[10] == 'A' || buf[10] == 'a') \
&& (buf[11] == 'N' || buf[11] == 'n') \
&& (buf[12] == 'S' || buf[12] == 's') \
&& (buf[13] == 'F' || buf[13] == 'f') \
&& (buf[14] == 'E' || buf[14] == 'e') \
&& (buf[15] == 'R' || buf[15] == 'r') \
&& (buf[16] == '-') \
&& (buf[17] == 'E' || buf[17] == 'e') \
&& (buf[18] == 'N' || buf[18] == 'n') \
&& (buf[19] == 'C' || buf[19] == 'c') \
&& (buf[20] == 'O' || buf[20] == 'o') \
&& (buf[21] == 'D' || buf[21] == 'd') \
&& (buf[22] == 'I' || buf[22] == 'i') \
&& (buf[23] == 'N' || buf[23] == 'n') \
&& (buf[24] == 'G' || buf[24] == 'g') \
&& (buf[25] == ':' || buf[25] == ' ' || buf[25] == '\t'))
#define ISCONTENT_TYPE(buf) ( \
(buf[0] == 'C' || buf[0] == 'c') \
&& (buf[1] == 'O' || buf[1] == 'o') \
&& (buf[2] == 'N' || buf[2] == 'n') \
&& (buf[3] == 'T' || buf[3] == 't') \
&& (buf[4] == 'E' || buf[4] == 'e') \
&& (buf[5] == 'N' || buf[5] == 'n') \
&& (buf[6] == 'T' || buf[6] == 't') \
&& (buf[7] == '-') \
&& (buf[8] == 'T' || buf[8] == 't') \
&& (buf[9] == 'Y' || buf[9] == 'y') \
&& (buf[10] == 'P' || buf[10] == 'p') \
&& (buf[11] == 'E' || buf[11] == 'e') \
&& (buf[12] == ':' || buf[12] == ' ' || buf[12] == '\t'))
#define ISDATE(buf) ( \
(buf[0] == 'D' || buf[0] == 'd') \
&& (buf[1] == 'A' || buf[1] == 'a') \
&& (buf[2] == 'T' || buf[2] == 't') \
&& (buf[3] == 'E' || buf[3] == 'e') \
&& (buf[4] == ':' || buf[4] == ' ' || buf[4] == '\t'))
#define ISFROM(buf) ( \
(buf[0] == 'F' || buf[0] == 'f') \
&& (buf[1] == 'R' || buf[1] == 'r') \
&& (buf[2] == 'O' || buf[2] == 'o') \
&& (buf[3] == 'M' || buf[3] == 'm') \
&& (buf[4] == ':' || buf[4] == ' ' || buf[4] == '\t'))
#define ISIN_REPLY_TO(buf) ( \
(buf[0] == 'I' || buf[0] == 'i') \
&& (buf[1] == 'N' || buf[1] == 'n') \
&& (buf[2] == '-' || buf[2] == '-') \
&& (buf[3] == 'R' || buf[3] == 'r') \
&& (buf[4] == 'E' || buf[4] == 'e') \
&& (buf[5] == 'P' || buf[5] == 'p') \
&& (buf[6] == 'L' || buf[6] == 'l') \
&& (buf[7] == 'Y' || buf[7] == 'y') \
&& (buf[8] == '-') \
&& (buf[9] == 'T' || buf[9] == 't') \
&& (buf[10] == 'O' || buf[10] == 'o') \
&& (buf[11] == ':' || buf[11] == ' ' || buf[11] == '\t'))
#define ISMESSAGE_ID(buf) ( \
(buf[0] == 'M' || buf[0] == 'm') \
&& (buf[1] == 'E' || buf[1] == 'e') \
&& (buf[2] == 'S' || buf[2] == 's') \
&& (buf[3] == 'S' || buf[3] == 's') \
&& (buf[4] == 'A' || buf[4] == 'a') \
&& (buf[5] == 'G' || buf[5] == 'g') \
&& (buf[6] == 'E' || buf[6] == 'e') \
&& (buf[7] == '-') \
&& (buf[8] == 'I' || buf[8] == 'i') \
&& (buf[9] == 'D' || buf[9] == 'd') \
&& (buf[10] == ':' || buf[10] == ' ' || buf[10] == '\t'))
#define ISREFERENCE(buf) ( \
(buf[0] == 'R' || buf[0] == 'r') \
&& (buf[1] == 'E' || buf[1] == 'e') \
&& (buf[2] == 'F' || buf[2] == 'f') \
&& (buf[3] == 'E' || buf[3] == 'e') \
&& (buf[4] == 'R' || buf[4] == 'r') \
&& (buf[5] == 'E' || buf[5] == 'e') \
&& (buf[6] == 'n' || buf[6] == 'n') \
&& (buf[7] == 'C' || buf[7] == 'c') \
&& (buf[8] == 'E' || buf[8] == 'e') \
&& (buf[9] == ':' || buf[9] == ' ' || buf[9] == '\t'))
#define ISREPLY_TO(buf) ( \
(buf[0] == 'R' || buf[0] == 'r') \
&& (buf[1] == 'E' || buf[1] == 'e') \
&& (buf[2] == 'P' || buf[2] == 'p') \
&& (buf[3] == 'L' || buf[3] == 'l') \
&& (buf[4] == 'Y' || buf[4] == 'y') \
&& (buf[5] == '-') \
&& (buf[6] == 'T' || buf[6] == 't') \
&& (buf[7] == 'O' || buf[7] == 'o') \
&& (buf[8] == ':' || buf[8] == ' ' || buf[8] == '\t'))
#define ISSENDER(buf) ( \
(buf[0] == 'S' || buf[0] == 's') \
&& (buf[1] == 'E' || buf[1] == 'e') \
&& (buf[2] == 'N' || buf[2] == 'n') \
&& (buf[3] == 'D' || buf[3] == 'd') \
&& (buf[4] == 'E' || buf[4] == 'e') \
&& (buf[5] == 'R' || buf[5] == 'r') \
&& (buf[6] == ':' || buf[6] == ' ' || buf[6] == '\t'))
#define ISSTATUS(buf) ( \
(buf[0] == 'S' || buf[0] == 's') \
&& (buf[1] == 'T' || buf[1] == 't') \
&& (buf[2] == 'A' || buf[2] == 'a') \
&& (buf[3] == 'T' || buf[3] == 't') \
&& (buf[4] == 'U' || buf[4] == 'u') \
&& (buf[5] == 'S' || buf[5] == 's') \
&& (buf[6] == ':' || buf[6] == ' ' || buf[6] == '\t'))
#define ISSUBJECT(buf) ( \
(buf[0] == 'S' || buf[0] == 's') \
&& (buf[1] == 'U' || buf[1] == 'u') \
&& (buf[2] == 'B' || buf[2] == 'b') \
&& (buf[3] == 'J' || buf[3] == 'j') \
&& (buf[4] == 'E' || buf[4] == 'e') \
&& (buf[5] == 'C' || buf[5] == 'c') \
&& (buf[6] == 'T' || buf[6] == 't') \
&& (buf[7] == ':' || buf[7] == ' ' || buf[7] == '\t'))
#define ISTO(buf) ( \
(buf[0] == 'T' || buf[0] == 't') \
&& (buf[1] == 'O' || buf[1] == 'o') \
&& (buf[2] == ':' || buf[2] == ' ' || buf[2] == '\t'))
#define ISX_IMAPBASE(buf) ( \
(buf[0] == 'X' || buf[0] == 'x') \
&& (buf[1] == '-') \
&& (buf[2] == 'I' || buf[2] == 'i') \
&& (buf[3] == 'M' || buf[3] == 'm') \
&& (buf[4] == 'A' || buf[4] == 'a') \
&& (buf[5] == 'P' || buf[5] == 'p') \
&& (buf[6] == 'B' || buf[6] == 'b') \
&& (buf[7] == 'A' || buf[7] == 'a') \
&& (buf[8] == 'S' || buf[8] == 's') \
&& (buf[9] == 'E' || buf[9] == 'e') \
&& (buf[10] == ':' || buf[10] == ' ' || buf[10] == '\t'))
#define ISX_UIDL(buf) ( \
(buf[0] == 'X' || buf[0] == 'x') \
&& (buf[1] == '-') \
&& (buf[2] == 'U' || buf[2] == 'u') \
&& (buf[3] == 'I' || buf[3] == 'i') \
&& (buf[4] == 'D' || buf[4] == 'd') \
&& (buf[5] == 'L' || buf[5] == 'l') \
&& (buf[6] == ':' || buf[6] == ' ' || buf[6] == '\t'))
#define ISX_UID(buf) ( \
(buf[0] == 'X' || buf[0] == 'x') \
&& (buf[1] == '-') \
&& (buf[2] == 'U' || buf[2] == 'u') \
&& (buf[3] == 'I' || buf[3] == 'i') \
&& (buf[4] == 'D' || buf[4] == 'd') \
&& (buf[5] == ':' || buf[5] == ' ' || buf[5] == '\t'))
/* Skip prepend spaces. */
#define SKIPSPACE(p) while (*p == ' ') p++
#define ATOI(a,i) \
do { \
SKIPSPACE(a); \
for (i = 0; *a >= '0' && *a <= '9'; a++) \
i = 10 * i + (*a - '0'); \
} while (0)
/* Notifications ADD_MESG. */
#define DISPATCH_ADD_MSG(mbox,mud) \
......@@ -419,8 +209,6 @@ do \
} \
if (bailing != 0) \
{ \
if (pcount) \
*pcount = (mud)->messages_count; \
mu_locker_unlock (mbox->locker); \
return EINTR; \
} \
......@@ -444,8 +232,6 @@ do \
MU_EVT_MAILBOX_PROGRESS, NULL); \
if (bailing != 0) \
{ \
if (pcount) \
*pcount = (mud)->messages_count; \
mu_locker_unlock (mbox->locker); \
return EINTR; \
} \
......@@ -481,16 +267,29 @@ do \
} \
} while (0)
#define ISSTATUS(buf) ( \
(buf[0] == 'S' || buf[0] == 's') \
&& (buf[1] == 'T' || buf[1] == 't') \
&& (buf[2] == 'A' || buf[2] == 'a') \
&& (buf[3] == 'T' || buf[3] == 't') \
&& (buf[4] == 'U' || buf[4] == 'u') \
&& (buf[5] == 'S' || buf[5] == 's') \
&& (buf[6] == ':' || buf[6] == ' ' || buf[6] == '\t'))
#define MBOX_SCAN_NOTIFY 0x1
#define MBOX_SCAN_ONEMSG 0x2
int
mbox_scan0 (mu_mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
mbox_scan_internal (mu_mailbox_t mailbox, mbox_message_t mum,
mu_off_t total,
size_t *pmin_uid,
int flags)
{
#define MSGLINELEN 1024
char buf[MSGLINELEN];
int inheader;
int inbody;
mu_off_t total = 0;
mbox_data_t mud = mailbox->data;
mbox_message_t mum = NULL;
int status = 0;
size_t lines;
int newline;
......@@ -499,60 +298,28 @@ mbox_scan0 (mu_mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
size_t min_uid = 0;
int zn, isfrom = 0;
char *temp;
/* Sanity. */
if (mud == NULL)
return EINVAL;
/* Grab the lock. */
mu_monitor_wrlock (mailbox->monitor);
#ifdef WITH_PTHREAD
/* read() is cancellation point since we're doing a potentially
long operation. Lets make sure we clean the state. */
pthread_cleanup_push (mbox_cleanup, (void *)mailbox);
#endif
/* Save the timestamp and size. */
status = mu_stream_size (mailbox->stream, &(mud->size));
if (status != 0)
{
mu_monitor_unlock (mailbox->monitor);
return status;
}
if ((status = mu_locker_lock (mailbox->locker)))
{
mu_monitor_unlock (mailbox->monitor);
return status;
}
/* Seek to the starting point. */
if (mud->umessages && msgno > 0 && mud->messages_count > 0
&& msgno <= mud->messages_count)
{
mum = mud->umessages[msgno - 1];
if (mum)
total = mum->header_from;
mud->messages_count = msgno - 1;
}
else
mud->messages_count = 0;
newline = 1;
errno = lines = inheader = inbody = 0;
stream = mailbox->stream;
while ((status = mu_stream_readline (mailbox->stream, buf, sizeof (buf),
while ((status = mu_stream_readline (stream, buf, sizeof (buf),
total, &n)) == 0 && n != 0)
{
int nl;
total += n;
nl = (*buf == '\n') ? 1 : 0;
VALID(buf, temp, isfrom, zn);
VALID (buf, temp, isfrom, zn);
isfrom = (isfrom) ? 1 : 0;
if ((flags & MBOX_SCAN_ONEMSG) && mum == NULL)
{
/* In one-message mode, the positioning should be exact. */
if (!isfrom)
return EINVAL; /* FIXME: Better error code, please? */
}
/* Which part of the message are we in ? */
inheader = isfrom | ((!nl) & inheader);
inbody = (!isfrom) & (!inheader);
......@@ -579,13 +346,15 @@ mbox_scan0 (mu_mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
}
else
min_uid = mum->uid;
if (do_notif)
DISPATCH_ADD_MSG (mailbox, mud);
if (flags & MBOX_SCAN_ONEMSG)
break;
if (flags & MBOX_SCAN_NOTIFY)
DISPATCH_ADD_MSG (mailbox, mud);
}
/* Allocate_msgs will initialize mum. */
ALLOCATE_MSGS(mailbox, mud);
ALLOCATE_MSGS (mailbox, mud);
mud->messages_count++;
mum = mud->umessages[mud->messages_count - 1];
mum->mud = mud;
......@@ -623,9 +392,9 @@ mbox_scan0 (mu_mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
mu_locker_touchlock (mailbox->locker);
/* Ping them every 1000 lines. Should be tunable. */
if (do_notif)
if (flags & MBOX_SCAN_NOTIFY)
if (((lines +1) % 1000) == 0)
DISPATCH_PROGRESS(mailbox, mud);
DISPATCH_PROGRESS (mailbox, mud);
} /* while */
......@@ -643,9 +412,65 @@ mbox_scan0 (mu_mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
else
min_uid = mum->uid;
if (do_notif)
if (flags & MBOX_SCAN_NOTIFY)
DISPATCH_ADD_MSG (mailbox, mud);
}
if (pmin_uid)
*pmin_uid = min_uid;
return status;
}
int
mbox_scan0 (mu_mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
{
int status;
mbox_data_t mud = mailbox->data;
mbox_message_t mum = NULL;
mu_off_t total = 0;
size_t min_uid;
/* Sanity. */
if (mud == NULL)
return EINVAL;
/* Grab the lock. */
mu_monitor_wrlock (mailbox->monitor);
#ifdef WITH_PTHREAD
/* read() is cancellation point since we're doing a potentially
long operation. Lets make sure we clean the state. */
pthread_cleanup_push (mbox_cleanup, (void *)mailbox);
#endif
/* Save the timestamp and size. */
status = mu_stream_size (mailbox->stream, &mud->size);
if (status != 0)
{
mu_monitor_unlock (mailbox->monitor);
return status;
}
if ((status = mu_locker_lock (mailbox->locker)))
{
mu_monitor_unlock (mailbox->monitor);
return status;
}
/* Seek to the starting point. */
if (mud->umessages && msgno > 0 && mud->messages_count > 0
&& msgno <= mud->messages_count)
{
mum = mud->umessages[msgno - 1];
if (mum)
total = mum->header_from;
mud->messages_count = msgno - 1;
}
else
mud->messages_count = 0;
status = mbox_scan_internal (mailbox, mum, total, &min_uid,
do_notif ? MBOX_SCAN_NOTIFY : 0);
if (pcount)
*pcount = mud->messages_count;
mu_locker_unlock (mailbox->locker);
......@@ -674,5 +499,52 @@ mbox_scan0 (mu_mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
#ifdef WITH_PTHREAD
pthread_cleanup_pop (0);
#endif
return status;
}
int
mbox_scan1 (mu_mailbox_t mailbox, mu_off_t offset, int do_notif)
{
int status;
mbox_data_t mud = mailbox->data;
if (mud == NULL)
return EINVAL;
/* Grab the lock. */
mu_monitor_wrlock (mailbox->monitor);
#ifdef WITH_PTHREAD
/* read() is cancellation point since we're doing a potentially
long operation. Lets make sure we clean the state. */
pthread_cleanup_push (mbox_cleanup, (void *)mailbox);
#endif
if ((status = mu_locker_lock (mailbox->locker)))
{
mu_monitor_unlock (mailbox->monitor);
return status;
}
status = mu_stream_seek (mailbox->stream, offset, SEEK_SET);
if (status)
{
mu_monitor_unlock (mailbox->monitor);
mu_locker_unlock (mailbox->locker);
return status;
}
status = mbox_scan_internal (mailbox, NULL, offset, NULL,
MBOX_SCAN_ONEMSG |
(do_notif ? MBOX_SCAN_NOTIFY : 0));
mu_locker_unlock (mailbox->locker);
mu_monitor_unlock (mailbox->monitor);
#ifdef WITH_PTHREAD
pthread_cleanup_pop (0);
#endif
return status;
}
......
......@@ -31,12 +31,15 @@
typedef int (*sieve_module_init_t) (mu_sieve_machine_t mach);
#if 0
/* FIXME: See comment below */
static void
_free_loaded_module (void *data)
{
lt_dlclose ((lt_dlhandle)data);
lt_dlexit ();
}
#endif
static lt_dlhandle
load_module (mu_sieve_machine_t mach, const char *name)
......@@ -54,7 +57,13 @@ load_module (mu_sieve_machine_t mach, const char *name)
if (init)
{
init (mach);
mu_sieve_machine_add_destructor (mach, _free_loaded_module, handle);
/* FIXME: We used to have this:
mu_sieve_machine_add_destructor (mach, _free_loaded_module,
handle);
However, unloading modules can lead to random segfaults in
case they allocated any global-access data (e.g. mach->msg).
In particular, this was the case with extensions/pipe.c.
*/
return handle;
}
else
......
......@@ -131,7 +131,7 @@ char *saved_envelope; /* A hack to spare mu_envelope_ calls */
static void
set_debug_flags (const mu_cfg_locus_t *locus, const char *arg)
{
for (; *arg; arg++);
for (; *arg; arg++)
{
switch (*arg)
{
......@@ -508,7 +508,7 @@ sieve_test (struct mu_auth_data *auth, mu_mailbox_t mbx)
chdir (auth->dir);
rc = mu_sieve_message (mach, msg);
if (rc == 0)
if (rc == 0)
rc = mu_attribute_is_deleted (attr) == 0;
switch_user_id (auth, 0);
......
......@@ -380,6 +380,16 @@ amd_close (mu_mailbox_t mailbox)
return 0;
}
static int
amd_message_qid (mu_message_t msg, mu_message_qid_t *pqid)
{
struct _amd_message *mhm = mu_message_get_owner (msg);
*pqid = mhm->amd->msg_file_name (mhm,
mhm->attr_flags & MU_ATTRIBUTE_DELETED);
return 0;
}
struct _amd_message *
_amd_get_message (struct _amd_data *amd, size_t msgno)
{
......@@ -480,7 +490,8 @@ _amd_attach_message (mu_mailbox_t mailbox, struct _amd_message *mhm,
/* Set the UID. */
if (mhm->amd->message_uid)
mu_message_set_uid (msg, mhm->amd->message_uid, mhm);
mu_message_set_qid (msg, amd_message_qid, mhm);
/* Attach the message to the mailbox mbox data. */
mhm->message = msg;
mu_message_set_mailbox (msg, mailbox, mhm);
......@@ -725,7 +736,15 @@ amd_append_message (mu_mailbox_t mailbox, mu_message_t msg)
if (amd->msg_finish_delivery)
amd->msg_finish_delivery (amd, mhm);
if (mailbox->observable)
{
char *qid = amd->msg_file_name (mhm,
mhm->attr_flags & MU_ATTRIBUTE_DELETED);
mu_observable_notify (mailbox->observable, MU_EVT_MESSAGE_APPEND, qid);
free (qid);
}
return status;
}
......
......@@ -80,5 +80,6 @@ MU_ERR_BAD_COLUMN _("Bad column address")
MU_ERR_NO_RESULT _("No result from the previous query available")
MU_ERR_NO_INTERFACE _("No such interface")
MU_ERR_BADOP _("Inappropriate operation for this mode")
MU_ERR_BAD_FILENAME _("Badly formed file or directory name")
MU_READ_ERROR _("Read error")
MU_ERR_READ _("Read error")
......
......@@ -704,28 +704,6 @@ _prog_stream_unregister (struct _prog_stream *stream)
mu_list_remove (prog_stream_list, stream);
}
static int
_prog_waitpid (void *item, void *data MU_ARG_UNUSED)
{
struct _prog_stream *str = item;
int status;
if (str->pid > 0)
{
if (waitpid (str->pid, &str->status, WNOHANG) == str->pid)
str->pid = -1;
}
if (str->writer_pid > 0)
waitpid (str->writer_pid, &status, WNOHANG);
return 0;
}
static void
_prog_stream_wait (struct _prog_stream *fs)
{
if (fs->pid > 0)
waitpid (fs->pid, &fs->status, 0);
}
#if defined (HAVE_SYSCONF) && defined (_SC_OPEN_MAX)
# define getmaxfd() sysconf (_SC_OPEN_MAX)
#elif defined (HAVE_GETDTABLESIZE)
......@@ -841,23 +819,34 @@ start_program_filter (pid_t *pid, int *p, int argc, char **argv,
}
static void
_prog_wait (pid_t pid, int *pstatus)
{
if (pid > 0)
{
pid_t t;
do
t = waitpid (pid, pstatus, 0);
while (t == -1 && errno == EINTR);
}
}
static void
_prog_destroy (mu_stream_t stream)
{
struct _prog_stream *fs = mu_stream_get_owner (stream);
int status;
mu_argcv_free (fs->argc, fs->argv);
if (fs->in)
mu_stream_destroy (&fs->in, mu_stream_get_owner (fs->in));
if (fs->out)
mu_stream_destroy (&fs->out, mu_stream_get_owner (fs->out));
if (fs->pid > 0)
{
kill (fs->pid, SIGTERM);
mu_list_do (prog_stream_list, _prog_waitpid, NULL);
kill (fs->pid, SIGKILL);
if (fs->writer_pid > 0)
kill (fs->writer_pid, SIGKILL);
mu_list_do (prog_stream_list, _prog_waitpid, NULL);
}
_prog_wait (fs->pid, &fs->status);
fs->pid = -1;
_prog_wait (fs->writer_pid, &status);
fs->writer_pid = -1;
_prog_stream_unregister (fs);
}
......@@ -865,6 +854,7 @@ static int
_prog_close (mu_stream_t stream)
{
struct _prog_stream *fs = mu_stream_get_owner (stream);
int status;
if (!stream)
return EINVAL;
......@@ -875,7 +865,10 @@ _prog_close (mu_stream_t stream)
mu_stream_close (fs->out);
mu_stream_destroy (&fs->out, mu_stream_get_owner (fs->out));
_prog_stream_wait (fs);
_prog_wait (fs->pid, &fs->status);
fs->pid = -1;
_prog_wait (fs->writer_pid, &status);
fs->writer_pid = -1;
mu_stream_close (fs->in);
mu_stream_destroy (&fs->in, mu_stream_get_owner (fs->in));
......@@ -1101,7 +1094,7 @@ mu_prog_stream_create (mu_stream_t *stream, const char *progname, int flags)
int
mu_filter_prog_stream_create (mu_stream_t *stream, const char *progname,
mu_stream_t input)
mu_stream_t input)
{
struct _prog_stream *fs;
int rc = _prog_stream_create (&fs, stream, progname, MU_STREAM_RDWR);
......
......@@ -174,7 +174,8 @@ mu_mailbox_destroy (mu_mailbox_t *pmbox)
/* Notify the observers. */
if (mbox->observable)
{
mu_observable_notify (mbox->observable, MU_EVT_MAILBOX_DESTROY, mbox);
mu_observable_notify (mbox->observable, MU_EVT_MAILBOX_DESTROY,
mbox);
mu_observable_destroy (&mbox->observable, mbox);
}
......@@ -223,6 +224,13 @@ mu_mailbox_open (mu_mailbox_t mbox, int flag)
{
if (mbox == NULL || mbox->_open == NULL)
return MU_ERR_EMPTY_VFN;
if (flag & MU_STREAM_QACCESS)
{
/* Quick access mailboxes are read-only */
if (flag & (MU_STREAM_WRITE | MU_STREAM_RDWR
| MU_STREAM_APPEND | MU_STREAM_CREAT))
return EINVAL; /* FIXME: Better error code, please? */
}
return mbox->_open (mbox, flag);
}
......@@ -284,6 +292,8 @@ mu_mailbox_get_message (mu_mailbox_t mbox, size_t msgno, mu_message_t *pmsg)
{
if (mbox == NULL || mbox->_get_message == NULL)
return MU_ERR_EMPTY_VFN;
if (mbox->flags & MU_STREAM_QACCESS)
return MU_ERR_BADOP;
return mbox->_get_message (mbox, msgno, pmsg);
}
......@@ -293,6 +303,8 @@ mu_mailbox_quick_get_message (mu_mailbox_t mbox, mu_message_qid_t qid,
{
if (mbox == NULL || mbox->_quick_get_message == NULL)
return MU_ERR_EMPTY_VFN;
if (!(mbox->flags & MU_STREAM_QACCESS))
return MU_ERR_BADOP;
return mbox->_quick_get_message (mbox, qid, pmsg);
}
......@@ -301,6 +313,8 @@ mu_mailbox_messages_count (mu_mailbox_t mbox, size_t *num)
{
if (mbox == NULL || mbox->_messages_count == NULL)
return MU_ERR_EMPTY_VFN;
if (mbox->flags & MU_STREAM_QACCESS)
return MU_ERR_BADOP;
return mbox->_messages_count (mbox, num);
}
......@@ -309,6 +323,8 @@ mu_mailbox_messages_recent (mu_mailbox_t mbox, size_t *num)
{
if (mbox == NULL || mbox->_messages_recent == NULL)
return MU_ERR_EMPTY_VFN;
if (mbox->flags & MU_STREAM_QACCESS)
return MU_ERR_BADOP;
return mbox->_messages_recent (mbox, num);
}
......@@ -317,6 +333,8 @@ mu_mailbox_message_unseen (mu_mailbox_t mbox, size_t *num)
{
if (mbox == NULL || mbox->_message_unseen == NULL)
return MU_ERR_EMPTY_VFN;
if (mbox->flags & MU_STREAM_QACCESS)
return MU_ERR_BADOP;
return mbox->_message_unseen (mbox, num);
}
......@@ -356,6 +374,8 @@ mu_mailbox_is_updated (mu_mailbox_t mbox)
{
if (mbox == NULL || mbox->_is_updated == NULL)
return 1;
if (mbox->flags & MU_STREAM_QACCESS)
return 1;
return mbox->_is_updated (mbox);
}
......@@ -364,6 +384,8 @@ mu_mailbox_scan (mu_mailbox_t mbox, size_t msgno, size_t *pcount)
{
if (mbox == NULL || mbox->_scan == NULL)
return MU_ERR_EMPTY_VFN;
if (mbox->flags & MU_STREAM_QACCESS)
return MU_ERR_BADOP;
return mbox->_scan (mbox, msgno, pcount);
}
......@@ -373,6 +395,8 @@ mu_mailbox_get_size (mu_mailbox_t mbox, mu_off_t *psize)
int status;
if (mbox == NULL)
return MU_ERR_EMPTY_VFN;
if (mbox->flags & MU_STREAM_QACCESS)
return MU_ERR_BADOP;
if (mbox->_get_size == NULL
|| (status = mbox->_get_size (mbox, psize)) == ENOSYS)
{
......@@ -405,6 +429,8 @@ mu_mailbox_uidvalidity (mu_mailbox_t mbox, unsigned long *pvalid)
{
if (mbox == NULL || mbox->_uidvalidity == NULL)
return MU_ERR_EMPTY_VFN;
if (mbox->flags & MU_STREAM_QACCESS)
return MU_ERR_BADOP;
return mbox->_uidvalidity (mbox, pvalid);
}
......@@ -413,6 +439,8 @@ mu_mailbox_uidnext (mu_mailbox_t mbox, size_t *puidnext)
{
if (mbox == NULL || mbox->_uidnext == NULL)
return MU_ERR_EMPTY_VFN;
if (mbox->flags & MU_STREAM_QACCESS)
return MU_ERR_BADOP;
return mbox->_uidnext (mbox, puidnext);
}
......@@ -455,6 +483,8 @@ mu_mailbox_set_stream (mu_mailbox_t mbox, mu_stream_t stream)
{
if (mbox == NULL)
return MU_ERR_MBX_NULL;
if (mbox->flags & MU_STREAM_QACCESS)
return MU_ERR_BADOP;
if (mbox->stream)
mu_stream_destroy (&mbox->stream, mbox);
mbox->stream = stream;
......