More or less completely rewrite mime_enc.c..
[s-mailx.git] / cmd1.c
blobad1285b71f19fac8bcaf871ee1acbb3093131f48
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ User commands.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2016 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 cmd1
38 #ifndef HAVE_AMALGAMATION
39 # include "nail.h"
40 #endif
42 static int _screen;
44 /* Prepare and print "[Message: xy]:" intro */
45 static void _show_msg_overview(FILE *obuf, struct message *mp, int msg_no);
47 /* ... And place the extracted date in `date' */
48 static void _parse_from_(struct message *mp, char date[FROM_DATEBUF]);
50 /* Print out the header of a specific message
51 * __hprf: handle *headline*
52 * __subject: return -1 if Subject: yet seen, otherwise smalloc()d Subject:
53 * __putindent: print out the indenting in threaded display */
54 static void _print_head(size_t yetprinted, size_t msgno, FILE *f,
55 bool_t threaded);
56 static void __hprf(size_t yetprinted, char const *fmt, size_t msgno,
57 FILE *f, bool_t threaded, char const *attrlist);
58 static char * __subject(struct message *mp, bool_t threaded,
59 size_t yetprinted);
60 static int __putindent(FILE *fp, struct message *mp, int maxwidth);
62 static int _dispc(struct message *mp, char const *a);
64 /* Shared `z' implementation */
65 static int a_cmd_scroll(char const *arg, bool_t onlynew);
67 /* Shared `headers' implementation */
68 static int _headers(int msgspec);
70 /* Show the requested messages */
71 static int _type1(int *msgvec, bool_t doign, bool_t dopage, bool_t dopipe,
72 bool_t dodecode, char *cmd, ui64_t *tstats);
74 /* Pipe the requested messages */
75 static int _pipe1(char *str, int doign);
77 /* `top' / `Top' */
78 static int a_cmd_top(void *vp, struct ignoretab *itp);
80 static void
81 _show_msg_overview(FILE *obuf, struct message *mp, int msg_no)
83 char const *cpre = "", *csuf = "";
84 NYD_ENTER;
86 #ifdef HAVE_COLOUR
87 if (pstate & PS_COLOUR_ACTIVE) {
88 struct n_colour_pen *cpen;
90 if ((cpen = n_colour_pen_create(n_COLOUR_ID_VIEW_MSGINFO, NULL)) != NULL){
91 struct str const *sp;
93 if ((sp = n_colour_pen_to_str(cpen)) != NULL)
94 cpre = sp->s;
95 if ((sp = n_colour_reset_to_str()) != NULL)
96 csuf = sp->s;
99 #endif
100 fprintf(obuf, _("%s[-- Message %2d -- %lu lines, %lu bytes --]:%s\n"),
101 cpre, msg_no, (ul_i)mp->m_lines, (ul_i)mp->m_size, csuf);
102 NYD_LEAVE;
105 static void
106 _parse_from_(struct message *mp, char date[FROM_DATEBUF]) /* TODO line pool */
108 FILE *ibuf;
109 int hlen;
110 char *hline = NULL;
111 size_t hsize = 0;
112 NYD_ENTER;
114 if ((ibuf = setinput(&mb, mp, NEED_HEADER)) != NULL &&
115 (hlen = readline_restart(ibuf, &hline, &hsize, 0)) > 0)
116 extract_date_from_from_(hline, hlen, date);
117 if (hline != NULL)
118 free(hline);
119 NYD_LEAVE;
122 static void
123 _print_head(size_t yetprinted, size_t msgno, FILE *f, bool_t threaded)
125 enum {attrlen = 14};
126 char attrlist[attrlen +1], *cp;
127 char const *fmt;
128 NYD_ENTER;
130 if ((cp = ok_vlook(attrlist)) != NULL) {
131 if (strlen(cp) == attrlen) {
132 memcpy(attrlist, cp, attrlen +1);
133 goto jattrok;
135 n_err(_("*attrlist* is not of the correct length, using builtin\n"));
138 if (ok_blook(bsdcompat) || ok_blook(bsdflags)) {
139 char const bsdattr[attrlen +1] = "NU *HMFAT+-$~";
140 memcpy(attrlist, bsdattr, sizeof bsdattr);
141 } else if (ok_blook(SYSV3)) {
142 char const bsdattr[attrlen +1] = "NU *HMFAT+-$~";
143 memcpy(attrlist, bsdattr, sizeof bsdattr);
144 OBSOLETE(_("*SYSV3*: please use *bsdcompat* or *bsdflags*, "
145 "or set *attrlist*"));
146 } else {
147 char const pattr[attrlen +1] = "NUROSPMFAT+-$~";
148 memcpy(attrlist, pattr, sizeof pattr);
151 jattrok:
152 if ((fmt = ok_vlook(headline)) == NULL) {
153 fmt = ((ok_blook(bsdcompat) || ok_blook(bsdheadline))
154 ? "%>%a%m %-20f %16d %3l/%-5o %i%-S"
155 : "%>%a%m %-18f %16d %4l/%-5o %i%-s");
158 __hprf(yetprinted, fmt, msgno, f, threaded, attrlist);
159 NYD_LEAVE;
162 static void
163 __hprf(size_t yetprinted, char const *fmt, size_t msgno, FILE *f,
164 bool_t threaded, char const *attrlist)
166 char buf[16], datebuf[FROM_DATEBUF], cbuf[8], *cp, *subjline;
167 char const *datefmt, *date, *name, *fp n_COLOUR( COMMA *colo_tag );
168 int i, n, s, wleft, subjlen;
169 struct message *mp;
170 time_t datet;
171 n_COLOUR( struct n_colour_pen *cpen_new COMMA *cpen_cur COMMA *cpen_bas; )
172 enum {
173 _NONE = 0,
174 _ISDOT = 1<<0,
175 _ISADDR = 1<<1,
176 _ISTO = 1<<2,
177 _IFMT = 1<<3,
178 _LOOP_MASK = (1<<4) - 1,
179 _SFMT = 1<<4, /* It is 'S' */
180 /* For the simple byte-based counts in wleft and n we sometimes need
181 * adjustments to compensate for additional bytes of UTF-8 sequences */
182 _PUTCB_UTF8_SHIFT = 5,
183 _PUTCB_UTF8_MASK = 3<<5
184 } flags = _NONE;
185 NYD_ENTER;
186 n_UNUSED(buf);
188 if ((mp = message + msgno - 1) == dot)
189 flags = _ISDOT;
190 datet = mp->m_time;
191 date = NULL;
192 n_COLOUR( colo_tag = NULL; )
194 datefmt = ok_vlook(datefield);
195 jredo:
196 if (datefmt != NULL) {
197 fp = hfield1("date", mp);/* TODO use m_date field! */
198 if (fp == NULL) {
199 datefmt = NULL;
200 goto jredo;
202 datet = rfctime(fp);
203 date = fakedate(datet);
204 fp = ok_vlook(datefield_markout_older);
205 i = (*datefmt != '\0');
206 if (fp != NULL)
207 i |= (*fp != '\0') ? 2 | 4 : 2; /* XXX no magics */
209 /* May we strftime(3)? */
210 if (i & (1 | 4))
211 memcpy(&time_current.tc_local, localtime(&datet),
212 sizeof time_current.tc_local);
214 if ((i & 2) && (datet > time_current.tc_time + DATE_SECSDAY ||
215 #define _6M ((DATE_DAYSYEAR / 2) * DATE_SECSDAY)
216 (datet + _6M < time_current.tc_time))) {
217 #undef _6M
218 if ((datefmt = (i & 4) ? fp : NULL) == NULL) {
219 memset(datebuf, ' ', FROM_DATEBUF); /* xxx ur */
220 memcpy(datebuf + 4, date + 4, 7);
221 datebuf[4 + 7] = ' ';
222 memcpy(datebuf + 4 + 7 + 1, date + 20, 4);
223 datebuf[4 + 7 + 1 + 4] = '\0';
224 date = datebuf;
226 n_COLOUR( colo_tag = n_COLOUR_TAG_SUM_OLDER; )
227 } else if ((i & 1) == 0)
228 datefmt = NULL;
229 } else if (datet == (time_t)0 && !(mp->m_flag & MNOFROM)) {
230 /* TODO eliminate this path, query the FROM_ date in setptr(),
231 * TODO all other codepaths do so by themselves ALREADY ?????
232 * TODO assert(mp->m_time != 0);, then
233 * TODO ALSO changes behaviour of datefield_markout_older */
234 _parse_from_(mp, datebuf);
235 date = datebuf;
236 } else
237 date = fakedate(datet);
239 flags |= _ISADDR;
240 name = name1(mp, 0);
241 if (name != NULL && ok_blook(showto) && is_myname(skin(name))) {
242 if ((cp = hfield1("to", mp)) != NULL) {
243 name = cp;
244 flags |= _ISTO;
247 if (name == NULL) {
248 name = "";
249 flags &= ~_ISADDR;
251 if (flags & _ISADDR)
252 name = ok_blook(showname) ? realname(name) : prstr(skin(name));
254 subjline = NULL;
256 /* Detect the width of the non-format characters in *headline*;
257 * like that we can simply use putc() in the next loop, since we have
258 * already calculated their column widths (TODO it's sick) */
259 wleft = subjlen = scrnwidth;
261 for (fp = fmt; *fp != '\0'; ++fp) {
262 if (*fp == '%') {
263 if (*++fp == '-')
264 ++fp;
265 else if (*fp == '+')
266 ++fp;
267 if (digitchar(*fp)) {
268 n = 0;
270 n = 10*n + *fp - '0';
271 while (++fp, digitchar(*fp));
272 subjlen -= n;
274 if (*fp == 'i')
275 flags |= _IFMT;
277 if (*fp == '\0')
278 break;
279 } else {
280 #ifdef HAVE_WCWIDTH
281 if (mb_cur_max > 1) {
282 wchar_t wc;
283 if ((s = mbtowc(&wc, fp, mb_cur_max)) == -1)
284 n = s = 1;
285 else if ((n = wcwidth(wc)) == -1)
286 n = 1;
287 } else
288 #endif
289 n = s = 1;
290 subjlen -= n;
291 wleft -= n;
292 while (--s > 0)
293 ++fp;
297 /* Walk *headline*, producing output TODO not (really) MB safe */
298 #ifdef HAVE_COLOUR
299 if (flags & _ISDOT)
300 colo_tag = n_COLOUR_TAG_SUM_DOT;
301 cpen_bas = n_colour_pen_create(n_COLOUR_ID_SUM_HEADER, colo_tag);
302 n_colour_pen_put(cpen_new = cpen_cur = cpen_bas, f);
303 #endif
305 for (fp = fmt; *fp != '\0'; ++fp) {
306 char c;
308 if ((c = *fp & 0xFF) != '%') {
309 #ifdef HAVE_COLOUR
310 if ((cpen_new = cpen_bas) != cpen_cur)
311 n_colour_pen_put(cpen_cur = cpen_new, f);
312 #endif
313 putc(c, f);
314 continue;
317 flags &= _LOOP_MASK;
318 n = 0;
319 s = 1;
320 if ((c = *++fp) == '-') {
321 s = -1;
322 ++fp;
323 } else if (c == '+')
324 ++fp;
325 if (digitchar(*fp)) {
327 n = 10*n + *fp - '0';
328 while (++fp, digitchar(*fp));
331 if ((c = *fp & 0xFF) == '\0')
332 break;
333 n *= s;
335 cbuf[1] = '\0';
336 switch (c) {
337 case '%':
338 goto jputcb;
339 case '>':
340 case '<':
341 if (flags & _ISDOT) {
342 n_COLOUR( cpen_new = n_colour_pen_create(n_COLOUR_ID_SUM_DOTMARK,
343 colo_tag); );
344 if (options & OPT_UNICODE) {
345 if (c == '>')
346 /* 25B8;BLACK RIGHT-POINTING SMALL TRIANGLE: â–¸ */
347 cbuf[1] = (char)0x96, cbuf[2] = (char)0xB8;
348 else
349 /* 25C2;BLACK LEFT-POINTING SMALL TRIANGLE: â—‚ */
350 cbuf[1] = (char)0x97, cbuf[2] = (char)0x82;
351 c = (char)0xE2;
352 cbuf[3] = '\0';
353 flags |= 2 << _PUTCB_UTF8_SHIFT;
355 } else
356 c = ' ';
357 goto jputcb;
358 case '$':
359 #ifdef HAVE_SPAM
360 if (n == 0)
361 n = 5;
362 if (UICMP(32, n_ABS(n), >, wleft))
363 n = (n < 0) ? -wleft : wleft;
364 snprintf(buf, sizeof buf, "%u.%02u",
365 (mp->m_spamscore >> 8), (mp->m_spamscore & 0xFF));
366 n = fprintf(f, "%*s", n, buf);
367 wleft = (n >= 0) ? wleft - n : 0;
368 break;
369 #else
370 c = '?';
371 goto jputcb;
372 #endif
373 case 'a':
374 c = _dispc(mp, attrlist);
375 jputcb:
376 #ifdef HAVE_COLOUR
377 if (cpen_new == cpen_cur)
378 cpen_new = cpen_bas;
379 if (cpen_new != cpen_cur)
380 n_colour_pen_put(cpen_cur = cpen_new, f);
381 #endif
382 if (UICMP(32, n_ABS(n), >, wleft))
383 n = (n < 0) ? -wleft : wleft;
384 cbuf[0] = c;
385 n = fprintf(f, "%*s", n, cbuf);
386 if (n >= 0) {
387 wleft -= n;
388 if ((n = (flags & _PUTCB_UTF8_MASK)) != 0) {
389 n >>= _PUTCB_UTF8_SHIFT;
390 wleft += n;
392 } else {
393 wleft = 0; /* TODO I/O error.. ? break? */
395 #ifdef HAVE_COLOUR
396 if ((cpen_new = cpen_bas) != cpen_cur)
397 n_colour_pen_put(cpen_cur = cpen_new, f);
398 #endif
399 break;
400 case 'd':
401 if (datefmt != NULL) {
402 i = strftime(datebuf, sizeof datebuf, datefmt,
403 &time_current.tc_local);
404 if (i != 0)
405 date = datebuf;
406 else
407 n_err(_("Ignored date format, it excesses the target "
408 "buffer (%lu bytes)\n"), (ul_i)sizeof(datebuf));
409 datefmt = NULL;
411 if (n == 0)
412 n = 16;
413 if (UICMP(32, n_ABS(n), >, wleft))
414 n = (n < 0) ? -wleft : wleft;
415 n = fprintf(f, "%*.*s", n, n, date);
416 wleft = (n >= 0) ? wleft - n : 0;
417 break;
418 case 'e':
419 if (n == 0)
420 n = 2;
421 if (UICMP(32, n_ABS(n), >, wleft))
422 n = (n < 0) ? -wleft : wleft;
423 n = fprintf(f, "%*u", n, (threaded == 1 ? mp->m_level : 0));
424 wleft = (n >= 0) ? wleft - n : 0;
425 break;
426 case 'f':
427 if (n == 0) {
428 n = 18;
429 if (s < 0)
430 n = -n;
432 i = n_ABS(n);
433 if (i > wleft) {
434 i = wleft;
435 n = (n < 0) ? -wleft : wleft;
437 if (flags & _ISTO) /* XXX tr()! */
438 i -= 3;
439 n = fprintf(f, "%s%s", ((flags & _ISTO) ? "To " : ""),
440 colalign(name, i, n, &wleft));
441 if (n < 0)
442 wleft = 0;
443 else if (flags & _ISTO)
444 wleft -= 3;
445 break;
446 case 'i':
447 if (threaded) {
448 #ifdef HAVE_COLOUR
449 cpen_new = n_colour_pen_create(n_COLOUR_ID_SUM_THREAD, colo_tag);
450 if (cpen_new != cpen_cur)
451 n_colour_pen_put(cpen_cur = cpen_new, f);
452 #endif
453 n = __putindent(f, mp, n_MIN(wleft, scrnwidth - 60));
454 wleft = (n >= 0) ? wleft - n : 0;
455 #ifdef HAVE_COLOUR
456 if ((cpen_new = cpen_bas) != cpen_cur)
457 n_colour_pen_put(cpen_cur = cpen_new, f);
458 #endif
460 break;
461 case 'l':
462 if (n == 0)
463 n = 4;
464 if (UICMP(32, n_ABS(n), >, wleft))
465 n = (n < 0) ? -wleft : wleft;
466 if (mp->m_xlines) {
467 n = fprintf(f, "%*ld", n, mp->m_xlines);
468 wleft = (n >= 0) ? wleft - n : 0;
469 } else {
470 n = n_ABS(n);
471 wleft -= n;
472 while (n-- != 0)
473 putc(' ', f);
475 break;
476 case 'm':
477 if (n == 0) {
478 n = 3;
479 if (threaded)
480 for (i = msgCount; i > 999; i /= 10)
481 ++n;
483 if (UICMP(32, n_ABS(n), >, wleft))
484 n = (n < 0) ? -wleft : wleft;
485 n = fprintf(f, "%*lu", n, (ul_i)msgno);
486 wleft = (n >= 0) ? wleft - n : 0;
487 break;
488 case 'o':
489 if (n == 0)
490 n = -5;
491 if (UICMP(32, n_ABS(n), >, wleft))
492 n = (n < 0) ? -wleft : wleft;
493 n = fprintf(f, "%*lu", n, (ul_i)mp->m_xsize);
494 wleft = (n >= 0) ? wleft - n : 0;
495 break;
496 case 'S':
497 flags |= _SFMT;
498 /*FALLTHRU*/
499 case 's':
500 if (n == 0)
501 n = subjlen - 2;
502 if (n > 0 && s < 0)
503 n = -n;
504 if (subjlen > wleft)
505 subjlen = wleft;
506 if (UICMP(32, n_ABS(n), >, subjlen))
507 n = (n < 0) ? -subjlen : subjlen;
508 if (flags & _SFMT)
509 n -= (n < 0) ? -2 : 2;
510 if (n == 0)
511 break;
512 if (subjline == NULL)
513 subjline = __subject(mp, (threaded && (flags & _IFMT)), yetprinted);
514 if (subjline == (char*)-1) {
515 n = fprintf(f, "%*s", n, "");
516 wleft = (n >= 0) ? wleft - n : 0;
517 } else {
518 n = fprintf(f, ((flags & _SFMT) ? "\"%s\"" : "%s"),
519 colalign(subjline, n_ABS(n), n, &wleft));
520 if (n < 0)
521 wleft = 0;
523 break;
524 case 'T': { /* Message recipient flags */
525 /* We never can reuse "name" since it's the full name */
526 struct name const *np = lextract(hfield1("to", mp), GTO | GSKIN);
527 c = ' ';
528 i = 0;
529 j_A_redo:
530 for (; np != NULL; np = np->n_flink) {
531 switch (is_mlist(np->n_name, FAL0)) {
532 case MLIST_SUBSCRIBED: c = 'S'; goto jputcb;
533 case MLIST_KNOWN: c = 'L'; goto jputcb;
534 case MLIST_OTHER:
535 default: break;
538 if (i != 0)
539 goto jputcb;
540 ++i;
541 np = lextract(hfield1("cc", mp), GCC | GSKIN);
542 goto j_A_redo;
544 case 't':
545 if (n == 0) {
546 n = 3;
547 if (threaded)
548 for (i = msgCount; i > 999; i /= 10)
549 ++n;
551 if (UICMP(32, n_ABS(n), >, wleft))
552 n = (n < 0) ? -wleft : wleft;
553 n = fprintf(f, "%*lu",
554 n, (threaded ? (ul_i)mp->m_threadpos : (ul_i)msgno));
555 wleft = (n >= 0) ? wleft - n : 0;
556 break;
557 default:
558 if (options & OPT_D_V)
559 n_err(_("Unkown *headline* format: %%%c\n"), c);
560 c = '?';
561 goto jputcb;
564 if (wleft <= 0)
565 break;
568 #ifdef HAVE_COLOUR
569 n_colour_reset(f);
570 #endif
571 putc('\n', f);
573 if (subjline != NULL && subjline != (char*)-1)
574 free(subjline);
575 NYD_LEAVE;
578 static char *
579 __subject(struct message *mp, bool_t threaded, size_t yetprinted)
581 struct str in, out;
582 char *rv = (char*)-1, *ms;
583 NYD_ENTER;
585 if ((ms = hfield1("subject", mp)) == NULL)
586 goto jleave;
588 in.l = strlen(in.s = ms);
589 mime_fromhdr(&in, &out, TD_ICONV | TD_ISPR);
590 rv = ms = out.s;
592 if (!threaded || mp->m_level == 0)
593 goto jleave;
595 /* In a display thread - check whether this message uses the same
596 * Subject: as it's parent or elder neighbour, suppress printing it if
597 * this is the case. To extend this a bit, ignore any leading Re: or
598 * Fwd: plus follow-up WS. Ignore invisible messages along the way */
599 ms = subject_re_trim(ms);
601 for (; (mp = prev_in_thread(mp)) != NULL && yetprinted-- > 0;) {
602 char *os;
604 if (visible(mp) && (os = hfield1("subject", mp)) != NULL) {
605 struct str oout;
606 int x;
608 in.l = strlen(in.s = os);
609 mime_fromhdr(&in, &oout, TD_ICONV | TD_ISPR);
610 x = asccasecmp(ms, subject_re_trim(oout.s));
611 free(oout.s);
613 if (!x) {
614 free(out.s);
615 rv = (char*)-1;
617 break;
620 jleave:
621 NYD_LEAVE;
622 return rv;
625 static int
626 __putindent(FILE *fp, struct message *mp, int maxwidth)/* XXX no magic consts */
628 struct message *mq;
629 int *us, indlvl, indw, i, important = MNEW | MFLAGGED;
630 char *cs;
631 NYD_ENTER;
633 if (mp->m_level == 0 || maxwidth == 0) {
634 indw = 0;
635 goto jleave;
638 cs = ac_alloc(mp->m_level);
639 us = ac_alloc(mp->m_level * sizeof *us);
641 i = mp->m_level - 1;
642 if (mp->m_younger && UICMP(32, i + 1, ==, mp->m_younger->m_level)) {
643 if (mp->m_parent && mp->m_parent->m_flag & important)
644 us[i] = mp->m_flag & important ? 0x2523 : 0x2520;
645 else
646 us[i] = mp->m_flag & important ? 0x251D : 0x251C;
647 cs[i] = '+';
648 } else {
649 if (mp->m_parent && mp->m_parent->m_flag & important)
650 us[i] = mp->m_flag & important ? 0x2517 : 0x2516;
651 else
652 us[i] = mp->m_flag & important ? 0x2515 : 0x2514;
653 cs[i] = '\\';
656 mq = mp->m_parent;
657 for (i = mp->m_level - 2; i >= 0; --i) {
658 if (mq) {
659 if (UICMP(32, i, >, mq->m_level - 1)) {
660 us[i] = cs[i] = ' ';
661 continue;
663 if (mq->m_younger) {
664 if (mq->m_parent && (mq->m_parent->m_flag & important))
665 us[i] = 0x2503;
666 else
667 us[i] = 0x2502;
668 cs[i] = '|';
669 } else
670 us[i] = cs[i] = ' ';
671 mq = mq->m_parent;
672 } else
673 us[i] = cs[i] = ' ';
676 --maxwidth;
677 for (indlvl = indw = 0; (ui8_t)indlvl < mp->m_level && indw < maxwidth;
678 ++indlvl) {
679 if (indw < maxwidth - 1)
680 indw += (int)putuc(us[indlvl], cs[indlvl] & 0xFF, fp);
681 else
682 indw += (int)putuc(0x21B8, '^', fp);
684 indw += putuc(0x25B8, '>', fp);
686 ac_free(us);
687 ac_free(cs);
688 jleave:
689 NYD_LEAVE;
690 return indw;
693 static int
694 _dispc(struct message *mp, char const *a)
696 int i = ' ';
697 NYD_ENTER;
699 if ((mp->m_flag & (MREAD | MNEW)) == MREAD)
700 i = a[3];
701 if ((mp->m_flag & (MREAD | MNEW)) == (MREAD | MNEW))
702 i = a[2];
703 if (mp->m_flag & MANSWERED)
704 i = a[8];
705 if (mp->m_flag & MDRAFTED)
706 i = a[9];
707 if ((mp->m_flag & (MREAD | MNEW)) == MNEW)
708 i = a[0];
709 if (!(mp->m_flag & (MREAD | MNEW)))
710 i = a[1];
711 if (mp->m_flag & MSPAM)
712 i = a[12];
713 if (mp->m_flag & MSPAMUNSURE)
714 i = a[13];
715 if (mp->m_flag & MSAVED)
716 i = a[4];
717 if (mp->m_flag & MPRESERVE)
718 i = a[5];
719 if (mp->m_flag & (MBOX | MBOXED))
720 i = a[6];
721 if (mp->m_flag & MFLAGGED)
722 i = a[7];
723 if (mb.mb_threaded == 1 && mp->m_collapsed > 0)
724 i = a[11];
725 if (mb.mb_threaded == 1 && mp->m_collapsed < 0)
726 i = a[10];
727 NYD_LEAVE;
728 return i;
731 static int
732 a_cmd_scroll(char const *arg, bool_t onlynew){
733 long l;
734 char *eptr;
735 bool_t isabs;
736 int msgspec, size, maxs;
737 NYD2_ENTER;
739 /* TODO scroll problem: we do not know whether + and $ have already reached
740 * TODO the last screen in threaded mode */
741 msgspec = onlynew ? -1 : 0;
742 size = screensize();
743 if((maxs = msgCount / size) > 0 && msgCount % size == 0)
744 --maxs;
746 switch(*arg){
747 case '\0':
748 ++_screen;
749 goto jfwd;
750 case '^':
751 if(arg[1] != '\0')
752 goto jerr;
753 if(_screen == 0)
754 goto jerrbwd;
755 _screen = 0;
756 break;
757 case '$':
758 if(arg[1] != '\0')
759 goto jerr;
760 if(_screen == maxs)
761 goto jerrfwd;
762 _screen = maxs;
763 break;
764 case '+':
765 if(arg[1] == '\0')
766 ++_screen;
767 else{
768 isabs = FAL0;
770 ++arg;
771 if(0){
772 case '1': case '2': case '3': case '4': case '5':
773 case '6': case '7': case '8': case '9': case '0':
774 isabs = TRU1;
776 l = strtol(arg, &eptr, 10);
777 if(*eptr != '\0')
778 goto jerr;
779 if(l > maxs - (isabs ? 0 : _screen))
780 goto jerrfwd;
781 _screen = isabs ? (int)l : _screen + l;
783 jfwd:
784 if(_screen > maxs){
785 jerrfwd:
786 _screen = maxs;
787 printf(_("On last screenful of messages\n"));
789 break;
791 case '-':
792 if(arg[1] == '\0')
793 --_screen;
794 else{
795 ++arg;
796 l = strtol(arg, &eptr, 10);
797 if(*eptr != '\0')
798 goto jerr;
799 if(l > _screen)
800 goto jerrbwd;
801 _screen -= l;
803 if(_screen < 0){
804 jerrbwd:
805 _screen = 0;
806 printf(_("On first screenful of messages\n"));
808 if(msgspec == -1)
809 msgspec = -2;
810 break;
811 default:
812 jerr:
813 n_err(_("Unrecognized scrolling command: %s\n"), arg);
814 size = 1;
815 goto jleave;
818 size = _headers(msgspec);
819 jleave:
820 NYD2_LEAVE;
821 return size;
824 static int
825 _headers(int msgspec) /* TODO rework v15 */
827 struct n_sigman sm;
828 bool_t volatile isrelax;
829 ui32_t volatile flag;
830 int g, k, mesg, size;
831 int volatile lastg = 1;
832 struct message *mp, *mq, *lastmq = NULL;
833 enum mflag fl = MNEW | MFLAGGED;
834 NYD_ENTER;
836 time_current_update(&time_current, FAL0);
838 flag = 0;
839 isrelax = FAL0;
840 n_SIGMAN_ENTER_SWITCH(&sm, n_SIGMAN_ALL) {
841 case 0:
842 break;
843 default:
844 goto jleave;
847 #ifdef HAVE_COLOUR
848 if (options & OPT_INTERACTIVE)
849 n_colour_env_create(n_COLOUR_CTX_SUM, FAL0);
850 #endif
852 size = screensize();
853 if (_screen < 0)
854 _screen = 0;
855 #if 0 /* FIXME original code path */
856 k = _screen * size;
857 #else
858 if (msgspec <= 0)
859 k = _screen * size;
860 else
861 k = msgspec;
862 #endif
863 if (k >= msgCount)
864 k = msgCount - size;
865 if (k < 0)
866 k = 0;
868 if (mb.mb_threaded == 0) {
869 g = 0;
870 mq = message;
871 for (mp = message; PTRCMP(mp, <, message + msgCount); ++mp)
872 if (visible(mp)) {
873 if (g % size == 0)
874 mq = mp;
875 if (mp->m_flag & fl) {
876 lastg = g;
877 lastmq = mq;
879 if ((msgspec > 0 && PTRCMP(mp, ==, message + msgspec - 1)) ||
880 (msgspec == 0 && g == k) ||
881 (msgspec == -2 && g == k + size && lastmq) ||
882 (msgspec < 0 && g >= k && (mp->m_flag & fl) != 0))
883 break;
884 g++;
886 if (lastmq && (msgspec == -2 ||
887 (msgspec == -1 && PTRCMP(mp, ==, message + msgCount)))) {
888 g = lastg;
889 mq = lastmq;
891 _screen = g / size;
893 mp = mq;
894 mesg = (int)PTR2SIZE(mp - message);
895 if (PTRCMP(dot, !=, message + msgspec - 1)) { /* TODO really?? */
896 for (mq = mp; PTRCMP(mq, <, message + msgCount); ++mq)
897 if (visible(mq)) {
898 setdot(mq);
899 break;
903 srelax_hold();
904 isrelax = TRU1;
905 for (; PTRCMP(mp, <, message + msgCount); ++mp) {
906 ++mesg;
907 if (!visible(mp))
908 continue;
909 if (UICMP(32, flag++, >=, size))
910 break;
911 _print_head(0, mesg, stdout, 0);
912 srelax();
914 srelax_rele();
915 isrelax = FAL0;
916 } else { /* threaded */
917 g = 0;
918 mq = threadroot;
919 for (mp = threadroot; mp; mp = next_in_thread(mp))
920 if (visible(mp) &&
921 (mp->m_collapsed <= 0 ||
922 PTRCMP(mp, ==, message + msgspec - 1))) {
923 if (g % size == 0)
924 mq = mp;
925 if (mp->m_flag & fl) {
926 lastg = g;
927 lastmq = mq;
929 if ((msgspec > 0 && PTRCMP(mp, ==, message + msgspec - 1)) ||
930 (msgspec == 0 && g == k) ||
931 (msgspec == -2 && g == k + size && lastmq) ||
932 (msgspec < 0 && g >= k && (mp->m_flag & fl) != 0))
933 break;
934 g++;
936 if (lastmq && (msgspec == -2 ||
937 (msgspec == -1 && PTRCMP(mp, ==, message + msgCount)))) {
938 g = lastg;
939 mq = lastmq;
941 _screen = g / size;
942 mp = mq;
943 if (PTRCMP(dot, !=, message + msgspec - 1)) { /* TODO really?? */
944 for (mq = mp; mq; mq = next_in_thread(mq))
945 if (visible(mq) && mq->m_collapsed <= 0) {
946 setdot(mq);
947 break;
951 srelax_hold();
952 isrelax = TRU1;
953 while (mp) {
954 if (visible(mp) &&
955 (mp->m_collapsed <= 0 ||
956 PTRCMP(mp, ==, message + msgspec - 1))) {
957 if (UICMP(32, flag++, >=, size))
958 break;
959 _print_head(flag - 1, PTR2SIZE(mp - message + 1), stdout,
960 mb.mb_threaded);
961 srelax();
963 mp = next_in_thread(mp);
965 srelax_rele();
966 isrelax = FAL0;
969 if (!flag) {
970 printf(_("No more mail.\n"));
971 if (pstate & (PS_HOOK_MASK | PS_ROBOT))
972 flag = !flag;
975 n_sigman_cleanup_ping(&sm);
976 jleave:
977 if (isrelax)
978 srelax_rele();
979 n_COLOUR( n_colour_env_gut((sm.sm_signo != SIGPIPE) ? stdout : NULL); )
980 NYD_LEAVE;
981 n_sigman_leave(&sm, n_SIGMAN_VIPSIGS_NTTYOUT);
982 return !flag;
985 static int
986 _type1(int *msgvec, bool_t doign, bool_t dopage, bool_t dopipe,
987 bool_t dodecode, char *cmd, ui64_t *tstats)
989 struct n_sigman sm;
990 ui64_t mstats[1];
991 int volatile rv = 1;
992 int *ip;
993 struct message *mp;
994 char const *cp;
995 FILE * volatile obuf;
996 bool_t volatile isrelax = FAL0;
997 NYD_ENTER;
998 {/* C89.. */
999 enum sendaction const action = ((dopipe && ok_blook(piperaw))
1000 ? SEND_MBOX : dodecode
1001 ? SEND_SHOW : doign
1002 ? SEND_TODISP : SEND_TODISP_ALL);
1003 bool_t const volatile formfeed = (dopipe && ok_blook(page));
1004 obuf = stdout;
1006 n_SIGMAN_ENTER_SWITCH(&sm, n_SIGMAN_ALL) {
1007 case 0:
1008 break;
1009 default:
1010 goto jleave;
1013 if (dopipe) {
1014 if ((obuf = Popen(cmd, "w", ok_vlook(SHELL), NULL, 1)) == NULL) {
1015 n_perr(cmd, 0);
1016 obuf = stdout;
1018 } else if ((options & OPT_TTYOUT) && (dopage ||
1019 ((options & OPT_INTERACTIVE) && (cp = ok_vlook(crt)) != NULL))) {
1020 size_t nlines = 0;
1022 if (!dopage) {
1023 for (ip = msgvec; *ip && PTRCMP(ip - msgvec, <, msgCount); ++ip) {
1024 mp = message + *ip - 1;
1025 if (!(mp->m_have & HAVE_BODY))
1026 if (get_body(mp) != OKAY)
1027 goto jcleanup_leave;
1028 nlines += mp->m_lines + 1; /* Message info XXX and PARTS... */
1032 /* >= not <: we return to the prompt */
1033 if (dopage || UICMP(z, nlines, >=,
1034 (*cp != '\0' ? strtoul(cp, NULL, 0) : (size_t)realscreenheight))) {
1035 if ((obuf = n_pager_open()) == NULL)
1036 obuf = stdout;
1038 #ifdef HAVE_COLOUR
1039 if ((options & OPT_INTERACTIVE) &&
1040 (action == SEND_TODISP || action == SEND_TODISP_ALL ||
1041 action == SEND_SHOW))
1042 n_colour_env_create(n_COLOUR_CTX_VIEW, obuf != stdout);
1043 #endif
1045 #ifdef HAVE_COLOUR
1046 else if ((options & OPT_INTERACTIVE) &&
1047 (action == SEND_TODISP || action == SEND_TODISP_ALL))
1048 n_colour_env_create(n_COLOUR_CTX_VIEW, FAL0);
1049 #endif
1051 /*TODO unless we have our signal manager special care must be taken */
1052 srelax_hold();
1053 isrelax = TRU1;
1054 for (ip = msgvec; *ip && PTRCMP(ip - msgvec, <, msgCount); ++ip) {
1055 mp = message + *ip - 1;
1056 touch(mp);
1057 setdot(mp);
1058 pstate |= PS_DID_PRINT_DOT;
1059 uncollapse1(mp, 1);
1060 if (!dopipe && ip != msgvec)
1061 fprintf(obuf, "\n");
1062 if (action != SEND_MBOX)
1063 _show_msg_overview(obuf, mp, *ip);
1064 sendmp(mp, obuf, (doign ? ignore : NULL), NULL, action, mstats);
1065 srelax();
1066 if (formfeed) /* TODO a nicer way to separate piped messages! */
1067 putc('\f', obuf);
1068 if (tstats != NULL)
1069 tstats[0] += mstats[0];
1071 srelax_rele();
1072 isrelax = FAL0;
1074 rv = 0;
1075 jcleanup_leave:
1076 n_sigman_cleanup_ping(&sm);
1077 jleave:
1078 if (isrelax)
1079 srelax_rele();
1080 n_COLOUR( n_colour_env_gut((sm.sm_signo != SIGPIPE) ? obuf : NULL); )
1081 if (obuf != stdout)
1082 n_pager_close(obuf);
1084 NYD_LEAVE;
1085 n_sigman_leave(&sm, n_SIGMAN_VIPSIGS_NTTYOUT);
1086 return rv;
1089 static int
1090 _pipe1(char *str, int doign)
1092 ui64_t stats[1];
1093 char const *cmd, *cmdq;
1094 int *msgvec, rv = 1;
1095 bool_t needs_list;
1096 NYD_ENTER;
1098 if ((cmd = laststring(str, &needs_list, TRU1)) == NULL) {
1099 cmd = ok_vlook(cmd);
1100 if (cmd == NULL || *cmd == '\0') {
1101 n_err(_("Variable *cmd* not set\n"));
1102 goto jleave;
1106 msgvec = salloc((msgCount + 2) * sizeof *msgvec);
1108 if (!needs_list) {
1109 *msgvec = first(0, MMNORM);
1110 if (*msgvec == 0) {
1111 if (pstate & (PS_HOOK_MASK | PS_ROBOT)) {
1112 rv = 0;
1113 goto jleave;
1115 puts(_("No messages to pipe."));
1116 goto jleave;
1118 msgvec[1] = 0;
1119 } else if (getmsglist(str, msgvec, 0) < 0)
1120 goto jleave;
1121 if (*msgvec == 0) {
1122 if (pstate & (PS_HOOK_MASK | PS_ROBOT)) {
1123 rv = 0;
1124 goto jleave;
1126 printf("No applicable messages.\n");
1127 goto jleave;
1130 cmdq = n_shexp_quote_cp(cmd, FAL0);
1131 printf(_("Pipe to: %s\n"), cmdq);
1132 stats[0] = 0;
1133 if ((rv = _type1(msgvec, doign, FAL0, TRU1, FAL0, n_UNCONST(cmd), stats)
1134 ) == 0)
1135 printf("%s %" PRIu64 " bytes\n", cmdq, stats[0]);
1136 jleave:
1137 NYD_LEAVE;
1138 return rv;
1141 static int
1142 a_cmd_top(void *vp, struct ignoretab *itp){
1143 struct n_string s;
1144 int *msgvec, *ip;
1145 enum{a_NONE, a_SQUEEZE = 1u<<0,
1146 a_EMPTY = 1u<<8, a_STOP = 1u<<9, a_WORKMASK = 0xFF00u} f;
1147 size_t tmax, plines;
1148 FILE *iobuf, *pbuf;
1149 NYD2_ENTER;
1151 if((iobuf = Ftmp(NULL, "topio", OF_RDWR | OF_UNLINK | OF_REGISTER)) == NULL){
1152 n_perr(_("`top': I/O temporary file"), 0);
1153 vp = NULL;
1154 goto jleave;
1156 if((pbuf = Ftmp(NULL, "toppag", OF_RDWR | OF_UNLINK | OF_REGISTER)) == NULL){
1157 n_perr(_("`top': temporary pager file"), 0);
1158 vp = NULL;
1159 goto jleave1;
1162 /* TODO In v15 we should query the m_message object, and directly send only
1163 * TODO those parts, optionally over empty-line-squeeze and quote-strip
1164 * TODO filters, in which we are interested in: only text content!
1165 * TODO And: with *topsqueeze*, header/content separating empty line.. */
1166 pstate &= ~PS_MSGLIST_DIRECT; /* TODO NO ATTACHMENTS */
1167 plines = 0;
1169 #ifdef HAVE_COLOUR
1170 if (options & OPT_INTERACTIVE)
1171 n_colour_env_create(n_COLOUR_CTX_VIEW, TRU1);
1172 #endif
1173 n_string_creat_auto(&s);
1174 /* C99 */{
1175 long l;
1177 if((l = strtol(ok_vlook(toplines), NULL, 0)) <= 0){
1178 tmax = (size_t)screensize();
1179 if(l < 0){
1180 l = n_ABS(l);
1181 tmax >>= l;
1183 }else
1184 tmax = (size_t)l;
1186 f = ok_blook(topsqueeze) ? a_SQUEEZE : a_NONE;
1188 for(ip = msgvec = vp;
1189 *ip != 0 && UICMP(z, PTR2SIZE(ip - msgvec), <, msgCount); ++ip){
1190 struct message *mp;
1192 mp = &message[*ip - 1];
1193 touch(mp);
1194 setdot(mp);
1195 pstate |= PS_DID_PRINT_DOT;
1196 uncollapse1(mp, 1);
1198 rewind(iobuf);
1199 if(ftruncate(fileno(iobuf), 0)){
1200 n_perr(_("`top': ftruncate(2)"), 0);
1201 vp = NULL;
1202 break;
1204 if(sendmp(mp, iobuf, itp, NULL, SEND_TODISP_ALL, NULL) < 0){
1205 n_err(_("`top': failed to prepare message %d\n"), *ip);
1206 vp = NULL;
1207 break;
1209 fflush_rewind(iobuf);
1211 _show_msg_overview(pbuf, mp, *ip);
1212 ++plines;
1213 /* C99 */{
1214 size_t l;
1216 n_string_trunc(&s, 0);
1217 for(l = 0, f &= ~a_WORKMASK; !(f & a_STOP);){
1218 int c;
1220 if((c = getc(iobuf)) == EOF){
1221 f |= a_STOP;
1222 c = '\n';
1225 if(c != '\n')
1226 n_string_push_c(&s, c);
1227 else if((f & a_SQUEEZE) && s.s_len == 0){
1228 if(!(f & a_STOP) && ((f & a_EMPTY) || tmax - 1 <= l))
1229 continue;
1230 if(putc('\n', pbuf) == EOF){
1231 vp = NULL;
1232 break;
1234 f |= a_EMPTY;
1235 ++l;
1236 }else{
1237 char const *cp, *xcp;
1239 cp = n_string_cp_const(&s);
1240 /* TODO Brute simple skip part overviews; see above.. */
1241 if(!(f & a_SQUEEZE))
1242 c = '\1';
1243 else if(s.s_len > 8 &&
1244 (xcp = strstr(cp, "[-- ")) != NULL &&
1245 strstr(&xcp[1], " --]") != NULL)
1246 c = '\0';
1247 else for(; (c = *cp) != '\0'; ++cp){
1248 if(!asciichar(c))
1249 break;
1250 if(!blankspacechar(c)){
1251 if(!ISQUOTE(c))
1252 break;
1253 c = '\0';
1254 break;
1258 if(c != '\0'){
1259 if(fputs(n_string_cp_const(&s), pbuf) == EOF ||
1260 putc('\n', pbuf) == EOF){
1261 vp = NULL;
1262 break;
1264 if(++l >= tmax)
1265 break;
1266 f &= ~a_EMPTY;
1267 }else
1268 f |= a_EMPTY;
1269 n_string_trunc(&s, 0);
1272 if(vp == NULL)
1273 break;
1274 if(l > 0)
1275 plines += l;
1276 else{
1277 if(!(f & a_EMPTY) && putc('\n', pbuf) == EOF){
1278 vp = NULL;
1279 break;
1281 ++plines;
1286 n_string_gut(&s);
1287 n_COLOUR( n_colour_env_gut(pbuf); )
1289 fflush(pbuf);
1290 page_or_print(pbuf, plines);
1292 Fclose(pbuf);
1293 jleave1:
1294 Fclose(iobuf);
1295 jleave:
1296 NYD2_LEAVE;
1297 return (vp != NULL);
1300 FL int
1301 c_cmdnotsupp(void *v) /* TODO -> lex.c */
1303 NYD_ENTER;
1304 n_UNUSED(v);
1305 n_err(_("The requested feature is not compiled in\n"));
1306 NYD_LEAVE;
1307 return 1;
1310 FL int
1311 c_headers(void *v)
1313 int rv;
1314 NYD_ENTER;
1316 rv = print_header_group((int*)v);
1317 NYD_LEAVE;
1318 return rv;
1321 FL int
1322 print_header_group(int *vector)
1324 int rv;
1325 NYD_ENTER;
1327 assert(vector != NULL && vector != (void*)-1);
1328 rv = _headers(vector[0]);
1329 NYD_LEAVE;
1330 return rv;
1333 FL int
1334 c_scroll(void *v)
1336 int rv;
1337 NYD_ENTER;
1339 rv = a_cmd_scroll(v, FAL0);
1340 NYD_LEAVE;
1341 return rv;
1344 FL int
1345 c_Scroll(void *v)
1347 int rv;
1348 NYD_ENTER;
1350 rv = a_cmd_scroll(v, TRU1);
1351 NYD_LEAVE;
1352 return rv;
1355 FL int
1356 c_from(void *v)
1358 struct n_sigman sm;
1359 int *msgvec = v, *ip, n;
1360 char *cp;
1361 FILE * volatile obuf;
1362 bool_t volatile isrelax;
1363 NYD_ENTER;
1365 time_current_update(&time_current, FAL0);
1367 obuf = stdout;
1368 isrelax = FAL0;
1369 n_SIGMAN_ENTER_SWITCH(&sm, n_SIGMAN_ALL) {
1370 case 0:
1371 break;
1372 default:
1373 goto jleave;
1376 if (options & OPT_INTERACTIVE) {
1377 if ((cp = ok_vlook(crt)) != NULL) {
1378 for (n = 0, ip = msgvec; *ip != 0; ++ip)
1379 ++n;
1380 if (UICMP(z, n, >, (*cp == '\0'
1381 ? (size_t)screensize() : strtoul(cp, NULL, 0)) + 3) &&
1382 (obuf = n_pager_open()) == NULL)
1383 obuf = stdout;
1385 n_COLOUR( n_colour_env_create(n_COLOUR_CTX_SUM, obuf != stdout); )
1388 /* Update dot before display so that the dotmark etc. are correct */
1389 for (ip = msgvec; *ip != 0; ++ip)
1391 if (--ip >= msgvec)
1392 setdot(message + *ip - 1);
1394 srelax_hold();
1395 isrelax = TRU1;
1396 for (n = 0, ip = msgvec; *ip != 0; ++ip) { /* TODO join into _print_head() */
1397 _print_head((size_t)n++, (size_t)*ip, obuf, mb.mb_threaded);
1398 srelax();
1400 srelax_rele();
1401 isrelax = FAL0;
1403 n_sigman_cleanup_ping(&sm);
1404 jleave:
1405 if (isrelax)
1406 srelax_rele();
1407 n_COLOUR( n_colour_env_gut((sm.sm_signo != SIGPIPE) ? obuf : NULL); )
1408 if (obuf != stdout)
1409 n_pager_close(obuf);
1410 NYD_LEAVE;
1411 n_sigman_leave(&sm, n_SIGMAN_VIPSIGS_NTTYOUT);
1412 return 0;
1415 FL void
1416 print_headers(size_t bottom, size_t topx, bool_t only_marked)
1418 struct n_sigman sm;
1419 bool_t volatile isrelax;
1420 size_t printed;
1421 NYD_ENTER;
1423 time_current_update(&time_current, FAL0);
1425 isrelax = FAL0;
1426 n_SIGMAN_ENTER_SWITCH(&sm, n_SIGMAN_ALL) {
1427 case 0:
1428 break;
1429 default:
1430 goto jleave;
1433 #ifdef HAVE_COLOUR
1434 if (options & OPT_INTERACTIVE)
1435 n_colour_env_create(n_COLOUR_CTX_SUM, FAL0);
1436 #endif
1438 srelax_hold();
1439 isrelax = TRU1;
1440 for (printed = 0; bottom <= topx; ++bottom) {
1441 struct message *mp = message + bottom - 1;
1442 if (only_marked) {
1443 if (!(mp->m_flag & MMARK))
1444 continue;
1445 } else if (!visible(mp))
1446 continue;
1447 _print_head(printed++, bottom, stdout, FAL0);
1448 srelax();
1450 srelax_rele();
1451 isrelax = FAL0;
1453 n_sigman_cleanup_ping(&sm);
1454 jleave:
1455 if (isrelax)
1456 srelax_rele();
1457 n_COLOUR( n_colour_env_gut((sm.sm_signo != SIGPIPE) ? stdout : NULL); )
1458 NYD_LEAVE;
1459 n_sigman_leave(&sm, n_SIGMAN_VIPSIGS_NTTYOUT);
1462 FL int
1463 c_pdot(void *v)
1465 NYD_ENTER;
1466 n_UNUSED(v);
1467 printf("%d\n", (int)PTR2SIZE(dot - message + 1));
1468 NYD_LEAVE;
1469 return 0;
1472 FL int
1473 c_more(void *v)
1475 int *msgvec = v, rv;
1476 NYD_ENTER;
1478 rv = _type1(msgvec, TRU1, TRU1, FAL0, FAL0, NULL, NULL);
1479 NYD_LEAVE;
1480 return rv;
1483 FL int
1484 c_More(void *v)
1486 int *msgvec = v, rv;
1487 NYD_ENTER;
1489 rv = _type1(msgvec, FAL0, TRU1, FAL0, FAL0, NULL, NULL);
1490 NYD_LEAVE;
1491 return rv;
1494 FL int
1495 c_type(void *v)
1497 int *msgvec = v, rv;
1498 NYD_ENTER;
1500 rv = _type1(msgvec, TRU1, FAL0, FAL0, FAL0, NULL, NULL);
1501 NYD_LEAVE;
1502 return rv;
1505 FL int
1506 c_Type(void *v)
1508 int *msgvec = v, rv;
1509 NYD_ENTER;
1511 rv = _type1(msgvec, FAL0, FAL0, FAL0, FAL0, NULL, NULL);
1512 NYD_LEAVE;
1513 return rv;
1516 FL int
1517 c_show(void *v)
1519 int *msgvec = v, rv;
1520 NYD_ENTER;
1522 rv = _type1(msgvec, FAL0, FAL0, FAL0, TRU1, NULL, NULL);
1523 NYD_LEAVE;
1524 return rv;
1527 FL int
1528 c_pipe(void *v)
1530 char *str = v;
1531 int rv;
1532 NYD_ENTER;
1534 rv = _pipe1(str, 1);
1535 NYD_LEAVE;
1536 return rv;
1539 FL int
1540 c_Pipe(void *v)
1542 char *str = v;
1543 int rv;
1544 NYD_ENTER;
1546 rv = _pipe1(str, 0);
1547 NYD_LEAVE;
1548 return rv;
1551 FL int
1552 c_top(void *v){
1553 struct ignoretab it[2];
1554 int rv;
1555 NYD_ENTER;
1557 n_ignoretab_creat(&it[0], TRU1);
1558 n_ignoretab_creat(&it[1], TRU1);
1559 n_ignoretab_insert(&it[1], "from", sizeof("from") -1);
1560 n_ignoretab_insert(&it[1], "to", sizeof("to") -1);
1561 n_ignoretab_insert(&it[1], "cc", sizeof("cc") -1);
1562 n_ignoretab_insert(&it[1], "subject", sizeof("subject") -1);
1564 rv = !a_cmd_top(v, it);
1565 NYD_LEAVE;
1566 return rv;
1569 FL int
1570 c_Top(void *v){
1571 int rv;
1572 NYD_ENTER;
1574 rv = !a_cmd_top(v, ignore);
1575 NYD_LEAVE;
1576 return rv;
1579 FL int
1580 c_folders(void *v)
1582 char const *cp;
1583 char **argv;
1584 int rv;
1585 NYD_ENTER;
1587 rv = 1;
1589 if(*(argv = v) != NULL){
1590 if((cp = fexpand(*argv, FEXP_NSHELL | FEXP_LOCAL)) == NULL)
1591 goto jleave;
1592 }else
1593 cp = folder_query();
1595 rv = run_command(ok_vlook(LISTER), 0, COMMAND_FD_PASS, COMMAND_FD_PASS, cp,
1596 NULL, NULL, NULL);
1597 if(rv < 0)
1598 rv = 1; /* XXX */
1599 jleave:
1600 NYD_LEAVE;
1601 return rv;
1604 /* s-it-mode */