a_go_evaluate(): fix un/signed comparison
[s-mailx.git] / cmd-message.c
blob1ae54da56355ad138a64e6686a38524413dbd032
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 - 2018 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 bool_t a_cmsg_show_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 a_cmsg_pipe1(void *vp, bool_t 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 bool_t
59 a_cmsg_show_overview(FILE *obuf, struct message *mp, int msg_no){
60 bool_t rv;
61 char const *cpre, *csuf;
62 NYD2_ENTER;
64 cpre = csuf = n_empty;
65 #ifdef HAVE_COLOUR
66 if(n_COLOUR_IS_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 rv = (fprintf(obuf,
81 A_("%s[-- Message %2d -- %lu lines, %lu bytes --]:%s\n"),
82 cpre, msg_no, (ul_i)mp->m_lines, (ul_i)mp->m_size, csuf) > 0);
83 NYD2_LEAVE;
84 return rv;
87 static int
88 _type1(int *msgvec, bool_t doign, bool_t dopage, bool_t dopipe,
89 bool_t donotdecode, char *cmd, ui64_t *tstats)
91 ui64_t mstats[1];
92 int *ip;
93 struct message *mp;
94 char const *cp;
95 enum sendaction action;
96 bool_t volatile formfeed;
97 FILE * volatile obuf;
98 int volatile rv;
99 NYD_ENTER;
101 rv = 1;
102 obuf = n_stdout;
103 formfeed = (dopipe && ok_blook(page));
104 action = ((dopipe && ok_blook(piperaw))
105 ? SEND_MBOX : donotdecode
106 ? SEND_SHOW : doign
107 ? SEND_TODISP : SEND_TODISP_ALL);
109 if (dopipe) {
110 if ((obuf = Popen(cmd, "w", ok_vlook(SHELL), NULL, 1)) == NULL) {
111 n_perr(cmd, 0);
112 obuf = n_stdout;
114 } else if ((n_psonce & n_PSO_TTYOUT) && (dopage ||
115 ((n_psonce & n_PSO_INTERACTIVE) && (cp = ok_vlook(crt)) != NULL))) {
116 uiz_t nlines, lib;
118 nlines = 0;
120 if (!dopage) {
121 for (ip = msgvec; *ip && PTRCMP(ip - msgvec, <, msgCount); ++ip) {
122 mp = message + *ip - 1;
123 if (!(mp->m_content_info & CI_HAVE_BODY))
124 if (get_body(mp) != OKAY)
125 goto jleave;
126 nlines += mp->m_lines + 1; /* TODO BUT wire format, not display! */
130 /* >= not <: we return to the prompt */
131 if(dopage || nlines >= (*cp != '\0'
132 ? (n_idec_uiz_cp(&lib, cp, 0, NULL), lib)
133 : (uiz_t)n_realscreenheight)){
134 if((obuf = n_pager_open()) == NULL)
135 obuf = n_stdout;
137 n_COLOUR(
138 if(action == SEND_TODISP || action == SEND_TODISP_ALL)
139 n_colour_env_create(n_COLOUR_CTX_VIEW, obuf, obuf != n_stdout);
142 n_COLOUR(
143 else if(action == SEND_TODISP || action == SEND_TODISP_ALL)
144 n_colour_env_create(n_COLOUR_CTX_VIEW, n_stdout, FAL0);
147 rv = 0;
148 srelax_hold();
149 for (ip = msgvec; *ip && PTRCMP(ip - msgvec, <, msgCount); ++ip) {
150 mp = message + *ip - 1;
151 touch(mp);
152 setdot(mp);
153 n_pstate |= n_PS_DID_PRINT_DOT;
154 uncollapse1(mp, 1);
155 if(!dopipe && ip != msgvec && fprintf(obuf, "\n") < 0){
156 rv = 1;
157 break;
159 if(action != SEND_MBOX && !a_cmsg_show_overview(obuf, mp, *ip)){
160 rv = 1;
161 break;
163 if(sendmp(mp, obuf, (doign ? n_IGNORE_TYPE : NULL), NULL, action, mstats
164 ) < 0){
165 rv = 1;
166 break;
168 srelax();
169 if(formfeed){ /* TODO a nicer way to separate piped messages! */
170 if(putc('\f', obuf) == EOF){
171 rv = 1;
172 break;
175 if (tstats != NULL)
176 tstats[0] += mstats[0];
178 srelax_rele();
179 n_COLOUR(
180 if(!dopipe && (action == SEND_TODISP || action == SEND_TODISP_ALL))
181 n_colour_env_gut();
183 jleave:
184 if (obuf != n_stdout)
185 n_pager_close(obuf);
186 NYD_LEAVE;
187 return rv;
190 static int
191 a_cmsg_pipe1(void *vp, bool_t doign){
192 ui64_t stats[1];
193 char const *cmd, *cmdq;
194 int *msgvec, rv;
195 struct n_cmd_arg *cap;
196 struct n_cmd_arg_ctx *cacp;
197 NYD2_ENTER;
199 cacp = vp;
200 cap = cacp->cac_arg;
201 msgvec = cap->ca_arg.ca_msglist;
202 cap = cap->ca_next;
203 rv = 1;
205 if((cmd = cap->ca_arg.ca_str.s)[0] == '\0' &&
206 ((cmd = ok_vlook(cmd)) == NULL || *cmd == '\0')){
207 n_err(_("%s: variable *cmd* not set\n"), cacp->cac_desc->cad_name);
208 goto jleave;
211 cmdq = n_shexp_quote_cp(cmd, FAL0);
212 fprintf(n_stdout, _("Pipe to: %s\n"), cmdq);
213 stats[0] = 0;
214 if((rv = _type1(msgvec, doign, FAL0, TRU1, FAL0, n_UNCONST(cmd), stats)
215 ) == 0)
216 fprintf(n_stdout, "%s %" PRIu64 " bytes\n", cmdq, stats[0]);
217 jleave:
218 NYD2_LEAVE;
219 return rv;
222 static int
223 a_cmsg_top(void *vp, struct n_ignore const *itp){
224 struct n_string s;
225 int *msgvec, *ip;
226 enum{a_NONE, a_SQUEEZE = 1u<<0,
227 a_EMPTY = 1u<<8, a_STOP = 1u<<9, a_WORKMASK = 0xFF00u} f;
228 size_t tmax, plines;
229 FILE *iobuf, *pbuf;
230 NYD2_ENTER;
232 if((iobuf = Ftmp(NULL, "topio", OF_RDWR | OF_UNLINK | OF_REGISTER)) == NULL){
233 n_perr(_("`top': I/O temporary file"), 0);
234 vp = NULL;
235 goto jleave;
237 if((pbuf = Ftmp(NULL, "toppag", OF_RDWR | OF_UNLINK | OF_REGISTER)) == NULL){
238 n_perr(_("`top': temporary pager file"), 0);
239 vp = NULL;
240 goto jleave1;
243 /* TODO In v15 we should query the m_message object, and directly send only
244 * TODO those parts, optionally over empty-line-squeeze and quote-strip
245 * TODO filters, in which we are interested in: only text content!
246 * TODO And: with *topsqueeze*, header/content separating empty line.. */
247 n_pstate &= ~n_PS_MSGLIST_DIRECT; /* TODO NO ATTACHMENTS */
248 plines = 0;
250 n_COLOUR( n_colour_env_create(n_COLOUR_CTX_VIEW, iobuf, FAL0); )
251 n_string_creat_auto(&s);
252 /* C99 */{
253 siz_t l;
255 if((n_idec_siz_cp(&l, ok_vlook(toplines), 0, NULL
256 ) & (n_IDEC_STATE_EMASK | n_IDEC_STATE_CONSUMED)
257 ) != n_IDEC_STATE_CONSUMED)
258 l = 0;
259 if(l <= 0){
260 tmax = n_screensize();
261 if(l < 0){
262 l = n_ABS(l);
263 tmax >>= l;
265 }else
266 tmax = (size_t)l;
268 f = ok_blook(topsqueeze) ? a_SQUEEZE : a_NONE;
270 for(ip = msgvec = vp; *ip != 0; ++ip){
271 struct message *mp;
273 mp = &message[*ip - 1];
274 touch(mp);
275 setdot(mp);
276 n_pstate |= n_PS_DID_PRINT_DOT;
277 uncollapse1(mp, 1);
279 rewind(iobuf);
280 if(ftruncate(fileno(iobuf), 0)){
281 n_perr(_("`top': ftruncate(2)"), 0);
282 vp = NULL;
283 break;
286 if(!a_cmsg_show_overview(iobuf, mp, *ip) ||
287 sendmp(mp, iobuf, itp, NULL, SEND_TODISP_ALL, NULL) < 0){
288 n_err(_("`top': failed to prepare message %d\n"), *ip);
289 vp = NULL;
290 break;
292 fflush_rewind(iobuf);
294 /* TODO Skip over the _msg_overview line -- this is a hack to make
295 * TODO colours work: colour contexts should be objects */
296 for(;;){
297 int c;
299 if((c = getc(iobuf)) == EOF || putc(c, pbuf) == EOF){
300 vp = NULL;
301 break;
302 }else if(c == '\n')
303 break;
305 if(vp == NULL)
306 break;
307 ++plines;
309 /* C99 */{
310 size_t l;
312 n_string_trunc(&s, 0);
313 for(l = 0, f &= ~a_WORKMASK; !(f & a_STOP);){
314 int c;
316 if((c = getc(iobuf)) == EOF){
317 f |= a_STOP;
318 c = '\n';
321 if(c != '\n')
322 n_string_push_c(&s, c);
323 else if((f & a_SQUEEZE) && s.s_len == 0){
324 if(!(f & a_STOP) && ((f & a_EMPTY) || tmax - 1 <= l))
325 continue;
326 if(putc('\n', pbuf) == EOF){
327 vp = NULL;
328 break;
330 f |= a_EMPTY;
331 ++l;
332 }else{
333 char const *cp, *xcp;
335 cp = n_string_cp_const(&s);
336 /* TODO Brute simple skip part overviews; see above.. */
337 if(!(f & a_SQUEEZE))
338 c = '\1';
339 else if(s.s_len > 8 &&
340 (xcp = strstr(cp, "[-- ")) != NULL &&
341 strstr(&xcp[1], " --]") != NULL)
342 c = '\0';
343 else{
344 char const *qcp;
346 for(qcp = ok_vlook(quote_chars); (c = *cp) != '\0'; ++cp){
347 if(!asciichar(c))
348 break;
349 if(!blankspacechar(c)){
350 if(strchr(qcp, c) == NULL)
351 break;
352 c = '\0';
353 break;
358 if(c != '\0'){
359 if(fputs(n_string_cp_const(&s), pbuf) == EOF ||
360 putc('\n', pbuf) == EOF){
361 vp = NULL;
362 break;
364 if(++l >= tmax)
365 break;
366 f &= ~a_EMPTY;
367 }else
368 f |= a_EMPTY;
369 n_string_trunc(&s, 0);
372 if(vp == NULL)
373 break;
374 if(l > 0)
375 plines += l;
376 else{
377 if(!(f & a_EMPTY) && putc('\n', pbuf) == EOF){
378 vp = NULL;
379 break;
381 ++plines;
386 n_string_gut(&s);
387 n_COLOUR( n_colour_env_gut(); )
389 fflush(pbuf);
390 page_or_print(pbuf, plines);
392 Fclose(pbuf);
393 jleave1:
394 Fclose(iobuf);
395 jleave:
396 NYD2_LEAVE;
397 return (vp != NULL);
400 static int
401 delm(int *msgvec)
403 struct message *mp;
404 int rv = -1, *ip, last;
405 NYD_ENTER;
407 last = 0;
408 for (ip = msgvec; *ip != 0; ++ip) {
409 mp = message + *ip - 1;
410 touch(mp);
411 mp->m_flag |= MDELETED | MTOUCH;
412 mp->m_flag &= ~(MPRESERVE | MSAVED | MBOX);
413 last = *ip;
415 if (last != 0) {
416 setdot(message + last - 1);
417 last = first(0, MDELETED);
418 if (last != 0) {
419 setdot(message + last - 1);
420 rv = 0;
421 } else {
422 setdot(message);
425 NYD_LEAVE;
426 return rv;
429 FL int
430 c_more(void *v)
432 int *msgvec = v, rv;
433 NYD_ENTER;
435 rv = _type1(msgvec, TRU1, TRU1, FAL0, FAL0, NULL, NULL);
436 NYD_LEAVE;
437 return rv;
440 FL int
441 c_More(void *v)
443 int *msgvec = v, rv;
444 NYD_ENTER;
446 rv = _type1(msgvec, FAL0, TRU1, FAL0, FAL0, NULL, NULL);
447 NYD_LEAVE;
448 return rv;
451 FL int
452 c_type(void *v)
454 int *msgvec = v, rv;
455 NYD_ENTER;
457 rv = _type1(msgvec, TRU1, FAL0, FAL0, FAL0, NULL, NULL);
458 NYD_LEAVE;
459 return rv;
462 FL int
463 c_Type(void *v)
465 int *msgvec = v, rv;
466 NYD_ENTER;
468 rv = _type1(msgvec, FAL0, FAL0, FAL0, FAL0, NULL, NULL);
469 NYD_LEAVE;
470 return rv;
473 FL int
474 c_show(void *v)
476 int *msgvec = v, rv;
477 NYD_ENTER;
479 rv = _type1(msgvec, FAL0, FAL0, FAL0, TRU1, NULL, NULL);
480 NYD_LEAVE;
481 return rv;
484 FL int
485 c_mimeview(void *vp){ /* TODO direct addressable parts, multiple such */
486 struct message *mp;
487 int rv, *msgvec;
488 NYD_ENTER;
490 if((msgvec = vp)[1] != 0){
491 n_err(_("`mimeview': can yet only take one message, sorry!\n"));/* TODO */
492 n_pstate_err_no = n_ERR_NOTSUP;
493 rv = 1;
494 goto jleave;
497 mp = &message[*msgvec - 1];
498 touch(mp);
499 setdot(mp);
500 n_pstate |= n_PS_DID_PRINT_DOT;
501 uncollapse1(mp, 1);
503 n_COLOUR(
504 n_colour_env_create(n_COLOUR_CTX_VIEW, n_stdout, FAL0);
507 if(!a_cmsg_show_overview(n_stdout, mp, *msgvec))
508 n_pstate_err_no = n_ERR_IO;
509 else if(sendmp(mp, n_stdout, n_IGNORE_TYPE, NULL, SEND_TODISP_PARTS,
510 NULL) < 0)
511 n_pstate_err_no = n_ERR_IO;
512 else
513 n_pstate_err_no = n_ERR_NONE;
515 n_COLOUR(
516 n_colour_env_gut();
519 rv = (n_pstate_err_no != n_ERR_NONE);
520 jleave:
521 NYD_LEAVE;
522 return rv;
525 FL int
526 c_pipe(void *vp){
527 int rv;
528 NYD_ENTER;
530 rv = a_cmsg_pipe1(vp, TRU1);
531 NYD_LEAVE;
532 return rv;
535 FL int
536 c_Pipe(void *vp){
537 int rv;
538 NYD_ENTER;
540 rv = a_cmsg_pipe1(vp, FAL0);
541 NYD_LEAVE;
542 return rv;
545 FL int
546 c_top(void *v){
547 struct n_ignore *itp;
548 int rv;
549 NYD_ENTER;
551 if(n_ignore_is_any(n_IGNORE_TOP))
552 itp = n_IGNORE_TOP;
553 else{
554 itp = n_ignore_new(TRU1);
555 n_ignore_insert(itp, TRU1, "from", sizeof("from") -1);
556 n_ignore_insert(itp, TRU1, "to", sizeof("to") -1);
557 n_ignore_insert(itp, TRU1, "cc", sizeof("cc") -1);
558 n_ignore_insert(itp, TRU1, "subject", sizeof("subject") -1);
561 rv = !a_cmsg_top(v, itp);
562 NYD_LEAVE;
563 return rv;
566 FL int
567 c_Top(void *v){
568 int rv;
569 NYD_ENTER;
571 rv = !a_cmsg_top(v, n_IGNORE_TYPE);
572 NYD_LEAVE;
573 return rv;
576 FL int
577 c_next(void *v)
579 int list[2], *ip, *ip2, mdot, *msgvec = v, rv = 1;
580 struct message *mp;
581 NYD_ENTER;
583 if (*msgvec != 0) {
584 /* If some messages were supplied, find the first applicable one
585 * following dot using wrap around */
586 mdot = (int)PTR2SIZE(dot - message + 1);
588 /* Find first message in supplied message list which follows dot */
589 for (ip = msgvec; *ip != 0; ++ip) {
590 if ((mb.mb_threaded ? message[*ip - 1].m_threadpos > dot->m_threadpos
591 : *ip > mdot))
592 break;
594 if (*ip == 0)
595 ip = msgvec;
596 ip2 = ip;
597 do {
598 mp = message + *ip2 - 1;
599 if (!(mp->m_flag & MMNDEL)) {
600 setdot(mp);
601 goto jhitit;
603 if (*ip2 != 0)
604 ++ip2;
605 if (*ip2 == 0)
606 ip2 = msgvec;
607 } while (ip2 != ip);
608 fprintf(n_stdout, _("No messages applicable\n"));
609 goto jleave;
612 /* If this is the first command, select message 1. Note that this must
613 * exist for us to get here at all */
614 if (!(n_pstate & n_PS_SAW_COMMAND)) {
615 if (msgCount == 0)
616 goto jateof;
617 goto jhitit;
620 /* Just find the next good message after dot, no wraparound */
621 if (mb.mb_threaded == 0) {
622 for (mp = dot + !!(n_pstate & n_PS_DID_PRINT_DOT);
623 PTRCMP(mp, <, message + msgCount); ++mp)
624 if (!(mp->m_flag & MMNORM))
625 break;
626 } else {
627 /* TODO The threading code had some bugs that caused crashes.
628 * TODO The last thing (before the deep look) happens here,
629 * TODO so let's not trust n_PS_DID_PRINT_DOT but check & hope it fixes */
630 if ((mp = dot) != NULL && (n_pstate & n_PS_DID_PRINT_DOT))
631 mp = next_in_thread(mp);
632 while (mp != NULL && (mp->m_flag & MMNORM))
633 mp = next_in_thread(mp);
635 if (mp == NULL || PTRCMP(mp, >=, message + msgCount)) {
636 jateof:
637 fprintf(n_stdout, _("At EOF\n"));
638 rv = 0;
639 goto jleave;
641 setdot(mp);
643 /* Print dot */
644 jhitit:
645 list[0] = (int)PTR2SIZE(dot - message + 1);
646 list[1] = 0;
647 rv = c_type(list);
648 jleave:
649 NYD_LEAVE;
650 return rv;
653 FL int
654 c_pdot(void *vp)
656 NYD_ENTER;
657 n_UNUSED(vp);
658 fprintf(n_stdout, "%d\n",
659 (msgCount == 0) ? 0 : (int)PTR2SIZE(dot - message + 1));
660 NYD_LEAVE;
661 return 0;
664 FL int
665 c_messize(void *v)
667 int *msgvec = v, *ip, mesg;
668 struct message *mp;
669 NYD_ENTER;
671 for (ip = msgvec; *ip != 0; ++ip) {
672 mesg = *ip;
673 mp = message + mesg - 1;
674 fprintf(n_stdout, "%d: ", mesg);
675 if (mp->m_xlines > 0)
676 fprintf(n_stdout, "%ld", mp->m_xlines);
677 else
678 putc(' ', n_stdout);
679 fprintf(n_stdout, "/%lu\n", (ul_i)mp->m_xsize);
681 NYD_LEAVE;
682 return 0;
685 FL int
686 c_delete(void *v)
688 int *msgvec = v;
689 NYD_ENTER;
691 delm(msgvec);
692 NYD_LEAVE;
693 return 0;
696 FL int
697 c_deltype(void *v)
699 int list[2], rv = 0, *msgvec = v, lastdot;
700 NYD_ENTER;
702 lastdot = (int)PTR2SIZE(dot - message + 1);
703 if (delm(msgvec) >= 0) {
704 list[0] = (int)PTR2SIZE(dot - message + 1);
705 if (list[0] > lastdot) {
706 touch(dot);
707 list[1] = 0;
708 rv = c_type(list);
709 goto jleave;
711 fprintf(n_stdout, _("At EOF\n"));
712 } else
713 fprintf(n_stdout, _("No more messages\n"));
714 jleave:
715 NYD_LEAVE;
716 return rv;
719 FL int
720 c_undelete(void *v)
722 int *msgvec = v, *ip;
723 struct message *mp;
724 NYD_ENTER;
726 for (ip = msgvec; *ip != 0; ++ip) {
727 mp = &message[*ip - 1];
728 touch(mp);
729 setdot(mp);
730 if (mp->m_flag & (MDELETED | MSAVED))
731 mp->m_flag &= ~(MDELETED | MSAVED);
732 else
733 mp->m_flag &= ~MDELETED;
734 #ifdef HAVE_IMAP
735 if (mb.mb_type == MB_IMAP || mb.mb_type == MB_CACHE)
736 imap_undelete(mp, *ip);
737 #endif
739 NYD_LEAVE;
740 return 0;
743 FL int
744 c_stouch(void *v)
746 int *msgvec = v, *ip;
747 NYD_ENTER;
749 for (ip = msgvec; *ip != 0; ++ip) {
750 setdot(message + *ip - 1);
751 dot->m_flag |= MTOUCH;
752 dot->m_flag &= ~MPRESERVE;
753 n_pstate |= n_PS_DID_PRINT_DOT;
755 NYD_LEAVE;
756 return 0;
759 FL int
760 c_mboxit(void *v)
762 int *msgvec = v, *ip;
763 NYD_ENTER;
765 if (n_pstate & n_PS_EDIT) {
766 n_err(_("`mbox' can only be used in a system mailbox\n")); /* TODO */
767 goto jleave;
770 for (ip = msgvec; *ip != 0; ++ip) {
771 setdot(message + *ip - 1);
772 dot->m_flag |= MTOUCH | MBOX;
773 dot->m_flag &= ~MPRESERVE;
774 n_pstate |= n_PS_DID_PRINT_DOT;
776 jleave:
777 NYD_LEAVE;
778 return 0;
781 FL int
782 c_preserve(void *v)
784 int *msgvec = v, *ip, mesg, rv = 1;
785 struct message *mp;
786 NYD_ENTER;
788 if (n_pstate & n_PS_EDIT) {
789 fprintf(n_stdout, _("Cannot `preserve' in a system mailbox\n"));
790 goto jleave;
793 for (ip = msgvec; *ip != 0; ++ip) {
794 mesg = *ip;
795 mp = message + mesg - 1;
796 mp->m_flag |= MPRESERVE;
797 mp->m_flag &= ~MBOX;
798 setdot(mp);
799 n_pstate |= n_PS_DID_PRINT_DOT;
801 rv = 0;
802 jleave:
803 NYD_LEAVE;
804 return rv;
807 FL int
808 c_unread(void *v)
810 struct message *mp;
811 int *msgvec = v, *ip;
812 NYD_ENTER;
814 for (ip = msgvec; *ip != 0; ++ip) {
815 mp = &message[*ip - 1];
816 setdot(mp);
817 dot->m_flag &= ~(MREAD | MTOUCH);
818 dot->m_flag |= MSTATUS;
819 #ifdef HAVE_IMAP
820 if (mb.mb_type == MB_IMAP || mb.mb_type == MB_CACHE)
821 imap_unread(mp, *ip); /* TODO return? */
822 #endif
823 n_pstate |= n_PS_DID_PRINT_DOT;
825 NYD_LEAVE;
826 return 0;
829 FL int
830 c_seen(void *v)
832 int *msgvec = v, *ip;
833 NYD_ENTER;
835 for (ip = msgvec; *ip != 0; ++ip) {
836 struct message *mp = message + *ip - 1;
837 setdot(mp);
838 touch(mp);
840 NYD_LEAVE;
841 return 0;
844 FL int
845 c_flag(void *v)
847 struct message *m;
848 int *msgvec = v, *ip;
849 NYD_ENTER;
851 for (ip = msgvec; *ip != 0; ++ip) {
852 m = message + *ip - 1;
853 setdot(m);
854 if (!(m->m_flag & (MFLAG | MFLAGGED)))
855 m->m_flag |= MFLAG | MFLAGGED;
857 NYD_LEAVE;
858 return 0;
861 FL int
862 c_unflag(void *v)
864 struct message *m;
865 int *msgvec = v, *ip;
866 NYD_ENTER;
868 for (ip = msgvec; *ip != 0; ++ip) {
869 m = message + *ip - 1;
870 setdot(m);
871 if (m->m_flag & (MFLAG | MFLAGGED)) {
872 m->m_flag &= ~(MFLAG | MFLAGGED);
873 m->m_flag |= MUNFLAG;
876 NYD_LEAVE;
877 return 0;
880 FL int
881 c_answered(void *v)
883 struct message *m;
884 int *msgvec = v, *ip;
885 NYD_ENTER;
887 for (ip = msgvec; *ip != 0; ++ip) {
888 m = message + *ip - 1;
889 setdot(m);
890 if (!(m->m_flag & (MANSWER | MANSWERED)))
891 m->m_flag |= MANSWER | MANSWERED;
893 NYD_LEAVE;
894 return 0;
897 FL int
898 c_unanswered(void *v)
900 struct message *m;
901 int *msgvec = v, *ip;
902 NYD_ENTER;
904 for (ip = msgvec; *ip != 0; ++ip) {
905 m = message + *ip - 1;
906 setdot(m);
907 if (m->m_flag & (MANSWER | MANSWERED)) {
908 m->m_flag &= ~(MANSWER | MANSWERED);
909 m->m_flag |= MUNANSWER;
912 NYD_LEAVE;
913 return 0;
916 FL int
917 c_draft(void *v)
919 struct message *m;
920 int *msgvec = v, *ip;
921 NYD_ENTER;
923 for (ip = msgvec; *ip != 0; ++ip) {
924 m = message + *ip - 1;
925 setdot(m);
926 if (!(m->m_flag & (MDRAFT | MDRAFTED)))
927 m->m_flag |= MDRAFT | MDRAFTED;
929 NYD_LEAVE;
930 return 0;
933 FL int
934 c_undraft(void *v)
936 struct message *m;
937 int *msgvec = v, *ip;
938 NYD_ENTER;
940 for (ip = msgvec; *ip != 0; ++ip) {
941 m = message + *ip - 1;
942 setdot(m);
943 if (m->m_flag & (MDRAFT | MDRAFTED)) {
944 m->m_flag &= ~(MDRAFT | MDRAFTED);
945 m->m_flag |= MUNDRAFT;
948 NYD_LEAVE;
949 return 0;
952 /* s-it-mode */