FIX [1c4b8c918] (Address struct name memory usage.., 2015-07-08)..
[s-mailx.git] / cmd_message.c
blob834719a4b41d7a74b49edd8dd8c55caf5203a91d
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 (pstate & 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 fprintf(obuf, _("%s[-- Message %2d -- %lu lines, %lu bytes --]:%s\n"),
80 cpre, msg_no, (ul_i)mp->m_lines, (ul_i)mp->m_size, csuf);
81 NYD_LEAVE;
84 static int
85 _type1(int *msgvec, bool_t doign, bool_t dopage, bool_t dopipe,
86 bool_t donotdecode, char *cmd, ui64_t *tstats)
88 struct n_sigman sm;
89 ui64_t mstats[1];
90 int volatile rv = 1;
91 int *ip;
92 struct message *mp;
93 char const *cp;
94 FILE * volatile obuf;
95 bool_t volatile isrelax = FAL0;
96 NYD_ENTER;
97 {/* C89.. */
98 enum sendaction const action = ((dopipe && ok_blook(piperaw))
99 ? SEND_MBOX : donotdecode
100 ? SEND_SHOW : doign
101 ? SEND_TODISP : SEND_TODISP_ALL);
102 bool_t const volatile formfeed = (dopipe && ok_blook(page));
103 obuf = stdout;
105 n_SIGMAN_ENTER_SWITCH(&sm, n_SIGMAN_ALL) {
106 case 0:
107 break;
108 default:
109 goto jleave;
112 if (dopipe) {
113 if ((obuf = Popen(cmd, "w", ok_vlook(SHELL), NULL, 1)) == NULL) {
114 n_perr(cmd, 0);
115 obuf = stdout;
117 } else if ((options & OPT_TTYOUT) && (dopage ||
118 ((options & OPT_INTERACTIVE) && (cp = ok_vlook(crt)) != NULL))) {
119 size_t nlines = 0;
121 if (!dopage) {
122 for (ip = msgvec; *ip && PTRCMP(ip - msgvec, <, msgCount); ++ip) {
123 mp = message + *ip - 1;
124 if (!(mp->m_content_info & CI_HAVE_BODY))
125 if (get_body(mp) != OKAY)
126 goto jcleanup_leave;
127 nlines += mp->m_lines + 1; /* Message info XXX and PARTS... */
131 /* >= not <: we return to the prompt */
132 if (dopage || UICMP(z, nlines, >=,
133 (*cp != '\0' ? strtoul(cp, NULL, 0) : (size_t)realscreenheight))) {
134 if ((obuf = n_pager_open()) == NULL)
135 obuf = stdout;
137 #ifdef HAVE_COLOUR
138 if ((options & OPT_INTERACTIVE) &&
139 (action == SEND_TODISP || action == SEND_TODISP_ALL ||
140 action == SEND_SHOW))
141 n_colour_env_create(n_COLOUR_CTX_VIEW, obuf != stdout);
142 #endif
144 #ifdef HAVE_COLOUR
145 else if ((options & OPT_INTERACTIVE) &&
146 (action == SEND_TODISP || action == SEND_TODISP_ALL))
147 n_colour_env_create(n_COLOUR_CTX_VIEW, FAL0);
148 #endif
150 /*TODO unless we have our signal manager special care must be taken */
151 srelax_hold();
152 isrelax = TRU1;
153 for (ip = msgvec; *ip && PTRCMP(ip - msgvec, <, msgCount); ++ip) {
154 mp = message + *ip - 1;
155 touch(mp);
156 setdot(mp);
157 pstate |= PS_DID_PRINT_DOT;
158 uncollapse1(mp, 1);
159 if (!dopipe && ip != msgvec)
160 fprintf(obuf, "\n");
161 if (action != SEND_MBOX)
162 _show_msg_overview(obuf, mp, *ip);
163 sendmp(mp, obuf, (doign ? n_IGNORE_TYPE : NULL), NULL, action, mstats);
164 srelax();
165 if (formfeed) /* TODO a nicer way to separate piped messages! */
166 putc('\f', obuf);
167 if (tstats != NULL)
168 tstats[0] += mstats[0];
170 srelax_rele();
171 isrelax = FAL0;
173 rv = 0;
174 jcleanup_leave:
175 n_sigman_cleanup_ping(&sm);
176 jleave:
177 if (isrelax)
178 srelax_rele();
179 n_COLOUR( n_colour_env_gut((sm.sm_signo != SIGPIPE) ? obuf : NULL); )
180 if (obuf != stdout)
181 n_pager_close(obuf);
183 NYD_LEAVE;
184 n_sigman_leave(&sm, n_SIGMAN_VIPSIGS_NTTYOUT);
185 return rv;
188 static int
189 _pipe1(char *str, int doign)
191 ui64_t stats[1];
192 char const *cmd, *cmdq;
193 int *msgvec, rv = 1;
194 bool_t needs_list;
195 NYD_ENTER;
197 if ((cmd = laststring(str, &needs_list, TRU1)) == NULL) {
198 cmd = ok_vlook(cmd);
199 if (cmd == NULL || *cmd == '\0') {
200 n_err(_("Variable *cmd* not set\n"));
201 goto jleave;
205 msgvec = salloc((msgCount + 2) * sizeof *msgvec);
207 if (!needs_list) {
208 *msgvec = first(0, MMNORM);
209 if (*msgvec == 0) {
210 if (pstate & (PS_HOOK_MASK | PS_ROBOT)) {
211 rv = 0;
212 goto jleave;
214 puts(_("No messages to pipe."));
215 goto jleave;
217 msgvec[1] = 0;
218 } else if (getmsglist(str, msgvec, 0) < 0)
219 goto jleave;
220 if (*msgvec == 0) {
221 if (pstate & (PS_HOOK_MASK | PS_ROBOT)) {
222 rv = 0;
223 goto jleave;
225 printf("No applicable messages.\n");
226 goto jleave;
229 cmdq = n_shexp_quote_cp(cmd, FAL0);
230 printf(_("Pipe to: %s\n"), cmdq);
231 stats[0] = 0;
232 if ((rv = _type1(msgvec, doign, FAL0, TRU1, FAL0, n_UNCONST(cmd), stats)
233 ) == 0)
234 printf("%s %" PRIu64 " bytes\n", cmdq, stats[0]);
235 jleave:
236 NYD_LEAVE;
237 return rv;
240 static int
241 a_cmsg_top(void *vp, struct n_ignore const *itp){
242 struct n_string s;
243 int *msgvec, *ip;
244 enum{a_NONE, a_SQUEEZE = 1u<<0,
245 a_EMPTY = 1u<<8, a_STOP = 1u<<9, a_WORKMASK = 0xFF00u} f;
246 size_t tmax, plines;
247 FILE *iobuf, *pbuf;
248 NYD2_ENTER;
250 if((iobuf = Ftmp(NULL, "topio", OF_RDWR | OF_UNLINK | OF_REGISTER)) == NULL){
251 n_perr(_("`top': I/O temporary file"), 0);
252 vp = NULL;
253 goto jleave;
255 if((pbuf = Ftmp(NULL, "toppag", OF_RDWR | OF_UNLINK | OF_REGISTER)) == NULL){
256 n_perr(_("`top': temporary pager file"), 0);
257 vp = NULL;
258 goto jleave1;
261 /* TODO In v15 we should query the m_message object, and directly send only
262 * TODO those parts, optionally over empty-line-squeeze and quote-strip
263 * TODO filters, in which we are interested in: only text content!
264 * TODO And: with *topsqueeze*, header/content separating empty line.. */
265 pstate &= ~PS_MSGLIST_DIRECT; /* TODO NO ATTACHMENTS */
266 plines = 0;
268 #ifdef HAVE_COLOUR
269 if (options & OPT_INTERACTIVE)
270 n_colour_env_create(n_COLOUR_CTX_VIEW, TRU1);
271 #endif
272 n_string_creat_auto(&s);
273 /* C99 */{
274 long l;
276 if((l = strtol(ok_vlook(toplines), NULL, 0)) <= 0){
277 tmax = (size_t)screensize();
278 if(l < 0){
279 l = n_ABS(l);
280 tmax >>= l;
282 }else
283 tmax = (size_t)l;
285 f = ok_blook(topsqueeze) ? a_SQUEEZE : a_NONE;
287 for(ip = msgvec = vp;
288 *ip != 0 && UICMP(z, PTR2SIZE(ip - msgvec), <, msgCount); ++ip){
289 struct message *mp;
291 mp = &message[*ip - 1];
292 touch(mp);
293 setdot(mp);
294 pstate |= PS_DID_PRINT_DOT;
295 uncollapse1(mp, 1);
297 rewind(iobuf);
298 if(ftruncate(fileno(iobuf), 0)){
299 n_perr(_("`top': ftruncate(2)"), 0);
300 vp = NULL;
301 break;
303 if(sendmp(mp, iobuf, itp, NULL, SEND_TODISP_ALL, NULL) < 0){
304 n_err(_("`top': failed to prepare message %d\n"), *ip);
305 vp = NULL;
306 break;
308 fflush_rewind(iobuf);
310 _show_msg_overview(pbuf, mp, *ip);
311 ++plines;
312 /* C99 */{
313 size_t l;
315 n_string_trunc(&s, 0);
316 for(l = 0, f &= ~a_WORKMASK; !(f & a_STOP);){
317 int c;
319 if((c = getc(iobuf)) == EOF){
320 f |= a_STOP;
321 c = '\n';
324 if(c != '\n')
325 n_string_push_c(&s, c);
326 else if((f & a_SQUEEZE) && s.s_len == 0){
327 if(!(f & a_STOP) && ((f & a_EMPTY) || tmax - 1 <= l))
328 continue;
329 if(putc('\n', pbuf) == EOF){
330 vp = NULL;
331 break;
333 f |= a_EMPTY;
334 ++l;
335 }else{
336 char const *cp, *xcp;
338 cp = n_string_cp_const(&s);
339 /* TODO Brute simple skip part overviews; see above.. */
340 if(!(f & a_SQUEEZE))
341 c = '\1';
342 else if(s.s_len > 8 &&
343 (xcp = strstr(cp, "[-- ")) != NULL &&
344 strstr(&xcp[1], " --]") != NULL)
345 c = '\0';
346 else for(; (c = *cp) != '\0'; ++cp){
347 if(!asciichar(c))
348 break;
349 if(!blankspacechar(c)){
350 if(!ISQUOTE(c))
351 break;
352 c = '\0';
353 break;
357 if(c != '\0'){
358 if(fputs(n_string_cp_const(&s), pbuf) == EOF ||
359 putc('\n', pbuf) == EOF){
360 vp = NULL;
361 break;
363 if(++l >= tmax)
364 break;
365 f &= ~a_EMPTY;
366 }else
367 f |= a_EMPTY;
368 n_string_trunc(&s, 0);
371 if(vp == NULL)
372 break;
373 if(l > 0)
374 plines += l;
375 else{
376 if(!(f & a_EMPTY) && putc('\n', pbuf) == EOF){
377 vp = NULL;
378 break;
380 ++plines;
385 n_string_gut(&s);
386 n_COLOUR( n_colour_env_gut(pbuf); )
388 fflush(pbuf);
389 page_or_print(pbuf, plines);
391 Fclose(pbuf);
392 jleave1:
393 Fclose(iobuf);
394 jleave:
395 NYD2_LEAVE;
396 return (vp != NULL);
399 static int
400 delm(int *msgvec)
402 struct message *mp;
403 int rv = -1, *ip, last;
404 NYD_ENTER;
406 last = 0;
407 for (ip = msgvec; *ip != 0; ++ip) {
408 mp = message + *ip - 1;
409 touch(mp);
410 mp->m_flag |= MDELETED | MTOUCH;
411 mp->m_flag &= ~(MPRESERVE | MSAVED | MBOX);
412 last = *ip;
414 if (last != 0) {
415 setdot(message + last - 1);
416 last = first(0, MDELETED);
417 if (last != 0) {
418 setdot(message + last - 1);
419 rv = 0;
420 } else {
421 setdot(message);
424 NYD_LEAVE;
425 return rv;
428 FL int
429 c_more(void *v)
431 int *msgvec = v, rv;
432 NYD_ENTER;
434 rv = _type1(msgvec, TRU1, TRU1, FAL0, FAL0, NULL, NULL);
435 NYD_LEAVE;
436 return rv;
439 FL int
440 c_More(void *v)
442 int *msgvec = v, rv;
443 NYD_ENTER;
445 rv = _type1(msgvec, FAL0, TRU1, FAL0, FAL0, NULL, NULL);
446 NYD_LEAVE;
447 return rv;
450 FL int
451 c_type(void *v)
453 int *msgvec = v, rv;
454 NYD_ENTER;
456 rv = _type1(msgvec, TRU1, FAL0, FAL0, FAL0, NULL, NULL);
457 NYD_LEAVE;
458 return rv;
461 FL int
462 c_Type(void *v)
464 int *msgvec = v, rv;
465 NYD_ENTER;
467 rv = _type1(msgvec, FAL0, FAL0, FAL0, FAL0, NULL, NULL);
468 NYD_LEAVE;
469 return rv;
472 FL int
473 c_show(void *v)
475 int *msgvec = v, rv;
476 NYD_ENTER;
478 rv = _type1(msgvec, FAL0, FAL0, FAL0, TRU1, NULL, NULL);
479 NYD_LEAVE;
480 return rv;
483 FL int
484 c_pipe(void *v)
486 char *str = v;
487 int rv;
488 NYD_ENTER;
490 rv = _pipe1(str, 1);
491 NYD_LEAVE;
492 return rv;
495 FL int
496 c_Pipe(void *v)
498 char *str = v;
499 int rv;
500 NYD_ENTER;
502 rv = _pipe1(str, 0);
503 NYD_LEAVE;
504 return rv;
507 FL int
508 c_top(void *v){
509 struct n_ignore *itp;
510 int rv;
511 NYD_ENTER;
513 if(n_ignore_is_any(n_IGNORE_TOP))
514 itp = n_IGNORE_TOP;
515 else{
516 itp = n_ignore_new(TRU1);
517 n_ignore_insert(itp, TRU1, "from", sizeof("from") -1);
518 n_ignore_insert(itp, TRU1, "to", sizeof("to") -1);
519 n_ignore_insert(itp, TRU1, "cc", sizeof("cc") -1);
520 n_ignore_insert(itp, TRU1, "subject", sizeof("subject") -1);
523 rv = !a_cmsg_top(v, itp);
524 NYD_LEAVE;
525 return rv;
528 FL int
529 c_Top(void *v){
530 int rv;
531 NYD_ENTER;
533 rv = !a_cmsg_top(v, n_IGNORE_TYPE);
534 NYD_LEAVE;
535 return rv;
538 FL int
539 c_next(void *v)
541 int list[2], *ip, *ip2, mdot, *msgvec = v, rv = 1;
542 struct message *mp;
543 NYD_ENTER;
545 if (*msgvec != 0) {
546 /* If some messages were supplied, find the first applicable one
547 * following dot using wrap around */
548 mdot = (int)PTR2SIZE(dot - message + 1);
550 /* Find first message in supplied message list which follows dot */
551 for (ip = msgvec; *ip != 0; ++ip) {
552 if ((mb.mb_threaded ? message[*ip - 1].m_threadpos > dot->m_threadpos
553 : *ip > mdot))
554 break;
556 if (*ip == 0)
557 ip = msgvec;
558 ip2 = ip;
559 do {
560 mp = message + *ip2 - 1;
561 if (!(mp->m_flag & MMNDEL)) {
562 setdot(mp);
563 goto jhitit;
565 if (*ip2 != 0)
566 ++ip2;
567 if (*ip2 == 0)
568 ip2 = msgvec;
569 } while (ip2 != ip);
570 printf(_("No messages applicable\n"));
571 goto jleave;
574 /* If this is the first command, select message 1. Note that this must
575 * exist for us to get here at all */
576 if (!(pstate & PS_SAW_COMMAND)) {
577 if (msgCount == 0)
578 goto jateof;
579 goto jhitit;
582 /* Just find the next good message after dot, no wraparound */
583 if (mb.mb_threaded == 0) {
584 for (mp = dot + !!(pstate & PS_DID_PRINT_DOT);
585 PTRCMP(mp, <, message + msgCount); ++mp)
586 if (!(mp->m_flag & MMNORM))
587 break;
588 } else {
589 /* TODO The threading code had some bugs that caused crashes.
590 * TODO The last thing (before the deep look) happens here,
591 * TODO so let's not trust PS_DID_PRINT_DOT but check & hope it fixes */
592 if ((mp = dot) != NULL && (pstate & PS_DID_PRINT_DOT))
593 mp = next_in_thread(mp);
594 while (mp != NULL && (mp->m_flag & MMNORM))
595 mp = next_in_thread(mp);
597 if (mp == NULL || PTRCMP(mp, >=, message + msgCount)) {
598 jateof:
599 printf(_("At EOF\n"));
600 rv = 0;
601 goto jleave;
603 setdot(mp);
605 /* Print dot */
606 jhitit:
607 list[0] = (int)PTR2SIZE(dot - message + 1);
608 list[1] = 0;
609 rv = c_type(list);
610 jleave:
611 NYD_LEAVE;
612 return rv;
615 FL int
616 c_pdot(void *vp)
618 NYD_ENTER;
619 n_UNUSED(vp);
620 printf("%d\n", (int)PTR2SIZE(dot - message + 1));
621 NYD_LEAVE;
622 return 0;
625 FL int
626 c_messize(void *v)
628 int *msgvec = v, *ip, mesg;
629 struct message *mp;
630 NYD_ENTER;
632 for (ip = msgvec; *ip != 0; ++ip) {
633 mesg = *ip;
634 mp = message + mesg - 1;
635 printf("%d: ", mesg);
636 if (mp->m_xlines > 0)
637 printf("%ld", mp->m_xlines);
638 else
639 putchar(' ');
640 printf("/%lu\n", (ul_i)mp->m_xsize);
642 NYD_LEAVE;
643 return 0;
646 FL int
647 c_delete(void *v)
649 int *msgvec = v;
650 NYD_ENTER;
652 delm(msgvec);
653 NYD_LEAVE;
654 return 0;
657 FL int
658 c_deltype(void *v)
660 int list[2], rv = 0, *msgvec = v, lastdot;
661 NYD_ENTER;
663 lastdot = (int)PTR2SIZE(dot - message + 1);
664 if (delm(msgvec) >= 0) {
665 list[0] = (int)PTR2SIZE(dot - message + 1);
666 if (list[0] > lastdot) {
667 touch(dot);
668 list[1] = 0;
669 rv = c_type(list);
670 goto jleave;
672 printf(_("At EOF\n"));
673 } else
674 printf(_("No more messages\n"));
675 jleave:
676 NYD_LEAVE;
677 return rv;
680 FL int
681 c_undelete(void *v)
683 int *msgvec = v, *ip;
684 struct message *mp;
685 NYD_ENTER;
687 for (ip = msgvec; *ip != 0 && UICMP(z, PTR2SIZE(ip - msgvec), <, msgCount);
688 ++ip) {
689 mp = message + *ip - 1;
690 touch(mp);
691 setdot(mp);
692 if (mp->m_flag & (MDELETED | MSAVED))
693 mp->m_flag &= ~(MDELETED | MSAVED);
694 else
695 mp->m_flag &= ~MDELETED;
697 NYD_LEAVE;
698 return 0;
701 FL int
702 c_stouch(void *v)
704 int *msgvec = v, *ip;
705 NYD_ENTER;
707 for (ip = msgvec; *ip != 0; ++ip) {
708 setdot(message + *ip - 1);
709 dot->m_flag |= MTOUCH;
710 dot->m_flag &= ~MPRESERVE;
711 pstate |= PS_DID_PRINT_DOT;
713 NYD_LEAVE;
714 return 0;
717 FL int
718 c_mboxit(void *v)
720 int *msgvec = v, *ip;
721 NYD_ENTER;
723 if (pstate & PS_EDIT) {
724 n_err(_("`mbox' can only be used in a system mailbox\n")); /* TODO */
725 goto jleave;
728 for (ip = msgvec; *ip != 0; ++ip) {
729 setdot(message + *ip - 1);
730 dot->m_flag |= MTOUCH | MBOX;
731 dot->m_flag &= ~MPRESERVE;
732 pstate |= PS_DID_PRINT_DOT;
734 jleave:
735 NYD_LEAVE;
736 return 0;
739 FL int
740 c_preserve(void *v)
742 int *msgvec = v, *ip, mesg, rv = 1;
743 struct message *mp;
744 NYD_ENTER;
746 if (pstate & PS_EDIT) {
747 printf(_("Cannot `preserve' in a system mailbox\n"));
748 goto jleave;
751 for (ip = msgvec; *ip != 0; ++ip) {
752 mesg = *ip;
753 mp = message + mesg - 1;
754 mp->m_flag |= MPRESERVE;
755 mp->m_flag &= ~MBOX;
756 setdot(mp);
757 pstate |= PS_DID_PRINT_DOT;
759 rv = 0;
760 jleave:
761 NYD_LEAVE;
762 return rv;
765 FL int
766 c_unread(void *v)
768 int *msgvec = v, *ip;
769 NYD_ENTER;
771 for (ip = msgvec; *ip != 0; ++ip) {
772 setdot(message + *ip - 1);
773 dot->m_flag &= ~(MREAD | MTOUCH);
774 dot->m_flag |= MSTATUS;
775 pstate |= PS_DID_PRINT_DOT;
777 NYD_LEAVE;
778 return 0;
781 FL int
782 c_seen(void *v)
784 int *msgvec = v, *ip;
785 NYD_ENTER;
787 for (ip = msgvec; *ip != 0; ++ip) {
788 struct message *mp = message + *ip - 1;
789 setdot(mp);
790 touch(mp);
792 NYD_LEAVE;
793 return 0;
796 FL int
797 c_flag(void *v)
799 struct message *m;
800 int *msgvec = v, *ip;
801 NYD_ENTER;
803 for (ip = msgvec; *ip != 0; ++ip) {
804 m = message + *ip - 1;
805 setdot(m);
806 if (!(m->m_flag & (MFLAG | MFLAGGED)))
807 m->m_flag |= MFLAG | MFLAGGED;
809 NYD_LEAVE;
810 return 0;
813 FL int
814 c_unflag(void *v)
816 struct message *m;
817 int *msgvec = v, *ip;
818 NYD_ENTER;
820 for (ip = msgvec; *ip != 0; ++ip) {
821 m = message + *ip - 1;
822 setdot(m);
823 if (m->m_flag & (MFLAG | MFLAGGED)) {
824 m->m_flag &= ~(MFLAG | MFLAGGED);
825 m->m_flag |= MUNFLAG;
828 NYD_LEAVE;
829 return 0;
832 FL int
833 c_answered(void *v)
835 struct message *m;
836 int *msgvec = v, *ip;
837 NYD_ENTER;
839 for (ip = msgvec; *ip != 0; ++ip) {
840 m = message + *ip - 1;
841 setdot(m);
842 if (!(m->m_flag & (MANSWER | MANSWERED)))
843 m->m_flag |= MANSWER | MANSWERED;
845 NYD_LEAVE;
846 return 0;
849 FL int
850 c_unanswered(void *v)
852 struct message *m;
853 int *msgvec = v, *ip;
854 NYD_ENTER;
856 for (ip = msgvec; *ip != 0; ++ip) {
857 m = message + *ip - 1;
858 setdot(m);
859 if (m->m_flag & (MANSWER | MANSWERED)) {
860 m->m_flag &= ~(MANSWER | MANSWERED);
861 m->m_flag |= MUNANSWER;
864 NYD_LEAVE;
865 return 0;
868 FL int
869 c_draft(void *v)
871 struct message *m;
872 int *msgvec = v, *ip;
873 NYD_ENTER;
875 for (ip = msgvec; *ip != 0; ++ip) {
876 m = message + *ip - 1;
877 setdot(m);
878 if (!(m->m_flag & (MDRAFT | MDRAFTED)))
879 m->m_flag |= MDRAFT | MDRAFTED;
881 NYD_LEAVE;
882 return 0;
885 FL int
886 c_undraft(void *v)
888 struct message *m;
889 int *msgvec = v, *ip;
890 NYD_ENTER;
892 for (ip = msgvec; *ip != 0; ++ip) {
893 m = message + *ip - 1;
894 setdot(m);
895 if (m->m_flag & (MDRAFT | MDRAFTED)) {
896 m->m_flag &= ~(MDRAFT | MDRAFTED);
897 m->m_flag |= MUNDRAFT;
900 NYD_LEAVE;
901 return 0;
904 /* s-it-mode */