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) ...@@ -417,7 +417,7 @@ get_field (mu_sql_connection_t conn, const char *id, char **ret, int mandatory)
417 { 417 {
418 mu_error (_("SQL field `%s' (`%s') has NULL value"), 418 mu_error (_("SQL field `%s' (`%s') has NULL value"),
419 id, name ? *name : id); 419 id, name ? *name : id);
420 rc = MU_READ_ERROR; 420 rc = MU_ERR_READ;
421 } 421 }
422 422
423 return rc; 423 return rc;
......
...@@ -26,6 +26,11 @@ comsatd_SOURCES = action.c cfg.c comsat.c comsat.h ...@@ -26,6 +26,11 @@ comsatd_SOURCES = action.c cfg.c comsat.c comsat.h
26 comsatd_LDADD = \ 26 comsatd_LDADD = \
27 ../lib/libmuaux.la\ 27 ../lib/libmuaux.la\
28 ${MU_LIB_MBOX}\ 28 ${MU_LIB_MBOX}\
29 ${MU_LIB_IMAP}\
30 ${MU_LIB_POP}\
31 ${MU_LIB_NNTP}\
32 ${MU_LIB_MH}\
33 ${MU_LIB_MAILDIR}\
29 ${MU_LIB_MAILUTILS}\ 34 ${MU_LIB_MAILUTILS}\
30 @MU_COMMON_LIBRARIES@ 35 @MU_COMMON_LIBRARIES@
31 36
......
...@@ -110,7 +110,7 @@ netdef_parse (char *str) ...@@ -110,7 +110,7 @@ netdef_parse (char *str)
110 netdef = malloc (sizeof *netdef); 110 netdef = malloc (sizeof *netdef);
111 if (!netdef) 111 if (!netdef)
112 { 112 {
113 syslog (LOG_ERR, _("Out of memory")); 113 mu_error (_("Out of memory"));
114 exit (1); 114 exit (1);
115 } 115 }
116 116
...@@ -135,7 +135,8 @@ read_config (const char *config_file) ...@@ -135,7 +135,8 @@ read_config (const char *config_file)
135 fp = fopen (config_file, "r"); 135 fp = fopen (config_file, "r");
136 if (!fp) 136 if (!fp)
137 { 137 {
138 syslog (LOG_ERR, _("Cannot open config file %s: %m"), config_file); 138 mu_error (_("Cannot open config file %s: %s"), config_file,
139 mu_strerror (errno));
139 return; 140 return;
140 } 141 }
141 142
...@@ -162,7 +163,7 @@ read_config (const char *config_file) ...@@ -162,7 +163,7 @@ read_config (const char *config_file)
162 mu_argcv_get (ptr, "", NULL, &argc, &argv); 163 mu_argcv_get (ptr, "", NULL, &argc, &argv);
163 if (argc < 2) 164 if (argc < 2)
164 { 165 {
165 syslog (LOG_ERR, _("%s:%d: too few fields"), config_file, line); 166 mu_error (_("%s:%d: too few fields"), config_file, line);
166 mu_argcv_free (argc, argv); 167 mu_argcv_free (argc, argv);
167 continue; 168 continue;
168 } 169 }
...@@ -174,7 +175,7 @@ read_config (const char *config_file) ...@@ -174,7 +175,7 @@ read_config (const char *config_file)
174 else if (strcmp (argv[1], "no") == 0) 175 else if (strcmp (argv[1], "no") == 0)
175 allow_biffrc = 0; 176 allow_biffrc = 0;
176 else 177 else
177 syslog (LOG_ERR, _("%s:%d: yes or no expected"), config_file, line); 178 mu_error (_("%s:%d: yes or no expected"), config_file, line);
178 } 179 }
179 else if (strcmp (argv[0], "max-requests") == 0) 180 else if (strcmp (argv[0], "max-requests") == 0)
180 maxrequests = strtoul (argv[1], NULL, 0); 181 maxrequests = strtoul (argv[1], NULL, 0);
...@@ -194,7 +195,7 @@ read_config (const char *config_file) ...@@ -194,7 +195,7 @@ read_config (const char *config_file)
194 action = ACT_DENY; 195 action = ACT_DENY;
195 else 196 else
196 { 197 {
197 syslog (LOG_ERR, _("%s:%d: unknown keyword"), config_file, line); 198 mu_error (_("%s:%d: unknown keyword"), config_file, line);
198 mu_argcv_free (argc, argv); 199 mu_argcv_free (argc, argv);
199 continue; 200 continue;
200 } 201 }
...@@ -205,8 +206,8 @@ read_config (const char *config_file) ...@@ -205,8 +206,8 @@ read_config (const char *config_file)
205 netdef_t *cur = netdef_parse (argv[i]); 206 netdef_t *cur = netdef_parse (argv[i]);
206 if (!cur) 207 if (!cur)
207 { 208 {
208 syslog (LOG_ERR, _("%s:%d: cannot parse netdef: %s"), 209 mu_error (_("%s:%d: cannot parse netdef: %s"),
209 config_file, line, argv[i]); 210 config_file, line, argv[i]);
210 continue; 211 continue;
211 } 212 }
212 if (!tail) 213 if (!tail)
...@@ -221,7 +222,7 @@ read_config (const char *config_file) ...@@ -221,7 +222,7 @@ read_config (const char *config_file)
221 acl = malloc (sizeof *acl); 222 acl = malloc (sizeof *acl);
222 if (!acl) 223 if (!acl)
223 { 224 {
224 syslog (LOG_CRIT, _("Out of memory")); 225 mu_error (_("Out of memory"));
225 exit (1); 226 exit (1);
226 } 227 }
227 acl->next = NULL; 228 acl->next = NULL;
......
...@@ -57,7 +57,8 @@ static char doc[] = "GNU comsatd"; ...@@ -57,7 +57,8 @@ static char doc[] = "GNU comsatd";
57 57
58 static struct argp_option options[] = 58 static struct argp_option options[] =
59 { 59 {
60 {"config", 'c', N_("FILE"), 0, N_("Read configuration from FILE"), 0}, 60 { "config", 'c', N_("FILE"), 0, N_("Read configuration from FILE"), 0 },
61 { "test", 't', NULL, 0, N_("Run in test mode"), 0 },
61 { NULL, 0, NULL, 0, NULL, 0 } 62 { NULL, 0, NULL, 0, NULL, 0 }
62 }; 63 };
63 64
...@@ -104,7 +105,8 @@ static void comsat_init (void); ...@@ -104,7 +105,8 @@ static void comsat_init (void);
104 static void comsat_daemon_init (void); 105 static void comsat_daemon_init (void);
105 static void comsat_daemon (int _port); 106 static void comsat_daemon (int _port);
106 static int comsat_main (int fd); 107 static int comsat_main (int fd);
107 static void notify_user (const char *user, const char *device, const char *path, off_t offset); 108 static void notify_user (const char *user, const char *device,
109 const char *path, mu_message_qid_t qid);
108 static int find_user (const char *name, char *tty); 110 static int find_user (const char *name, char *tty);
109 static char *mailbox_path (const char *user); 111 static char *mailbox_path (const char *user);
110 static void change_user (const char *user); 112 static void change_user (const char *user);
...@@ -112,6 +114,7 @@ static void change_user (const char *user); ...@@ -112,6 +114,7 @@ static void change_user (const char *user);
112 static int xargc; 114 static int xargc;
113 static char **xargv; 115 static char **xargv;
114 char *config_file = NULL; 116 char *config_file = NULL;
117 int test_mode;
115 118
116 static error_t 119 static error_t
117 comsatd_parse_opt (int key, char *arg, struct argp_state *state) 120 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) ...@@ -125,6 +128,10 @@ comsatd_parse_opt (int key, char *arg, struct argp_state *state)
125 case 'c': 128 case 'c':
126 config_file = arg; 129 config_file = arg;
127 break; 130 break;
131
132 case 't':
133 test_mode = 1;
134 break;
128 135
129 default: 136 default:
130 return ARGP_ERR_UNKNOWN; 137 return ARGP_ERR_UNKNOWN;
...@@ -134,20 +141,59 @@ comsatd_parse_opt (int key, char *arg, struct argp_state *state) ...@@ -134,20 +141,59 @@ comsatd_parse_opt (int key, char *arg, struct argp_state *state)
134 141
135 142
136 int 143 int
137 main(int argc, char **argv) 144 main (int argc, char **argv)
138 { 145 {
139 int c; 146 int c;
140 147 int ind;
148
141 /* Native Language Support */ 149 /* Native Language Support */
142 mu_init_nls (); 150 mu_init_nls ();
143 151
144 mu_argp_init (program_version, NULL); 152 mu_argp_init (program_version, NULL);
145 mu_argp_parse (&argp, &argc, &argv, 0, comsat_argp_capa, 153 mu_argp_parse (&argp, &argc, &argv, 0, comsat_argp_capa,
146 NULL, &daemon_param); 154 &ind, &daemon_param);
147 155
156 argc -= ind;
157 argv += ind;
158
159 if (test_mode)
160 {
161 char *user, *url, *qid;
162
163 comsat_init ();
164 if (config_file)
165 read_config (config_file);
166 if (argc == 0)
167 exit (0);
168 if (argc < 2 || argc > 2)
169 {
170 mu_error (_("Mailbox URL and message QID are required in test mode"));
171 exit (EXIT_FAILURE);
172 }
173
174 user = getenv ("LOGNAME");
175 if (!user)
176 {
177 user = getenv ("USER");
178 if (!user)
179 {
180 struct passwd *pw = getpwuid (getuid ());
181 if (!pw)
182 {
183 mu_error (_("Cannot determine user name"));
184 exit (EXIT_FAILURE);
185 }
186 user = pw->pw_name;
187 }
188 }
189
190 notify_user (user, "/dev/tty", argv[0], argv[1]);
191 exit (0);
192 }
193
148 if (daemon_param.timeout > 0 && daemon_param.mode == MODE_DAEMON) 194 if (daemon_param.timeout > 0 && daemon_param.mode == MODE_DAEMON)
149 { 195 {
150 fprintf (stderr, _("--timeout and --daemon are incompatible\n")); 196 mu_error (_("--timeout and --daemon are incompatible"));
151 exit (EXIT_FAILURE); 197 exit (EXIT_FAILURE);
152 } 198 }
153 199
...@@ -194,7 +240,8 @@ sig_hup (int sig) ...@@ -194,7 +240,8 @@ sig_hup (int sig)
194 void 240 void
195 comsat_init () 241 comsat_init ()
196 { 242 {
197 mu_registrar_record (mu_path_record); 243 /* Register mailbox formats */
244 mu_register_all_mbox_formats ();
198 245
199 gethostname (hostname, sizeof hostname); 246 gethostname (hostname, sizeof hostname);
200 247
...@@ -324,10 +371,10 @@ comsat_main (int fd) ...@@ -324,10 +371,10 @@ comsat_main (int fd)
324 char buffer[216]; /*FIXME: Arbitrary size */ 371 char buffer[216]; /*FIXME: Arbitrary size */
325 pid_t pid; 372 pid_t pid;
326 char tty[MAX_TTY_SIZE]; 373 char tty[MAX_TTY_SIZE];
327 char *p, *endp; 374 char *p;
328 size_t offset;
329 char *path = NULL; 375 char *path = NULL;
330 376 mu_message_qid_t qid;
377
331 len = sizeof sin_from; 378 len = sizeof sin_from;
332 rdlen = recvfrom (fd, buffer, sizeof buffer, 0, 379 rdlen = recvfrom (fd, buffer, sizeof buffer, 0,
333 (struct sockaddr*)&sin_from, &len); 380 (struct sockaddr*)&sin_from, &len);
...@@ -362,19 +409,8 @@ comsat_main (int fd) ...@@ -362,19 +409,8 @@ comsat_main (int fd)
362 } 409 }
363 *p++ = 0; 410 *p++ = 0;
364 411
365 offset = strtoul (p, &endp, 0); 412 qid = p;
366 switch (*endp) 413
367 {
368 case 0:
369 break;
370 case ':':
371 path = endp+1;
372 break;
373 default:
374 if (!isspace (*endp))
375 syslog (LOG_ERR, _("Malformed input: %s@%s (near %s)"), buffer, p, endp);
376 }
377
378 if (find_user (buffer, tty) != SUCCESS) 414 if (find_user (buffer, tty) != SUCCESS)
379 return 0; 415 return 0;
380 416
...@@ -400,7 +436,7 @@ comsat_main (int fd) ...@@ -400,7 +436,7 @@ comsat_main (int fd)
400 } 436 }
401 437
402 /* Child: do actual I/O */ 438 /* Child: do actual I/O */
403 notify_user (buffer, tty, path, offset); 439 notify_user (buffer, tty, path, qid);
404 exit (0); 440 exit (0);
405 } 441 }
406 442
...@@ -423,17 +459,14 @@ get_newline_str (FILE *fp) ...@@ -423,17 +459,14 @@ get_newline_str (FILE *fp)
423 /* NOTE: Do not bother to free allocated memory, as the program exits 459 /* NOTE: Do not bother to free allocated memory, as the program exits
424 immediately after executing this */ 460 immediately after executing this */
425 static void 461 static void
426 notify_user (const char *user, const char *device, const char *path, off_t offset) 462 notify_user (const char *user, const char *device, const char *path,
463 mu_message_qid_t qid)
427 { 464 {
428 FILE *fp; 465 FILE *fp;
429 const char *cr; 466 const char *cr;
430 char *blurb; 467 mu_mailbox_t mbox = NULL;
431 mu_mailbox_t mbox = NULL, tmp = NULL;
432 mu_message_t msg; 468 mu_message_t msg;
433 mu_stream_t stream = NULL;
434 int status; 469 int status;
435 off_t size;
436 size_t count, n;
437 470
438 change_user (user); 471 change_user (user);
439 if ((fp = fopen (device, "w")) == NULL) 472 if ((fp = fopen (device, "w")) == NULL)
...@@ -452,56 +485,21 @@ notify_user (const char *user, const char *device, const char *path, off_t offse ...@@ -452,56 +485,21 @@ notify_user (const char *user, const char *device, const char *path, off_t offse
452 } 485 }
453 486
454 if ((status = mu_mailbox_create (&mbox, path)) != 0 487 if ((status = mu_mailbox_create (&mbox, path)) != 0
455 || (status = mu_mailbox_open (mbox, MU_STREAM_READ)) != 0) 488 || (status = mu_mailbox_open (mbox, MU_STREAM_READ|MU_STREAM_QACCESS)) != 0)
456 { 489 {
457 syslog (LOG_ERR, _("Cannot open mailbox %s: %s"), 490 syslog (LOG_ERR, _("Cannot open mailbox %s: %s"),
458 path, mu_strerror (status)); 491 path, mu_strerror (status));
459 return; 492 return;
460 } 493 }
461 494
462 if ((status = mu_mailbox_get_stream (mbox, &stream))) 495 status = mu_mailbox_quick_get_message (mbox, qid, &msg);
463 { 496 if (status)
464 syslog (LOG_ERR, _("Cannot get stream for mailbox %s: %s"),
465 path, mu_strerror (status));
466 return;
467 }
468
469 if ((status = mu_stream_size (stream, &size)))
470 {
471 syslog (LOG_ERR, _("Cannot get stream size (mailbox %s): %s"),
472 path, mu_strerror (status));
473 return;
474 }
475
476 /* Read headers */
477 size -= offset;
478 blurb = malloc (size + 1);
479 if (!blurb)
480 return;
481
482 mu_stream_read (stream, blurb, size, offset, &n);
483 blurb[size] = 0;
484
485 if ((status = mu_mailbox_create (&tmp, "/dev/null")) != 0
486 || (status = mu_mailbox_open (tmp, MU_STREAM_READ)) != 0)
487 {
488 syslog (LOG_ERR, _("Cannot create temporary mailbox: %s"),
489 mu_strerror (status));
490 return;
491 }
492
493 if ((status = mu_memory_stream_create (&stream, 0, 0)))
494 { 497 {
495 syslog (LOG_ERR, _("Cannot create temporary stream: %s"), 498 syslog (LOG_ERR, _("Cannot get message (mailbox %s, qid %s): %s"),
496 mu_strerror (status)); 499 path, qid, mu_strerror (status));
497 return; 500 return; /* FIXME: Notify the user, anyway */
498 } 501 }
499 502
500 mu_stream_write (stream, blurb, size, 0, &count);
501 mu_mailbox_set_stream (tmp, stream);
502 mu_mailbox_messages_count (tmp, &count);
503 mu_mailbox_get_message (tmp, 1, &msg);
504
505 run_user_action (fp, cr, msg); 503 run_user_action (fp, cr, msg);
506 fclose (fp); 504 fclose (fp);
507 } 505 }
......
...@@ -39,7 +39,9 @@ extern "C" { /*}*/ ...@@ -39,7 +39,9 @@ extern "C" { /*}*/
39 #define MU_STREAM_NO_CLOSE 0x00000100 39 #define MU_STREAM_NO_CLOSE 0x00000100
40 #define MU_STREAM_ALLOW_LINKS 0x00000200 40 #define MU_STREAM_ALLOW_LINKS 0x00000200
41 #define MU_STREAM_NONLOCK 0x00000400 41 #define MU_STREAM_NONLOCK 0x00000400
42 42 /* This one affects only mailboxes */
43 #define MU_STREAM_QACCESS 0x00000800
44
43 /* Functions useful to users of the pre-defined stream types. */ 45 /* Functions useful to users of the pre-defined stream types. */
44 46
45 extern int mu_file_stream_create (mu_stream_t *stream, const char* filename, 47 extern int mu_file_stream_create (mu_stream_t *stream, const char* filename,
......
...@@ -358,7 +358,7 @@ list_helper (struct search_data *data, ...@@ -358,7 +358,7 @@ list_helper (struct search_data *data,
358 break; 358 break;
359 359
360 case GLOB_ABORTED: 360 case GLOB_ABORTED:
361 status = MU_READ_ERROR; 361 status = MU_ERR_READ;
362 break; 362 break;
363 363
364 case GLOB_NOMATCH: 364 case GLOB_NOMATCH:
......
...@@ -35,6 +35,9 @@ static void mbox_destroy (mu_mailbox_t); ...@@ -35,6 +35,9 @@ static void mbox_destroy (mu_mailbox_t);
35 static int mbox_open (mu_mailbox_t, int); 35 static int mbox_open (mu_mailbox_t, int);
36 static int mbox_close (mu_mailbox_t); 36 static int mbox_close (mu_mailbox_t);
37 static int mbox_get_message (mu_mailbox_t, size_t, mu_message_t *); 37 static int mbox_get_message (mu_mailbox_t, size_t, mu_message_t *);
38 static int mbox_quick_get_message (mu_mailbox_t, mu_message_qid_t,
39 mu_message_t *);
40
38 /* static int mbox_get_message_by_uid (mu_mailbox_t, size_t, mu_message_t *); */ 41 /* static int mbox_get_message_by_uid (mu_mailbox_t, size_t, mu_message_t *); */
39 static int mbox_append_message (mu_mailbox_t, mu_message_t); 42 static int mbox_append_message (mu_mailbox_t, mu_message_t);
40 static int mbox_messages_count (mu_mailbox_t, size_t *); 43 static int mbox_messages_count (mu_mailbox_t, size_t *);
...@@ -136,6 +139,7 @@ _mailbox_mbox_init (mu_mailbox_t mailbox) ...@@ -136,6 +139,7 @@ _mailbox_mbox_init (mu_mailbox_t mailbox)
136 mailbox->_sync = mbox_sync; 139 mailbox->_sync = mbox_sync;
137 mailbox->_uidvalidity = mbox_uidvalidity; 140 mailbox->_uidvalidity = mbox_uidvalidity;
138 mailbox->_uidnext = mbox_uidnext; 141 mailbox->_uidnext = mbox_uidnext;
142 mailbox->_quick_get_message = mbox_quick_get_message;
139 143
140 mailbox->_scan = mbox_scan; 144 mailbox->_scan = mbox_scan;
141 mailbox->_is_updated = mbox_is_updated; 145 mailbox->_is_updated = mbox_is_updated;
...@@ -1065,45 +1069,10 @@ mbox_envelope_sender (mu_envelope_t envelope, char *buf, size_t len, ...@@ -1065,45 +1069,10 @@ mbox_envelope_sender (mu_envelope_t envelope, char *buf, size_t len,
1065 } 1069 }
1066 1070
1067 static int 1071 static int
1068 mbox_get_message (mu_mailbox_t mailbox, size_t msgno, mu_message_t *pmsg) 1072 new_message (mu_mailbox_t mailbox, mbox_message_t mum, mu_message_t *pmsg)
1069 { 1073 {
1070 int status; 1074 int status;
1071 mbox_data_t mud = mailbox->data; 1075 mu_message_t msg;
1072 mbox_message_t mum;
1073 mu_message_t msg = NULL;
1074
1075 /* Sanity checks. */
1076 if (pmsg == NULL)
1077 return MU_ERR_OUT_PTR_NULL;
1078 if (mud == NULL)
1079 return EINVAL;
1080
1081 /* If we did not start a scanning yet do it now. */
1082 if (mud->messages_count == 0)
1083 {
1084 status = mbox_scan0 (mailbox, 1, NULL, 0);
1085 if (status != 0)
1086 return status;
1087 }
1088
1089 /* Second sanity: check the message number. */
1090 if (!(mud->messages_count > 0
1091 && msgno > 0
1092 && msgno <= mud->messages_count))
1093 return EINVAL;
1094
1095 mum = mud->umessages[msgno - 1];
1096
1097 /* Check if we already have it. */
1098 if (mum->message)
1099 {
1100 if (pmsg)
1101 *pmsg = mum->message;
1102 return 0;
1103 }
1104
1105 MAILBOX_DEBUG2 (mailbox, MU_DEBUG_TRACE, "mbox_get_message (%s, %d)\n",
1106 mud->name, msgno);
1107 1076
1108 /* Get an empty message struct. */ 1077 /* Get an empty message struct. */
1109 status = mu_message_create (&msg, mum); 1078 status = mu_message_create (&msg, mum);
...@@ -1185,9 +1154,109 @@ mbox_get_message (mu_mailbox_t mailbox, size_t msgno, mu_message_t *pmsg) ...@@ -1185,9 +1154,109 @@ mbox_get_message (mu_mailbox_t mailbox, size_t msgno, mu_message_t *pmsg)
1185 mu_message_set_mailbox (msg, mailbox, mum); 1154 mu_message_set_mailbox (msg, mailbox, mum);
1186 1155
1187 *pmsg = msg; 1156 *pmsg = msg;
1157
1158 return 0;
1159 }
1160
1161 static int
1162 mbox_get_message (mu_mailbox_t mailbox, size_t msgno, mu_message_t *pmsg)
1163 {
1164 int status;
1165 mbox_data_t mud = mailbox->data;
1166 mbox_message_t mum;
1167
1168 /* Sanity checks. */
1169 if (pmsg == NULL)
1170 return MU_ERR_OUT_PTR_NULL;
1171 if (mud == NULL)
1172 return EINVAL;
1173
1174 /* If we did not start a scanning yet do it now. */
1175 if (mud->messages_count == 0)
1176 {
1177 status = mbox_scan0 (mailbox, 1, NULL, 0);
1178 if (status != 0)
1179 return status;
1180 }
1181
1182 /* Second sanity: check the message number. */
1183 if (!(mud->messages_count > 0
1184 && msgno > 0
1185 && msgno <= mud->messages_count))
1186 return EINVAL;
1187
1188 mum = mud->umessages[msgno - 1];
1189
1190 /* Check if we already have it. */
1191 if (mum->message)
1192 {
1193 if (pmsg)
1194 *pmsg = mum->message;
1195 return 0;
1196 }
1197
1198 MAILBOX_DEBUG2 (mailbox, MU_DEBUG_TRACE, "mbox_get_message (%s, %d)\n",
1199 mud->name, msgno);
1200
1201 return new_message (mailbox, mum, pmsg);
1202 }
1203
1204 static int
1205 qid2off (mu_message_qid_t qid, mu_off_t *pret)
1206 {
1207 mu_off_t ret = 0;
1208 for (;*qid; qid++)
1209 {
1210 if (!('0' <= *qid && *qid <= '9'))
1211 return 1;
1212 ret = ret * 10 + *qid - '0';
1213 }
1214 *pret = ret;
1188 return 0; 1215 return 0;
1189 } 1216 }
1217
1218 static int
1219 mbox_quick_get_message (mu_mailbox_t mailbox, mu_message_qid_t qid,
1220 mu_message_t *pmsg)
1221 {
1222 int status;
1223 mbox_data_t mud = mailbox->data;
1224 mbox_message_t mum;
1225 mu_off_t offset;
1226
1227 if (mailbox == NULL || qid2off (qid, &offset)
1228 || !(mailbox->flags & MU_STREAM_QACCESS))
1229 return EINVAL;
1190 1230
1231 if (mud->messages_count == 0)
1232 {
1233 status = mbox_scan1 (mailbox, offset, 0);
1234 if (status != 0)
1235 return status;
1236 }
1237
1238 /* Quick access mode retrieves only one message */
1239 mum = mud->umessages[0];
1240
1241 /* Check if we already have it and verify if it is the right one. */
1242 if (mum->message)
1243 {
1244 char *vqid;
1245 status = mu_message_get_qid (mum->message, &vqid);
1246 if (status)
1247 return status;
1248 status = strcmp (qid, vqid);
1249 free (vqid);
1250 if (status)
1251 return MU_ERR_EXISTS;
1252 if (pmsg)
1253 *pmsg = mum->message;
1254 return 0;
1255 }
1256
1257 return new_message (mailbox, mum, pmsg);
1258 }
1259
1191 static int 1260 static int
1192 mbox_append_message (mu_mailbox_t mailbox, mu_message_t msg) 1261 mbox_append_message (mu_mailbox_t mailbox, mu_message_t msg)
1193 { 1262 {
......
...@@ -124,6 +124,9 @@ struct _mbox_data ...@@ -124,6 +124,9 @@ struct _mbox_data
124 124
125 int mbox_scan0 (mu_mailbox_t mailbox, size_t msgno, size_t *pcount, 125 int mbox_scan0 (mu_mailbox_t mailbox, size_t msgno, size_t *pcount,
126 int do_notif); 126 int do_notif);
127 int mbox_scan1 (mu_mailbox_t mailbox, mu_off_t offset, int do_notif);
128
127 #ifdef WITH_PTHREAD 129 #ifdef WITH_PTHREAD
128 void mbox_cleanup (void *arg); 130 void mbox_cleanup (void *arg);
129 #endif 131 #endif
132
......
...@@ -31,12 +31,15 @@ ...@@ -31,12 +31,15 @@
31 31
32 typedef int (*sieve_module_init_t) (mu_sieve_machine_t mach); 32 typedef int (*sieve_module_init_t) (mu_sieve_machine_t mach);
33 33
34 #if 0
35 /* FIXME: See comment below */
34 static void 36 static void
35 _free_loaded_module (void *data) 37 _free_loaded_module (void *data)
36 { 38 {
37 lt_dlclose ((lt_dlhandle)data); 39 lt_dlclose ((lt_dlhandle)data);
38 lt_dlexit (); 40 lt_dlexit ();
39 } 41 }
42 #endif
40 43
41 static lt_dlhandle 44 static lt_dlhandle
42 load_module (mu_sieve_machine_t mach, const char *name) 45 load_module (mu_sieve_machine_t mach, const char *name)
...@@ -54,7 +57,13 @@ load_module (mu_sieve_machine_t mach, const char *name) ...@@ -54,7 +57,13 @@ load_module (mu_sieve_machine_t mach, const char *name)
54 if (init) 57 if (init)
55 { 58 {
56 init (mach); 59 init (mach);
57 mu_sieve_machine_add_destructor (mach, _free_loaded_module, handle); 60 /* FIXME: We used to have this:
61 mu_sieve_machine_add_destructor (mach, _free_loaded_module,
62 handle);
63 However, unloading modules can lead to random segfaults in
64 case they allocated any global-access data (e.g. mach->msg).
65 In particular, this was the case with extensions/pipe.c.
66 */
58 return handle; 67 return handle;
59 } 68 }
60 else 69 else
......
...@@ -131,7 +131,7 @@ char *saved_envelope; /* A hack to spare mu_envelope_ calls */ ...@@ -131,7 +131,7 @@ char *saved_envelope; /* A hack to spare mu_envelope_ calls */
131 static void 131 static void
132 set_debug_flags (const mu_cfg_locus_t *locus, const char *arg) 132 set_debug_flags (const mu_cfg_locus_t *locus, const char *arg)
133 { 133 {
134 for (; *arg; arg++); 134 for (; *arg; arg++)
135 { 135 {
136 switch (*arg) 136 switch (*arg)
137 { 137 {
...@@ -508,7 +508,7 @@ sieve_test (struct mu_auth_data *auth, mu_mailbox_t mbx) ...@@ -508,7 +508,7 @@ sieve_test (struct mu_auth_data *auth, mu_mailbox_t mbx)
508 chdir (auth->dir); 508 chdir (auth->dir);
509 509
510 rc = mu_sieve_message (mach, msg); 510 rc = mu_sieve_message (mach, msg);
511 if (rc == 0) 511 if (rc == 0)
512 rc = mu_attribute_is_deleted (attr) == 0; 512 rc = mu_attribute_is_deleted (attr) == 0;
513 513
514 switch_user_id (auth, 0); 514 switch_user_id (auth, 0);
......
...@@ -380,6 +380,16 @@ amd_close (mu_mailbox_t mailbox) ...@@ -380,6 +380,16 @@ amd_close (mu_mailbox_t mailbox)
380 return 0; 380 return 0;
381 } 381 }
382 382
383 static int
384 amd_message_qid (mu_message_t msg, mu_message_qid_t *pqid)
385 {
386 struct _amd_message *mhm = mu_message_get_owner (msg);
387
388 *pqid = mhm->amd->msg_file_name (mhm,
389 mhm->attr_flags & MU_ATTRIBUTE_DELETED);
390 return 0;
391 }
392
383 struct _amd_message * 393 struct _amd_message *
384 _amd_get_message (struct _amd_data *amd, size_t msgno) 394 _amd_get_message (struct _amd_data *amd, size_t msgno)
385 { 395 {
...@@ -480,7 +490,8 @@ _amd_attach_message (mu_mailbox_t mailbox, struct _amd_message *mhm, ...@@ -480,7 +490,8 @@ _amd_attach_message (mu_mailbox_t mailbox, struct _amd_message *mhm,
480 /* Set the UID. */ 490 /* Set the UID. */
481 if (mhm->amd->message_uid) 491 if (mhm->amd->message_uid)
482 mu_message_set_uid (msg, mhm->amd->message_uid, mhm); 492 mu_message_set_uid (msg, mhm->amd->message_uid, mhm);
483 493 mu_message_set_qid (msg, amd_message_qid, mhm);
494
484 /* Attach the message to the mailbox mbox data. */ 495 /* Attach the message to the mailbox mbox data. */
485 mhm->message = msg; 496 mhm->message = msg;
486 mu_message_set_mailbox (msg, mailbox, mhm); 497 mu_message_set_mailbox (msg, mailbox, mhm);
...@@ -725,7 +736,15 @@ amd_append_message (mu_mailbox_t mailbox, mu_message_t msg) ...@@ -725,7 +736,15 @@ amd_append_message (mu_mailbox_t mailbox, mu_message_t msg)
725 736
726 if (amd->msg_finish_delivery) 737 if (amd->msg_finish_delivery)
727 amd->msg_finish_delivery (amd, mhm); 738 amd->msg_finish_delivery (amd, mhm);
728 739
740 if (mailbox->observable)
741 {
742 char *qid = amd->msg_file_name (mhm,
743 mhm->attr_flags & MU_ATTRIBUTE_DELETED);
744 mu_observable_notify (mailbox->observable, MU_EVT_MESSAGE_APPEND, qid);
745 free (qid);
746 }
747
729 return status; 748 return status;
730 } 749 }
731 750
......
...@@ -80,5 +80,6 @@ MU_ERR_BAD_COLUMN _("Bad column address") ...@@ -80,5 +80,6 @@ MU_ERR_BAD_COLUMN _("Bad column address")
80 MU_ERR_NO_RESULT _("No result from the previous query available") 80 MU_ERR_NO_RESULT _("No result from the previous query available")
81 MU_ERR_NO_INTERFACE _("No such interface") 81 MU_ERR_NO_INTERFACE _("No such interface")
82 82
83 MU_ERR_BADOP _("Inappropriate operation for this mode")
83 MU_ERR_BAD_FILENAME _("Badly formed file or directory name") 84 MU_ERR_BAD_FILENAME _("Badly formed file or directory name")
84 MU_READ_ERROR _("Read error") 85 MU_ERR_READ _("Read error")
......
...@@ -704,28 +704,6 @@ _prog_stream_unregister (struct _prog_stream *stream) ...@@ -704,28 +704,6 @@ _prog_stream_unregister (struct _prog_stream *stream)
704 mu_list_remove (prog_stream_list, stream); 704 mu_list_remove (prog_stream_list, stream);
705 } 705 }
706 706
707 static int
708 _prog_waitpid (void *item, void *data MU_ARG_UNUSED)
709 {
710 struct _prog_stream *str = item;
711 int status;
712 if (str->pid > 0)
713 {
714 if (waitpid (str->pid, &str->status, WNOHANG) == str->pid)
715 str->pid = -1;
716 }
717 if (str->writer_pid > 0)
718 waitpid (str->writer_pid, &status, WNOHANG);
719 return 0;
720 }
721
722 static void
723 _prog_stream_wait (struct _prog_stream *fs)
724 {
725 if (fs->pid > 0)
726 waitpid (fs->pid, &fs->status, 0);
727 }
728
729 #if defined (HAVE_SYSCONF) && defined (_SC_OPEN_MAX) 707 #if defined (HAVE_SYSCONF) && defined (_SC_OPEN_MAX)
730 # define getmaxfd() sysconf (_SC_OPEN_MAX) 708 # define getmaxfd() sysconf (_SC_OPEN_MAX)
731 #elif defined (HAVE_GETDTABLESIZE) 709 #elif defined (HAVE_GETDTABLESIZE)
...@@ -841,23 +819,34 @@ start_program_filter (pid_t *pid, int *p, int argc, char **argv, ...@@ -841,23 +819,34 @@ start_program_filter (pid_t *pid, int *p, int argc, char **argv,
841 } 819 }
842 820
843 static void 821 static void
822 _prog_wait (pid_t pid, int *pstatus)
823 {
824 if (pid > 0)
825 {
826 pid_t t;
827 do
828 t = waitpid (pid, pstatus, 0);
829 while (t == -1 && errno == EINTR);
830 }
831 }
832
833 static void
844 _prog_destroy (mu_stream_t stream) 834 _prog_destroy (mu_stream_t stream)
845 { 835 {
846 struct _prog_stream *fs = mu_stream_get_owner (stream); 836 struct _prog_stream *fs = mu_stream_get_owner (stream);
837 int status;
838
847 mu_argcv_free (fs->argc, fs->argv); 839 mu_argcv_free (fs->argc, fs->argv);
848 if (fs->in) 840 if (fs->in)
849 mu_stream_destroy (&fs->in, mu_stream_get_owner (fs->in)); 841 mu_stream_destroy (&fs->in, mu_stream_get_owner (fs->in));
850 if (fs->out) 842 if (fs->out)
851 mu_stream_destroy (&fs->out, mu_stream_get_owner (fs->out)); 843 mu_stream_destroy (&fs->out, mu_stream_get_owner (fs->out));
852 if (fs->pid > 0) 844
853 { 845 _prog_wait (fs->pid, &fs->status);
854 kill (fs->pid, SIGTERM); 846 fs->pid = -1;
855 mu_list_do (prog_stream_list, _prog_waitpid, NULL); 847 _prog_wait (fs->writer_pid, &status);
856 kill (fs->pid, SIGKILL); 848 fs->writer_pid = -1;
857 if (fs->writer_pid > 0) 849
858 kill (fs->writer_pid, SIGKILL);
859 mu_list_do (prog_stream_list, _prog_waitpid, NULL);
860 }
861 _prog_stream_unregister (fs); 850 _prog_stream_unregister (fs);
862 } 851 }
863 852
...@@ -865,6 +854,7 @@ static int ...@@ -865,6 +854,7 @@ static int
865 _prog_close (mu_stream_t stream) 854 _prog_close (mu_stream_t stream)
866 { 855 {
867 struct _prog_stream *fs = mu_stream_get_owner (stream); 856 struct _prog_stream *fs = mu_stream_get_owner (stream);
857 int status;
868 858
869 if (!stream) 859 if (!stream)
870 return EINVAL; 860 return EINVAL;
...@@ -875,7 +865,10 @@ _prog_close (mu_stream_t stream) ...@@ -875,7 +865,10 @@ _prog_close (mu_stream_t stream)
875 mu_stream_close (fs->out); 865 mu_stream_close (fs->out);
876 mu_stream_destroy (&fs->out, mu_stream_get_owner (fs->out)); 866 mu_stream_destroy (&fs->out, mu_stream_get_owner (fs->out));
877 867
878 _prog_stream_wait (fs); 868 _prog_wait (fs->pid, &fs->status);
869 fs->pid = -1;
870 _prog_wait (fs->writer_pid, &status);
871 fs->writer_pid = -1;
879 872
880 mu_stream_close (fs->in); 873 mu_stream_close (fs->in);
881 mu_stream_destroy (&fs->in, mu_stream_get_owner (fs->in)); 874 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) ...@@ -1101,7 +1094,7 @@ mu_prog_stream_create (mu_stream_t *stream, const char *progname, int flags)
1101 1094
1102 int 1095 int
1103 mu_filter_prog_stream_create (mu_stream_t *stream, const char *progname, 1096 mu_filter_prog_stream_create (mu_stream_t *stream, const char *progname,
1104 mu_stream_t input) 1097 mu_stream_t input)
1105 { 1098 {
1106 struct _prog_stream *fs; 1099 struct _prog_stream *fs;
1107 int rc = _prog_stream_create (&fs, stream, progname, MU_STREAM_RDWR); 1100 int rc = _prog_stream_create (&fs, stream, progname, MU_STREAM_RDWR);
......
...@@ -174,7 +174,8 @@ mu_mailbox_destroy (mu_mailbox_t *pmbox) ...@@ -174,7 +174,8 @@ mu_mailbox_destroy (mu_mailbox_t *pmbox)
174 /* Notify the observers. */ 174 /* Notify the observers. */
175 if (mbox->observable) 175 if (mbox->observable)
176 { 176 {
177 mu_observable_notify (mbox->observable, MU_EVT_MAILBOX_DESTROY, mbox); 177 mu_observable_notify (mbox->observable, MU_EVT_MAILBOX_DESTROY,
178 mbox);
178 mu_observable_destroy (&mbox->observable, mbox); 179 mu_observable_destroy (&mbox->observable, mbox);
179 } 180 }
180 181
...@@ -223,6 +224,13 @@ mu_mailbox_open (mu_mailbox_t mbox, int flag) ...@@ -223,6 +224,13 @@ mu_mailbox_open (mu_mailbox_t mbox, int flag)
223 { 224 {
224 if (mbox == NULL || mbox->_open == NULL) 225 if (mbox == NULL || mbox->_open == NULL)
225 return MU_ERR_EMPTY_VFN; 226 return MU_ERR_EMPTY_VFN;
227 if (flag & MU_STREAM_QACCESS)
228 {
229 /* Quick access mailboxes are read-only */
230 if (flag & (MU_STREAM_WRITE | MU_STREAM_RDWR
231 | MU_STREAM_APPEND | MU_STREAM_CREAT))
232 return EINVAL; /* FIXME: Better error code, please? */
233 }
226 return mbox->_open (mbox, flag); 234 return mbox->_open (mbox, flag);
227 } 235 }
228 236
...@@ -284,6 +292,8 @@ mu_mailbox_get_message (mu_mailbox_t mbox, size_t msgno, mu_message_t *pmsg) ...@@ -284,6 +292,8 @@ mu_mailbox_get_message (mu_mailbox_t mbox, size_t msgno, mu_message_t *pmsg)
284 { 292 {
285 if (mbox == NULL || mbox->_get_message == NULL) 293 if (mbox == NULL || mbox->_get_message == NULL)
286 return MU_ERR_EMPTY_VFN; 294 return MU_ERR_EMPTY_VFN;
295 if (mbox->flags & MU_STREAM_QACCESS)
296 return MU_ERR_BADOP;
287 return mbox->_get_message (mbox, msgno, pmsg); 297 return mbox->_get_message (mbox, msgno, pmsg);
288 } 298 }
289 299
...@@ -293,6 +303,8 @@ mu_mailbox_quick_get_message (mu_mailbox_t mbox, mu_message_qid_t qid, ...@@ -293,6 +303,8 @@ mu_mailbox_quick_get_message (mu_mailbox_t mbox, mu_message_qid_t qid,
293 { 303 {
294 if (mbox == NULL || mbox->_quick_get_message == NULL) 304 if (mbox == NULL || mbox->_quick_get_message == NULL)
295 return MU_ERR_EMPTY_VFN; 305 return MU_ERR_EMPTY_VFN;
306 if (!(mbox->flags & MU_STREAM_QACCESS))
307 return MU_ERR_BADOP;
296 return mbox->_quick_get_message (mbox, qid, pmsg); 308 return mbox->_quick_get_message (mbox, qid, pmsg);
297 } 309 }
298 310
...@@ -301,6 +313,8 @@ mu_mailbox_messages_count (mu_mailbox_t mbox, size_t *num) ...@@ -301,6 +313,8 @@ mu_mailbox_messages_count (mu_mailbox_t mbox, size_t *num)
301 { 313 {
302 if (mbox == NULL || mbox->_messages_count == NULL) 314 if (mbox == NULL || mbox->_messages_count == NULL)
303 return MU_ERR_EMPTY_VFN; 315 return MU_ERR_EMPTY_VFN;
316 if (mbox->flags & MU_STREAM_QACCESS)
317 return MU_ERR_BADOP;
304 return mbox->_messages_count (mbox, num); 318 return mbox->_messages_count (mbox, num);
305 } 319 }
306 320
...@@ -309,6 +323,8 @@ mu_mailbox_messages_recent (mu_mailbox_t mbox, size_t *num) ...@@ -309,6 +323,8 @@ mu_mailbox_messages_recent (mu_mailbox_t mbox, size_t *num)
309 { 323 {
310 if (mbox == NULL || mbox->_messages_recent == NULL) 324 if (mbox == NULL || mbox->_messages_recent == NULL)
311 return MU_ERR_EMPTY_VFN; 325 return MU_ERR_EMPTY_VFN;
326 if (mbox->flags & MU_STREAM_QACCESS)
327 return MU_ERR_BADOP;
312 return mbox->_messages_recent (mbox, num); 328 return mbox->_messages_recent (mbox, num);
313 } 329 }
314 330
...@@ -317,6 +333,8 @@ mu_mailbox_message_unseen (mu_mailbox_t mbox, size_t *num) ...@@ -317,6 +333,8 @@ mu_mailbox_message_unseen (mu_mailbox_t mbox, size_t *num)
317 { 333 {
318 if (mbox == NULL || mbox->_message_unseen == NULL) 334 if (mbox == NULL || mbox->_message_unseen == NULL)
319 return MU_ERR_EMPTY_VFN; 335 return MU_ERR_EMPTY_VFN;
336 if (mbox->flags & MU_STREAM_QACCESS)
337 return MU_ERR_BADOP;
320 return mbox->_message_unseen (mbox, num); 338 return mbox->_message_unseen (mbox, num);
321 } 339 }
322 340
...@@ -356,6 +374,8 @@ mu_mailbox_is_updated (mu_mailbox_t mbox) ...@@ -356,6 +374,8 @@ mu_mailbox_is_updated (mu_mailbox_t mbox)
356 { 374 {
357 if (mbox == NULL || mbox->_is_updated == NULL) 375 if (mbox == NULL || mbox->_is_updated == NULL)
358 return 1; 376 return 1;
377 if (mbox->flags & MU_STREAM_QACCESS)
378 return 1;
359 return mbox->_is_updated (mbox); 379 return mbox->_is_updated (mbox);
360 } 380 }
361 381
...@@ -364,6 +384,8 @@ mu_mailbox_scan (mu_mailbox_t mbox, size_t msgno, size_t *pcount) ...@@ -364,6 +384,8 @@ mu_mailbox_scan (mu_mailbox_t mbox, size_t msgno, size_t *pcount)
364 { 384 {
365 if (mbox == NULL || mbox->_scan == NULL) 385 if (mbox == NULL || mbox->_scan == NULL)
366 return MU_ERR_EMPTY_VFN; 386 return MU_ERR_EMPTY_VFN;
387 if (mbox->flags & MU_STREAM_QACCESS)
388 return MU_ERR_BADOP;
367 return mbox->_scan (mbox, msgno, pcount); 389 return mbox->_scan (mbox, msgno, pcount);
368 } 390 }
369 391
...@@ -373,6 +395,8 @@ mu_mailbox_get_size (mu_mailbox_t mbox, mu_off_t *psize) ...@@ -373,6 +395,8 @@ mu_mailbox_get_size (mu_mailbox_t mbox, mu_off_t *psize)
373 int status; 395 int status;
374 if (mbox == NULL) 396 if (mbox == NULL)
375 return MU_ERR_EMPTY_VFN; 397 return MU_ERR_EMPTY_VFN;
398 if (mbox->flags & MU_STREAM_QACCESS)
399 return MU_ERR_BADOP;
376 if (mbox->_get_size == NULL 400 if (mbox->_get_size == NULL
377 || (status = mbox->_get_size (mbox, psize)) == ENOSYS) 401 || (status = mbox->_get_size (mbox, psize)) == ENOSYS)
378 { 402 {
...@@ -405,6 +429,8 @@ mu_mailbox_uidvalidity (mu_mailbox_t mbox, unsigned long *pvalid) ...@@ -405,6 +429,8 @@ mu_mailbox_uidvalidity (mu_mailbox_t mbox, unsigned long *pvalid)
405 { 429 {
406 if (mbox == NULL || mbox->_uidvalidity == NULL) 430 if (mbox == NULL || mbox->_uidvalidity == NULL)
407 return MU_ERR_EMPTY_VFN; 431 return MU_ERR_EMPTY_VFN;
432 if (mbox->flags & MU_STREAM_QACCESS)
433 return MU_ERR_BADOP;
408 return mbox->_uidvalidity (mbox, pvalid); 434 return mbox->_uidvalidity (mbox, pvalid);
409 } 435 }
410 436
...@@ -413,6 +439,8 @@ mu_mailbox_uidnext (mu_mailbox_t mbox, size_t *puidnext) ...@@ -413,6 +439,8 @@ mu_mailbox_uidnext (mu_mailbox_t mbox, size_t *puidnext)
413 { 439 {
414 if (mbox == NULL || mbox->_uidnext == NULL) 440 if (mbox == NULL || mbox->_uidnext == NULL)
415 return MU_ERR_EMPTY_VFN; 441 return MU_ERR_EMPTY_VFN;
442 if (mbox->flags & MU_STREAM_QACCESS)
443 return MU_ERR_BADOP;
416 return mbox->_uidnext (mbox, puidnext); 444 return mbox->_uidnext (mbox, puidnext);
417 } 445 }
418 446
...@@ -455,6 +483,8 @@ mu_mailbox_set_stream (mu_mailbox_t mbox, mu_stream_t stream) ...@@ -455,6 +483,8 @@ mu_mailbox_set_stream (mu_mailbox_t mbox, mu_stream_t stream)
455 { 483 {
456 if (mbox == NULL) 484 if (mbox == NULL)
457 return MU_ERR_MBX_NULL; 485 return MU_ERR_MBX_NULL;
486 if (mbox->flags & MU_STREAM_QACCESS)
487 return MU_ERR_BADOP;
458 if (mbox->stream) 488 if (mbox->stream)
459 mu_stream_destroy (&mbox->stream, mbox); 489 mu_stream_destroy (&mbox->stream, mbox);
460 mbox->stream = stream; 490 mbox->stream = stream;
......