Add n_iconv_normalize_name() and strip //SUFFIXes plusplus generically
[s-mailx.git] / cmd-message.c
blobc610f4ec3b6aac8b31eebf99a96c6b8dc21983a7
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 _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 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, _("%s[-- Message %2d -- %lu lines, %lu bytes --]:%s\n"),
81 cpre, msg_no, (ul_i)mp->m_lines, (ul_i)mp->m_size, csuf) > 0);
82 NYD2_LEAVE;
83 return rv;
86 static int
87 _type1(int *msgvec, bool_t doign, bool_t dopage, bool_t dopipe,
88 bool_t donotdecode, char *cmd, ui64_t *tstats)
90 ui64_t mstats[1];
91 int *ip;
92 struct message *mp;
93 char const *cp;
94 enum sendaction action;
95 bool_t volatile formfeed;
96 FILE * volatile obuf;
97 int volatile rv;
98 NYD_ENTER;
100 rv = 1;
101 obuf = n_stdout;
102 formfeed = (dopipe && ok_blook(page));
103 action = ((dopipe && ok_blook(piperaw))
104 ? SEND_MBOX : donotdecode
105 ? SEND_SHOW : doign
106 ? SEND_TODISP : SEND_TODISP_ALL);
108 if (dopipe) {
109 if ((obuf = Popen(cmd, "w", ok_vlook(SHELL), NULL, 1)) == NULL) {
110 n_perr(cmd, 0);
111 obuf = n_stdout;
113 } else if ((n_psonce & n_PSO_TTYOUT) && (dopage ||
114 ((n_psonce & n_PSO_INTERACTIVE) && (cp = ok_vlook(crt)) != NULL))) {
115 uiz_t nlines, lib;
117 nlines = 0;
119 if (!dopage) {
120 for (ip = msgvec; *ip && PTRCMP(ip - msgvec, <, msgCount); ++ip) {
121 mp = message + *ip - 1;
122 if (!(mp->m_content_info & CI_HAVE_BODY))
123 if (get_body(mp) != OKAY)
124 goto jleave;
125 nlines += mp->m_lines + 1; /* TODO BUT wire format, not display! */
129 /* >= not <: we return to the prompt */
130 if(dopage || nlines >= (*cp != '\0'
131 ? (n_idec_uiz_cp(&lib, cp, 0, NULL), lib)
132 : (uiz_t)n_realscreenheight)){
133 if((obuf = n_pager_open()) == NULL)
134 obuf = n_stdout;
136 n_COLOUR(
137 if(action == SEND_TODISP || action == SEND_TODISP_ALL)
138 n_colour_env_create(n_COLOUR_CTX_VIEW, obuf, obuf != n_stdout);
141 n_COLOUR(
142 else if(action == SEND_TODISP || action == SEND_TODISP_ALL)
143 n_colour_env_create(n_COLOUR_CTX_VIEW, n_stdout, FAL0);
146 rv = 0;
147 srelax_hold();
148 for (ip = msgvec; *ip && PTRCMP(ip - msgvec, <, msgCount); ++ip) {
149 mp = message + *ip - 1;
150 touch(mp);
151 setdot(mp);
152 n_pstate |= n_PS_DID_PRINT_DOT;
153 uncollapse1(mp, 1);
154 if(!dopipe && ip != msgvec && fprintf(obuf, "\n") < 0){
155 rv = 1;
156 break;
158 if(action != SEND_MBOX && !a_cmsg_show_overview(obuf, mp, *ip)){
159 rv = 1;
160 break;
162 if(sendmp(mp, obuf, (doign ? n_IGNORE_TYPE : NULL), NULL, action, mstats
163 ) < 0){
164 rv = 1;
165 break;
167 srelax();
168 if(formfeed){ /* TODO a nicer way to separate piped messages! */
169 if(putc('\f', obuf) == EOF){
170 rv = 1;
171 break;
174 if (tstats != NULL)
175 tstats[0] += mstats[0];
177 srelax_rele();
178 n_COLOUR(
179 if(!dopipe && (action == SEND_TODISP || action == SEND_TODISP_ALL))
180 n_colour_env_gut();
182 jleave:
183 if (obuf != n_stdout)
184 n_pager_close(obuf);
185 NYD_LEAVE;
186 return rv;
189 static int
190 _pipe1(char *str, int doign)
192 ui64_t stats[1];
193 char const *cmd, *cmdq;
194 int *msgvec, rv = 1;
195 bool_t needs_list;
196 NYD_ENTER;
198 if ((cmd = laststring(str, &needs_list, TRU1)) == NULL) {
199 cmd = ok_vlook(cmd);
200 if (cmd == NULL || *cmd == '\0') {
201 n_err(_("Variable *cmd* not set\n"));
202 goto jleave;
206 msgvec = salloc((msgCount + 2) * sizeof *msgvec);
208 if (!needs_list) {
209 *msgvec = first(0, MMNORM);
210 if (*msgvec == 0) {
211 if (n_pstate & (n_PS_ROBOT | n_PS_HOOK_MASK)) {
212 rv = 0;
213 goto jleave;
215 fputs(_("No messages to pipe.\n"), n_stdout);
216 goto jleave;
218 msgvec[1] = 0;
219 } else if (getmsglist(str, msgvec, 0) < 0)
220 goto jleave;
221 if (*msgvec == 0) {
222 if (n_pstate & (n_PS_ROBOT | n_PS_HOOK_MASK)) {
223 rv = 0;
224 goto jleave;
226 fprintf(n_stdout, "No applicable messages.\n");
227 goto jleave;
230 cmdq = n_shexp_quote_cp(cmd, FAL0);
231 fprintf(n_stdout, _("Pipe to: %s\n"), cmdq);
232 stats[0] = 0;
233 if ((rv = _type1(msgvec, doign, FAL0, TRU1, FAL0, n_UNCONST(cmd), stats)
234 ) == 0)
235 fprintf(n_stdout, "%s %" PRIu64 " bytes\n", cmdq, stats[0]);
236 jleave:
237 NYD_LEAVE;
238 return rv;
241 static int
242 a_cmsg_top(void *vp, struct n_ignore const *itp){
243 struct n_string s;
244 int *msgvec, *ip;
245 enum{a_NONE, a_SQUEEZE = 1u<<0,
246 a_EMPTY = 1u<<8, a_STOP = 1u<<9, a_WORKMASK = 0xFF00u} f;
247 size_t tmax, plines;
248 FILE *iobuf, *pbuf;
249 NYD2_ENTER;
251 if((iobuf = Ftmp(NULL, "topio", OF_RDWR | OF_UNLINK | OF_REGISTER)) == NULL){
252 n_perr(_("`top': I/O temporary file"), 0);
253 vp = NULL;
254 goto jleave;
256 if((pbuf = Ftmp(NULL, "toppag", OF_RDWR | OF_UNLINK | OF_REGISTER)) == NULL){
257 n_perr(_("`top': temporary pager file"), 0);
258 vp = NULL;
259 goto jleave1;
262 /* TODO In v15 we should query the m_message object, and directly send only
263 * TODO those parts, optionally over empty-line-squeeze and quote-strip
264 * TODO filters, in which we are interested in: only text content!
265 * TODO And: with *topsqueeze*, header/content separating empty line.. */
266 n_pstate &= ~n_PS_MSGLIST_DIRECT; /* TODO NO ATTACHMENTS */
267 plines = 0;
269 n_COLOUR( n_colour_env_create(n_COLOUR_CTX_VIEW, iobuf, FAL0); )
270 n_string_creat_auto(&s);
271 /* C99 */{
272 siz_t l;
274 if((n_idec_siz_cp(&l, ok_vlook(toplines), 0, NULL
275 ) & (n_IDEC_STATE_EMASK | n_IDEC_STATE_CONSUMED)
276 ) != n_IDEC_STATE_CONSUMED)
277 l = 0;
278 if(l <= 0){
279 tmax = n_screensize();
280 if(l < 0){
281 l = n_ABS(l);
282 tmax >>= l;
284 }else
285 tmax = (size_t)l;
287 f = ok_blook(topsqueeze) ? a_SQUEEZE : a_NONE;
289 for(ip = msgvec = vp;
290 *ip != 0 && UICMP(z, PTR2SIZE(ip - msgvec), <, msgCount); ++ip){
291 struct message *mp;
293 mp = &message[*ip - 1];
294 touch(mp);
295 setdot(mp);
296 n_pstate |= n_PS_DID_PRINT_DOT;
297 uncollapse1(mp, 1);
299 rewind(iobuf);
300 if(ftruncate(fileno(iobuf), 0)){
301 n_perr(_("`top': ftruncate(2)"), 0);
302 vp = NULL;
303 break;
306 if(!a_cmsg_show_overview(iobuf, mp, *ip) ||
307 sendmp(mp, iobuf, itp, NULL, SEND_TODISP_ALL, NULL) < 0){
308 n_err(_("`top': failed to prepare message %d\n"), *ip);
309 vp = NULL;
310 break;
312 fflush_rewind(iobuf);
314 /* TODO Skip over the _msg_overview line -- this is a hack to make
315 * TODO colours work: colour contexts should be objects */
316 for(;;){
317 int c;
319 if((c = getc(iobuf)) == EOF || putc(c, pbuf) == EOF){
320 vp = NULL;
321 break;
322 }else if(c == '\n')
323 break;
325 if(vp == NULL)
326 break;
327 ++plines;
329 /* C99 */{
330 size_t l;
332 n_string_trunc(&s, 0);
333 for(l = 0, f &= ~a_WORKMASK; !(f & a_STOP);){
334 int c;
336 if((c = getc(iobuf)) == EOF){
337 f |= a_STOP;
338 c = '\n';
341 if(c != '\n')
342 n_string_push_c(&s, c);
343 else if((f & a_SQUEEZE) && s.s_len == 0){
344 if(!(f & a_STOP) && ((f & a_EMPTY) || tmax - 1 <= l))
345 continue;
346 if(putc('\n', pbuf) == EOF){
347 vp = NULL;
348 break;
350 f |= a_EMPTY;
351 ++l;
352 }else{
353 char const *cp, *xcp;
355 cp = n_string_cp_const(&s);
356 /* TODO Brute simple skip part overviews; see above.. */
357 if(!(f & a_SQUEEZE))
358 c = '\1';
359 else if(s.s_len > 8 &&
360 (xcp = strstr(cp, "[-- ")) != NULL &&
361 strstr(&xcp[1], " --]") != NULL)
362 c = '\0';
363 else{
364 char const *qcp;
366 for(qcp = ok_vlook(quote_chars); (c = *cp) != '\0'; ++cp){
367 if(!asciichar(c))
368 break;
369 if(!blankspacechar(c)){
370 if(strchr(qcp, c) == NULL)
371 break;
372 c = '\0';
373 break;
378 if(c != '\0'){
379 if(fputs(n_string_cp_const(&s), pbuf) == EOF ||
380 putc('\n', pbuf) == EOF){
381 vp = NULL;
382 break;
384 if(++l >= tmax)
385 break;
386 f &= ~a_EMPTY;
387 }else
388 f |= a_EMPTY;
389 n_string_trunc(&s, 0);
392 if(vp == NULL)
393 break;
394 if(l > 0)
395 plines += l;
396 else{
397 if(!(f & a_EMPTY) && putc('\n', pbuf) == EOF){
398 vp = NULL;
399 break;
401 ++plines;
406 n_string_gut(&s);
407 n_COLOUR( n_colour_env_gut(); )
409 fflush(pbuf);
410 page_or_print(pbuf, plines);
412 Fclose(pbuf);
413 jleave1:
414 Fclose(iobuf);
415 jleave:
416 NYD2_LEAVE;
417 return (vp != NULL);
420 static int
421 delm(int *msgvec)
423 struct message *mp;
424 int rv = -1, *ip, last;
425 NYD_ENTER;
427 last = 0;
428 for (ip = msgvec; *ip != 0; ++ip) {
429 mp = message + *ip - 1;
430 touch(mp);
431 mp->m_flag |= MDELETED | MTOUCH;
432 mp->m_flag &= ~(MPRESERVE | MSAVED | MBOX);
433 last = *ip;
435 if (last != 0) {
436 setdot(message + last - 1);
437 last = first(0, MDELETED);
438 if (last != 0) {
439 setdot(message + last - 1);
440 rv = 0;
441 } else {
442 setdot(message);
445 NYD_LEAVE;
446 return rv;
449 FL int
450 c_more(void *v)
452 int *msgvec = v, rv;
453 NYD_ENTER;
455 rv = _type1(msgvec, TRU1, TRU1, FAL0, FAL0, NULL, NULL);
456 NYD_LEAVE;
457 return rv;
460 FL int
461 c_More(void *v)
463 int *msgvec = v, rv;
464 NYD_ENTER;
466 rv = _type1(msgvec, FAL0, TRU1, FAL0, FAL0, NULL, NULL);
467 NYD_LEAVE;
468 return rv;
471 FL int
472 c_type(void *v)
474 int *msgvec = v, rv;
475 NYD_ENTER;
477 rv = _type1(msgvec, TRU1, FAL0, FAL0, FAL0, NULL, NULL);
478 NYD_LEAVE;
479 return rv;
482 FL int
483 c_Type(void *v)
485 int *msgvec = v, rv;
486 NYD_ENTER;
488 rv = _type1(msgvec, FAL0, FAL0, FAL0, FAL0, NULL, NULL);
489 NYD_LEAVE;
490 return rv;
493 FL int
494 c_show(void *v)
496 int *msgvec = v, rv;
497 NYD_ENTER;
499 rv = _type1(msgvec, FAL0, FAL0, FAL0, TRU1, NULL, NULL);
500 NYD_LEAVE;
501 return rv;
504 FL int
505 c_mimeview(void *vp){ /* TODO direct addressable parts, multiple such */
506 struct message *mp;
507 int rv, *msgvec;
508 NYD_ENTER;
510 if((msgvec = vp)[1] != 0){
511 n_err(_("`mimeview': can yet only take one message, sorry!\n"));/* TODO */
512 n_pstate_err_no = n_ERR_NOTSUP;
513 rv = 1;
514 goto jleave;
517 mp = &message[*msgvec - 1];
518 touch(mp);
519 setdot(mp);
520 n_pstate |= n_PS_DID_PRINT_DOT;
521 uncollapse1(mp, 1);
523 n_COLOUR(
524 n_colour_env_create(n_COLOUR_CTX_VIEW, n_stdout, FAL0);
527 if(!a_cmsg_show_overview(n_stdout, mp, *msgvec))
528 n_pstate_err_no = n_ERR_IO;
529 else if(sendmp(mp, n_stdout, n_IGNORE_TYPE, NULL, SEND_TODISP_PARTS,
530 NULL) < 0)
531 n_pstate_err_no = n_ERR_IO;
532 else
533 n_pstate_err_no = n_ERR_NONE;
535 n_COLOUR(
536 n_colour_env_gut();
539 rv = (n_pstate_err_no != n_ERR_NONE);
540 jleave:
541 NYD_LEAVE;
542 return rv;
545 FL int
546 c_pipe(void *v)
548 char *str = v;
549 int rv;
550 NYD_ENTER;
552 rv = _pipe1(str, 1);
553 NYD_LEAVE;
554 return rv;
557 FL int
558 c_Pipe(void *v)
560 char *str = v;
561 int rv;
562 NYD_ENTER;
564 rv = _pipe1(str, 0);
565 NYD_LEAVE;
566 return rv;
569 FL int
570 c_top(void *v){
571 struct n_ignore *itp;
572 int rv;
573 NYD_ENTER;
575 if(n_ignore_is_any(n_IGNORE_TOP))
576 itp = n_IGNORE_TOP;
577 else{
578 itp = n_ignore_new(TRU1);
579 n_ignore_insert(itp, TRU1, "from", sizeof("from") -1);
580 n_ignore_insert(itp, TRU1, "to", sizeof("to") -1);
581 n_ignore_insert(itp, TRU1, "cc", sizeof("cc") -1);
582 n_ignore_insert(itp, TRU1, "subject", sizeof("subject") -1);
585 rv = !a_cmsg_top(v, itp);
586 NYD_LEAVE;
587 return rv;
590 FL int
591 c_Top(void *v){
592 int rv;
593 NYD_ENTER;
595 rv = !a_cmsg_top(v, n_IGNORE_TYPE);
596 NYD_LEAVE;
597 return rv;
600 FL int
601 c_next(void *v)
603 int list[2], *ip, *ip2, mdot, *msgvec = v, rv = 1;
604 struct message *mp;
605 NYD_ENTER;
607 if (*msgvec != 0) {
608 /* If some messages were supplied, find the first applicable one
609 * following dot using wrap around */
610 mdot = (int)PTR2SIZE(dot - message + 1);
612 /* Find first message in supplied message list which follows dot */
613 for (ip = msgvec; *ip != 0; ++ip) {
614 if ((mb.mb_threaded ? message[*ip - 1].m_threadpos > dot->m_threadpos
615 : *ip > mdot))
616 break;
618 if (*ip == 0)
619 ip = msgvec;
620 ip2 = ip;
621 do {
622 mp = message + *ip2 - 1;
623 if (!(mp->m_flag & MMNDEL)) {
624 setdot(mp);
625 goto jhitit;
627 if (*ip2 != 0)
628 ++ip2;
629 if (*ip2 == 0)
630 ip2 = msgvec;
631 } while (ip2 != ip);
632 fprintf(n_stdout, _("No messages applicable\n"));
633 goto jleave;
636 /* If this is the first command, select message 1. Note that this must
637 * exist for us to get here at all */
638 if (!(n_pstate & n_PS_SAW_COMMAND)) {
639 if (msgCount == 0)
640 goto jateof;
641 goto jhitit;
644 /* Just find the next good message after dot, no wraparound */
645 if (mb.mb_threaded == 0) {
646 for (mp = dot + !!(n_pstate & n_PS_DID_PRINT_DOT);
647 PTRCMP(mp, <, message + msgCount); ++mp)
648 if (!(mp->m_flag & MMNORM))
649 break;
650 } else {
651 /* TODO The threading code had some bugs that caused crashes.
652 * TODO The last thing (before the deep look) happens here,
653 * TODO so let's not trust n_PS_DID_PRINT_DOT but check & hope it fixes */
654 if ((mp = dot) != NULL && (n_pstate & n_PS_DID_PRINT_DOT))
655 mp = next_in_thread(mp);
656 while (mp != NULL && (mp->m_flag & MMNORM))
657 mp = next_in_thread(mp);
659 if (mp == NULL || PTRCMP(mp, >=, message + msgCount)) {
660 jateof:
661 fprintf(n_stdout, _("At EOF\n"));
662 rv = 0;
663 goto jleave;
665 setdot(mp);
667 /* Print dot */
668 jhitit:
669 list[0] = (int)PTR2SIZE(dot - message + 1);
670 list[1] = 0;
671 rv = c_type(list);
672 jleave:
673 NYD_LEAVE;
674 return rv;
677 FL int
678 c_pdot(void *vp)
680 NYD_ENTER;
681 n_UNUSED(vp);
682 fprintf(n_stdout, "%d\n", (int)PTR2SIZE(dot - message + 1));
683 NYD_LEAVE;
684 return 0;
687 FL int
688 c_messize(void *v)
690 int *msgvec = v, *ip, mesg;
691 struct message *mp;
692 NYD_ENTER;
694 for (ip = msgvec; *ip != 0; ++ip) {
695 mesg = *ip;
696 mp = message + mesg - 1;
697 fprintf(n_stdout, "%d: ", mesg);
698 if (mp->m_xlines > 0)
699 fprintf(n_stdout, "%ld", mp->m_xlines);
700 else
701 putc(' ', n_stdout);
702 fprintf(n_stdout, "/%lu\n", (ul_i)mp->m_xsize);
704 NYD_LEAVE;
705 return 0;
708 FL int
709 c_delete(void *v)
711 int *msgvec = v;
712 NYD_ENTER;
714 delm(msgvec);
715 NYD_LEAVE;
716 return 0;
719 FL int
720 c_deltype(void *v)
722 int list[2], rv = 0, *msgvec = v, lastdot;
723 NYD_ENTER;
725 lastdot = (int)PTR2SIZE(dot - message + 1);
726 if (delm(msgvec) >= 0) {
727 list[0] = (int)PTR2SIZE(dot - message + 1);
728 if (list[0] > lastdot) {
729 touch(dot);
730 list[1] = 0;
731 rv = c_type(list);
732 goto jleave;
734 fprintf(n_stdout, _("At EOF\n"));
735 } else
736 fprintf(n_stdout, _("No more messages\n"));
737 jleave:
738 NYD_LEAVE;
739 return rv;
742 FL int
743 c_undelete(void *v)
745 int *msgvec = v, *ip;
746 struct message *mp;
747 NYD_ENTER;
749 for (ip = msgvec; *ip != 0 && UICMP(z, PTR2SIZE(ip - msgvec), <, msgCount);
750 ++ip) {
751 mp = &message[*ip - 1];
752 touch(mp);
753 setdot(mp);
754 if (mp->m_flag & (MDELETED | MSAVED))
755 mp->m_flag &= ~(MDELETED | MSAVED);
756 else
757 mp->m_flag &= ~MDELETED;
758 #ifdef HAVE_IMAP
759 if (mb.mb_type == MB_IMAP || mb.mb_type == MB_CACHE)
760 imap_undelete(mp, *ip);
761 #endif
763 NYD_LEAVE;
764 return 0;
767 FL int
768 c_stouch(void *v)
770 int *msgvec = v, *ip;
771 NYD_ENTER;
773 for (ip = msgvec; *ip != 0; ++ip) {
774 setdot(message + *ip - 1);
775 dot->m_flag |= MTOUCH;
776 dot->m_flag &= ~MPRESERVE;
777 n_pstate |= n_PS_DID_PRINT_DOT;
779 NYD_LEAVE;
780 return 0;
783 FL int
784 c_mboxit(void *v)
786 int *msgvec = v, *ip;
787 NYD_ENTER;
789 if (n_pstate & n_PS_EDIT) {
790 n_err(_("`mbox' can only be used in a system mailbox\n")); /* TODO */
791 goto jleave;
794 for (ip = msgvec; *ip != 0; ++ip) {
795 setdot(message + *ip - 1);
796 dot->m_flag |= MTOUCH | MBOX;
797 dot->m_flag &= ~MPRESERVE;
798 n_pstate |= n_PS_DID_PRINT_DOT;
800 jleave:
801 NYD_LEAVE;
802 return 0;
805 FL int
806 c_preserve(void *v)
808 int *msgvec = v, *ip, mesg, rv = 1;
809 struct message *mp;
810 NYD_ENTER;
812 if (n_pstate & n_PS_EDIT) {
813 fprintf(n_stdout, _("Cannot `preserve' in a system mailbox\n"));
814 goto jleave;
817 for (ip = msgvec; *ip != 0; ++ip) {
818 mesg = *ip;
819 mp = message + mesg - 1;
820 mp->m_flag |= MPRESERVE;
821 mp->m_flag &= ~MBOX;
822 setdot(mp);
823 n_pstate |= n_PS_DID_PRINT_DOT;
825 rv = 0;
826 jleave:
827 NYD_LEAVE;
828 return rv;
831 FL int
832 c_unread(void *v)
834 struct message *mp;
835 int *msgvec = v, *ip;
836 NYD_ENTER;
838 for (ip = msgvec; *ip != 0; ++ip) {
839 mp = &message[*ip - 1];
840 setdot(mp);
841 dot->m_flag &= ~(MREAD | MTOUCH);
842 dot->m_flag |= MSTATUS;
843 #ifdef HAVE_IMAP
844 if (mb.mb_type == MB_IMAP || mb.mb_type == MB_CACHE)
845 imap_unread(mp, *ip); /* TODO return? */
846 #endif
847 n_pstate |= n_PS_DID_PRINT_DOT;
849 NYD_LEAVE;
850 return 0;
853 FL int
854 c_seen(void *v)
856 int *msgvec = v, *ip;
857 NYD_ENTER;
859 for (ip = msgvec; *ip != 0; ++ip) {
860 struct message *mp = message + *ip - 1;
861 setdot(mp);
862 touch(mp);
864 NYD_LEAVE;
865 return 0;
868 FL int
869 c_flag(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 & (MFLAG | MFLAGGED)))
879 m->m_flag |= MFLAG | MFLAGGED;
881 NYD_LEAVE;
882 return 0;
885 FL int
886 c_unflag(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 & (MFLAG | MFLAGGED)) {
896 m->m_flag &= ~(MFLAG | MFLAGGED);
897 m->m_flag |= MUNFLAG;
900 NYD_LEAVE;
901 return 0;
904 FL int
905 c_answered(void *v)
907 struct message *m;
908 int *msgvec = v, *ip;
909 NYD_ENTER;
911 for (ip = msgvec; *ip != 0; ++ip) {
912 m = message + *ip - 1;
913 setdot(m);
914 if (!(m->m_flag & (MANSWER | MANSWERED)))
915 m->m_flag |= MANSWER | MANSWERED;
917 NYD_LEAVE;
918 return 0;
921 FL int
922 c_unanswered(void *v)
924 struct message *m;
925 int *msgvec = v, *ip;
926 NYD_ENTER;
928 for (ip = msgvec; *ip != 0; ++ip) {
929 m = message + *ip - 1;
930 setdot(m);
931 if (m->m_flag & (MANSWER | MANSWERED)) {
932 m->m_flag &= ~(MANSWER | MANSWERED);
933 m->m_flag |= MUNANSWER;
936 NYD_LEAVE;
937 return 0;
940 FL int
941 c_draft(void *v)
943 struct message *m;
944 int *msgvec = v, *ip;
945 NYD_ENTER;
947 for (ip = msgvec; *ip != 0; ++ip) {
948 m = message + *ip - 1;
949 setdot(m);
950 if (!(m->m_flag & (MDRAFT | MDRAFTED)))
951 m->m_flag |= MDRAFT | MDRAFTED;
953 NYD_LEAVE;
954 return 0;
957 FL int
958 c_undraft(void *v)
960 struct message *m;
961 int *msgvec = v, *ip;
962 NYD_ENTER;
964 for (ip = msgvec; *ip != 0; ++ip) {
965 m = message + *ip - 1;
966 setdot(m);
967 if (m->m_flag & (MDRAFT | MDRAFTED)) {
968 m->m_flag &= ~(MDRAFT | MDRAFTED);
969 m->m_flag |= MUNDRAFT;
972 NYD_LEAVE;
973 return 0;
976 /* s-it-mode */