Add MIME_{SIGNED,ENCRYPTED} for multipart/{signed,encrypted}..
[s-mailx.git] / cmd1.c
blob288edc470965bcf3bf2283db4e21937326ffc7b2
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 n_ignore const *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 cpre = csuf = n_empty;
87 #ifdef HAVE_COLOUR
88 if (pstate & PS_COLOUR_ACTIVE) {
89 struct n_colour_pen *cpen;
91 if ((cpen = n_colour_pen_create(n_COLOUR_ID_VIEW_MSGINFO, NULL)) != NULL){
92 struct str const *sp;
94 if ((sp = n_colour_pen_to_str(cpen)) != NULL)
95 cpre = sp->s;
96 if ((sp = n_colour_reset_to_str()) != NULL)
97 csuf = sp->s;
100 #endif
101 fprintf(obuf, _("%s[-- Message %2d -- %lu lines, %lu bytes --]:%s\n"),
102 cpre, msg_no, (ul_i)mp->m_lines, (ul_i)mp->m_size, csuf);
103 NYD_LEAVE;
106 static void
107 _parse_from_(struct message *mp, char date[FROM_DATEBUF]) /* TODO line pool */
109 FILE *ibuf;
110 int hlen;
111 char *hline = NULL;
112 size_t hsize = 0;
113 NYD_ENTER;
115 if ((ibuf = setinput(&mb, mp, NEED_HEADER)) != NULL &&
116 (hlen = readline_restart(ibuf, &hline, &hsize, 0)) > 0)
117 extract_date_from_from_(hline, hlen, date);
118 if (hline != NULL)
119 free(hline);
120 NYD_LEAVE;
123 static void
124 _print_head(size_t yetprinted, size_t msgno, FILE *f, bool_t threaded)
126 enum {attrlen = 14};
127 char attrlist[attrlen +1], *cp;
128 char const *fmt;
129 NYD_ENTER;
131 if ((cp = ok_vlook(attrlist)) != NULL) {
132 if (strlen(cp) == attrlen) {
133 memcpy(attrlist, cp, attrlen +1);
134 goto jattrok;
136 n_err(_("*attrlist* is not of the correct length, using builtin\n"));
139 if (ok_blook(bsdcompat) || ok_blook(bsdflags)) {
140 char const bsdattr[attrlen +1] = "NU *HMFAT+-$~";
141 memcpy(attrlist, bsdattr, sizeof bsdattr);
142 } else if (ok_blook(SYSV3)) {
143 char const bsdattr[attrlen +1] = "NU *HMFAT+-$~";
144 memcpy(attrlist, bsdattr, sizeof bsdattr);
145 OBSOLETE(_("*SYSV3*: please use *bsdcompat* or *bsdflags*, "
146 "or set *attrlist*"));
147 } else {
148 char const pattr[attrlen +1] = "NUROSPMFAT+-$~";
149 memcpy(attrlist, pattr, sizeof pattr);
152 jattrok:
153 if ((fmt = ok_vlook(headline)) == NULL) {
154 fmt = ((ok_blook(bsdcompat) || ok_blook(bsdheadline))
155 ? "%>%a%m %-20f %16d %3l/%-5o %i%-S"
156 : "%>%a%m %-18f %16d %4l/%-5o %i%-s");
159 __hprf(yetprinted, fmt, msgno, f, threaded, attrlist);
160 NYD_LEAVE;
163 static void
164 __hprf(size_t yetprinted, char const *fmt, size_t msgno, FILE *f,
165 bool_t threaded, char const *attrlist)
167 char buf[16], datebuf[FROM_DATEBUF], cbuf[8], *cp, *subjline;
168 char const *datefmt, *date, *name, *fp n_COLOUR( COMMA *colo_tag );
169 int i, n, s, wleft, subjlen;
170 struct message *mp;
171 time_t datet;
172 n_COLOUR( struct n_colour_pen *cpen_new COMMA *cpen_cur COMMA *cpen_bas; )
173 enum {
174 _NONE = 0,
175 _ISDOT = 1<<0,
176 _ISADDR = 1<<1,
177 _ISTO = 1<<2,
178 _IFMT = 1<<3,
179 _LOOP_MASK = (1<<4) - 1,
180 _SFMT = 1<<4, /* It is 'S' */
181 /* For the simple byte-based counts in wleft and n we sometimes need
182 * adjustments to compensate for additional bytes of UTF-8 sequences */
183 _PUTCB_UTF8_SHIFT = 5,
184 _PUTCB_UTF8_MASK = 3<<5
185 } flags = _NONE;
186 NYD_ENTER;
187 n_UNUSED(buf);
189 if ((mp = message + msgno - 1) == dot)
190 flags = _ISDOT;
191 datet = mp->m_time;
192 date = NULL;
193 n_COLOUR( colo_tag = NULL; )
195 datefmt = ok_vlook(datefield);
196 jredo:
197 if (datefmt != NULL) {
198 fp = hfield1("date", mp);/* TODO use m_date field! */
199 if (fp == NULL) {
200 datefmt = NULL;
201 goto jredo;
203 datet = rfctime(fp);
204 date = fakedate(datet);
205 fp = ok_vlook(datefield_markout_older);
206 i = (*datefmt != '\0');
207 if (fp != NULL)
208 i |= (*fp != '\0') ? 2 | 4 : 2; /* XXX no magics */
210 /* May we strftime(3)? */
211 if (i & (1 | 4))
212 memcpy(&time_current.tc_local, localtime(&datet),
213 sizeof time_current.tc_local);
215 if ((i & 2) && (datet > time_current.tc_time + DATE_SECSDAY ||
216 #define _6M ((DATE_DAYSYEAR / 2) * DATE_SECSDAY)
217 (datet + _6M < time_current.tc_time))) {
218 #undef _6M
219 if ((datefmt = (i & 4) ? fp : NULL) == NULL) {
220 memset(datebuf, ' ', FROM_DATEBUF); /* xxx ur */
221 memcpy(datebuf + 4, date + 4, 7);
222 datebuf[4 + 7] = ' ';
223 memcpy(datebuf + 4 + 7 + 1, date + 20, 4);
224 datebuf[4 + 7 + 1 + 4] = '\0';
225 date = datebuf;
227 n_COLOUR( colo_tag = n_COLOUR_TAG_SUM_OLDER; )
228 } else if ((i & 1) == 0)
229 datefmt = NULL;
230 } else if (datet == (time_t)0 && !(mp->m_flag & MNOFROM)) {
231 /* TODO eliminate this path, query the FROM_ date in setptr(),
232 * TODO all other codepaths do so by themselves ALREADY ?????
233 * TODO assert(mp->m_time != 0);, then
234 * TODO ALSO changes behaviour of datefield_markout_older */
235 _parse_from_(mp, datebuf);
236 date = datebuf;
237 } else
238 date = fakedate(datet);
240 flags |= _ISADDR;
241 name = name1(mp, 0);
242 if (name != NULL && ok_blook(showto) && is_myname(skin(name))) {
243 if ((cp = hfield1("to", mp)) != NULL) {
244 name = cp;
245 flags |= _ISTO;
248 if (name == NULL) {
249 name = n_empty;
250 flags &= ~_ISADDR;
252 if (flags & _ISADDR)
253 name = ok_blook(showname) ? realname(name) : prstr(skin(name));
255 subjline = NULL;
257 /* Detect the width of the non-format characters in *headline*;
258 * like that we can simply use putc() in the next loop, since we have
259 * already calculated their column widths (TODO it's sick) */
260 wleft = subjlen = scrnwidth;
262 for (fp = fmt; *fp != '\0'; ++fp) {
263 if (*fp == '%') {
264 if (*++fp == '-')
265 ++fp;
266 else if (*fp == '+')
267 ++fp;
268 if (digitchar(*fp)) {
269 n = 0;
271 n = 10*n + *fp - '0';
272 while (++fp, digitchar(*fp));
273 subjlen -= n;
275 if (*fp == 'i')
276 flags |= _IFMT;
278 if (*fp == '\0')
279 break;
280 } else {
281 #ifdef HAVE_WCWIDTH
282 if (mb_cur_max > 1) {
283 wchar_t wc;
284 if ((s = mbtowc(&wc, fp, mb_cur_max)) == -1)
285 n = s = 1;
286 else if ((n = wcwidth(wc)) == -1)
287 n = 1;
288 } else
289 #endif
290 n = s = 1;
291 subjlen -= n;
292 wleft -= n;
293 while (--s > 0)
294 ++fp;
298 /* Walk *headline*, producing output TODO not (really) MB safe */
299 #ifdef HAVE_COLOUR
300 if (flags & _ISDOT)
301 colo_tag = n_COLOUR_TAG_SUM_DOT;
302 cpen_bas = n_colour_pen_create(n_COLOUR_ID_SUM_HEADER, colo_tag);
303 n_colour_pen_put(cpen_new = cpen_cur = cpen_bas, f);
304 #endif
306 for (fp = fmt; *fp != '\0'; ++fp) {
307 char c;
309 if ((c = *fp & 0xFF) != '%') {
310 #ifdef HAVE_COLOUR
311 if ((cpen_new = cpen_bas) != cpen_cur)
312 n_colour_pen_put(cpen_cur = cpen_new, f);
313 #endif
314 putc(c, f);
315 continue;
318 flags &= _LOOP_MASK;
319 n = 0;
320 s = 1;
321 if ((c = *++fp) == '-') {
322 s = -1;
323 ++fp;
324 } else if (c == '+')
325 ++fp;
326 if (digitchar(*fp)) {
328 n = 10*n + *fp - '0';
329 while (++fp, digitchar(*fp));
332 if ((c = *fp & 0xFF) == '\0')
333 break;
334 n *= s;
336 cbuf[1] = '\0';
337 switch (c) {
338 case '%':
339 goto jputcb;
340 case '>':
341 case '<':
342 if (flags & _ISDOT) {
343 n_COLOUR( cpen_new = n_colour_pen_create(n_COLOUR_ID_SUM_DOTMARK,
344 colo_tag); );
345 if (options & OPT_UNICODE) {
346 if (c == '>')
347 /* 25B8;BLACK RIGHT-POINTING SMALL TRIANGLE: â–¸ */
348 cbuf[1] = (char)0x96, cbuf[2] = (char)0xB8;
349 else
350 /* 25C2;BLACK LEFT-POINTING SMALL TRIANGLE: â—‚ */
351 cbuf[1] = (char)0x97, cbuf[2] = (char)0x82;
352 c = (char)0xE2;
353 cbuf[3] = '\0';
354 flags |= 2 << _PUTCB_UTF8_SHIFT;
356 } else
357 c = ' ';
358 goto jputcb;
359 case '$':
360 #ifdef HAVE_SPAM
361 if (n == 0)
362 n = 5;
363 if (UICMP(32, n_ABS(n), >, wleft))
364 n = (n < 0) ? -wleft : wleft;
365 snprintf(buf, sizeof buf, "%u.%02u",
366 (mp->m_spamscore >> 8), (mp->m_spamscore & 0xFF));
367 n = fprintf(f, "%*s", n, buf);
368 wleft = (n >= 0) ? wleft - n : 0;
369 break;
370 #else
371 c = '?';
372 goto jputcb;
373 #endif
374 case 'a':
375 c = _dispc(mp, attrlist);
376 jputcb:
377 #ifdef HAVE_COLOUR
378 if (cpen_new == cpen_cur)
379 cpen_new = cpen_bas;
380 if (cpen_new != cpen_cur)
381 n_colour_pen_put(cpen_cur = cpen_new, f);
382 #endif
383 if (UICMP(32, n_ABS(n), >, wleft))
384 n = (n < 0) ? -wleft : wleft;
385 cbuf[0] = c;
386 n = fprintf(f, "%*s", n, cbuf);
387 if (n >= 0) {
388 wleft -= n;
389 if ((n = (flags & _PUTCB_UTF8_MASK)) != 0) {
390 n >>= _PUTCB_UTF8_SHIFT;
391 wleft += n;
393 } else {
394 wleft = 0; /* TODO I/O error.. ? break? */
396 #ifdef HAVE_COLOUR
397 if ((cpen_new = cpen_bas) != cpen_cur)
398 n_colour_pen_put(cpen_cur = cpen_new, f);
399 #endif
400 break;
401 case 'd':
402 if (datefmt != NULL) {
403 i = strftime(datebuf, sizeof datebuf, datefmt,
404 &time_current.tc_local);
405 if (i != 0)
406 date = datebuf;
407 else
408 n_err(_("Ignored date format, it excesses the target "
409 "buffer (%lu bytes)\n"), (ul_i)sizeof(datebuf));
410 datefmt = NULL;
412 if (n == 0)
413 n = 16;
414 if (UICMP(32, n_ABS(n), >, wleft))
415 n = (n < 0) ? -wleft : wleft;
416 n = fprintf(f, "%*.*s", n, n, date);
417 wleft = (n >= 0) ? wleft - n : 0;
418 break;
419 case 'e':
420 if (n == 0)
421 n = 2;
422 if (UICMP(32, n_ABS(n), >, wleft))
423 n = (n < 0) ? -wleft : wleft;
424 n = fprintf(f, "%*u", n, (threaded == 1 ? mp->m_level : 0));
425 wleft = (n >= 0) ? wleft - n : 0;
426 break;
427 case 'f':
428 if (n == 0) {
429 n = 18;
430 if (s < 0)
431 n = -n;
433 i = n_ABS(n);
434 if (i > wleft) {
435 i = wleft;
436 n = (n < 0) ? -wleft : wleft;
438 if (flags & _ISTO) /* XXX tr()! */
439 i -= 3;
440 n = fprintf(f, "%s%s", ((flags & _ISTO) ? "To " : n_empty),
441 colalign(name, i, n, &wleft));
442 if (n < 0)
443 wleft = 0;
444 else if (flags & _ISTO)
445 wleft -= 3;
446 break;
447 case 'i':
448 if (threaded) {
449 #ifdef HAVE_COLOUR
450 cpen_new = n_colour_pen_create(n_COLOUR_ID_SUM_THREAD, colo_tag);
451 if (cpen_new != cpen_cur)
452 n_colour_pen_put(cpen_cur = cpen_new, f);
453 #endif
454 n = __putindent(f, mp, n_MIN(wleft, scrnwidth - 60));
455 wleft = (n >= 0) ? wleft - n : 0;
456 #ifdef HAVE_COLOUR
457 if ((cpen_new = cpen_bas) != cpen_cur)
458 n_colour_pen_put(cpen_cur = cpen_new, f);
459 #endif
461 break;
462 case 'l':
463 if (n == 0)
464 n = 4;
465 if (UICMP(32, n_ABS(n), >, wleft))
466 n = (n < 0) ? -wleft : wleft;
467 if (mp->m_xlines) {
468 n = fprintf(f, "%*ld", n, mp->m_xlines);
469 wleft = (n >= 0) ? wleft - n : 0;
470 } else {
471 n = n_ABS(n);
472 wleft -= n;
473 while (n-- != 0)
474 putc(' ', f);
476 break;
477 case 'm':
478 if (n == 0) {
479 n = 3;
480 if (threaded)
481 for (i = msgCount; i > 999; i /= 10)
482 ++n;
484 if (UICMP(32, n_ABS(n), >, wleft))
485 n = (n < 0) ? -wleft : wleft;
486 n = fprintf(f, "%*lu", n, (ul_i)msgno);
487 wleft = (n >= 0) ? wleft - n : 0;
488 break;
489 case 'o':
490 if (n == 0)
491 n = -5;
492 if (UICMP(32, n_ABS(n), >, wleft))
493 n = (n < 0) ? -wleft : wleft;
494 n = fprintf(f, "%*lu", n, (ul_i)mp->m_xsize);
495 wleft = (n >= 0) ? wleft - n : 0;
496 break;
497 case 'S':
498 flags |= _SFMT;
499 /*FALLTHRU*/
500 case 's':
501 if (n == 0)
502 n = subjlen - 2;
503 if (n > 0 && s < 0)
504 n = -n;
505 if (subjlen > wleft)
506 subjlen = wleft;
507 if (UICMP(32, n_ABS(n), >, subjlen))
508 n = (n < 0) ? -subjlen : subjlen;
509 if (flags & _SFMT)
510 n -= (n < 0) ? -2 : 2;
511 if (n == 0)
512 break;
513 if (subjline == NULL)
514 subjline = __subject(mp, (threaded && (flags & _IFMT)), yetprinted);
515 if (subjline == (char*)-1) {
516 n = fprintf(f, "%*s", n, n_empty);
517 wleft = (n >= 0) ? wleft - n : 0;
518 } else {
519 n = fprintf(f, ((flags & _SFMT) ? "\"%s\"" : "%s"),
520 colalign(subjline, n_ABS(n), n, &wleft));
521 if (n < 0)
522 wleft = 0;
524 break;
525 case 'T': { /* Message recipient flags */
526 /* We never can reuse "name" since it's the full name */
527 struct name const *np = lextract(hfield1("to", mp), GTO | GSKIN);
528 c = ' ';
529 i = 0;
530 j_A_redo:
531 for (; np != NULL; np = np->n_flink) {
532 switch (is_mlist(np->n_name, FAL0)) {
533 case MLIST_SUBSCRIBED: c = 'S'; goto jputcb;
534 case MLIST_KNOWN: c = 'L'; goto jputcb;
535 case MLIST_OTHER:
536 default: break;
539 if (i != 0)
540 goto jputcb;
541 ++i;
542 np = lextract(hfield1("cc", mp), GCC | GSKIN);
543 goto j_A_redo;
545 case 't':
546 if (n == 0) {
547 n = 3;
548 if (threaded)
549 for (i = msgCount; i > 999; i /= 10)
550 ++n;
552 if (UICMP(32, n_ABS(n), >, wleft))
553 n = (n < 0) ? -wleft : wleft;
554 n = fprintf(f, "%*lu",
555 n, (threaded ? (ul_i)mp->m_threadpos : (ul_i)msgno));
556 wleft = (n >= 0) ? wleft - n : 0;
557 break;
558 default:
559 if (options & OPT_D_V)
560 n_err(_("Unkown *headline* format: %%%c\n"), c);
561 c = '?';
562 goto jputcb;
565 if (wleft <= 0)
566 break;
569 #ifdef HAVE_COLOUR
570 n_colour_reset(f);
571 #endif
572 putc('\n', f);
574 if (subjline != NULL && subjline != (char*)-1)
575 free(subjline);
576 NYD_LEAVE;
579 static char *
580 __subject(struct message *mp, bool_t threaded, size_t yetprinted)
582 struct str in, out;
583 char *rv = (char*)-1, *ms;
584 NYD_ENTER;
586 if ((ms = hfield1("subject", mp)) == NULL)
587 goto jleave;
589 in.l = strlen(in.s = ms);
590 mime_fromhdr(&in, &out, TD_ICONV | TD_ISPR);
591 rv = ms = out.s;
593 if (!threaded || mp->m_level == 0)
594 goto jleave;
596 /* In a display thread - check whether this message uses the same
597 * Subject: as it's parent or elder neighbour, suppress printing it if
598 * this is the case. To extend this a bit, ignore any leading Re: or
599 * Fwd: plus follow-up WS. Ignore invisible messages along the way */
600 ms = subject_re_trim(ms);
602 for (; (mp = prev_in_thread(mp)) != NULL && yetprinted-- > 0;) {
603 char *os;
605 if (visible(mp) && (os = hfield1("subject", mp)) != NULL) {
606 struct str oout;
607 int x;
609 in.l = strlen(in.s = os);
610 mime_fromhdr(&in, &oout, TD_ICONV | TD_ISPR);
611 x = asccasecmp(ms, subject_re_trim(oout.s));
612 free(oout.s);
614 if (!x) {
615 free(out.s);
616 rv = (char*)-1;
618 break;
621 jleave:
622 NYD_LEAVE;
623 return rv;
626 static int
627 __putindent(FILE *fp, struct message *mp, int maxwidth)/* XXX no magic consts */
629 struct message *mq;
630 int *us, indlvl, indw, i, important = MNEW | MFLAGGED;
631 char *cs;
632 NYD_ENTER;
634 if (mp->m_level == 0 || maxwidth == 0) {
635 indw = 0;
636 goto jleave;
639 cs = ac_alloc(mp->m_level);
640 us = ac_alloc(mp->m_level * sizeof *us);
642 i = mp->m_level - 1;
643 if (mp->m_younger && UICMP(32, i + 1, ==, mp->m_younger->m_level)) {
644 if (mp->m_parent && mp->m_parent->m_flag & important)
645 us[i] = mp->m_flag & important ? 0x2523 : 0x2520;
646 else
647 us[i] = mp->m_flag & important ? 0x251D : 0x251C;
648 cs[i] = '+';
649 } else {
650 if (mp->m_parent && mp->m_parent->m_flag & important)
651 us[i] = mp->m_flag & important ? 0x2517 : 0x2516;
652 else
653 us[i] = mp->m_flag & important ? 0x2515 : 0x2514;
654 cs[i] = '\\';
657 mq = mp->m_parent;
658 for (i = mp->m_level - 2; i >= 0; --i) {
659 if (mq) {
660 if (UICMP(32, i, >, mq->m_level - 1)) {
661 us[i] = cs[i] = ' ';
662 continue;
664 if (mq->m_younger) {
665 if (mq->m_parent && (mq->m_parent->m_flag & important))
666 us[i] = 0x2503;
667 else
668 us[i] = 0x2502;
669 cs[i] = '|';
670 } else
671 us[i] = cs[i] = ' ';
672 mq = mq->m_parent;
673 } else
674 us[i] = cs[i] = ' ';
677 --maxwidth;
678 for (indlvl = indw = 0; (ui8_t)indlvl < mp->m_level && indw < maxwidth;
679 ++indlvl) {
680 if (indw < maxwidth - 1)
681 indw += (int)putuc(us[indlvl], cs[indlvl] & 0xFF, fp);
682 else
683 indw += (int)putuc(0x21B8, '^', fp);
685 indw += putuc(0x25B8, '>', fp);
687 ac_free(us);
688 ac_free(cs);
689 jleave:
690 NYD_LEAVE;
691 return indw;
694 static int
695 _dispc(struct message *mp, char const *a)
697 int i = ' ';
698 NYD_ENTER;
700 if ((mp->m_flag & (MREAD | MNEW)) == MREAD)
701 i = a[3];
702 if ((mp->m_flag & (MREAD | MNEW)) == (MREAD | MNEW))
703 i = a[2];
704 if (mp->m_flag & MANSWERED)
705 i = a[8];
706 if (mp->m_flag & MDRAFTED)
707 i = a[9];
708 if ((mp->m_flag & (MREAD | MNEW)) == MNEW)
709 i = a[0];
710 if (!(mp->m_flag & (MREAD | MNEW)))
711 i = a[1];
712 if (mp->m_flag & MSPAM)
713 i = a[12];
714 if (mp->m_flag & MSPAMUNSURE)
715 i = a[13];
716 if (mp->m_flag & MSAVED)
717 i = a[4];
718 if (mp->m_flag & MPRESERVE)
719 i = a[5];
720 if (mp->m_flag & (MBOX | MBOXED))
721 i = a[6];
722 if (mp->m_flag & MFLAGGED)
723 i = a[7];
724 if (mb.mb_threaded == 1 && mp->m_collapsed > 0)
725 i = a[11];
726 if (mb.mb_threaded == 1 && mp->m_collapsed < 0)
727 i = a[10];
728 NYD_LEAVE;
729 return i;
732 static int
733 a_cmd_scroll(char const *arg, bool_t onlynew){
734 long l;
735 char *eptr;
736 bool_t isabs;
737 int msgspec, size, maxs;
738 NYD2_ENTER;
740 /* TODO scroll problem: we do not know whether + and $ have already reached
741 * TODO the last screen in threaded mode */
742 msgspec = onlynew ? -1 : 0;
743 size = screensize();
744 if((maxs = msgCount / size) > 0 && msgCount % size == 0)
745 --maxs;
747 switch(*arg){
748 case '\0':
749 ++_screen;
750 goto jfwd;
751 case '^':
752 if(arg[1] != '\0')
753 goto jerr;
754 if(_screen == 0)
755 goto jerrbwd;
756 _screen = 0;
757 break;
758 case '$':
759 if(arg[1] != '\0')
760 goto jerr;
761 if(_screen == maxs)
762 goto jerrfwd;
763 _screen = maxs;
764 break;
765 case '+':
766 if(arg[1] == '\0')
767 ++_screen;
768 else{
769 isabs = FAL0;
771 ++arg;
772 if(0){
773 case '1': case '2': case '3': case '4': case '5':
774 case '6': case '7': case '8': case '9': case '0':
775 isabs = TRU1;
777 l = strtol(arg, &eptr, 10);
778 if(*eptr != '\0')
779 goto jerr;
780 if(l > maxs - (isabs ? 0 : _screen))
781 goto jerrfwd;
782 _screen = isabs ? (int)l : _screen + l;
784 jfwd:
785 if(_screen > maxs){
786 jerrfwd:
787 _screen = maxs;
788 printf(_("On last screenful of messages\n"));
790 break;
792 case '-':
793 if(arg[1] == '\0')
794 --_screen;
795 else{
796 ++arg;
797 l = strtol(arg, &eptr, 10);
798 if(*eptr != '\0')
799 goto jerr;
800 if(l > _screen)
801 goto jerrbwd;
802 _screen -= l;
804 if(_screen < 0){
805 jerrbwd:
806 _screen = 0;
807 printf(_("On first screenful of messages\n"));
809 if(msgspec == -1)
810 msgspec = -2;
811 break;
812 default:
813 jerr:
814 n_err(_("Unrecognized scrolling command: %s\n"), arg);
815 size = 1;
816 goto jleave;
819 size = _headers(msgspec);
820 jleave:
821 NYD2_LEAVE;
822 return size;
825 static int
826 _headers(int msgspec) /* TODO rework v15 */
828 struct n_sigman sm;
829 bool_t volatile isrelax;
830 ui32_t volatile flag;
831 int g, k, mesg, size;
832 int volatile lastg = 1;
833 struct message *mp, *mq, *lastmq = NULL;
834 enum mflag fl = MNEW | MFLAGGED;
835 NYD_ENTER;
837 time_current_update(&time_current, FAL0);
839 flag = 0;
840 isrelax = FAL0;
841 n_SIGMAN_ENTER_SWITCH(&sm, n_SIGMAN_ALL) {
842 case 0:
843 break;
844 default:
845 goto jleave;
848 #ifdef HAVE_COLOUR
849 if (options & OPT_INTERACTIVE)
850 n_colour_env_create(n_COLOUR_CTX_SUM, FAL0);
851 #endif
853 size = screensize();
854 if (_screen < 0)
855 _screen = 0;
856 #if 0 /* FIXME original code path */
857 k = _screen * size;
858 #else
859 if (msgspec <= 0)
860 k = _screen * size;
861 else
862 k = msgspec;
863 #endif
864 if (k >= msgCount)
865 k = msgCount - size;
866 if (k < 0)
867 k = 0;
869 if (mb.mb_threaded == 0) {
870 g = 0;
871 mq = message;
872 for (mp = message; PTRCMP(mp, <, message + msgCount); ++mp)
873 if (visible(mp)) {
874 if (g % size == 0)
875 mq = mp;
876 if (mp->m_flag & fl) {
877 lastg = g;
878 lastmq = mq;
880 if ((msgspec > 0 && PTRCMP(mp, ==, message + msgspec - 1)) ||
881 (msgspec == 0 && g == k) ||
882 (msgspec == -2 && g == k + size && lastmq) ||
883 (msgspec < 0 && g >= k && (mp->m_flag & fl) != 0))
884 break;
885 g++;
887 if (lastmq && (msgspec == -2 ||
888 (msgspec == -1 && PTRCMP(mp, ==, message + msgCount)))) {
889 g = lastg;
890 mq = lastmq;
892 _screen = g / size;
894 mp = mq;
895 mesg = (int)PTR2SIZE(mp - message);
896 if (PTRCMP(dot, !=, message + msgspec - 1)) { /* TODO really?? */
897 for (mq = mp; PTRCMP(mq, <, message + msgCount); ++mq)
898 if (visible(mq)) {
899 setdot(mq);
900 break;
904 srelax_hold();
905 isrelax = TRU1;
906 for (; PTRCMP(mp, <, message + msgCount); ++mp) {
907 ++mesg;
908 if (!visible(mp))
909 continue;
910 if (UICMP(32, flag++, >=, size))
911 break;
912 _print_head(0, mesg, stdout, 0);
913 srelax();
915 srelax_rele();
916 isrelax = FAL0;
917 } else { /* threaded */
918 g = 0;
919 mq = threadroot;
920 for (mp = threadroot; mp; mp = next_in_thread(mp))
921 if (visible(mp) &&
922 (mp->m_collapsed <= 0 ||
923 PTRCMP(mp, ==, message + msgspec - 1))) {
924 if (g % size == 0)
925 mq = mp;
926 if (mp->m_flag & fl) {
927 lastg = g;
928 lastmq = mq;
930 if ((msgspec > 0 && PTRCMP(mp, ==, message + msgspec - 1)) ||
931 (msgspec == 0 && g == k) ||
932 (msgspec == -2 && g == k + size && lastmq) ||
933 (msgspec < 0 && g >= k && (mp->m_flag & fl) != 0))
934 break;
935 g++;
937 if (lastmq && (msgspec == -2 ||
938 (msgspec == -1 && PTRCMP(mp, ==, message + msgCount)))) {
939 g = lastg;
940 mq = lastmq;
942 _screen = g / size;
943 mp = mq;
944 if (PTRCMP(dot, !=, message + msgspec - 1)) { /* TODO really?? */
945 for (mq = mp; mq; mq = next_in_thread(mq))
946 if (visible(mq) && mq->m_collapsed <= 0) {
947 setdot(mq);
948 break;
952 srelax_hold();
953 isrelax = TRU1;
954 while (mp) {
955 if (visible(mp) &&
956 (mp->m_collapsed <= 0 ||
957 PTRCMP(mp, ==, message + msgspec - 1))) {
958 if (UICMP(32, flag++, >=, size))
959 break;
960 _print_head(flag - 1, PTR2SIZE(mp - message + 1), stdout,
961 mb.mb_threaded);
962 srelax();
964 mp = next_in_thread(mp);
966 srelax_rele();
967 isrelax = FAL0;
970 if (!flag) {
971 printf(_("No more mail.\n"));
972 if (pstate & (PS_HOOK_MASK | PS_ROBOT))
973 flag = !flag;
976 n_sigman_cleanup_ping(&sm);
977 jleave:
978 if (isrelax)
979 srelax_rele();
980 n_COLOUR( n_colour_env_gut((sm.sm_signo != SIGPIPE) ? stdout : NULL); )
981 NYD_LEAVE;
982 n_sigman_leave(&sm, n_SIGMAN_VIPSIGS_NTTYOUT);
983 return !flag;
986 static int
987 _type1(int *msgvec, bool_t doign, bool_t dopage, bool_t dopipe,
988 bool_t dodecode, char *cmd, ui64_t *tstats)
990 struct n_sigman sm;
991 ui64_t mstats[1];
992 int volatile rv = 1;
993 int *ip;
994 struct message *mp;
995 char const *cp;
996 FILE * volatile obuf;
997 bool_t volatile isrelax = FAL0;
998 NYD_ENTER;
999 {/* C89.. */
1000 enum sendaction const action = ((dopipe && ok_blook(piperaw))
1001 ? SEND_MBOX : dodecode
1002 ? SEND_SHOW : doign
1003 ? SEND_TODISP : SEND_TODISP_ALL);
1004 bool_t const volatile formfeed = (dopipe && ok_blook(page));
1005 obuf = stdout;
1007 n_SIGMAN_ENTER_SWITCH(&sm, n_SIGMAN_ALL) {
1008 case 0:
1009 break;
1010 default:
1011 goto jleave;
1014 if (dopipe) {
1015 if ((obuf = Popen(cmd, "w", ok_vlook(SHELL), NULL, 1)) == NULL) {
1016 n_perr(cmd, 0);
1017 obuf = stdout;
1019 } else if ((options & OPT_TTYOUT) && (dopage ||
1020 ((options & OPT_INTERACTIVE) && (cp = ok_vlook(crt)) != NULL))) {
1021 size_t nlines = 0;
1023 if (!dopage) {
1024 for (ip = msgvec; *ip && PTRCMP(ip - msgvec, <, msgCount); ++ip) {
1025 mp = message + *ip - 1;
1026 if (!(mp->m_have & HAVE_BODY))
1027 if (get_body(mp) != OKAY)
1028 goto jcleanup_leave;
1029 nlines += mp->m_lines + 1; /* Message info XXX and PARTS... */
1033 /* >= not <: we return to the prompt */
1034 if (dopage || UICMP(z, nlines, >=,
1035 (*cp != '\0' ? strtoul(cp, NULL, 0) : (size_t)realscreenheight))) {
1036 if ((obuf = n_pager_open()) == NULL)
1037 obuf = stdout;
1039 #ifdef HAVE_COLOUR
1040 if ((options & OPT_INTERACTIVE) &&
1041 (action == SEND_TODISP || action == SEND_TODISP_ALL ||
1042 action == SEND_SHOW))
1043 n_colour_env_create(n_COLOUR_CTX_VIEW, obuf != stdout);
1044 #endif
1046 #ifdef HAVE_COLOUR
1047 else if ((options & OPT_INTERACTIVE) &&
1048 (action == SEND_TODISP || action == SEND_TODISP_ALL))
1049 n_colour_env_create(n_COLOUR_CTX_VIEW, FAL0);
1050 #endif
1052 /*TODO unless we have our signal manager special care must be taken */
1053 srelax_hold();
1054 isrelax = TRU1;
1055 for (ip = msgvec; *ip && PTRCMP(ip - msgvec, <, msgCount); ++ip) {
1056 mp = message + *ip - 1;
1057 touch(mp);
1058 setdot(mp);
1059 pstate |= PS_DID_PRINT_DOT;
1060 uncollapse1(mp, 1);
1061 if (!dopipe && ip != msgvec)
1062 fprintf(obuf, "\n");
1063 if (action != SEND_MBOX)
1064 _show_msg_overview(obuf, mp, *ip);
1065 sendmp(mp, obuf, (doign ? n_IGNORE_TYPE : NULL), NULL, action, mstats);
1066 srelax();
1067 if (formfeed) /* TODO a nicer way to separate piped messages! */
1068 putc('\f', obuf);
1069 if (tstats != NULL)
1070 tstats[0] += mstats[0];
1072 srelax_rele();
1073 isrelax = FAL0;
1075 rv = 0;
1076 jcleanup_leave:
1077 n_sigman_cleanup_ping(&sm);
1078 jleave:
1079 if (isrelax)
1080 srelax_rele();
1081 n_COLOUR( n_colour_env_gut((sm.sm_signo != SIGPIPE) ? obuf : NULL); )
1082 if (obuf != stdout)
1083 n_pager_close(obuf);
1085 NYD_LEAVE;
1086 n_sigman_leave(&sm, n_SIGMAN_VIPSIGS_NTTYOUT);
1087 return rv;
1090 static int
1091 _pipe1(char *str, int doign)
1093 ui64_t stats[1];
1094 char const *cmd, *cmdq;
1095 int *msgvec, rv = 1;
1096 bool_t needs_list;
1097 NYD_ENTER;
1099 if ((cmd = laststring(str, &needs_list, TRU1)) == NULL) {
1100 cmd = ok_vlook(cmd);
1101 if (cmd == NULL || *cmd == '\0') {
1102 n_err(_("Variable *cmd* not set\n"));
1103 goto jleave;
1107 msgvec = salloc((msgCount + 2) * sizeof *msgvec);
1109 if (!needs_list) {
1110 *msgvec = first(0, MMNORM);
1111 if (*msgvec == 0) {
1112 if (pstate & (PS_HOOK_MASK | PS_ROBOT)) {
1113 rv = 0;
1114 goto jleave;
1116 puts(_("No messages to pipe."));
1117 goto jleave;
1119 msgvec[1] = 0;
1120 } else if (getmsglist(str, msgvec, 0) < 0)
1121 goto jleave;
1122 if (*msgvec == 0) {
1123 if (pstate & (PS_HOOK_MASK | PS_ROBOT)) {
1124 rv = 0;
1125 goto jleave;
1127 printf("No applicable messages.\n");
1128 goto jleave;
1131 cmdq = n_shexp_quote_cp(cmd, FAL0);
1132 printf(_("Pipe to: %s\n"), cmdq);
1133 stats[0] = 0;
1134 if ((rv = _type1(msgvec, doign, FAL0, TRU1, FAL0, n_UNCONST(cmd), stats)
1135 ) == 0)
1136 printf("%s %" PRIu64 " bytes\n", cmdq, stats[0]);
1137 jleave:
1138 NYD_LEAVE;
1139 return rv;
1142 static int
1143 a_cmd_top(void *vp, struct n_ignore const *itp){
1144 struct n_string s;
1145 int *msgvec, *ip;
1146 enum{a_NONE, a_SQUEEZE = 1u<<0,
1147 a_EMPTY = 1u<<8, a_STOP = 1u<<9, a_WORKMASK = 0xFF00u} f;
1148 size_t tmax, plines;
1149 FILE *iobuf, *pbuf;
1150 NYD2_ENTER;
1152 if((iobuf = Ftmp(NULL, "topio", OF_RDWR | OF_UNLINK | OF_REGISTER)) == NULL){
1153 n_perr(_("`top': I/O temporary file"), 0);
1154 vp = NULL;
1155 goto jleave;
1157 if((pbuf = Ftmp(NULL, "toppag", OF_RDWR | OF_UNLINK | OF_REGISTER)) == NULL){
1158 n_perr(_("`top': temporary pager file"), 0);
1159 vp = NULL;
1160 goto jleave1;
1163 /* TODO In v15 we should query the m_message object, and directly send only
1164 * TODO those parts, optionally over empty-line-squeeze and quote-strip
1165 * TODO filters, in which we are interested in: only text content!
1166 * TODO And: with *topsqueeze*, header/content separating empty line.. */
1167 pstate &= ~PS_MSGLIST_DIRECT; /* TODO NO ATTACHMENTS */
1168 plines = 0;
1170 #ifdef HAVE_COLOUR
1171 if (options & OPT_INTERACTIVE)
1172 n_colour_env_create(n_COLOUR_CTX_VIEW, TRU1);
1173 #endif
1174 n_string_creat_auto(&s);
1175 /* C99 */{
1176 long l;
1178 if((l = strtol(ok_vlook(toplines), NULL, 0)) <= 0){
1179 tmax = (size_t)screensize();
1180 if(l < 0){
1181 l = n_ABS(l);
1182 tmax >>= l;
1184 }else
1185 tmax = (size_t)l;
1187 f = ok_blook(topsqueeze) ? a_SQUEEZE : a_NONE;
1189 for(ip = msgvec = vp;
1190 *ip != 0 && UICMP(z, PTR2SIZE(ip - msgvec), <, msgCount); ++ip){
1191 struct message *mp;
1193 mp = &message[*ip - 1];
1194 touch(mp);
1195 setdot(mp);
1196 pstate |= PS_DID_PRINT_DOT;
1197 uncollapse1(mp, 1);
1199 rewind(iobuf);
1200 if(ftruncate(fileno(iobuf), 0)){
1201 n_perr(_("`top': ftruncate(2)"), 0);
1202 vp = NULL;
1203 break;
1205 if(sendmp(mp, iobuf, itp, NULL, SEND_TODISP_ALL, NULL) < 0){
1206 n_err(_("`top': failed to prepare message %d\n"), *ip);
1207 vp = NULL;
1208 break;
1210 fflush_rewind(iobuf);
1212 _show_msg_overview(pbuf, mp, *ip);
1213 ++plines;
1214 /* C99 */{
1215 size_t l;
1217 n_string_trunc(&s, 0);
1218 for(l = 0, f &= ~a_WORKMASK; !(f & a_STOP);){
1219 int c;
1221 if((c = getc(iobuf)) == EOF){
1222 f |= a_STOP;
1223 c = '\n';
1226 if(c != '\n')
1227 n_string_push_c(&s, c);
1228 else if((f & a_SQUEEZE) && s.s_len == 0){
1229 if(!(f & a_STOP) && ((f & a_EMPTY) || tmax - 1 <= l))
1230 continue;
1231 if(putc('\n', pbuf) == EOF){
1232 vp = NULL;
1233 break;
1235 f |= a_EMPTY;
1236 ++l;
1237 }else{
1238 char const *cp, *xcp;
1240 cp = n_string_cp_const(&s);
1241 /* TODO Brute simple skip part overviews; see above.. */
1242 if(!(f & a_SQUEEZE))
1243 c = '\1';
1244 else if(s.s_len > 8 &&
1245 (xcp = strstr(cp, "[-- ")) != NULL &&
1246 strstr(&xcp[1], " --]") != NULL)
1247 c = '\0';
1248 else for(; (c = *cp) != '\0'; ++cp){
1249 if(!asciichar(c))
1250 break;
1251 if(!blankspacechar(c)){
1252 if(!ISQUOTE(c))
1253 break;
1254 c = '\0';
1255 break;
1259 if(c != '\0'){
1260 if(fputs(n_string_cp_const(&s), pbuf) == EOF ||
1261 putc('\n', pbuf) == EOF){
1262 vp = NULL;
1263 break;
1265 if(++l >= tmax)
1266 break;
1267 f &= ~a_EMPTY;
1268 }else
1269 f |= a_EMPTY;
1270 n_string_trunc(&s, 0);
1273 if(vp == NULL)
1274 break;
1275 if(l > 0)
1276 plines += l;
1277 else{
1278 if(!(f & a_EMPTY) && putc('\n', pbuf) == EOF){
1279 vp = NULL;
1280 break;
1282 ++plines;
1287 n_string_gut(&s);
1288 n_COLOUR( n_colour_env_gut(pbuf); )
1290 fflush(pbuf);
1291 page_or_print(pbuf, plines);
1293 Fclose(pbuf);
1294 jleave1:
1295 Fclose(iobuf);
1296 jleave:
1297 NYD2_LEAVE;
1298 return (vp != NULL);
1301 FL int
1302 c_cmdnotsupp(void *v) /* TODO -> lex.c */
1304 NYD_ENTER;
1305 n_UNUSED(v);
1306 n_err(_("The requested feature is not compiled in\n"));
1307 NYD_LEAVE;
1308 return 1;
1311 FL int
1312 c_headers(void *v)
1314 int rv;
1315 NYD_ENTER;
1317 rv = print_header_group((int*)v);
1318 NYD_LEAVE;
1319 return rv;
1322 FL int
1323 print_header_group(int *vector)
1325 int rv;
1326 NYD_ENTER;
1328 assert(vector != NULL && vector != (void*)-1);
1329 rv = _headers(vector[0]);
1330 NYD_LEAVE;
1331 return rv;
1334 FL int
1335 c_scroll(void *v)
1337 int rv;
1338 NYD_ENTER;
1340 rv = a_cmd_scroll(v, FAL0);
1341 NYD_LEAVE;
1342 return rv;
1345 FL int
1346 c_Scroll(void *v)
1348 int rv;
1349 NYD_ENTER;
1351 rv = a_cmd_scroll(v, TRU1);
1352 NYD_LEAVE;
1353 return rv;
1356 FL int
1357 c_from(void *v)
1359 struct n_sigman sm;
1360 int *msgvec = v, *ip, n;
1361 char *cp;
1362 FILE * volatile obuf;
1363 bool_t volatile isrelax;
1364 NYD_ENTER;
1366 time_current_update(&time_current, FAL0);
1368 obuf = stdout;
1369 isrelax = FAL0;
1370 n_SIGMAN_ENTER_SWITCH(&sm, n_SIGMAN_ALL) {
1371 case 0:
1372 break;
1373 default:
1374 goto jleave;
1377 if (options & OPT_INTERACTIVE) {
1378 if ((cp = ok_vlook(crt)) != NULL) {
1379 for (n = 0, ip = msgvec; *ip != 0; ++ip)
1380 ++n;
1381 if (UICMP(z, n, >, (*cp == '\0'
1382 ? (size_t)screensize() : strtoul(cp, NULL, 0)) + 3) &&
1383 (obuf = n_pager_open()) == NULL)
1384 obuf = stdout;
1386 n_COLOUR( n_colour_env_create(n_COLOUR_CTX_SUM, obuf != stdout); )
1389 /* Update dot before display so that the dotmark etc. are correct */
1390 for (ip = msgvec; *ip != 0; ++ip)
1392 if (--ip >= msgvec)
1393 setdot(message + *ip - 1);
1395 srelax_hold();
1396 isrelax = TRU1;
1397 for (n = 0, ip = msgvec; *ip != 0; ++ip) { /* TODO join into _print_head() */
1398 _print_head((size_t)n++, (size_t)*ip, obuf, mb.mb_threaded);
1399 srelax();
1401 srelax_rele();
1402 isrelax = FAL0;
1404 n_sigman_cleanup_ping(&sm);
1405 jleave:
1406 if (isrelax)
1407 srelax_rele();
1408 n_COLOUR( n_colour_env_gut((sm.sm_signo != SIGPIPE) ? obuf : NULL); )
1409 if (obuf != stdout)
1410 n_pager_close(obuf);
1411 NYD_LEAVE;
1412 n_sigman_leave(&sm, n_SIGMAN_VIPSIGS_NTTYOUT);
1413 return 0;
1416 FL void
1417 print_headers(size_t bottom, size_t topx, bool_t only_marked)
1419 struct n_sigman sm;
1420 bool_t volatile isrelax;
1421 size_t printed;
1422 NYD_ENTER;
1424 time_current_update(&time_current, FAL0);
1426 isrelax = FAL0;
1427 n_SIGMAN_ENTER_SWITCH(&sm, n_SIGMAN_ALL) {
1428 case 0:
1429 break;
1430 default:
1431 goto jleave;
1434 #ifdef HAVE_COLOUR
1435 if (options & OPT_INTERACTIVE)
1436 n_colour_env_create(n_COLOUR_CTX_SUM, FAL0);
1437 #endif
1439 srelax_hold();
1440 isrelax = TRU1;
1441 for (printed = 0; bottom <= topx; ++bottom) {
1442 struct message *mp = message + bottom - 1;
1443 if (only_marked) {
1444 if (!(mp->m_flag & MMARK))
1445 continue;
1446 } else if (!visible(mp))
1447 continue;
1448 _print_head(printed++, bottom, stdout, FAL0);
1449 srelax();
1451 srelax_rele();
1452 isrelax = FAL0;
1454 n_sigman_cleanup_ping(&sm);
1455 jleave:
1456 if (isrelax)
1457 srelax_rele();
1458 n_COLOUR( n_colour_env_gut((sm.sm_signo != SIGPIPE) ? stdout : NULL); )
1459 NYD_LEAVE;
1460 n_sigman_leave(&sm, n_SIGMAN_VIPSIGS_NTTYOUT);
1463 FL int
1464 c_pdot(void *v)
1466 NYD_ENTER;
1467 n_UNUSED(v);
1468 printf("%d\n", (int)PTR2SIZE(dot - message + 1));
1469 NYD_LEAVE;
1470 return 0;
1473 FL int
1474 c_more(void *v)
1476 int *msgvec = v, rv;
1477 NYD_ENTER;
1479 rv = _type1(msgvec, TRU1, TRU1, FAL0, FAL0, NULL, NULL);
1480 NYD_LEAVE;
1481 return rv;
1484 FL int
1485 c_More(void *v)
1487 int *msgvec = v, rv;
1488 NYD_ENTER;
1490 rv = _type1(msgvec, FAL0, TRU1, FAL0, FAL0, NULL, NULL);
1491 NYD_LEAVE;
1492 return rv;
1495 FL int
1496 c_type(void *v)
1498 int *msgvec = v, rv;
1499 NYD_ENTER;
1501 rv = _type1(msgvec, TRU1, FAL0, FAL0, FAL0, NULL, NULL);
1502 NYD_LEAVE;
1503 return rv;
1506 FL int
1507 c_Type(void *v)
1509 int *msgvec = v, rv;
1510 NYD_ENTER;
1512 rv = _type1(msgvec, FAL0, FAL0, FAL0, FAL0, NULL, NULL);
1513 NYD_LEAVE;
1514 return rv;
1517 FL int
1518 c_show(void *v)
1520 int *msgvec = v, rv;
1521 NYD_ENTER;
1523 rv = _type1(msgvec, FAL0, FAL0, FAL0, TRU1, NULL, NULL);
1524 NYD_LEAVE;
1525 return rv;
1528 FL int
1529 c_pipe(void *v)
1531 char *str = v;
1532 int rv;
1533 NYD_ENTER;
1535 rv = _pipe1(str, 1);
1536 NYD_LEAVE;
1537 return rv;
1540 FL int
1541 c_Pipe(void *v)
1543 char *str = v;
1544 int rv;
1545 NYD_ENTER;
1547 rv = _pipe1(str, 0);
1548 NYD_LEAVE;
1549 return rv;
1552 FL int
1553 c_top(void *v){
1554 struct n_ignore *itp;
1555 int rv;
1556 NYD_ENTER;
1558 if(n_ignore_is_any(n_IGNORE_TOP))
1559 itp = n_IGNORE_TOP;
1560 else{
1561 itp = n_ignore_new(TRU1);
1562 n_ignore_insert(itp, TRU1, "from", sizeof("from") -1);
1563 n_ignore_insert(itp, TRU1, "to", sizeof("to") -1);
1564 n_ignore_insert(itp, TRU1, "cc", sizeof("cc") -1);
1565 n_ignore_insert(itp, TRU1, "subject", sizeof("subject") -1);
1568 rv = !a_cmd_top(v, itp);
1569 NYD_LEAVE;
1570 return rv;
1573 FL int
1574 c_Top(void *v){
1575 int rv;
1576 NYD_ENTER;
1578 rv = !a_cmd_top(v, n_IGNORE_TYPE);
1579 NYD_LEAVE;
1580 return rv;
1583 FL int
1584 c_folders(void *v)
1586 char const *cp;
1587 char **argv;
1588 int rv;
1589 NYD_ENTER;
1591 rv = 1;
1593 if(*(argv = v) != NULL){
1594 if((cp = fexpand(*argv, FEXP_NSHELL | FEXP_LOCAL)) == NULL)
1595 goto jleave;
1596 }else
1597 cp = folder_query();
1599 rv = run_command(ok_vlook(LISTER), 0, COMMAND_FD_PASS, COMMAND_FD_PASS, cp,
1600 NULL, NULL, NULL);
1601 if(rv < 0)
1602 rv = 1; /* XXX */
1603 jleave:
1604 NYD_LEAVE;
1605 return rv;
1608 /* s-it-mode */