`write'++: !interactive: urlxenc() attachment paths (Ralph Corderoy)..
[s-mailx.git] / cmd1.c
blobb1e017ca8e23acd7eb2dac4796673dcfc48ffeea
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
180 } flags = _NONE;
181 NYD_ENTER;
182 UNUSED(buf);
184 if ((mp = message + msgno - 1) == dot)
185 flags = _ISDOT;
186 datet = mp->m_time;
187 date = NULL;
188 n_COLOUR( colo_tag = NULL; )
190 datefmt = ok_vlook(datefield);
191 jredo:
192 if (datefmt != NULL) {
193 fp = hfield1("date", mp);/* TODO use m_date field! */
194 if (fp == NULL) {
195 datefmt = NULL;
196 goto jredo;
198 datet = rfctime(fp);
199 date = fakedate(datet);
200 fp = ok_vlook(datefield_markout_older);
201 i = (*datefmt != '\0');
202 if (fp != NULL)
203 i |= (*fp != '\0') ? 2 | 4 : 2; /* XXX no magics */
205 /* May we strftime(3)? */
206 if (i & (1 | 4))
207 memcpy(&time_current.tc_local, localtime(&datet),
208 sizeof time_current.tc_local);
210 if ((i & 2) && (datet > time_current.tc_time + DATE_SECSDAY ||
211 #define _6M ((DATE_DAYSYEAR / 2) * DATE_SECSDAY)
212 (datet + _6M < time_current.tc_time))) {
213 #undef _6M
214 if ((datefmt = (i & 4) ? fp : NULL) == NULL) {
215 memset(datebuf, ' ', FROM_DATEBUF); /* xxx ur */
216 memcpy(datebuf + 4, date + 4, 7);
217 datebuf[4 + 7] = ' ';
218 memcpy(datebuf + 4 + 7 + 1, date + 20, 4);
219 datebuf[4 + 7 + 1 + 4] = '\0';
220 date = datebuf;
222 n_COLOUR( colo_tag = n_COLOUR_TAG_SUM_OLDER; )
223 } else if ((i & 1) == 0)
224 datefmt = NULL;
225 } else if (datet == (time_t)0 && !(mp->m_flag & MNOFROM)) {
226 /* TODO eliminate this path, query the FROM_ date in setptr(),
227 * TODO all other codepaths do so by themselves ALREADY ?????
228 * TODO assert(mp->m_time != 0);, then
229 * TODO ALSO changes behaviour of datefield_markout_older */
230 _parse_from_(mp, datebuf);
231 date = datebuf;
232 } else
233 date = fakedate(datet);
235 flags |= _ISADDR;
236 name = name1(mp, 0);
237 if (name != NULL && ok_blook(showto) && is_myname(skin(name))) {
238 if ((cp = hfield1("to", mp)) != NULL) {
239 name = cp;
240 flags |= _ISTO;
243 if (name == NULL) {
244 name = "";
245 flags &= ~_ISADDR;
247 if (flags & _ISADDR)
248 name = ok_blook(showname) ? realname(name) : prstr(skin(name));
250 subjline = NULL;
252 /* Detect the width of the non-format characters in *headline*;
253 * like that we can simply use putc() in the next loop, since we have
254 * already calculated their column widths (TODO it's sick) */
255 wleft = subjlen = scrnwidth;
257 for (fp = fmt; *fp != '\0'; ++fp) {
258 if (*fp == '%') {
259 if (*++fp == '-')
260 ++fp;
261 else if (*fp == '+')
262 ++fp;
263 if (digitchar(*fp)) {
264 n = 0;
266 n = 10*n + *fp - '0';
267 while (++fp, digitchar(*fp));
268 subjlen -= n;
270 if (*fp == 'i')
271 flags |= _IFMT;
273 if (*fp == '\0')
274 break;
275 } else {
276 #ifdef HAVE_WCWIDTH
277 if (mb_cur_max > 1) {
278 wchar_t wc;
279 if ((s = mbtowc(&wc, fp, mb_cur_max)) == -1)
280 n = s = 1;
281 else if ((n = wcwidth(wc)) == -1)
282 n = 1;
283 } else
284 #endif
285 n = s = 1;
286 subjlen -= n;
287 wleft -= n;
288 while (--s > 0)
289 ++fp;
293 /* Walk *headline*, producing output TODO not (really) MB safe */
294 #ifdef HAVE_COLOUR
295 if (flags & _ISDOT)
296 colo_tag = n_COLOUR_TAG_SUM_DOT;
297 cpen_bas = n_colour_pen_create(n_COLOUR_ID_SUM_HEADER, colo_tag);
298 n_colour_pen_put(cpen_new = cpen_cur = cpen_bas, f);
299 #endif
301 for (fp = fmt; *fp != '\0'; ++fp) {
302 char c;
304 if ((c = *fp & 0xFF) != '%') {
305 #ifdef HAVE_COLOUR
306 if ((cpen_new = cpen_bas) != cpen_cur)
307 n_colour_pen_put(cpen_cur = cpen_new, f);
308 #endif
309 putc(c, f);
310 continue;
313 flags &= _LOOP_MASK;
314 n = 0;
315 s = 1;
316 if ((c = *++fp) == '-') {
317 s = -1;
318 ++fp;
319 } else if (c == '+')
320 ++fp;
321 if (digitchar(*fp)) {
323 n = 10*n + *fp - '0';
324 while (++fp, digitchar(*fp));
327 if ((c = *fp & 0xFF) == '\0')
328 break;
329 n *= s;
331 cbuf[1] = '\0';
332 switch (c) {
333 case '%':
334 goto jputcb;
335 case '>':
336 case '<':
337 if (flags & _ISDOT) {
338 n_COLOUR( cpen_new = n_colour_pen_create(n_COLOUR_ID_SUM_DOTMARK,
339 colo_tag); );
340 if (options & OPT_UNICODE) {
341 if (c == '>')
342 /* 25B8;BLACK RIGHT-POINTING SMALL TRIANGLE: â–¸ */
343 cbuf[1] = (char)0x96, cbuf[2] = (char)0xB8;
344 else
345 /* 25C2;BLACK LEFT-POINTING SMALL TRIANGLE: â—‚ */
346 cbuf[1] = (char)0x97, cbuf[2] = (char)0x82;
347 c = (char)0xE2;
348 cbuf[3] = '\0';
350 } else
351 c = ' ';
352 goto jputcb;
353 case '$':
354 #ifdef HAVE_SPAM
355 if (n == 0)
356 n = 5;
357 if (UICMP(32, ABS(n), >, wleft))
358 n = (n < 0) ? -wleft : wleft;
359 snprintf(buf, sizeof buf, "%u.%02u",
360 (mp->m_spamscore >> 8), (mp->m_spamscore & 0xFF));
361 n = fprintf(f, "%*s", n, buf);
362 wleft = (n >= 0) ? wleft - n : 0;
363 break;
364 #else
365 c = '?';
366 goto jputcb;
367 #endif
368 case 'a':
369 c = _dispc(mp, attrlist);
370 jputcb:
371 #ifdef HAVE_COLOUR
372 if (cpen_new == cpen_cur)
373 cpen_new = cpen_bas;
374 if (cpen_new != cpen_cur)
375 n_colour_pen_put(cpen_cur = cpen_new, f);
376 #endif
377 if (UICMP(32, ABS(n), >, wleft))
378 n = (n < 0) ? -wleft : wleft;
379 cbuf[0] = c;
380 n = fprintf(f, "%*s", n, cbuf);
381 wleft = (n >= 0) ? wleft - n : 0;
382 #ifdef HAVE_COLOUR
383 if ((cpen_new = cpen_bas) != cpen_cur)
384 n_colour_pen_put(cpen_cur = cpen_new, f);
385 #endif
386 break;
387 case 'd':
388 if (datefmt != NULL) {
389 i = strftime(datebuf, sizeof datebuf, datefmt,
390 &time_current.tc_local);
391 if (i != 0)
392 date = datebuf;
393 else
394 n_err(_("Ignored date format, it excesses the target "
395 "buffer (%lu bytes)\n"), (ul_i)sizeof(datebuf));
396 datefmt = NULL;
398 if (n == 0)
399 n = 16;
400 if (UICMP(32, ABS(n), >, wleft))
401 n = (n < 0) ? -wleft : wleft;
402 n = fprintf(f, "%*.*s", n, n, date);
403 wleft = (n >= 0) ? wleft - n : 0;
404 break;
405 case 'e':
406 if (n == 0)
407 n = 2;
408 if (UICMP(32, ABS(n), >, wleft))
409 n = (n < 0) ? -wleft : wleft;
410 n = fprintf(f, "%*u", n, (threaded == 1 ? mp->m_level : 0));
411 wleft = (n >= 0) ? wleft - n : 0;
412 break;
413 case 'f':
414 if (n == 0) {
415 n = 18;
416 if (s < 0)
417 n = -n;
419 i = ABS(n);
420 if (i > wleft) {
421 i = wleft;
422 n = (n < 0) ? -wleft : wleft;
424 if (flags & _ISTO) /* XXX tr()! */
425 i -= 3;
426 n = fprintf(f, "%s%s", ((flags & _ISTO) ? "To " : ""),
427 colalign(name, i, n, &wleft));
428 if (n < 0)
429 wleft = 0;
430 else if (flags & _ISTO)
431 wleft -= 3;
432 break;
433 case 'i':
434 if (threaded) {
435 #ifdef HAVE_COLOUR
436 cpen_new = n_colour_pen_create(n_COLOUR_ID_SUM_THREAD, colo_tag);
437 if (cpen_new != cpen_cur)
438 n_colour_pen_put(cpen_cur = cpen_new, f);
439 #endif
440 n = __putindent(f, mp, MIN(wleft, scrnwidth - 60));
441 wleft = (n >= 0) ? wleft - n : 0;
442 #ifdef HAVE_COLOUR
443 if ((cpen_new = cpen_bas) != cpen_cur)
444 n_colour_pen_put(cpen_cur = cpen_new, f);
445 #endif
447 break;
448 case 'l':
449 if (n == 0)
450 n = 4;
451 if (UICMP(32, ABS(n), >, wleft))
452 n = (n < 0) ? -wleft : wleft;
453 if (mp->m_xlines) {
454 n = fprintf(f, "%*ld", n, mp->m_xlines);
455 wleft = (n >= 0) ? wleft - n : 0;
456 } else {
457 n = ABS(n);
458 wleft -= n;
459 while (n-- != 0)
460 putc(' ', f);
462 break;
463 case 'm':
464 if (n == 0) {
465 n = 3;
466 if (threaded)
467 for (i = msgCount; i > 999; i /= 10)
468 ++n;
470 if (UICMP(32, ABS(n), >, wleft))
471 n = (n < 0) ? -wleft : wleft;
472 n = fprintf(f, "%*lu", n, (ul_i)msgno);
473 wleft = (n >= 0) ? wleft - n : 0;
474 break;
475 case 'o':
476 if (n == 0)
477 n = -5;
478 if (UICMP(32, ABS(n), >, wleft))
479 n = (n < 0) ? -wleft : wleft;
480 n = fprintf(f, "%*lu", n, (ul_i)mp->m_xsize);
481 wleft = (n >= 0) ? wleft - n : 0;
482 break;
483 case 'S':
484 flags |= _SFMT;
485 /*FALLTHRU*/
486 case 's':
487 if (n == 0)
488 n = subjlen - 2;
489 if (n > 0 && s < 0)
490 n = -n;
491 if (subjlen > wleft)
492 subjlen = wleft;
493 if (UICMP(32, ABS(n), >, subjlen))
494 n = (n < 0) ? -subjlen : subjlen;
495 if (flags & _SFMT)
496 n -= (n < 0) ? -2 : 2;
497 if (n == 0)
498 break;
499 if (subjline == NULL)
500 subjline = __subject(mp, (threaded && (flags & _IFMT)), yetprinted);
501 if (subjline == (char*)-1) {
502 n = fprintf(f, "%*s", n, "");
503 wleft = (n >= 0) ? wleft - n : 0;
504 } else {
505 n = fprintf(f, ((flags & _SFMT) ? "\"%s\"" : "%s"),
506 colalign(subjline, ABS(n), n, &wleft));
507 if (n < 0)
508 wleft = 0;
510 break;
511 case 'T': { /* Message recipient flags */
512 /* We never can reuse "name" since it's the full name */
513 struct name const *np = lextract(hfield1("to", mp), GTO | GSKIN);
514 c = ' ';
515 i = 0;
516 j_A_redo:
517 for (; np != NULL; np = np->n_flink) {
518 switch (is_mlist(np->n_name, FAL0)) {
519 case MLIST_SUBSCRIBED: c = 'S'; goto jputcb;
520 case MLIST_KNOWN: c = 'L'; goto jputcb;
521 case MLIST_OTHER:
522 default: break;
525 if (i != 0)
526 goto jputcb;
527 ++i;
528 np = lextract(hfield1("cc", mp), GCC | GSKIN);
529 goto j_A_redo;
531 case 't':
532 if (n == 0) {
533 n = 3;
534 if (threaded)
535 for (i = msgCount; i > 999; i /= 10)
536 ++n;
538 if (UICMP(32, ABS(n), >, wleft))
539 n = (n < 0) ? -wleft : wleft;
540 n = fprintf(f, "%*lu",
541 n, (threaded ? (ul_i)mp->m_threadpos : (ul_i)msgno));
542 wleft = (n >= 0) ? wleft - n : 0;
543 break;
544 default:
545 if (options & OPT_D_V)
546 n_err(_("Unkown *headline* format: %%%c\n"), c);
547 c = '?';
548 goto jputcb;
551 if (wleft <= 0)
552 break;
555 #ifdef HAVE_COLOUR
556 n_colour_reset(f);
557 #endif
558 putc('\n', f);
560 if (subjline != NULL && subjline != (char*)-1)
561 free(subjline);
562 NYD_LEAVE;
565 static char *
566 __subject(struct message *mp, bool_t threaded, size_t yetprinted)
568 struct str in, out;
569 char *rv = (char*)-1, *ms;
570 NYD_ENTER;
572 if ((ms = hfield1("subject", mp)) == NULL)
573 goto jleave;
575 in.l = strlen(in.s = ms);
576 mime_fromhdr(&in, &out, TD_ICONV | TD_ISPR);
577 rv = ms = out.s;
579 if (!threaded || mp->m_level == 0)
580 goto jleave;
582 /* In a display thread - check whether this message uses the same
583 * Subject: as it's parent or elder neighbour, suppress printing it if
584 * this is the case. To extend this a bit, ignore any leading Re: or
585 * Fwd: plus follow-up WS. Ignore invisible messages along the way */
586 ms = subject_re_trim(ms);
588 for (; (mp = prev_in_thread(mp)) != NULL && yetprinted-- > 0;) {
589 char *os;
591 if (visible(mp) && (os = hfield1("subject", mp)) != NULL) {
592 struct str oout;
593 int x;
595 in.l = strlen(in.s = os);
596 mime_fromhdr(&in, &oout, TD_ICONV | TD_ISPR);
597 x = asccasecmp(ms, subject_re_trim(oout.s));
598 free(oout.s);
600 if (!x) {
601 free(out.s);
602 rv = (char*)-1;
604 break;
607 jleave:
608 NYD_LEAVE;
609 return rv;
612 static int
613 __putindent(FILE *fp, struct message *mp, int maxwidth)/* XXX no magic consts */
615 struct message *mq;
616 int *us, indlvl, indw, i, important = MNEW | MFLAGGED;
617 char *cs;
618 NYD_ENTER;
620 if (mp->m_level == 0 || maxwidth == 0) {
621 indw = 0;
622 goto jleave;
625 cs = ac_alloc(mp->m_level);
626 us = ac_alloc(mp->m_level * sizeof *us);
628 i = mp->m_level - 1;
629 if (mp->m_younger && UICMP(32, i + 1, ==, mp->m_younger->m_level)) {
630 if (mp->m_parent && mp->m_parent->m_flag & important)
631 us[i] = mp->m_flag & important ? 0x2523 : 0x2520;
632 else
633 us[i] = mp->m_flag & important ? 0x251D : 0x251C;
634 cs[i] = '+';
635 } else {
636 if (mp->m_parent && mp->m_parent->m_flag & important)
637 us[i] = mp->m_flag & important ? 0x2517 : 0x2516;
638 else
639 us[i] = mp->m_flag & important ? 0x2515 : 0x2514;
640 cs[i] = '\\';
643 mq = mp->m_parent;
644 for (i = mp->m_level - 2; i >= 0; --i) {
645 if (mq) {
646 if (UICMP(32, i, >, mq->m_level - 1)) {
647 us[i] = cs[i] = ' ';
648 continue;
650 if (mq->m_younger) {
651 if (mq->m_parent && (mq->m_parent->m_flag & important))
652 us[i] = 0x2503;
653 else
654 us[i] = 0x2502;
655 cs[i] = '|';
656 } else
657 us[i] = cs[i] = ' ';
658 mq = mq->m_parent;
659 } else
660 us[i] = cs[i] = ' ';
663 --maxwidth;
664 for (indlvl = indw = 0; (ui8_t)indlvl < mp->m_level && indw < maxwidth;
665 ++indlvl) {
666 if (indw < maxwidth - 1)
667 indw += (int)putuc(us[indlvl], cs[indlvl] & 0xFF, fp);
668 else
669 indw += (int)putuc(0x21B8, '^', fp);
671 indw += putuc(0x25B8, '>', fp);
673 ac_free(us);
674 ac_free(cs);
675 jleave:
676 NYD_LEAVE;
677 return indw;
680 static int
681 _dispc(struct message *mp, char const *a)
683 int i = ' ';
684 NYD_ENTER;
686 if ((mp->m_flag & (MREAD | MNEW)) == MREAD)
687 i = a[3];
688 if ((mp->m_flag & (MREAD | MNEW)) == (MREAD | MNEW))
689 i = a[2];
690 if (mp->m_flag & MANSWERED)
691 i = a[8];
692 if (mp->m_flag & MDRAFTED)
693 i = a[9];
694 if ((mp->m_flag & (MREAD | MNEW)) == MNEW)
695 i = a[0];
696 if (!(mp->m_flag & (MREAD | MNEW)))
697 i = a[1];
698 if (mp->m_flag & MSPAM)
699 i = a[12];
700 if (mp->m_flag & MSPAMUNSURE)
701 i = a[13];
702 if (mp->m_flag & MSAVED)
703 i = a[4];
704 if (mp->m_flag & MPRESERVE)
705 i = a[5];
706 if (mp->m_flag & (MBOX | MBOXED))
707 i = a[6];
708 if (mp->m_flag & MFLAGGED)
709 i = a[7];
710 if (mb.mb_threaded == 1 && mp->m_collapsed > 0)
711 i = a[11];
712 if (mb.mb_threaded == 1 && mp->m_collapsed < 0)
713 i = a[10];
714 NYD_LEAVE;
715 return i;
718 static int
719 a_cmd_scroll(char const *arg, bool_t onlynew){
720 long l;
721 char *eptr;
722 bool_t isabs;
723 int msgspec, size, maxs;
724 NYD2_ENTER;
726 /* TODO scroll problem: we do not know whether + and $ have already reached
727 * TODO the last screen in threaded mode */
728 msgspec = onlynew ? -1 : 0;
729 size = screensize();
730 if((maxs = msgCount / size) > 0 && msgCount % size == 0)
731 --maxs;
733 switch(*arg){
734 case '\0':
735 ++_screen;
736 goto jfwd;
737 case '^':
738 if(arg[1] != '\0')
739 goto jerr;
740 if(_screen == 0)
741 goto jerrbwd;
742 _screen = 0;
743 break;
744 case '$':
745 if(arg[1] != '\0')
746 goto jerr;
747 if(_screen == maxs)
748 goto jerrfwd;
749 _screen = maxs;
750 break;
751 case '+':
752 if(arg[1] == '\0')
753 ++_screen;
754 else{
755 isabs = FAL0;
757 ++arg;
758 if(0){
759 case '1': case '2': case '3': case '4': case '5':
760 case '6': case '7': case '8': case '9': case '0':
761 isabs = TRU1;
763 l = strtol(arg, &eptr, 10);
764 if(*eptr != '\0')
765 goto jerr;
766 if(l > maxs - (isabs ? 0 : _screen))
767 goto jerrfwd;
768 _screen = isabs ? (int)l : _screen + l;
770 jfwd:
771 if(_screen > maxs){
772 jerrfwd:
773 _screen = maxs;
774 printf(_("On last screenful of messages\n"));
776 break;
778 case '-':
779 if(arg[1] == '\0')
780 --_screen;
781 else{
782 ++arg;
783 l = strtol(arg, &eptr, 10);
784 if(*eptr != '\0')
785 goto jerr;
786 if(l > _screen)
787 goto jerrbwd;
788 _screen -= l;
790 if(_screen < 0){
791 jerrbwd:
792 _screen = 0;
793 printf(_("On first screenful of messages\n"));
795 if(msgspec == -1)
796 msgspec = -2;
797 break;
798 default:
799 jerr:
800 n_err(_("Unrecognized scrolling command: %s\n"), arg);
801 size = 1;
802 goto jleave;
805 size = _headers(msgspec);
806 jleave:
807 NYD2_LEAVE;
808 return size;
811 static int
812 _headers(int msgspec) /* TODO rework v15 */
814 struct n_sigman sm;
815 bool_t volatile isrelax;
816 ui32_t volatile flag;
817 int g, k, mesg, size;
818 int volatile lastg = 1;
819 struct message *mp, *mq, *lastmq = NULL;
820 enum mflag fl = MNEW | MFLAGGED;
821 NYD_ENTER;
823 time_current_update(&time_current, FAL0);
825 flag = 0;
826 isrelax = FAL0;
827 n_SIGMAN_ENTER_SWITCH(&sm, n_SIGMAN_ALL) {
828 case 0:
829 break;
830 default:
831 goto jleave;
834 #ifdef HAVE_COLOUR
835 if (options & OPT_INTERACTIVE)
836 n_colour_env_create(n_COLOUR_CTX_SUM, FAL0);
837 #endif
839 size = screensize();
840 if (_screen < 0)
841 _screen = 0;
842 #if 0 /* FIXME original code path */
843 k = _screen * size;
844 #else
845 if (msgspec <= 0)
846 k = _screen * size;
847 else
848 k = msgspec;
849 #endif
850 if (k >= msgCount)
851 k = msgCount - size;
852 if (k < 0)
853 k = 0;
855 if (mb.mb_threaded == 0) {
856 g = 0;
857 mq = message;
858 for (mp = message; PTRCMP(mp, <, message + msgCount); ++mp)
859 if (visible(mp)) {
860 if (g % size == 0)
861 mq = mp;
862 if (mp->m_flag & fl) {
863 lastg = g;
864 lastmq = mq;
866 if ((msgspec > 0 && PTRCMP(mp, ==, message + msgspec - 1)) ||
867 (msgspec == 0 && g == k) ||
868 (msgspec == -2 && g == k + size && lastmq) ||
869 (msgspec < 0 && g >= k && (mp->m_flag & fl) != 0))
870 break;
871 g++;
873 if (lastmq && (msgspec == -2 ||
874 (msgspec == -1 && PTRCMP(mp, ==, message + msgCount)))) {
875 g = lastg;
876 mq = lastmq;
878 _screen = g / size;
880 mp = mq;
881 mesg = (int)PTR2SIZE(mp - message);
882 if (PTRCMP(dot, !=, message + msgspec - 1)) { /* TODO really?? */
883 for (mq = mp; PTRCMP(mq, <, message + msgCount); ++mq)
884 if (visible(mq)) {
885 setdot(mq);
886 break;
890 srelax_hold();
891 isrelax = TRU1;
892 for (; PTRCMP(mp, <, message + msgCount); ++mp) {
893 ++mesg;
894 if (!visible(mp))
895 continue;
896 if (UICMP(32, flag++, >=, size))
897 break;
898 _print_head(0, mesg, stdout, 0);
899 srelax();
901 srelax_rele();
902 isrelax = FAL0;
903 } else { /* threaded */
904 g = 0;
905 mq = threadroot;
906 for (mp = threadroot; mp; mp = next_in_thread(mp))
907 if (visible(mp) &&
908 (mp->m_collapsed <= 0 ||
909 PTRCMP(mp, ==, message + msgspec - 1))) {
910 if (g % size == 0)
911 mq = mp;
912 if (mp->m_flag & fl) {
913 lastg = g;
914 lastmq = mq;
916 if ((msgspec > 0 && PTRCMP(mp, ==, message + msgspec - 1)) ||
917 (msgspec == 0 && g == k) ||
918 (msgspec == -2 && g == k + size && lastmq) ||
919 (msgspec < 0 && g >= k && (mp->m_flag & fl) != 0))
920 break;
921 g++;
923 if (lastmq && (msgspec == -2 ||
924 (msgspec == -1 && PTRCMP(mp, ==, message + msgCount)))) {
925 g = lastg;
926 mq = lastmq;
928 _screen = g / size;
929 mp = mq;
930 if (PTRCMP(dot, !=, message + msgspec - 1)) { /* TODO really?? */
931 for (mq = mp; mq; mq = next_in_thread(mq))
932 if (visible(mq) && mq->m_collapsed <= 0) {
933 setdot(mq);
934 break;
938 srelax_hold();
939 isrelax = TRU1;
940 while (mp) {
941 if (visible(mp) &&
942 (mp->m_collapsed <= 0 ||
943 PTRCMP(mp, ==, message + msgspec - 1))) {
944 if (UICMP(32, flag++, >=, size))
945 break;
946 _print_head(flag - 1, PTR2SIZE(mp - message + 1), stdout,
947 mb.mb_threaded);
948 srelax();
950 mp = next_in_thread(mp);
952 srelax_rele();
953 isrelax = FAL0;
956 if (!flag) {
957 printf(_("No more mail.\n"));
958 if (pstate & (PS_HOOK_MASK | PS_ROBOT))
959 flag = !flag;
962 n_sigman_cleanup_ping(&sm);
963 jleave:
964 if (isrelax)
965 srelax_rele();
966 n_COLOUR( n_colour_env_gut((sm.sm_signo != SIGPIPE) ? stdout : NULL); )
967 NYD_LEAVE;
968 n_sigman_leave(&sm, n_SIGMAN_VIPSIGS_NTTYOUT);
969 return !flag;
972 static int
973 _type1(int *msgvec, bool_t doign, bool_t dopage, bool_t dopipe,
974 bool_t dodecode, char *cmd, ui64_t *tstats)
976 struct n_sigman sm;
977 ui64_t mstats[1];
978 int volatile rv = 1;
979 int *ip;
980 struct message *mp;
981 char const *cp;
982 FILE * volatile obuf;
983 bool_t volatile isrelax = FAL0;
984 NYD_ENTER;
985 {/* C89.. */
986 enum sendaction const action = ((dopipe && ok_blook(piperaw))
987 ? SEND_MBOX : dodecode
988 ? SEND_SHOW : doign
989 ? SEND_TODISP : SEND_TODISP_ALL);
990 bool_t const volatile formfeed = (dopipe && ok_blook(page));
991 obuf = stdout;
993 n_SIGMAN_ENTER_SWITCH(&sm, n_SIGMAN_ALL) {
994 case 0:
995 break;
996 default:
997 goto jleave;
1000 if (dopipe) {
1001 if ((obuf = Popen(cmd, "w", ok_vlook(SHELL), NULL, 1)) == NULL) {
1002 n_perr(cmd, 0);
1003 obuf = stdout;
1005 } else if ((options & OPT_TTYOUT) && (dopage ||
1006 ((options & OPT_INTERACTIVE) && (cp = ok_vlook(crt)) != NULL))) {
1007 size_t nlines = 0;
1009 if (!dopage) {
1010 for (ip = msgvec; *ip && PTRCMP(ip - msgvec, <, msgCount); ++ip) {
1011 mp = message + *ip - 1;
1012 if (!(mp->m_have & HAVE_BODY))
1013 if (get_body(mp) != OKAY)
1014 goto jcleanup_leave;
1015 nlines += mp->m_lines + 1; /* Message info XXX and PARTS... */
1019 /* >= not <: we return to the prompt */
1020 if (dopage || UICMP(z, nlines, >=,
1021 (*cp != '\0' ? strtoul(cp, NULL, 0) : (size_t)realscreenheight))) {
1022 if ((obuf = n_pager_open()) == NULL)
1023 obuf = stdout;
1025 #ifdef HAVE_COLOUR
1026 if ((options & OPT_INTERACTIVE) &&
1027 (action == SEND_TODISP || action == SEND_TODISP_ALL ||
1028 action == SEND_SHOW))
1029 n_colour_env_create(n_COLOUR_CTX_VIEW, obuf != stdout);
1030 #endif
1032 #ifdef HAVE_COLOUR
1033 else if ((options & OPT_INTERACTIVE) &&
1034 (action == SEND_TODISP || action == SEND_TODISP_ALL))
1035 n_colour_env_create(n_COLOUR_CTX_VIEW, FAL0);
1036 #endif
1038 /*TODO unless we have our signal manager special care must be taken */
1039 srelax_hold();
1040 isrelax = TRU1;
1041 for (ip = msgvec; *ip && PTRCMP(ip - msgvec, <, msgCount); ++ip) {
1042 mp = message + *ip - 1;
1043 touch(mp);
1044 setdot(mp);
1045 pstate |= PS_DID_PRINT_DOT;
1046 uncollapse1(mp, 1);
1047 if (!dopipe && ip != msgvec)
1048 fprintf(obuf, "\n");
1049 if (action != SEND_MBOX)
1050 _show_msg_overview(obuf, mp, *ip);
1051 sendmp(mp, obuf, (doign ? ignore : NULL), NULL, action, mstats);
1052 srelax();
1053 if (formfeed) /* TODO a nicer way to separate piped messages! */
1054 putc('\f', obuf);
1055 if (tstats != NULL)
1056 tstats[0] += mstats[0];
1058 srelax_rele();
1059 isrelax = FAL0;
1061 rv = 0;
1062 jcleanup_leave:
1063 n_sigman_cleanup_ping(&sm);
1064 jleave:
1065 if (isrelax)
1066 srelax_rele();
1067 n_COLOUR( n_colour_env_gut((sm.sm_signo != SIGPIPE) ? obuf : NULL); )
1068 if (obuf != stdout)
1069 n_pager_close(obuf);
1071 NYD_LEAVE;
1072 n_sigman_leave(&sm, n_SIGMAN_VIPSIGS_NTTYOUT);
1073 return rv;
1076 static int
1077 _pipe1(char *str, int doign)
1079 ui64_t stats[1];
1080 char const *cmd, *cmdq;
1081 int *msgvec, rv = 1;
1082 bool_t needs_list;
1083 NYD_ENTER;
1085 if ((cmd = laststring(str, &needs_list, TRU1)) == NULL) {
1086 cmd = ok_vlook(cmd);
1087 if (cmd == NULL || *cmd == '\0') {
1088 n_err(_("Variable *cmd* not set\n"));
1089 goto jleave;
1093 msgvec = salloc((msgCount + 2) * sizeof *msgvec);
1095 if (!needs_list) {
1096 *msgvec = first(0, MMNORM);
1097 if (*msgvec == 0) {
1098 if (pstate & (PS_HOOK_MASK | PS_ROBOT)) {
1099 rv = 0;
1100 goto jleave;
1102 puts(_("No messages to pipe."));
1103 goto jleave;
1105 msgvec[1] = 0;
1106 } else if (getmsglist(str, msgvec, 0) < 0)
1107 goto jleave;
1108 if (*msgvec == 0) {
1109 if (pstate & (PS_HOOK_MASK | PS_ROBOT)) {
1110 rv = 0;
1111 goto jleave;
1113 printf("No applicable messages.\n");
1114 goto jleave;
1117 cmdq = n_shexp_quote_cp(cmd, FAL0);
1118 printf(_("Pipe to: %s\n"), cmdq);
1119 stats[0] = 0;
1120 if ((rv = _type1(msgvec, doign, FAL0, TRU1, FAL0, UNCONST(cmd), stats)) == 0)
1121 printf("%s %" PRIu64 " bytes\n", cmdq, stats[0]);
1122 jleave:
1123 NYD_LEAVE;
1124 return rv;
1127 static int
1128 a_cmd_top(void *vp, struct ignoretab *itp){
1129 struct n_string s;
1130 int *msgvec, *ip;
1131 enum{a_NONE, a_SQUEEZE = 1u<<0,
1132 a_EMPTY = 1u<<8, a_STOP = 1u<<9, a_WORKMASK = 0xFF00u} f;
1133 size_t tmax, plines;
1134 FILE *iobuf, *pbuf;
1135 NYD2_ENTER;
1137 if((iobuf = Ftmp(NULL, "topio", OF_RDWR | OF_UNLINK | OF_REGISTER)) == NULL){
1138 n_perr(_("`top': I/O temporary file"), 0);
1139 vp = NULL;
1140 goto jleave;
1142 if((pbuf = Ftmp(NULL, "toppag", OF_RDWR | OF_UNLINK | OF_REGISTER)) == NULL){
1143 n_perr(_("`top': temporary pager file"), 0);
1144 vp = NULL;
1145 goto jleave1;
1148 /* TODO In v15 we should query the m_message object, and directly send only
1149 * TODO those parts, optionally over empty-line-squeeze and quote-strip
1150 * TODO filters, in which we are interested in: only text content!
1151 * TODO And: with *topsqueeze*, header/content separating empty line.. */
1152 pstate &= ~PS_MSGLIST_DIRECT; /* TODO NO ATTACHMENTS */
1153 plines = 0;
1155 #ifdef HAVE_COLOUR
1156 if (options & OPT_INTERACTIVE)
1157 n_colour_env_create(n_COLOUR_CTX_VIEW, TRU1);
1158 #endif
1159 n_string_creat_auto(&s);
1160 /* C99 */{
1161 long l;
1163 if((l = strtol(ok_vlook(toplines), NULL, 0)) <= 0){
1164 tmax = (size_t)screensize();
1165 if(l < 0){
1166 l = ABS(l);
1167 tmax >>= l;
1169 }else
1170 tmax = (size_t)l;
1172 f = ok_blook(topsqueeze) ? a_SQUEEZE : a_NONE;
1174 for(ip = msgvec = vp;
1175 *ip != 0 && UICMP(z, PTR2SIZE(ip - msgvec), <, msgCount); ++ip){
1176 struct message *mp;
1178 mp = &message[*ip - 1];
1179 touch(mp);
1180 setdot(mp);
1181 pstate |= PS_DID_PRINT_DOT;
1182 uncollapse1(mp, 1);
1184 rewind(iobuf);
1185 if(ftruncate(fileno(iobuf), 0)){
1186 n_perr(_("`top': ftruncate(2)"), 0);
1187 vp = NULL;
1188 break;
1190 if(sendmp(mp, iobuf, itp, NULL, SEND_TODISP_ALL, NULL) < 0){
1191 n_err(_("`top': failed to prepare message %d\n"), *ip);
1192 vp = NULL;
1193 break;
1195 fflush_rewind(iobuf);
1197 _show_msg_overview(pbuf, mp, *ip);
1198 ++plines;
1199 /* C99 */{
1200 size_t l;
1202 n_string_trunc(&s, 0);
1203 for(l = 0, f &= ~a_WORKMASK; !(f & a_STOP);){
1204 int c;
1206 if((c = getc(iobuf)) == EOF){
1207 f |= a_STOP;
1208 c = '\n';
1211 if(c != '\n')
1212 n_string_push_c(&s, c);
1213 else if((f & a_SQUEEZE) && s.s_len == 0){
1214 if(!(f & a_STOP) && ((f & a_EMPTY) || tmax - 1 <= l))
1215 continue;
1216 if(putc('\n', pbuf) == EOF){
1217 vp = NULL;
1218 break;
1220 f |= a_EMPTY;
1221 ++l;
1222 }else{
1223 char const *cp, *xcp;
1225 cp = n_string_cp_const(&s);
1226 /* TODO Brute simple skip part overviews; see above.. */
1227 if(!(f & a_SQUEEZE))
1228 c = '\1';
1229 else if(s.s_len > 8 &&
1230 (xcp = strstr(cp, "[-- ")) != NULL &&
1231 PTRCMP(xcp, <, strstr(cp, " --]")))
1232 c = '\0';
1233 else for(; (c = *cp) != '\0'; ++cp){
1234 if(!asciichar(c))
1235 break;
1236 if(!blankspacechar(c)){
1237 if(!ISQUOTE(c))
1238 break;
1239 c = '\0';
1240 break;
1244 if(c != '\0'){
1245 if(fputs(n_string_cp_const(&s), pbuf) == EOF ||
1246 putc('\n', pbuf) == EOF){
1247 vp = NULL;
1248 break;
1250 if(++l >= tmax)
1251 break;
1252 f &= ~a_EMPTY;
1253 }else
1254 f |= a_EMPTY;
1255 n_string_trunc(&s, 0);
1258 if(vp == NULL)
1259 break;
1260 if(l > 0)
1261 plines += l;
1262 else{
1263 if(!(f & a_EMPTY) && putc('\n', pbuf) == EOF){
1264 vp = NULL;
1265 break;
1267 ++plines;
1272 n_string_gut(&s);
1273 n_COLOUR( n_colour_env_gut(pbuf); )
1275 fflush(pbuf);
1276 page_or_print(pbuf, plines);
1278 Fclose(pbuf);
1279 jleave1:
1280 Fclose(iobuf);
1281 jleave:
1282 NYD2_LEAVE;
1283 return (vp != NULL);
1286 FL int
1287 c_cmdnotsupp(void *v) /* TODO -> lex.c */
1289 NYD_ENTER;
1290 UNUSED(v);
1291 n_err(_("The requested feature is not compiled in\n"));
1292 NYD_LEAVE;
1293 return 1;
1296 FL int
1297 c_headers(void *v)
1299 int rv;
1300 NYD_ENTER;
1302 rv = print_header_group((int*)v);
1303 NYD_LEAVE;
1304 return rv;
1307 FL int
1308 print_header_group(int *vector)
1310 int rv;
1311 NYD_ENTER;
1313 assert(vector != NULL && vector != (void*)-1);
1314 rv = _headers(vector[0]);
1315 NYD_LEAVE;
1316 return rv;
1319 FL int
1320 c_scroll(void *v)
1322 int rv;
1323 NYD_ENTER;
1325 rv = a_cmd_scroll(v, FAL0);
1326 NYD_LEAVE;
1327 return rv;
1330 FL int
1331 c_Scroll(void *v)
1333 int rv;
1334 NYD_ENTER;
1336 rv = a_cmd_scroll(v, TRU1);
1337 NYD_LEAVE;
1338 return rv;
1341 FL int
1342 c_from(void *v)
1344 struct n_sigman sm;
1345 int *msgvec = v, *ip, n;
1346 char *cp;
1347 FILE * volatile obuf;
1348 bool_t volatile isrelax;
1349 NYD_ENTER;
1351 time_current_update(&time_current, FAL0);
1353 obuf = stdout;
1354 isrelax = FAL0;
1355 n_SIGMAN_ENTER_SWITCH(&sm, n_SIGMAN_ALL) {
1356 case 0:
1357 break;
1358 default:
1359 goto jleave;
1362 if (options & OPT_INTERACTIVE) {
1363 if ((cp = ok_vlook(crt)) != NULL) {
1364 for (n = 0, ip = msgvec; *ip != 0; ++ip)
1365 ++n;
1366 if (UICMP(z, n, >, (*cp == '\0'
1367 ? (size_t)screensize() : strtoul(cp, NULL, 0)) + 3) &&
1368 (obuf = n_pager_open()) == NULL)
1369 obuf = stdout;
1371 n_COLOUR( n_colour_env_create(n_COLOUR_CTX_SUM, obuf != stdout); )
1374 /* Update dot before display so that the dotmark etc. are correct */
1375 for (ip = msgvec; *ip != 0; ++ip)
1377 if (--ip >= msgvec)
1378 setdot(message + *ip - 1);
1380 srelax_hold();
1381 isrelax = TRU1;
1382 for (n = 0, ip = msgvec; *ip != 0; ++ip) { /* TODO join into _print_head() */
1383 _print_head((size_t)n++, (size_t)*ip, obuf, mb.mb_threaded);
1384 srelax();
1386 srelax_rele();
1387 isrelax = FAL0;
1389 n_sigman_cleanup_ping(&sm);
1390 jleave:
1391 if (isrelax)
1392 srelax_rele();
1393 n_COLOUR( n_colour_env_gut((sm.sm_signo != SIGPIPE) ? obuf : NULL); )
1394 if (obuf != stdout)
1395 n_pager_close(obuf);
1396 NYD_LEAVE;
1397 n_sigman_leave(&sm, n_SIGMAN_VIPSIGS_NTTYOUT);
1398 return 0;
1401 FL void
1402 print_headers(size_t bottom, size_t topx, bool_t only_marked)
1404 struct n_sigman sm;
1405 bool_t volatile isrelax;
1406 size_t printed;
1407 NYD_ENTER;
1409 time_current_update(&time_current, FAL0);
1411 isrelax = FAL0;
1412 n_SIGMAN_ENTER_SWITCH(&sm, n_SIGMAN_ALL) {
1413 case 0:
1414 break;
1415 default:
1416 goto jleave;
1419 #ifdef HAVE_COLOUR
1420 if (options & OPT_INTERACTIVE)
1421 n_colour_env_create(n_COLOUR_CTX_SUM, FAL0);
1422 #endif
1424 srelax_hold();
1425 isrelax = TRU1;
1426 for (printed = 0; bottom <= topx; ++bottom) {
1427 struct message *mp = message + bottom - 1;
1428 if (only_marked) {
1429 if (!(mp->m_flag & MMARK))
1430 continue;
1431 } else if (!visible(mp))
1432 continue;
1433 _print_head(printed++, bottom, stdout, FAL0);
1434 srelax();
1436 srelax_rele();
1437 isrelax = FAL0;
1439 n_sigman_cleanup_ping(&sm);
1440 jleave:
1441 if (isrelax)
1442 srelax_rele();
1443 n_COLOUR( n_colour_env_gut((sm.sm_signo != SIGPIPE) ? stdout : NULL); )
1444 NYD_LEAVE;
1445 n_sigman_leave(&sm, n_SIGMAN_VIPSIGS_NTTYOUT);
1448 FL int
1449 c_pdot(void *v)
1451 NYD_ENTER;
1452 UNUSED(v);
1453 printf("%d\n", (int)PTR2SIZE(dot - message + 1));
1454 NYD_LEAVE;
1455 return 0;
1458 FL int
1459 c_more(void *v)
1461 int *msgvec = v, rv;
1462 NYD_ENTER;
1464 rv = _type1(msgvec, TRU1, TRU1, FAL0, FAL0, NULL, NULL);
1465 NYD_LEAVE;
1466 return rv;
1469 FL int
1470 c_More(void *v)
1472 int *msgvec = v, rv;
1473 NYD_ENTER;
1475 rv = _type1(msgvec, FAL0, TRU1, FAL0, FAL0, NULL, NULL);
1476 NYD_LEAVE;
1477 return rv;
1480 FL int
1481 c_type(void *v)
1483 int *msgvec = v, rv;
1484 NYD_ENTER;
1486 rv = _type1(msgvec, TRU1, FAL0, FAL0, FAL0, NULL, NULL);
1487 NYD_LEAVE;
1488 return rv;
1491 FL int
1492 c_Type(void *v)
1494 int *msgvec = v, rv;
1495 NYD_ENTER;
1497 rv = _type1(msgvec, FAL0, FAL0, FAL0, FAL0, NULL, NULL);
1498 NYD_LEAVE;
1499 return rv;
1502 FL int
1503 c_show(void *v)
1505 int *msgvec = v, rv;
1506 NYD_ENTER;
1508 rv = _type1(msgvec, FAL0, FAL0, FAL0, TRU1, NULL, NULL);
1509 NYD_LEAVE;
1510 return rv;
1513 FL int
1514 c_pipe(void *v)
1516 char *str = v;
1517 int rv;
1518 NYD_ENTER;
1520 rv = _pipe1(str, 1);
1521 NYD_LEAVE;
1522 return rv;
1525 FL int
1526 c_Pipe(void *v)
1528 char *str = v;
1529 int rv;
1530 NYD_ENTER;
1532 rv = _pipe1(str, 0);
1533 NYD_LEAVE;
1534 return rv;
1537 FL int
1538 c_top(void *v){
1539 struct ignoretab it[2];
1540 int rv;
1541 NYD_ENTER;
1543 n_ignoretab_creat(&it[0], TRU1);
1544 n_ignoretab_creat(&it[1], TRU1);
1545 n_ignoretab_insert(&it[1], "from", sizeof("from") -1);
1546 n_ignoretab_insert(&it[1], "to", sizeof("to") -1);
1547 n_ignoretab_insert(&it[1], "cc", sizeof("cc") -1);
1548 n_ignoretab_insert(&it[1], "subject", sizeof("subject") -1);
1550 rv = !a_cmd_top(v, it);
1551 NYD_LEAVE;
1552 return rv;
1555 FL int
1556 c_Top(void *v){
1557 int rv;
1558 NYD_ENTER;
1560 rv = !a_cmd_top(v, ignore);
1561 NYD_LEAVE;
1562 return rv;
1565 FL int
1566 c_folders(void *v)
1568 char const *cp;
1569 char **argv;
1570 int rv;
1571 NYD_ENTER;
1573 rv = 1;
1575 if(*(argv = v) != NULL){
1576 if((cp = fexpand(*argv, FEXP_NSHELL | FEXP_LOCAL)) == NULL)
1577 goto jleave;
1578 }else
1579 cp = folder_query();
1581 run_command(ok_vlook(LISTER), 0, COMMAND_FD_PASS, COMMAND_FD_PASS, cp,
1582 NULL, NULL, NULL);
1583 jleave:
1584 NYD_LEAVE;
1585 return rv;
1588 /* s-it-mode */