a_coll_ocds__mac(): fix NOTEACHED function return
[s-mailx.git] / cmd_message.c
blob5391965cdd1707cf2c5b7e08ce5a1fd962903cd9
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ Iterating over, and over such housekeeping message user commands.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2017 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
6 */
7 /*
8 * Copyright (c) 1980, 1993
9 * The Regents of the University of California. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
35 #undef n_FILE
36 #define n_FILE cmd_message
38 #ifndef HAVE_AMALGAMATION
39 # include "nail.h"
40 #endif
42 /* Prepare and print "[Message: xy]:" intro */
43 static void _show_msg_overview(FILE *obuf, struct message *mp, int msg_no);
45 /* Show the requested messages */
46 static int _type1(int *msgvec, bool_t doign, bool_t dopage, bool_t dopipe,
47 bool_t donotdecode, char *cmd, ui64_t *tstats);
49 /* Pipe the requested messages */
50 static int _pipe1(char *str, int doign);
52 /* `top' / `Top' */
53 static int a_cmsg_top(void *vp, struct n_ignore const *itp);
55 /* Delete the indicated messages. Set dot to some nice place afterwards */
56 static int delm(int *msgvec);
58 static void
59 _show_msg_overview(FILE *obuf, struct message *mp, int msg_no)
61 char const *cpre, *csuf;
62 NYD_ENTER;
64 cpre = csuf = n_empty;
65 #ifdef HAVE_COLOUR
66 if (n_pstate & n_PS_COLOUR_ACTIVE) {
67 struct n_colour_pen *cpen;
69 if ((cpen = n_colour_pen_create(n_COLOUR_ID_VIEW_MSGINFO, NULL)) != NULL){
70 struct str const *sp;
72 if ((sp = n_colour_pen_to_str(cpen)) != NULL)
73 cpre = sp->s;
74 if ((sp = n_colour_reset_to_str()) != NULL)
75 csuf = sp->s;
78 #endif
79 /* XXX Message info uses wire format for line count */
80 fprintf(obuf, _("%s[-- Message %2d -- %lu lines, %lu bytes --]:%s\n"),
81 cpre, msg_no, (ul_i)mp->m_lines, (ul_i)mp->m_size, csuf);
82 NYD_LEAVE;
85 static int
86 _type1(int *msgvec, bool_t doign, bool_t dopage, bool_t dopipe,
87 bool_t donotdecode, char *cmd, ui64_t *tstats)
89 struct n_sigman sm;
90 ui64_t mstats[1];
91 int volatile rv = 1;
92 int *ip;
93 struct message *mp;
94 char const *cp;
95 FILE * volatile obuf;
96 bool_t volatile isrelax = FAL0;
97 NYD_ENTER;
98 {/* C89.. */
99 enum sendaction const action = ((dopipe && ok_blook(piperaw))
100 ? SEND_MBOX : donotdecode
101 ? SEND_SHOW : doign
102 ? SEND_TODISP : SEND_TODISP_ALL);
103 bool_t const volatile formfeed = (dopipe && ok_blook(page));
104 obuf = n_stdout;
106 n_SIGMAN_ENTER_SWITCH(&sm, n_SIGMAN_ALL) {
107 case 0:
108 break;
109 default:
110 goto jleave;
113 if (dopipe) {
114 if ((obuf = Popen(cmd, "w", ok_vlook(SHELL), NULL, 1)) == NULL) {
115 n_perr(cmd, 0);
116 obuf = n_stdout;
118 } else if ((n_psonce & n_PSO_TTYOUT) && (dopage ||
119 ((n_psonce & n_PSO_INTERACTIVE) && (cp = ok_vlook(crt)) != NULL))) {
120 uiz_t nlines, lib;
122 nlines = 0;
124 if (!dopage) {
125 for (ip = msgvec; *ip && PTRCMP(ip - msgvec, <, msgCount); ++ip) {
126 mp = message + *ip - 1;
127 if (!(mp->m_content_info & CI_HAVE_BODY))
128 if (get_body(mp) != OKAY)
129 goto jcleanup_leave;
130 nlines += mp->m_lines + 1; /* TODO BUT wire format, not display! */
134 /* >= not <: we return to the prompt */
135 if(dopage || nlines >= (*cp != '\0'
136 ? (n_idec_uiz_cp(&lib, cp, 0, NULL), lib)
137 : (uiz_t)n_realscreenheight)){
138 if((obuf = n_pager_open()) == NULL)
139 obuf = n_stdout;
141 #ifdef HAVE_COLOUR
142 if ((n_psonce & n_PSO_INTERACTIVE) &&
143 (action == SEND_TODISP || action == SEND_TODISP_ALL))
144 n_colour_env_create(n_COLOUR_CTX_VIEW, obuf != n_stdout);
145 #endif
147 #ifdef HAVE_COLOUR
148 else if ((n_psonce & n_PSO_INTERACTIVE) &&
149 (action == SEND_TODISP || action == SEND_TODISP_ALL))
150 n_colour_env_create(n_COLOUR_CTX_VIEW, FAL0);
151 #endif
153 /*TODO unless we have our signal manager special care must be taken */
154 srelax_hold();
155 isrelax = TRU1;
156 for (ip = msgvec; *ip && PTRCMP(ip - msgvec, <, msgCount); ++ip) {
157 mp = message + *ip - 1;
158 touch(mp);
159 setdot(mp);
160 n_pstate |= n_PS_DID_PRINT_DOT;
161 uncollapse1(mp, 1);
162 if (!dopipe && ip != msgvec)
163 fprintf(obuf, "\n");
164 if (action != SEND_MBOX)
165 _show_msg_overview(obuf, mp, *ip);
166 sendmp(mp, obuf, (doign ? n_IGNORE_TYPE : NULL), NULL, action, mstats);
167 srelax();
168 if (formfeed) /* TODO a nicer way to separate piped messages! */
169 putc('\f', obuf);
170 if (tstats != NULL)
171 tstats[0] += mstats[0];
173 srelax_rele();
174 isrelax = FAL0;
176 rv = 0;
177 jcleanup_leave:
178 n_sigman_cleanup_ping(&sm);
179 jleave:
180 if (isrelax)
181 srelax_rele();
182 n_COLOUR( n_colour_env_gut((sm.sm_signo != SIGPIPE) ? obuf : NULL); )
183 if (obuf != n_stdout)
184 n_pager_close(obuf);
186 NYD_LEAVE;
187 n_sigman_leave(&sm, n_SIGMAN_VIPSIGS_NTTYOUT);
188 return rv;
191 static int
192 _pipe1(char *str, int doign)
194 ui64_t stats[1];
195 char const *cmd, *cmdq;
196 int *msgvec, rv = 1;
197 bool_t needs_list;
198 NYD_ENTER;
200 if ((cmd = laststring(str, &needs_list, TRU1)) == NULL) {
201 cmd = ok_vlook(cmd);
202 if (cmd == NULL || *cmd == '\0') {
203 n_err(_("Variable *cmd* not set\n"));
204 goto jleave;
208 msgvec = salloc((msgCount + 2) * sizeof *msgvec);
210 if (!needs_list) {
211 *msgvec = first(0, MMNORM);
212 if (*msgvec == 0) {
213 if (n_pstate & (n_PS_ROBOT | n_PS_HOOK_MASK)) {
214 rv = 0;
215 goto jleave;
217 fputs(_("No messages to pipe.\n"), n_stdout);
218 goto jleave;
220 msgvec[1] = 0;
221 } else if (getmsglist(str, msgvec, 0) < 0)
222 goto jleave;
223 if (*msgvec == 0) {
224 if (n_pstate & (n_PS_ROBOT | n_PS_HOOK_MASK)) {
225 rv = 0;
226 goto jleave;
228 fprintf(n_stdout, "No applicable messages.\n");
229 goto jleave;
232 cmdq = n_shexp_quote_cp(cmd, FAL0);
233 fprintf(n_stdout, _("Pipe to: %s\n"), cmdq);
234 stats[0] = 0;
235 if ((rv = _type1(msgvec, doign, FAL0, TRU1, FAL0, n_UNCONST(cmd), stats)
236 ) == 0)
237 fprintf(n_stdout, "%s %" PRIu64 " bytes\n", cmdq, stats[0]);
238 jleave:
239 NYD_LEAVE;
240 return rv;
243 static int
244 a_cmsg_top(void *vp, struct n_ignore const *itp){
245 struct n_string s;
246 int *msgvec, *ip;
247 enum{a_NONE, a_SQUEEZE = 1u<<0,
248 a_EMPTY = 1u<<8, a_STOP = 1u<<9, a_WORKMASK = 0xFF00u} f;
249 size_t tmax, plines;
250 FILE *iobuf, *pbuf;
251 NYD2_ENTER;
253 if((iobuf = Ftmp(NULL, "topio", OF_RDWR | OF_UNLINK | OF_REGISTER)) == NULL){
254 n_perr(_("`top': I/O temporary file"), 0);
255 vp = NULL;
256 goto jleave;
258 if((pbuf = Ftmp(NULL, "toppag", OF_RDWR | OF_UNLINK | OF_REGISTER)) == NULL){
259 n_perr(_("`top': temporary pager file"), 0);
260 vp = NULL;
261 goto jleave1;
264 /* TODO In v15 we should query the m_message object, and directly send only
265 * TODO those parts, optionally over empty-line-squeeze and quote-strip
266 * TODO filters, in which we are interested in: only text content!
267 * TODO And: with *topsqueeze*, header/content separating empty line.. */
268 n_pstate &= ~n_PS_MSGLIST_DIRECT; /* TODO NO ATTACHMENTS */
269 plines = 0;
271 #ifdef HAVE_COLOUR
272 if (n_psonce & n_PSO_INTERACTIVE)
273 n_colour_env_create(n_COLOUR_CTX_VIEW, TRU1);
274 #endif
275 n_string_creat_auto(&s);
276 /* C99 */{
277 siz_t l;
279 if((n_idec_siz_cp(&l, ok_vlook(toplines), 0, NULL
280 ) & (n_IDEC_STATE_EMASK | n_IDEC_STATE_CONSUMED)
281 ) != n_IDEC_STATE_CONSUMED)
282 l = 0;
283 if(l <= 0){
284 tmax = n_screensize();
285 if(l < 0){
286 l = n_ABS(l);
287 tmax >>= l;
289 }else
290 tmax = (size_t)l;
292 f = ok_blook(topsqueeze) ? a_SQUEEZE : a_NONE;
294 for(ip = msgvec = vp;
295 *ip != 0 && UICMP(z, PTR2SIZE(ip - msgvec), <, msgCount); ++ip){
296 struct message *mp;
298 mp = &message[*ip - 1];
299 touch(mp);
300 setdot(mp);
301 n_pstate |= n_PS_DID_PRINT_DOT;
302 uncollapse1(mp, 1);
304 rewind(iobuf);
305 if(ftruncate(fileno(iobuf), 0)){
306 n_perr(_("`top': ftruncate(2)"), 0);
307 vp = NULL;
308 break;
310 if(sendmp(mp, iobuf, itp, NULL, SEND_TODISP_ALL, NULL) < 0){
311 n_err(_("`top': failed to prepare message %d\n"), *ip);
312 vp = NULL;
313 break;
315 fflush_rewind(iobuf);
317 _show_msg_overview(pbuf, mp, *ip);
318 ++plines;
319 /* C99 */{
320 size_t l;
322 n_string_trunc(&s, 0);
323 for(l = 0, f &= ~a_WORKMASK; !(f & a_STOP);){
324 int c;
326 if((c = getc(iobuf)) == EOF){
327 f |= a_STOP;
328 c = '\n';
331 if(c != '\n')
332 n_string_push_c(&s, c);
333 else if((f & a_SQUEEZE) && s.s_len == 0){
334 if(!(f & a_STOP) && ((f & a_EMPTY) || tmax - 1 <= l))
335 continue;
336 if(putc('\n', pbuf) == EOF){
337 vp = NULL;
338 break;
340 f |= a_EMPTY;
341 ++l;
342 }else{
343 char const *cp, *xcp;
345 cp = n_string_cp_const(&s);
346 /* TODO Brute simple skip part overviews; see above.. */
347 if(!(f & a_SQUEEZE))
348 c = '\1';
349 else if(s.s_len > 8 &&
350 (xcp = strstr(cp, "[-- ")) != NULL &&
351 strstr(&xcp[1], " --]") != NULL)
352 c = '\0';
353 else for(; (c = *cp) != '\0'; ++cp){
354 if(!asciichar(c))
355 break;
356 if(!blankspacechar(c)){
357 if(!ISQUOTE(c))
358 break;
359 c = '\0';
360 break;
364 if(c != '\0'){
365 if(fputs(n_string_cp_const(&s), pbuf) == EOF ||
366 putc('\n', pbuf) == EOF){
367 vp = NULL;
368 break;
370 if(++l >= tmax)
371 break;
372 f &= ~a_EMPTY;
373 }else
374 f |= a_EMPTY;
375 n_string_trunc(&s, 0);
378 if(vp == NULL)
379 break;
380 if(l > 0)
381 plines += l;
382 else{
383 if(!(f & a_EMPTY) && putc('\n', pbuf) == EOF){
384 vp = NULL;
385 break;
387 ++plines;
392 n_string_gut(&s);
393 n_COLOUR( n_colour_env_gut(pbuf); )
395 fflush(pbuf);
396 page_or_print(pbuf, plines);
398 Fclose(pbuf);
399 jleave1:
400 Fclose(iobuf);
401 jleave:
402 NYD2_LEAVE;
403 return (vp != NULL);
406 static int
407 delm(int *msgvec)
409 struct message *mp;
410 int rv = -1, *ip, last;
411 NYD_ENTER;
413 last = 0;
414 for (ip = msgvec; *ip != 0; ++ip) {
415 mp = message + *ip - 1;
416 touch(mp);
417 mp->m_flag |= MDELETED | MTOUCH;
418 mp->m_flag &= ~(MPRESERVE | MSAVED | MBOX);
419 last = *ip;
421 if (last != 0) {
422 setdot(message + last - 1);
423 last = first(0, MDELETED);
424 if (last != 0) {
425 setdot(message + last - 1);
426 rv = 0;
427 } else {
428 setdot(message);
431 NYD_LEAVE;
432 return rv;
435 FL int
436 c_more(void *v)
438 int *msgvec = v, rv;
439 NYD_ENTER;
441 rv = _type1(msgvec, TRU1, TRU1, FAL0, FAL0, NULL, NULL);
442 NYD_LEAVE;
443 return rv;
446 FL int
447 c_More(void *v)
449 int *msgvec = v, rv;
450 NYD_ENTER;
452 rv = _type1(msgvec, FAL0, TRU1, FAL0, FAL0, NULL, NULL);
453 NYD_LEAVE;
454 return rv;
457 FL int
458 c_type(void *v)
460 int *msgvec = v, rv;
461 NYD_ENTER;
463 rv = _type1(msgvec, TRU1, FAL0, FAL0, FAL0, NULL, NULL);
464 NYD_LEAVE;
465 return rv;
468 FL int
469 c_Type(void *v)
471 int *msgvec = v, rv;
472 NYD_ENTER;
474 rv = _type1(msgvec, FAL0, FAL0, FAL0, FAL0, NULL, NULL);
475 NYD_LEAVE;
476 return rv;
479 FL int
480 c_show(void *v)
482 int *msgvec = v, rv;
483 NYD_ENTER;
485 rv = _type1(msgvec, FAL0, FAL0, FAL0, TRU1, NULL, NULL);
486 NYD_LEAVE;
487 return rv;
490 FL int
491 c_pipe(void *v)
493 char *str = v;
494 int rv;
495 NYD_ENTER;
497 rv = _pipe1(str, 1);
498 NYD_LEAVE;
499 return rv;
502 FL int
503 c_Pipe(void *v)
505 char *str = v;
506 int rv;
507 NYD_ENTER;
509 rv = _pipe1(str, 0);
510 NYD_LEAVE;
511 return rv;
514 FL int
515 c_top(void *v){
516 struct n_ignore *itp;
517 int rv;
518 NYD_ENTER;
520 if(n_ignore_is_any(n_IGNORE_TOP))
521 itp = n_IGNORE_TOP;
522 else{
523 itp = n_ignore_new(TRU1);
524 n_ignore_insert(itp, TRU1, "from", sizeof("from") -1);
525 n_ignore_insert(itp, TRU1, "to", sizeof("to") -1);
526 n_ignore_insert(itp, TRU1, "cc", sizeof("cc") -1);
527 n_ignore_insert(itp, TRU1, "subject", sizeof("subject") -1);
530 rv = !a_cmsg_top(v, itp);
531 NYD_LEAVE;
532 return rv;
535 FL int
536 c_Top(void *v){
537 int rv;
538 NYD_ENTER;
540 rv = !a_cmsg_top(v, n_IGNORE_TYPE);
541 NYD_LEAVE;
542 return rv;
545 FL int
546 c_next(void *v)
548 int list[2], *ip, *ip2, mdot, *msgvec = v, rv = 1;
549 struct message *mp;
550 NYD_ENTER;
552 if (*msgvec != 0) {
553 /* If some messages were supplied, find the first applicable one
554 * following dot using wrap around */
555 mdot = (int)PTR2SIZE(dot - message + 1);
557 /* Find first message in supplied message list which follows dot */
558 for (ip = msgvec; *ip != 0; ++ip) {
559 if ((mb.mb_threaded ? message[*ip - 1].m_threadpos > dot->m_threadpos
560 : *ip > mdot))
561 break;
563 if (*ip == 0)
564 ip = msgvec;
565 ip2 = ip;
566 do {
567 mp = message + *ip2 - 1;
568 if (!(mp->m_flag & MMNDEL)) {
569 setdot(mp);
570 goto jhitit;
572 if (*ip2 != 0)
573 ++ip2;
574 if (*ip2 == 0)
575 ip2 = msgvec;
576 } while (ip2 != ip);
577 fprintf(n_stdout, _("No messages applicable\n"));
578 goto jleave;
581 /* If this is the first command, select message 1. Note that this must
582 * exist for us to get here at all */
583 if (!(n_pstate & n_PS_SAW_COMMAND)) {
584 if (msgCount == 0)
585 goto jateof;
586 goto jhitit;
589 /* Just find the next good message after dot, no wraparound */
590 if (mb.mb_threaded == 0) {
591 for (mp = dot + !!(n_pstate & n_PS_DID_PRINT_DOT);
592 PTRCMP(mp, <, message + msgCount); ++mp)
593 if (!(mp->m_flag & MMNORM))
594 break;
595 } else {
596 /* TODO The threading code had some bugs that caused crashes.
597 * TODO The last thing (before the deep look) happens here,
598 * TODO so let's not trust n_PS_DID_PRINT_DOT but check & hope it fixes */
599 if ((mp = dot) != NULL && (n_pstate & n_PS_DID_PRINT_DOT))
600 mp = next_in_thread(mp);
601 while (mp != NULL && (mp->m_flag & MMNORM))
602 mp = next_in_thread(mp);
604 if (mp == NULL || PTRCMP(mp, >=, message + msgCount)) {
605 jateof:
606 fprintf(n_stdout, _("At EOF\n"));
607 rv = 0;
608 goto jleave;
610 setdot(mp);
612 /* Print dot */
613 jhitit:
614 list[0] = (int)PTR2SIZE(dot - message + 1);
615 list[1] = 0;
616 rv = c_type(list);
617 jleave:
618 NYD_LEAVE;
619 return rv;
622 FL int
623 c_pdot(void *vp)
625 NYD_ENTER;
626 n_UNUSED(vp);
627 fprintf(n_stdout, "%d\n", (int)PTR2SIZE(dot - message + 1));
628 NYD_LEAVE;
629 return 0;
632 FL int
633 c_messize(void *v)
635 int *msgvec = v, *ip, mesg;
636 struct message *mp;
637 NYD_ENTER;
639 for (ip = msgvec; *ip != 0; ++ip) {
640 mesg = *ip;
641 mp = message + mesg - 1;
642 fprintf(n_stdout, "%d: ", mesg);
643 if (mp->m_xlines > 0)
644 fprintf(n_stdout, "%ld", mp->m_xlines);
645 else
646 putc(' ', n_stdout);
647 fprintf(n_stdout, "/%lu\n", (ul_i)mp->m_xsize);
649 NYD_LEAVE;
650 return 0;
653 FL int
654 c_delete(void *v)
656 int *msgvec = v;
657 NYD_ENTER;
659 delm(msgvec);
660 NYD_LEAVE;
661 return 0;
664 FL int
665 c_deltype(void *v)
667 int list[2], rv = 0, *msgvec = v, lastdot;
668 NYD_ENTER;
670 lastdot = (int)PTR2SIZE(dot - message + 1);
671 if (delm(msgvec) >= 0) {
672 list[0] = (int)PTR2SIZE(dot - message + 1);
673 if (list[0] > lastdot) {
674 touch(dot);
675 list[1] = 0;
676 rv = c_type(list);
677 goto jleave;
679 fprintf(n_stdout, _("At EOF\n"));
680 } else
681 fprintf(n_stdout, _("No more messages\n"));
682 jleave:
683 NYD_LEAVE;
684 return rv;
687 FL int
688 c_undelete(void *v)
690 int *msgvec = v, *ip;
691 struct message *mp;
692 NYD_ENTER;
694 for (ip = msgvec; *ip != 0 && UICMP(z, PTR2SIZE(ip - msgvec), <, msgCount);
695 ++ip) {
696 mp = message + *ip - 1;
697 touch(mp);
698 setdot(mp);
699 if (mp->m_flag & (MDELETED | MSAVED))
700 mp->m_flag &= ~(MDELETED | MSAVED);
701 else
702 mp->m_flag &= ~MDELETED;
704 NYD_LEAVE;
705 return 0;
708 FL int
709 c_stouch(void *v)
711 int *msgvec = v, *ip;
712 NYD_ENTER;
714 for (ip = msgvec; *ip != 0; ++ip) {
715 setdot(message + *ip - 1);
716 dot->m_flag |= MTOUCH;
717 dot->m_flag &= ~MPRESERVE;
718 n_pstate |= n_PS_DID_PRINT_DOT;
720 NYD_LEAVE;
721 return 0;
724 FL int
725 c_mboxit(void *v)
727 int *msgvec = v, *ip;
728 NYD_ENTER;
730 if (n_pstate & n_PS_EDIT) {
731 n_err(_("`mbox' can only be used in a system mailbox\n")); /* TODO */
732 goto jleave;
735 for (ip = msgvec; *ip != 0; ++ip) {
736 setdot(message + *ip - 1);
737 dot->m_flag |= MTOUCH | MBOX;
738 dot->m_flag &= ~MPRESERVE;
739 n_pstate |= n_PS_DID_PRINT_DOT;
741 jleave:
742 NYD_LEAVE;
743 return 0;
746 FL int
747 c_preserve(void *v)
749 int *msgvec = v, *ip, mesg, rv = 1;
750 struct message *mp;
751 NYD_ENTER;
753 if (n_pstate & n_PS_EDIT) {
754 fprintf(n_stdout, _("Cannot `preserve' in a system mailbox\n"));
755 goto jleave;
758 for (ip = msgvec; *ip != 0; ++ip) {
759 mesg = *ip;
760 mp = message + mesg - 1;
761 mp->m_flag |= MPRESERVE;
762 mp->m_flag &= ~MBOX;
763 setdot(mp);
764 n_pstate |= n_PS_DID_PRINT_DOT;
766 rv = 0;
767 jleave:
768 NYD_LEAVE;
769 return rv;
772 FL int
773 c_unread(void *v)
775 int *msgvec = v, *ip;
776 NYD_ENTER;
778 for (ip = msgvec; *ip != 0; ++ip) {
779 setdot(message + *ip - 1);
780 dot->m_flag &= ~(MREAD | MTOUCH);
781 dot->m_flag |= MSTATUS;
782 n_pstate |= n_PS_DID_PRINT_DOT;
784 NYD_LEAVE;
785 return 0;
788 FL int
789 c_seen(void *v)
791 int *msgvec = v, *ip;
792 NYD_ENTER;
794 for (ip = msgvec; *ip != 0; ++ip) {
795 struct message *mp = message + *ip - 1;
796 setdot(mp);
797 touch(mp);
799 NYD_LEAVE;
800 return 0;
803 FL int
804 c_flag(void *v)
806 struct message *m;
807 int *msgvec = v, *ip;
808 NYD_ENTER;
810 for (ip = msgvec; *ip != 0; ++ip) {
811 m = message + *ip - 1;
812 setdot(m);
813 if (!(m->m_flag & (MFLAG | MFLAGGED)))
814 m->m_flag |= MFLAG | MFLAGGED;
816 NYD_LEAVE;
817 return 0;
820 FL int
821 c_unflag(void *v)
823 struct message *m;
824 int *msgvec = v, *ip;
825 NYD_ENTER;
827 for (ip = msgvec; *ip != 0; ++ip) {
828 m = message + *ip - 1;
829 setdot(m);
830 if (m->m_flag & (MFLAG | MFLAGGED)) {
831 m->m_flag &= ~(MFLAG | MFLAGGED);
832 m->m_flag |= MUNFLAG;
835 NYD_LEAVE;
836 return 0;
839 FL int
840 c_answered(void *v)
842 struct message *m;
843 int *msgvec = v, *ip;
844 NYD_ENTER;
846 for (ip = msgvec; *ip != 0; ++ip) {
847 m = message + *ip - 1;
848 setdot(m);
849 if (!(m->m_flag & (MANSWER | MANSWERED)))
850 m->m_flag |= MANSWER | MANSWERED;
852 NYD_LEAVE;
853 return 0;
856 FL int
857 c_unanswered(void *v)
859 struct message *m;
860 int *msgvec = v, *ip;
861 NYD_ENTER;
863 for (ip = msgvec; *ip != 0; ++ip) {
864 m = message + *ip - 1;
865 setdot(m);
866 if (m->m_flag & (MANSWER | MANSWERED)) {
867 m->m_flag &= ~(MANSWER | MANSWERED);
868 m->m_flag |= MUNANSWER;
871 NYD_LEAVE;
872 return 0;
875 FL int
876 c_draft(void *v)
878 struct message *m;
879 int *msgvec = v, *ip;
880 NYD_ENTER;
882 for (ip = msgvec; *ip != 0; ++ip) {
883 m = message + *ip - 1;
884 setdot(m);
885 if (!(m->m_flag & (MDRAFT | MDRAFTED)))
886 m->m_flag |= MDRAFT | MDRAFTED;
888 NYD_LEAVE;
889 return 0;
892 FL int
893 c_undraft(void *v)
895 struct message *m;
896 int *msgvec = v, *ip;
897 NYD_ENTER;
899 for (ip = msgvec; *ip != 0; ++ip) {
900 m = message + *ip - 1;
901 setdot(m);
902 if (m->m_flag & (MDRAFT | MDRAFTED)) {
903 m->m_flag &= ~(MDRAFT | MDRAFTED);
904 m->m_flag |= MUNDRAFT;
907 NYD_LEAVE;
908 return 0;
911 /* s-it-mode */