1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ Iterating over, and over such housekeeping message user commands.
3 *
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2020 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8 /*
9 * Copyright (c) 1980, 1993
10 * The Regents of the University of California. All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36 #undef su_FILE
37 #define su_FILE cmd_msg
38 #define mx_SOURCE
39
40 #ifndef mx_HAVE_AMALGAMATION
41 # include "mx/nail.h"
42 #endif
43
44 #include <su/cs.h>
45 #include <su/icodec.h>
46
47 #include "mx/cmd.h"
48 #include "mx/colour.h"
49 #include "mx/file-streams.h"
50 #include "mx/termios.h"
51
52 /* TODO fake */
53 #include "su/code-in.h"
54
55 /* Prepare and print "[Message: xy]:" intro */
56 static boole a_cmsg_show_overview(FILE *obuf, struct message *mp, int msg_no);
57
58 /* Show the requested messages */
59 static int _type1(int *msgvec, boole doign, boole dopage, boole dopipe,
60 boole donotdecode, char *cmd, u64 *tstats);
61
62 /* Pipe the requested messages */
63 static int a_cmsg_pipe1(void *vp, boole doign);
64
65 /* `top' / `Top' */
66 static int a_cmsg_top(void *vp, struct n_ignore const *itp);
67
68 /* Delete the indicated messages. Set dot to some nice place afterwards */
69 static int delm(int *msgvec);
70
71 static boole
a_cmsg_show_overview(FILE * obuf,struct message * mp,int msg_no)72 a_cmsg_show_overview(FILE *obuf, struct message *mp, int msg_no){
73 boole rv;
74 char const *cpre, *csuf;
75 NYD2_IN;
76
77 cpre = csuf = n_empty;
78 #ifdef mx_HAVE_COLOUR
79 if(mx_COLOUR_IS_ACTIVE()){
80 struct mx_colour_pen *cpen;
81
82 if((cpen = mx_colour_pen_create(mx_COLOUR_ID_VIEW_MSGINFO, NULL)
83 ) != NIL){
84 struct str const *s;
85
86 if((s = mx_colour_pen_to_str(cpen)) != NIL)
87 cpre = s->s;
88 if((s = mx_colour_reset_to_str()) != NIL)
89 csuf = s->s;
90 }
91 }
92 #endif
93 /* XXX Message info uses wire format for line count */
94 rv = (fprintf(obuf,
95 A_("%s[-- Message %2d -- %lu lines, %lu bytes --]:%s\n"),
96 cpre, msg_no, (ul)mp->m_lines, (ul)mp->m_size, csuf) > 0);
97 NYD2_OU;
98 return rv;
99 }
100
101 static int
_type1(int * msgvec,boole doign,boole dopage,boole dopipe,boole donotdecode,char * cmd,u64 * tstats)102 _type1(int *msgvec, boole doign, boole dopage, boole dopipe,
103 boole donotdecode, char *cmd, u64 *tstats)
104 {
105 u64 mstats[1];
106 int *ip;
107 struct message *mp;
108 char const *cp;
109 enum sendaction action;
110 boole volatile formfeed;
111 FILE * volatile obuf;
112 int volatile rv;
113 NYD_IN;
114
115 rv = 1;
116 obuf = n_stdout;
117 formfeed = (dopipe && ok_blook(page));
118 action = ((dopipe && ok_blook(piperaw))
119 ? SEND_MBOX : donotdecode
120 ? SEND_SHOW : doign
121 ? SEND_TODISP : SEND_TODISP_ALL);
122 UNINIT(cp, NIL);
123
124 if(dopipe){
125 if((obuf = mx_fs_pipe_open(cmd, "w", ok_vlook(SHELL), NIL, -1)) == NIL){
126 n_perr(cmd, 0);
127 obuf = n_stdout;
128 }
129 } else if ((n_psonce & n_PSO_TTYOUT) && (dopage ||
130 ((n_psonce & n_PSO_INTERACTIVE) && (cp = ok_vlook(crt)) != NULL))) {
131 uz nlines, lib;
132
133 nlines = 0;
134
135 if (!dopage) {
136 for (ip = msgvec; *ip && PCMP(ip - msgvec, <, msgCount); ++ip) {
137 mp = message + *ip - 1;
138 if (!(mp->m_content_info & CI_HAVE_BODY))
139 if (get_body(mp) != OKAY)
140 goto jleave;
141 nlines += mp->m_lines + 1; /* TODO BUT wire format, not display! */
142 }
143 }
144
145 /* >= not <: we return to the prompt */
146 if(dopage || nlines >= (*cp != '\0'
147 ? (su_idec_uz_cp(&lib, cp, 0, NULL), lib)
148 : S(uz,mx_termios_dimen.tiosd_real_height))){
149 if((obuf = mx_pager_open()) == NULL)
150 obuf = n_stdout;
151 }
152 mx_COLOUR(
153 if(action == SEND_TODISP || action == SEND_TODISP_ALL)
154 mx_colour_env_create(mx_COLOUR_CTX_VIEW, obuf, obuf != n_stdout);
155 )
156 }
157 mx_COLOUR(
158 else if(action == SEND_TODISP || action == SEND_TODISP_ALL)
159 mx_colour_env_create(mx_COLOUR_CTX_VIEW, n_stdout, FAL0);
160 )
161
162 rv = 0;
163 n_autorec_relax_create();
164 for (ip = msgvec; *ip && PCMP(ip - msgvec, <, msgCount); ++ip) {
165 mp = message + *ip - 1;
166 touch(mp);
167 setdot(mp);
168 n_pstate |= n_PS_DID_PRINT_DOT;
169 uncollapse1(mp, 1);
170 if(!dopipe && ip != msgvec && fprintf(obuf, "\n") < 0){
171 rv = 1;
172 break;
173 }
174 if(action != SEND_MBOX && !a_cmsg_show_overview(obuf, mp, *ip)){
175 rv = 1;
176 break;
177 }
178 if(sendmp(mp, obuf, (doign ? n_IGNORE_TYPE : NULL), NULL, action, mstats
179 ) < 0){
180 rv = 1;
181 break;
182 }
183 n_autorec_relax_unroll();
184 if(formfeed){ /* TODO a nicer way to separate piped messages! */
185 if(putc('\f', obuf) == EOF){
186 rv = 1;
187 break;
188 }
189 }
190 if (tstats != NULL)
191 tstats[0] += mstats[0];
192 }
193 n_autorec_relax_gut();
194 mx_COLOUR(
195 if(!dopipe && (action == SEND_TODISP || action == SEND_TODISP_ALL))
196 mx_colour_env_gut();
197 )
198
199 jleave:
200 if(obuf != n_stdout)
201 mx_pager_close(obuf);
202 else
203 clearerr(obuf);
204
205 NYD_OU;
206 return rv;
207 }
208
209 static int
a_cmsg_pipe1(void * vp,boole doign)210 a_cmsg_pipe1(void *vp, boole doign){
211 u64 stats[1];
212 char const *cmd, *cmdq;
213 int *msgvec, rv;
214 struct mx_cmd_arg *cap;
215 struct mx_cmd_arg_ctx *cacp;
216 NYD2_IN;
217
218 cacp = vp;
219 cap = cacp->cac_arg;
220 msgvec = cap->ca_arg.ca_msglist;
221 cap = cap->ca_next;
222 rv = 1;
223
224 if((cmd = cap->ca_arg.ca_str.s)[0] == '\0' &&
225 ((cmd = ok_vlook(cmd)) == NULL || *cmd == '\0')){
226 n_err(_("%s: variable *cmd* not set\n"), cacp->cac_desc->cad_name);
227 goto jleave;
228 }
229
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 NYD2_OU;
238 return rv;
239 }
240
241 static int
a_cmsg_top(void * vp,struct n_ignore const * itp)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 uz tmax, plines;
248 FILE *iobuf, *pbuf;
249 NYD2_IN;
250
251 if((iobuf = mx_fs_tmp_open("topio", (mx_FS_O_RDWR | mx_FS_O_UNLINK |
252 mx_FS_O_REGISTER), NIL)) == NIL){
253 n_perr(_("top: I/O temporary file"), 0);
254 vp = NIL;
255 goto jleave;
256 }
257 if((pbuf = mx_fs_tmp_open("toppag", (mx_FS_O_RDWR | mx_FS_O_UNLINK |
258 mx_FS_O_REGISTER), NIL)) == NIL)
259 pbuf = n_stdout;
260
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 n_pstate &= ~n_PS_MSGLIST_DIRECT; /* TODO NO ATTACHMENTS */
266 plines = 0;
267
268 mx_COLOUR( mx_colour_env_create(mx_COLOUR_CTX_VIEW, iobuf, FAL0); )
269 n_string_creat_auto(&s);
270 /* C99 */{
271 sz l;
272
273 if((su_idec_sz_cp(&l, ok_vlook(toplines), 0, NULL
274 ) & (su_IDEC_STATE_EMASK | su_IDEC_STATE_CONSUMED)
275 ) != su_IDEC_STATE_CONSUMED)
276 l = 0;
277 if(l <= 0){
278 tmax = n_screensize();
279 if(l < 0){
280 l = ABS(l);
281 tmax >>= l;
282 }
283 }else
284 tmax = (uz)l;
285 }
286 f = ok_blook(topsqueeze) ? a_SQUEEZE : a_NONE;
287
288 for(ip = msgvec = vp; *ip != 0; ++ip){
289 struct message *mp;
290
291 mp = &message[*ip - 1];
292 touch(mp);
293 setdot(mp);
294 n_pstate |= n_PS_DID_PRINT_DOT;
295 uncollapse1(mp, 1);
296
297 rewind(iobuf);
298 if(ftruncate(fileno(iobuf), 0)){
299 n_perr(_("top: ftruncate(2)"), 0);
300 vp = NULL;
301 break;
302 }
303
304 if(!a_cmsg_show_overview(iobuf, mp, *ip) ||
305 sendmp(mp, iobuf, itp, NULL, SEND_TODISP_ALL, NULL) < 0){
306 n_err(_("top: failed to prepare message %d\n"), *ip);
307 vp = NULL;
308 break;
309 }
310 fflush_rewind(iobuf);
311
312 /* TODO Skip over the _msg_overview line -- this is a hack to make
313 * TODO colours work: colour contexts should be objects */
314 for(;;){
315 int c;
316
317 if((c = getc(iobuf)) == EOF || putc(c, pbuf) == EOF){
318 vp = NULL;
319 break;
320 }else if(c == '\n')
321 break;
322 }
323 if(vp == NULL)
324 break;
325 ++plines;
326
327 /* C99 */{
328 uz l;
329
330 n_string_trunc(&s, 0);
331 for(l = 0, f &= ~a_WORKMASK; !(f & a_STOP);){
332 int c;
333
334 if((c = getc(iobuf)) == EOF){
335 f |= a_STOP;
336 c = '\n';
337 }
338
339 if(c != '\n')
340 n_string_push_c(&s, c);
341 else if((f & a_SQUEEZE) && s.s_len == 0){
342 if(!(f & a_STOP) && ((f & a_EMPTY) || tmax - 1 <= l))
343 continue;
344 if(putc('\n', pbuf) == EOF){
345 vp = NULL;
346 break;
347 }
348 f |= a_EMPTY;
349 ++l;
350 }else{
351 char const *cp, *xcp;
352
353 cp = n_string_cp_const(&s);
354 /* TODO Brute simple skip part overviews; see above.. */
355 if(!(f & a_SQUEEZE))
356 c = '\1';
357 else if(s.s_len > 8 &&
358 (xcp = su_cs_find(cp, "[-- ")) != NULL &&
359 su_cs_find(&xcp[1], " --]") != NULL)
360 c = '\0';
361 else{
362 char const *qcp;
363
364 for(qcp = ok_vlook(quote_chars); (c = *cp) != '\0'; ++cp){
365 if(!su_cs_is_ascii(c))
366 break;
367 if(!su_cs_is_space(c)){
368 if(su_cs_find_c(qcp, c) == NULL)
369 break;
370 c = '\0';
371 break;
372 }
373 }
374 }
375
376 if(c != '\0'){
377 if(fputs(n_string_cp_const(&s), pbuf) == EOF ||
378 putc('\n', pbuf) == EOF){
379 vp = NULL;
380 break;
381 }
382 if(++l >= tmax)
383 break;
384 f &= ~a_EMPTY;
385 }else
386 f |= a_EMPTY;
387 n_string_trunc(&s, 0);
388 }
389 }
390 if(vp == NULL)
391 break;
392 if(l > 0)
393 plines += l;
394 else{
395 if(!(f & a_EMPTY) && putc('\n', pbuf) == EOF){
396 vp = NULL;
397 break;
398 }
399 ++plines;
400 }
401 }
402 }
403
404 n_string_gut(&s);
405 mx_COLOUR( mx_colour_env_gut(); )
406
407 if(pbuf != n_stdout){
408 page_or_print(pbuf, plines);
409
410 mx_fs_close(pbuf);
411 }else
412 clearerr(pbuf);
413
414 mx_fs_close(iobuf);
415
416 jleave:
417 NYD2_OU;
418 return (vp != NIL);
419 }
420
421 static int
delm(int * msgvec)422 delm(int *msgvec)
423 {
424 struct message *mp;
425 int rv = -1, *ip, last;
426 NYD_IN;
427
428 last = 0;
429 for (ip = msgvec; *ip != 0; ++ip) {
430 mp = message + *ip - 1;
431 touch(mp);
432 mp->m_flag |= MDELETED | MTOUCH;
433 mp->m_flag &= ~(MPRESERVE | MSAVED | MBOX);
434 last = *ip;
435 }
436 if (last != 0) {
437 setdot(message + last - 1);
438 last = first(0, MDELETED);
439 if (last != 0) {
440 setdot(message + last - 1);
441 rv = 0;
442 } else {
443 setdot(message);
444 }
445 }
446 NYD_OU;
447 return rv;
448 }
449
450 FL int
c_more(void * v)451 c_more(void *v)
452 {
453 int *msgvec = v, rv;
454 NYD_IN;
455
456 rv = _type1(msgvec, TRU1, TRU1, FAL0, FAL0, NULL, NULL);
457 NYD_OU;
458 return rv;
459 }
460
461 FL int
c_More(void * v)462 c_More(void *v)
463 {
464 int *msgvec = v, rv;
465 NYD_IN;
466
467 rv = _type1(msgvec, FAL0, TRU1, FAL0, FAL0, NULL, NULL);
468 NYD_OU;
469 return rv;
470 }
471
472 FL int
c_type(void * v)473 c_type(void *v)
474 {
475 int *msgvec = v, rv;
476 NYD_IN;
477
478 rv = _type1(msgvec, TRU1, FAL0, FAL0, FAL0, NULL, NULL);
479 NYD_OU;
480 return rv;
481 }
482
483 FL int
c_Type(void * v)484 c_Type(void *v)
485 {
486 int *msgvec = v, rv;
487 NYD_IN;
488
489 rv = _type1(msgvec, FAL0, FAL0, FAL0, FAL0, NULL, NULL);
490 NYD_OU;
491 return rv;
492 }
493
494 FL int
c_show(void * v)495 c_show(void *v)
496 {
497 int *msgvec = v, rv;
498 NYD_IN;
499
500 rv = _type1(msgvec, FAL0, FAL0, FAL0, TRU1, NULL, NULL);
501 NYD_OU;
502 return rv;
503 }
504
505 FL int
c_mimeview(void * vp)506 c_mimeview(void *vp){ /* TODO direct addressable parts, multiple such */
507 struct message *mp;
508 int rv, *msgvec;
509 NYD_IN;
510
511 if((msgvec = vp)[1] != 0){
512 n_err(_("mimeview: can yet only take one message, sorry!\n"));/* TODO */
513 n_pstate_err_no = su_ERR_NOTSUP;
514 rv = 1;
515 goto jleave;
516 }
517
518 mp = &message[*msgvec - 1];
519 touch(mp);
520 setdot(mp);
521 n_pstate |= n_PS_DID_PRINT_DOT;
522 uncollapse1(mp, 1);
523
524 mx_COLOUR( mx_colour_env_create(mx_COLOUR_CTX_VIEW, n_stdout, FAL0); )
525
526 if(!a_cmsg_show_overview(n_stdout, mp, *msgvec))
527 n_pstate_err_no = su_ERR_IO;
528 else if(sendmp(mp, n_stdout, n_IGNORE_TYPE, NULL, SEND_TODISP_PARTS,
529 NULL) < 0)
530 n_pstate_err_no = su_ERR_IO;
531 else
532 n_pstate_err_no = su_ERR_NONE;
533
534 mx_COLOUR( mx_colour_env_gut(); )
535
536 rv = (n_pstate_err_no != su_ERR_NONE);
537 jleave:
538 NYD_OU;
539 return rv;
540 }
541
542 FL int
c_pipe(void * vp)543 c_pipe(void *vp){
544 int rv;
545 NYD_IN;
546
547 rv = a_cmsg_pipe1(vp, TRU1);
548 NYD_OU;
549 return rv;
550 }
551
552 FL int
c_Pipe(void * vp)553 c_Pipe(void *vp){
554 int rv;
555 NYD_IN;
556
557 rv = a_cmsg_pipe1(vp, FAL0);
558 NYD_OU;
559 return rv;
560 }
561
562 FL int
c_top(void * v)563 c_top(void *v){
564 struct n_ignore *itp;
565 int rv;
566 NYD_IN;
567
568 if(n_ignore_is_any(n_IGNORE_TOP))
569 itp = n_IGNORE_TOP;
570 else{
571 itp = n_ignore_new(TRU1);
572 n_ignore_insert(itp, TRU1, "from", sizeof("from") -1);
573 n_ignore_insert(itp, TRU1, "to", sizeof("to") -1);
574 n_ignore_insert(itp, TRU1, "cc", sizeof("cc") -1);
575 n_ignore_insert(itp, TRU1, "subject", sizeof("subject") -1);
576 }
577
578 rv = !a_cmsg_top(v, itp);
579 NYD_OU;
580 return rv;
581 }
582
583 FL int
c_Top(void * v)584 c_Top(void *v){
585 int rv;
586 NYD_IN;
587
588 rv = !a_cmsg_top(v, n_IGNORE_TYPE);
589 NYD_OU;
590 return rv;
591 }
592
593 FL int
c_next(void * v)594 c_next(void *v)
595 {
596 int list[2], *ip, *ip2, mdot, *msgvec = v, rv = 1;
597 struct message *mp;
598 NYD_IN;
599
600 if (*msgvec != 0) {
601 /* If some messages were supplied, find the first applicable one
602 * following dot using wrap around */
603 mdot = (int)P2UZ(dot - message + 1);
604
605 /* Find first message in supplied message list which follows dot */
606 for (ip = msgvec; *ip != 0; ++ip) {
607 if ((mb.mb_threaded ? message[*ip - 1].m_threadpos > dot->m_threadpos
608 : *ip > mdot))
609 break;
610 }
611 if (*ip == 0)
612 ip = msgvec;
613 ip2 = ip;
614 do {
615 mp = message + *ip2 - 1;
616 if (!(mp->m_flag & MMNDEL)) {
617 setdot(mp);
618 goto jhitit;
619 }
620 if (*ip2 != 0)
621 ++ip2;
622 if (*ip2 == 0)
623 ip2 = msgvec;
624 } while (ip2 != ip);
625 fprintf(n_stdout, _("No messages applicable\n"));
626 goto jleave;
627 }
628
629 /* If this is the first command, select message 1. Note that this must
630 * exist for us to get here at all */
631 if (!(n_pstate & n_PS_SAW_COMMAND)) {
632 if (msgCount == 0)
633 goto jateof;
634 goto jhitit;
635 }
636
637 /* Just find the next good message after dot, no wraparound */
638 if (mb.mb_threaded == 0) {
639 for (mp = dot + !!(n_pstate & n_PS_DID_PRINT_DOT);
640 PCMP(mp, <, message + msgCount); ++mp)
641 if (!(mp->m_flag & MMNORM))
642 break;
643 } else {
644 /* TODO The threading code had some bugs that caused crashes.
645 * TODO The last thing (before the deep look) happens here,
646 * TODO let's not trust n_PS_DID_PRINT_DOT but check & hope it fixes */
647 if ((mp = dot) != NULL && (n_pstate & n_PS_DID_PRINT_DOT))
648 mp = next_in_thread(mp);
649 while (mp != NULL && (mp->m_flag & MMNORM))
650 mp = next_in_thread(mp);
651 }
652 if (mp == NULL || PCMP(mp, >=, message + msgCount)) {
653 jateof:
654 fprintf(n_stdout, _("At EOF\n"));
655 rv = 0;
656 goto jleave;
657 }
658 setdot(mp);
659
660 /* Print dot */
661 jhitit:
662 list[0] = (int)P2UZ(dot - message + 1);
663 list[1] = 0;
664 rv = c_type(list);
665 jleave:
666 NYD_OU;
667 return rv;
668 }
669
670 FL int
c_pdot(void * vp)671 c_pdot(void *vp){
672 char cbuf[su_IENC_BUFFER_SIZE], sep1, sep2;
673 struct n_string s_b, *s;
674 int *mlp;
675 struct mx_cmd_arg_ctx *cacp;
676 NYD_IN;
677 UNUSED(vp);
678
679 n_pstate_err_no = su_ERR_NONE;
680 s = n_string_creat_auto(&s_b);
681 sep1 = *ok_vlook(ifs);
682 sep2 = *ok_vlook(ifs_ws);
683 if(sep1 == sep2)
684 sep2 = '\0';
685 if(sep1 == '\0')
686 sep1 = ' ';
687
688 cacp = vp;
689
690 for(mlp = cacp->cac_arg->ca_arg.ca_msglist; *mlp != 0; ++mlp){
691 if(!n_string_can_book(s, su_IENC_BUFFER_SIZE + 2u)){
692 n_err(_("=: overflow: string too long!\n"));
693 n_pstate_err_no = su_ERR_OVERFLOW;
694 vp = NULL;
695 goto jleave;
696 }
697 if(s->s_len > 0){
698 s = n_string_push_c(s, sep1);
699 if(sep2 != '\0')
700 s = n_string_push_c(s, sep2);
701 }
702 s = n_string_push_cp(s,
703 su_ienc(cbuf, (u32)*mlp, 10, su_IENC_MODE_NONE));
704 }
705
706 (void)n_string_cp(s);
707 if(cacp->cac_vput == NULL){
708 if(fprintf(n_stdout, "%s\n", s->s_dat) < 0){
709 n_pstate_err_no = su_err_no();
710 vp = NULL;
711 }
712 }else if(!n_var_vset(cacp->cac_vput, (up)s->s_dat)){
713 n_pstate_err_no = su_ERR_NOTSUP;
714 vp = NULL;
715 }
716 jleave:
717 /* n_string_gut(s); */
718 NYD_OU;
719 return (vp == NULL);
720 }
721
722 FL int
c_messize(void * v)723 c_messize(void *v)
724 {
725 int *msgvec = v, *ip, mesg;
726 struct message *mp;
727 NYD_IN;
728
729 for (ip = msgvec; *ip != 0; ++ip) {
730 mesg = *ip;
731 mp = message + mesg - 1;
732 fprintf(n_stdout, "%d: ", mesg);
733 if (mp->m_xlines > 0)
734 fprintf(n_stdout, "%ld", mp->m_xlines);
735 else
736 putc(' ', n_stdout);
737 fprintf(n_stdout, "/%lu\n", (ul)mp->m_xsize);
738 }
739 NYD_OU;
740 return 0;
741 }
742
743 FL int
c_delete(void * v)744 c_delete(void *v)
745 {
746 int *msgvec = v;
747 NYD_IN;
748
749 delm(msgvec);
750 NYD_OU;
751 return 0;
752 }
753
754 FL int
c_deltype(void * v)755 c_deltype(void *v)
756 {
757 int list[2], rv = 0, *msgvec = v, lastdot;
758 NYD_IN;
759
760 lastdot = (int)P2UZ(dot - message + 1);
761 if (delm(msgvec) >= 0) {
762 list[0] = (int)P2UZ(dot - message + 1);
763 if (list[0] > lastdot) {
764 touch(dot);
765 list[1] = 0;
766 rv = c_type(list);
767 goto jleave;
768 }
769 fprintf(n_stdout, _("At EOF\n"));
770 } else
771 fprintf(n_stdout, _("No more messages\n"));
772 jleave:
773 NYD_OU;
774 return rv;
775 }
776
777 FL int
c_undelete(void * v)778 c_undelete(void *v)
779 {
780 int *msgvec = v, *ip;
781 struct message *mp;
782 NYD_IN;
783
784 for (ip = msgvec; *ip != 0; ++ip) {
785 mp = &message[*ip - 1];
786 touch(mp);
787 setdot(mp);
788 if (mp->m_flag & (MDELETED | MSAVED))
789 mp->m_flag &= ~(MDELETED | MSAVED);
790 else
791 mp->m_flag &= ~MDELETED;
792 #ifdef mx_HAVE_IMAP
793 if (mb.mb_type == MB_IMAP || mb.mb_type == MB_CACHE)
794 imap_undelete(mp, *ip);
795 #endif
796 }
797 NYD_OU;
798 return 0;
799 }
800
801 FL int
c_stouch(void * v)802 c_stouch(void *v)
803 {
804 int *msgvec = v, *ip;
805 NYD_IN;
806
807 for (ip = msgvec; *ip != 0; ++ip) {
808 setdot(message + *ip - 1);
809 dot->m_flag |= MTOUCH;
810 dot->m_flag &= ~MPRESERVE;
811 n_pstate |= n_PS_DID_PRINT_DOT;
812 }
813 NYD_OU;
814 return 0;
815 }
816
817 FL int
c_mboxit(void * v)818 c_mboxit(void *v)
819 {
820 int *msgvec = v, *ip;
821 NYD_IN;
822
823 if (n_pstate & n_PS_EDIT) {
824 n_err(_("mbox: can only be used in a system mailbox\n")); /* TODO */
825 goto jleave;
826 }
827
828 for (ip = msgvec; *ip != 0; ++ip) {
829 setdot(message + *ip - 1);
830 dot->m_flag |= MTOUCH | MBOX;
831 dot->m_flag &= ~MPRESERVE;
832 n_pstate |= n_PS_DID_PRINT_DOT;
833 }
834 jleave:
835 NYD_OU;
836 return 0;
837 }
838
839 FL int
c_preserve(void * v)840 c_preserve(void *v)
841 {
842 int *msgvec = v, *ip, mesg, rv = 1;
843 struct message *mp;
844 NYD_IN;
845
846 if (n_pstate & n_PS_EDIT) {
847 fprintf(n_stdout, _("preserve: cannot be used in a system mailbox\n"));
848 goto jleave;
849 }
850
851 for (ip = msgvec; *ip != 0; ++ip) {
852 mesg = *ip;
853 mp = message + mesg - 1;
854 mp->m_flag |= MPRESERVE;
855 mp->m_flag &= ~MBOX;
856 setdot(mp);
857 n_pstate |= n_PS_DID_PRINT_DOT;
858 }
859 rv = 0;
860 jleave:
861 NYD_OU;
862 return rv;
863 }
864
865 FL int
c_unread(void * v)866 c_unread(void *v)
867 {
868 struct message *mp;
869 int *msgvec = v, *ip;
870 NYD_IN;
871
872 for (ip = msgvec; *ip != 0; ++ip) {
873 mp = &message[*ip - 1];
874 setdot(mp);
875 dot->m_flag &= ~(MREAD | MTOUCH);
876 dot->m_flag |= MSTATUS;
877 #ifdef mx_HAVE_IMAP
878 if (mb.mb_type == MB_IMAP || mb.mb_type == MB_CACHE)
879 imap_unread(mp, *ip); /* TODO return? */
880 #endif
881 n_pstate |= n_PS_DID_PRINT_DOT;
882 }
883 NYD_OU;
884 return 0;
885 }
886
887 FL int
c_seen(void * v)888 c_seen(void *v)
889 {
890 int *msgvec = v, *ip;
891 NYD_IN;
892
893 for (ip = msgvec; *ip != 0; ++ip) {
894 struct message *mp = message + *ip - 1;
895 setdot(mp);
896 touch(mp);
897 }
898 NYD_OU;
899 return 0;
900 }
901
902 FL int
c_flag(void * v)903 c_flag(void *v)
904 {
905 struct message *m;
906 int *msgvec = v, *ip;
907 NYD_IN;
908
909 for (ip = msgvec; *ip != 0; ++ip) {
910 m = message + *ip - 1;
911 setdot(m);
912 if (!(m->m_flag & (MFLAG | MFLAGGED)))
913 m->m_flag |= MFLAG | MFLAGGED;
914 }
915 NYD_OU;
916 return 0;
917 }
918
919 FL int
c_unflag(void * v)920 c_unflag(void *v)
921 {
922 struct message *m;
923 int *msgvec = v, *ip;
924 NYD_IN;
925
926 for (ip = msgvec; *ip != 0; ++ip) {
927 m = message + *ip - 1;
928 setdot(m);
929 if (m->m_flag & (MFLAG | MFLAGGED)) {
930 m->m_flag &= ~(MFLAG | MFLAGGED);
931 m->m_flag |= MUNFLAG;
932 }
933 }
934 NYD_OU;
935 return 0;
936 }
937
938 FL int
c_answered(void * v)939 c_answered(void *v)
940 {
941 struct message *m;
942 int *msgvec = v, *ip;
943 NYD_IN;
944
945 for (ip = msgvec; *ip != 0; ++ip) {
946 m = message + *ip - 1;
947 setdot(m);
948 if (!(m->m_flag & (MANSWER | MANSWERED)))
949 m->m_flag |= MANSWER | MANSWERED;
950 }
951 NYD_OU;
952 return 0;
953 }
954
955 FL int
c_unanswered(void * v)956 c_unanswered(void *v)
957 {
958 struct message *m;
959 int *msgvec = v, *ip;
960 NYD_IN;
961
962 for (ip = msgvec; *ip != 0; ++ip) {
963 m = message + *ip - 1;
964 setdot(m);
965 if (m->m_flag & (MANSWER | MANSWERED)) {
966 m->m_flag &= ~(MANSWER | MANSWERED);
967 m->m_flag |= MUNANSWER;
968 }
969 }
970 NYD_OU;
971 return 0;
972 }
973
974 FL int
c_draft(void * v)975 c_draft(void *v)
976 {
977 struct message *m;
978 int *msgvec = v, *ip;
979 NYD_IN;
980
981 for (ip = msgvec; *ip != 0; ++ip) {
982 m = message + *ip - 1;
983 setdot(m);
984 if (!(m->m_flag & (MDRAFT | MDRAFTED)))
985 m->m_flag |= MDRAFT | MDRAFTED;
986 }
987 NYD_OU;
988 return 0;
989 }
990
991 FL int
c_undraft(void * v)992 c_undraft(void *v)
993 {
994 struct message *m;
995 int *msgvec = v, *ip;
996 NYD_IN;
997
998 for (ip = msgvec; *ip != 0; ++ip) {
999 m = message + *ip - 1;
1000 setdot(m);
1001 if (m->m_flag & (MDRAFT | MDRAFTED)) {
1002 m->m_flag &= ~(MDRAFT | MDRAFTED);
1003 m->m_flag |= MUNDRAFT;
1004 }
1005 }
1006 NYD_OU;
1007 return 0;
1008 }
1009
1010 #include "su/code-ou.h"
1011 /* s-it-mode */
1012