makefile:_update-release: suck most from template mail
[s-mailx.git] / cmd1.c
blobd201d2d86240fee3f645ba101dd597ed1554f74b
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 - 2015 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
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 static void
78 _show_msg_overview(FILE *obuf, struct message *mp, int msg_no)
80 char const *cpre = "", *csuf = "";
81 NYD_ENTER;
83 #ifdef HAVE_COLOUR
84 if (pstate & PS_COLOUR_ACTIVE) {
85 struct n_colour_pen *cpen;
87 if ((cpen = n_colour_pen_create(n_COLOUR_ID_VIEW_MSGINFO, NULL)) != NULL){
88 struct str const *sp;
90 if ((sp = n_colour_pen_to_str(cpen)) != NULL)
91 cpre = sp->s;
92 if ((sp = n_colour_reset_to_str()) != NULL)
93 csuf = sp->s;
96 #endif
97 fprintf(obuf, _("%s[-- Message %2d -- %lu lines, %lu bytes --]:%s\n"),
98 cpre, msg_no, (ul_i)mp->m_lines, (ul_i)mp->m_size, csuf);
99 NYD_LEAVE;
102 static void
103 _parse_from_(struct message *mp, char date[FROM_DATEBUF]) /* TODO line pool */
105 FILE *ibuf;
106 int hlen;
107 char *hline = NULL;
108 size_t hsize = 0;
109 NYD_ENTER;
111 if ((ibuf = setinput(&mb, mp, NEED_HEADER)) != NULL &&
112 (hlen = readline_restart(ibuf, &hline, &hsize, 0)) > 0)
113 extract_date_from_from_(hline, hlen, date);
114 if (hline != NULL)
115 free(hline);
116 NYD_LEAVE;
119 static void
120 _print_head(size_t yetprinted, size_t msgno, FILE *f, bool_t threaded)
122 enum {attrlen = 14};
123 char attrlist[attrlen +1], *cp;
124 char const *fmt;
125 NYD_ENTER;
127 if ((cp = ok_vlook(attrlist)) != NULL) {
128 if (strlen(cp) == attrlen) {
129 memcpy(attrlist, cp, attrlen +1);
130 goto jattrok;
132 n_err(_("*attrlist* is not of the correct length, using builtin\n"));
135 if (ok_blook(bsdcompat) || ok_blook(bsdflags)) {
136 char const bsdattr[attrlen +1] = "NU *HMFAT+-$~";
137 memcpy(attrlist, bsdattr, sizeof bsdattr);
138 } else if (ok_blook(SYSV3)) {
139 char const bsdattr[attrlen +1] = "NU *HMFAT+-$~";
140 memcpy(attrlist, bsdattr, sizeof bsdattr);
141 OBSOLETE(_("*SYSV3*: please use *bsdcompat* or *bsdflags*, "
142 "or set *attrlist*"));
143 } else {
144 char const pattr[attrlen +1] = "NUROSPMFAT+-$~";
145 memcpy(attrlist, pattr, sizeof pattr);
148 jattrok:
149 if ((fmt = ok_vlook(headline)) == NULL) {
150 fmt = ((ok_blook(bsdcompat) || ok_blook(bsdheadline))
151 ? "%>%a%m %-20f %16d %3l/%-5o %i%-S"
152 : "%>%a%m %-18f %16d %4l/%-5o %i%-s");
155 __hprf(yetprinted, fmt, msgno, f, threaded, attrlist);
156 NYD_LEAVE;
159 static void
160 __hprf(size_t yetprinted, char const *fmt, size_t msgno, FILE *f,
161 bool_t threaded, char const *attrlist)
163 char buf[16], datebuf[FROM_DATEBUF], cbuf[8], *cp, *subjline;
164 char const *datefmt, *date, *name, *fp n_COLOUR( COMMA *colo_tag );
165 int i, n, s, wleft, subjlen;
166 struct message *mp;
167 time_t datet;
168 n_COLOUR( struct n_colour_pen *cpen_new COMMA *cpen_cur COMMA *cpen_bas; )
169 enum {
170 _NONE = 0,
171 _ISDOT = 1<<0,
172 _ISADDR = 1<<1,
173 _ISTO = 1<<2,
174 _IFMT = 1<<3,
175 _LOOP_MASK = (1<<4) - 1,
176 _SFMT = 1<<4
177 } flags = _NONE;
178 NYD_ENTER;
179 UNUSED(buf);
181 if ((mp = message + msgno - 1) == dot)
182 flags = _ISDOT;
183 datet = mp->m_time;
184 date = NULL;
185 n_COLOUR( colo_tag = NULL; )
187 datefmt = ok_vlook(datefield);
188 jredo:
189 if (datefmt != NULL) {
190 fp = hfield1("date", mp);/* TODO use m_date field! */
191 if (fp == NULL) {
192 datefmt = NULL;
193 goto jredo;
195 datet = rfctime(fp);
196 date = fakedate(datet);
197 fp = ok_vlook(datefield_markout_older);
198 i = (*datefmt != '\0');
199 if (fp != NULL)
200 i |= (*fp != '\0') ? 2 | 4 : 2; /* XXX no magics */
202 /* May we strftime(3)? */
203 if (i & (1 | 4))
204 memcpy(&time_current.tc_local, localtime(&datet),
205 sizeof time_current.tc_local);
207 if ((i & 2) && (datet > time_current.tc_time + DATE_SECSDAY ||
208 #define _6M ((DATE_DAYSYEAR / 2) * DATE_SECSDAY)
209 (datet + _6M < time_current.tc_time))) {
210 #undef _6M
211 if ((datefmt = (i & 4) ? fp : NULL) == NULL) {
212 memset(datebuf, ' ', FROM_DATEBUF); /* xxx ur */
213 memcpy(datebuf + 4, date + 4, 7);
214 datebuf[4 + 7] = ' ';
215 memcpy(datebuf + 4 + 7 + 1, date + 20, 4);
216 datebuf[4 + 7 + 1 + 4] = '\0';
217 date = datebuf;
219 n_COLOUR( colo_tag = n_COLOUR_TAG_SUM_OLDER; )
220 } else if ((i & 1) == 0)
221 datefmt = NULL;
222 } else if (datet == (time_t)0 && !(mp->m_flag & MNOFROM)) {
223 /* TODO eliminate this path, query the FROM_ date in setptr(),
224 * TODO all other codepaths do so by themselves ALREADY ?????
225 * TODO assert(mp->m_time != 0);, then
226 * TODO ALSO changes behaviour of datefield_markout_older */
227 _parse_from_(mp, datebuf);
228 date = datebuf;
229 } else
230 date = fakedate(datet);
232 flags |= _ISADDR;
233 name = name1(mp, 0);
234 if (name != NULL && ok_blook(showto) && is_myname(skin(name))) {
235 if ((cp = hfield1("to", mp)) != NULL) {
236 name = cp;
237 flags |= _ISTO;
240 if (name == NULL) {
241 name = "";
242 flags &= ~_ISADDR;
244 if (flags & _ISADDR)
245 name = ok_blook(showname) ? realname(name) : prstr(skin(name));
247 subjline = NULL;
249 /* Detect the width of the non-format characters in *headline*;
250 * like that we can simply use putc() in the next loop, since we have
251 * already calculated their column widths (TODO it's sick) */
252 wleft = subjlen = scrnwidth;
254 for (fp = fmt; *fp != '\0'; ++fp) {
255 if (*fp == '%') {
256 if (*++fp == '-')
257 ++fp;
258 else if (*fp == '+')
259 ++fp;
260 if (digitchar(*fp)) {
261 n = 0;
263 n = 10*n + *fp - '0';
264 while (++fp, digitchar(*fp));
265 subjlen -= n;
267 if (*fp == 'i')
268 flags |= _IFMT;
270 if (*fp == '\0')
271 break;
272 } else {
273 #ifdef HAVE_WCWIDTH
274 if (mb_cur_max > 1) {
275 wchar_t wc;
276 if ((s = mbtowc(&wc, fp, mb_cur_max)) == -1)
277 n = s = 1;
278 else if ((n = wcwidth(wc)) == -1)
279 n = 1;
280 } else
281 #endif
282 n = s = 1;
283 subjlen -= n;
284 wleft -= n;
285 while (--s > 0)
286 ++fp;
290 /* Walk *headline*, producing output TODO not (really) MB safe */
291 #ifdef HAVE_COLOUR
292 if (flags & _ISDOT)
293 colo_tag = n_COLOUR_TAG_SUM_DOT;
294 cpen_bas = n_colour_pen_create(n_COLOUR_ID_SUM_HEADER, colo_tag);
295 n_colour_pen_put(cpen_new = cpen_cur = cpen_bas, f);
296 #endif
298 for (fp = fmt; *fp != '\0'; ++fp) {
299 char c;
301 if ((c = *fp & 0xFF) != '%') {
302 #ifdef HAVE_COLOUR
303 if ((cpen_new = cpen_bas) != cpen_cur)
304 n_colour_pen_put(cpen_cur = cpen_new, f);
305 #endif
306 putc(c, f);
307 continue;
310 flags &= _LOOP_MASK;
311 n = 0;
312 s = 1;
313 if ((c = *++fp) == '-') {
314 s = -1;
315 ++fp;
316 } else if (c == '+')
317 ++fp;
318 if (digitchar(*fp)) {
320 n = 10*n + *fp - '0';
321 while (++fp, digitchar(*fp));
324 if ((c = *fp & 0xFF) == '\0')
325 break;
326 n *= s;
328 cbuf[1] = '\0';
329 switch (c) {
330 case '%':
331 goto jputcb;
332 case '>':
333 case '<':
334 if (flags & _ISDOT) {
335 n_COLOUR( cpen_new = n_colour_pen_create(n_COLOUR_ID_SUM_DOTMARK,
336 colo_tag); );
337 if (options & OPT_UNICODE) {
338 if (c == '>')
339 /* 25B8;BLACK RIGHT-POINTING SMALL TRIANGLE: â–¸ */
340 cbuf[1] = (char)0x96, cbuf[2] = (char)0xB8;
341 else
342 /* 25C2;BLACK LEFT-POINTING SMALL TRIANGLE: â—‚ */
343 cbuf[1] = (char)0x97, cbuf[2] = (char)0x82;
344 c = (char)0xE2;
345 cbuf[3] = '\0';
347 } else
348 c = ' ';
349 goto jputcb;
350 case '$':
351 #ifdef HAVE_SPAM
352 if (n == 0)
353 n = 5;
354 if (UICMP(32, ABS(n), >, wleft))
355 n = (n < 0) ? -wleft : wleft;
356 snprintf(buf, sizeof buf, "%u.%02u",
357 (mp->m_spamscore >> 8), (mp->m_spamscore & 0xFF));
358 n = fprintf(f, "%*s", n, buf);
359 wleft = (n >= 0) ? wleft - n : 0;
360 break;
361 #else
362 c = '?';
363 goto jputcb;
364 #endif
365 case 'a':
366 c = _dispc(mp, attrlist);
367 jputcb:
368 #ifdef HAVE_COLOUR
369 if (cpen_new == cpen_cur)
370 cpen_new = cpen_bas;
371 if (cpen_new != cpen_cur)
372 n_colour_pen_put(cpen_cur = cpen_new, f);
373 #endif
374 if (UICMP(32, ABS(n), >, wleft))
375 n = (n < 0) ? -wleft : wleft;
376 cbuf[0] = c;
377 n = fprintf(f, "%*s", n, cbuf);
378 wleft = (n >= 0) ? wleft - n : 0;
379 #ifdef HAVE_COLOUR
380 if ((cpen_new = cpen_bas) != cpen_cur)
381 n_colour_pen_put(cpen_cur = cpen_new, f);
382 #endif
383 break;
384 case 'd':
385 if (datefmt != NULL) {
386 i = strftime(datebuf, sizeof datebuf, datefmt,
387 &time_current.tc_local);
388 if (i != 0)
389 date = datebuf;
390 else
391 n_err(_("Ignored date format, it excesses the target "
392 "buffer (%lu bytes)\n"), (ul_i)sizeof(datebuf));
393 datefmt = NULL;
395 if (n == 0)
396 n = 16;
397 if (UICMP(32, ABS(n), >, wleft))
398 n = (n < 0) ? -wleft : wleft;
399 n = fprintf(f, "%*.*s", n, n, date);
400 wleft = (n >= 0) ? wleft - n : 0;
401 break;
402 case 'e':
403 if (n == 0)
404 n = 2;
405 if (UICMP(32, ABS(n), >, wleft))
406 n = (n < 0) ? -wleft : wleft;
407 n = fprintf(f, "%*u", n, (threaded == 1 ? mp->m_level : 0));
408 wleft = (n >= 0) ? wleft - n : 0;
409 break;
410 case 'f':
411 if (n == 0) {
412 n = 18;
413 if (s < 0)
414 n = -n;
416 i = ABS(n);
417 if (i > wleft) {
418 i = wleft;
419 n = (n < 0) ? -wleft : wleft;
421 if (flags & _ISTO) /* XXX tr()! */
422 i -= 3;
423 n = fprintf(f, "%s%s", ((flags & _ISTO) ? "To " : ""),
424 colalign(name, i, n, &wleft));
425 if (n < 0)
426 wleft = 0;
427 else if (flags & _ISTO)
428 wleft -= 3;
429 break;
430 case 'i':
431 if (threaded) {
432 #ifdef HAVE_COLOUR
433 cpen_new = n_colour_pen_create(n_COLOUR_ID_SUM_THREAD, colo_tag);
434 if (cpen_new != cpen_cur)
435 n_colour_pen_put(cpen_cur = cpen_new, f);
436 #endif
437 n = __putindent(f, mp, MIN(wleft, scrnwidth - 60));
438 wleft = (n >= 0) ? wleft - n : 0;
439 #ifdef HAVE_COLOUR
440 if ((cpen_new = cpen_bas) != cpen_cur)
441 n_colour_pen_put(cpen_cur = cpen_new, f);
442 #endif
444 break;
445 case 'l':
446 if (n == 0)
447 n = 4;
448 if (UICMP(32, ABS(n), >, wleft))
449 n = (n < 0) ? -wleft : wleft;
450 if (mp->m_xlines) {
451 n = fprintf(f, "%*ld", n, mp->m_xlines);
452 wleft = (n >= 0) ? wleft - n : 0;
453 } else {
454 n = ABS(n);
455 wleft -= n;
456 while (n-- != 0)
457 putc(' ', f);
459 break;
460 case 'm':
461 if (n == 0) {
462 n = 3;
463 if (threaded)
464 for (i = msgCount; i > 999; i /= 10)
465 ++n;
467 if (UICMP(32, ABS(n), >, wleft))
468 n = (n < 0) ? -wleft : wleft;
469 n = fprintf(f, "%*lu", n, (ul_i)msgno);
470 wleft = (n >= 0) ? wleft - n : 0;
471 break;
472 case 'o':
473 if (n == 0)
474 n = -5;
475 if (UICMP(32, ABS(n), >, wleft))
476 n = (n < 0) ? -wleft : wleft;
477 n = fprintf(f, "%*lu", n, (ul_i)mp->m_xsize);
478 wleft = (n >= 0) ? wleft - n : 0;
479 break;
480 case 'S':
481 flags |= _SFMT;
482 /*FALLTHRU*/
483 case 's':
484 if (n == 0)
485 n = subjlen - 2;
486 if (n > 0 && s < 0)
487 n = -n;
488 if (subjlen > wleft)
489 subjlen = wleft;
490 if (UICMP(32, ABS(n), >, subjlen))
491 n = (n < 0) ? -subjlen : subjlen;
492 if (flags & _SFMT)
493 n -= (n < 0) ? -2 : 2;
494 if (n == 0)
495 break;
496 if (subjline == NULL)
497 subjline = __subject(mp, (threaded && (flags & _IFMT)), yetprinted);
498 if (subjline == (char*)-1) {
499 n = fprintf(f, "%*s", n, "");
500 wleft = (n >= 0) ? wleft - n : 0;
501 } else {
502 n = fprintf(f, ((flags & _SFMT) ? "\"%s\"" : "%s"),
503 colalign(subjline, ABS(n), n, &wleft));
504 if (n < 0)
505 wleft = 0;
507 break;
508 case 'T': { /* Message recipient flags */
509 /* We never can reuse "name" since it's the full name */
510 struct name const *np = lextract(hfield1("to", mp), GTO | GSKIN);
511 c = ' ';
512 i = 0;
513 j_A_redo:
514 for (; np != NULL; np = np->n_flink) {
515 switch (is_mlist(np->n_name, FAL0)) {
516 case MLIST_SUBSCRIBED: c = 'S'; goto jputcb;
517 case MLIST_KNOWN: c = 'L'; goto jputcb;
518 case MLIST_OTHER:
519 default: break;
522 if (i != 0)
523 goto jputcb;
524 ++i;
525 np = lextract(hfield1("cc", mp), GCC | GSKIN);
526 goto j_A_redo;
528 case 't':
529 if (n == 0) {
530 n = 3;
531 if (threaded)
532 for (i = msgCount; i > 999; i /= 10)
533 ++n;
535 if (UICMP(32, ABS(n), >, wleft))
536 n = (n < 0) ? -wleft : wleft;
537 n = fprintf(f, "%*lu",
538 n, (threaded ? (ul_i)mp->m_threadpos : (ul_i)msgno));
539 wleft = (n >= 0) ? wleft - n : 0;
540 break;
541 default:
542 if (options & OPT_D_V)
543 n_err(_("Unkown *headline* format: \"%%%c\"\n"), c);
544 c = '?';
545 goto jputcb;
548 if (wleft <= 0)
549 break;
552 #ifdef HAVE_COLOUR
553 n_colour_reset(f);
554 #endif
555 putc('\n', f);
557 if (subjline != NULL && subjline != (char*)-1)
558 free(subjline);
559 NYD_LEAVE;
562 static char *
563 __subject(struct message *mp, bool_t threaded, size_t yetprinted)
565 struct str in, out;
566 char *rv = (char*)-1, *ms;
567 NYD_ENTER;
569 if ((ms = hfield1("subject", mp)) == NULL)
570 goto jleave;
572 in.l = strlen(in.s = ms);
573 mime_fromhdr(&in, &out, TD_ICONV | TD_ISPR);
574 rv = ms = out.s;
576 if (!threaded || mp->m_level == 0)
577 goto jleave;
579 /* In a display thread - check wether this message uses the same
580 * Subject: as it's parent or elder neighbour, suppress printing it if
581 * this is the case. To extend this a bit, ignore any leading Re: or
582 * Fwd: plus follow-up WS. Ignore invisible messages along the way */
583 ms = subject_re_trim(ms);
585 for (; (mp = prev_in_thread(mp)) != NULL && yetprinted-- > 0;) {
586 char *os;
588 if (visible(mp) && (os = hfield1("subject", mp)) != NULL) {
589 struct str oout;
590 int x;
592 in.l = strlen(in.s = os);
593 mime_fromhdr(&in, &oout, TD_ICONV | TD_ISPR);
594 x = asccasecmp(ms, subject_re_trim(oout.s));
595 free(oout.s);
597 if (!x) {
598 free(out.s);
599 rv = (char*)-1;
601 break;
604 jleave:
605 NYD_LEAVE;
606 return rv;
609 static int
610 __putindent(FILE *fp, struct message *mp, int maxwidth)/* XXX no magic consts */
612 struct message *mq;
613 int *us, indlvl, indw, i, important = MNEW | MFLAGGED;
614 char *cs;
615 NYD_ENTER;
617 if (mp->m_level == 0 || maxwidth == 0) {
618 indw = 0;
619 goto jleave;
622 cs = ac_alloc(mp->m_level);
623 us = ac_alloc(mp->m_level * sizeof *us);
625 i = mp->m_level - 1;
626 if (mp->m_younger && UICMP(32, i + 1, ==, mp->m_younger->m_level)) {
627 if (mp->m_parent && mp->m_parent->m_flag & important)
628 us[i] = mp->m_flag & important ? 0x2523 : 0x2520;
629 else
630 us[i] = mp->m_flag & important ? 0x251D : 0x251C;
631 cs[i] = '+';
632 } else {
633 if (mp->m_parent && mp->m_parent->m_flag & important)
634 us[i] = mp->m_flag & important ? 0x2517 : 0x2516;
635 else
636 us[i] = mp->m_flag & important ? 0x2515 : 0x2514;
637 cs[i] = '\\';
640 mq = mp->m_parent;
641 for (i = mp->m_level - 2; i >= 0; --i) {
642 if (mq) {
643 if (UICMP(32, i, >, mq->m_level - 1)) {
644 us[i] = cs[i] = ' ';
645 continue;
647 if (mq->m_younger) {
648 if (mq->m_parent && (mq->m_parent->m_flag & important))
649 us[i] = 0x2503;
650 else
651 us[i] = 0x2502;
652 cs[i] = '|';
653 } else
654 us[i] = cs[i] = ' ';
655 mq = mq->m_parent;
656 } else
657 us[i] = cs[i] = ' ';
660 --maxwidth;
661 for (indlvl = indw = 0; (ui8_t)indlvl < mp->m_level && indw < maxwidth;
662 ++indlvl) {
663 if (indw < maxwidth - 1)
664 indw += (int)putuc(us[indlvl], cs[indlvl] & 0xFF, fp);
665 else
666 indw += (int)putuc(0x21B8, '^', fp);
668 indw += putuc(0x25B8, '>', fp);
670 ac_free(us);
671 ac_free(cs);
672 jleave:
673 NYD_LEAVE;
674 return indw;
677 static int
678 _dispc(struct message *mp, char const *a)
680 int i = ' ';
681 NYD_ENTER;
683 if ((mp->m_flag & (MREAD | MNEW)) == MREAD)
684 i = a[3];
685 if ((mp->m_flag & (MREAD | MNEW)) == (MREAD | MNEW))
686 i = a[2];
687 if (mp->m_flag & MANSWERED)
688 i = a[8];
689 if (mp->m_flag & MDRAFTED)
690 i = a[9];
691 if ((mp->m_flag & (MREAD | MNEW)) == MNEW)
692 i = a[0];
693 if (!(mp->m_flag & (MREAD | MNEW)))
694 i = a[1];
695 if (mp->m_flag & MSPAM)
696 i = a[12];
697 if (mp->m_flag & MSPAMUNSURE)
698 i = a[13];
699 if (mp->m_flag & MSAVED)
700 i = a[4];
701 if (mp->m_flag & MPRESERVE)
702 i = a[5];
703 if (mp->m_flag & (MBOX | MBOXED))
704 i = a[6];
705 if (mp->m_flag & MFLAGGED)
706 i = a[7];
707 if (mb.mb_threaded == 1 && mp->m_collapsed > 0)
708 i = a[11];
709 if (mb.mb_threaded == 1 && mp->m_collapsed < 0)
710 i = a[10];
711 NYD_LEAVE;
712 return i;
715 static int
716 a_cmd_scroll(char const *arg, bool_t onlynew){
717 long l;
718 char *eptr;
719 bool_t isabs;
720 int msgspec, size, maxs;
721 NYD2_ENTER;
723 msgspec = onlynew ? -1 : 0;
724 size = screensize();
725 maxs = msgCount / size;
727 switch(*arg){
728 case '\0':
729 ++_screen;
730 goto jfwd;
731 case '$':
732 if(arg[1] != '\0')
733 goto jerr;
734 if(_screen == maxs)
735 goto jerrfwd;
736 _screen = maxs;
737 break;
738 case '+':
739 if(arg[1] == '\0')
740 ++_screen;
741 else{
742 isabs = FAL0;
744 ++arg;
745 if(0){
746 case '1': case '2': case '3': case '4': case '5':
747 case '6': case '7': case '8': case '9': case '0':
748 isabs = TRU1;
750 l = strtol(arg, &eptr, 10);
751 if(*eptr != '\0')
752 goto jerr;
753 if(l > maxs - (isabs ? 0 : _screen))
754 goto jerrfwd;
755 _screen = isabs ? (int)l : _screen + l;
757 jfwd:
758 if(_screen > maxs){
759 jerrfwd:
760 _screen = maxs;
761 printf(_("On last screenful of messages\n"));
763 break;
765 case '-':
766 if(arg[1] == '\0')
767 --_screen;
768 else{
769 ++arg;
770 l = strtol(arg, &eptr, 10);
771 if(*eptr != '\0')
772 goto jerr;
773 if(l > _screen)
774 goto jerrbwd;
775 _screen -= l;
777 if(_screen < 0){
778 jerrbwd:
779 _screen = 0;
780 printf(_("On first screenful of messages\n"));
782 if(msgspec == -1)
783 msgspec = -2;
784 break;
785 default:
786 jerr:
787 n_err(_("Unrecognized scrolling command \"%s\"\n"), arg);
788 size = 1;
789 goto jleave;
792 size = _headers(msgspec);
793 jleave:
794 NYD2_LEAVE;
795 return size;
798 static int
799 _headers(int msgspec) /* TODO rework v15 */
801 struct n_sigman sm;
802 bool_t volatile isrelax;
803 ui32_t volatile flag;
804 int g, k, mesg, size, lastg = 1;
805 struct message *mp, *mq, *lastmq = NULL;
806 enum mflag fl = MNEW | MFLAGGED;
807 NYD_ENTER;
809 time_current_update(&time_current, FAL0);
811 flag = 0;
812 isrelax = FAL0;
813 n_SIGMAN_ENTER_SWITCH(&sm, n_SIGMAN_ALL) {
814 case 0:
815 break;
816 default:
817 goto jleave;
820 #ifdef HAVE_COLOUR
821 if (options & OPT_INTERACTIVE)
822 n_colour_env_create(n_COLOUR_CTX_SUM, FAL0);
823 #endif
825 size = screensize();
826 if (_screen < 0)
827 _screen = 0;
828 #if 0 /* FIXME original code path */
829 k = _screen * size;
830 #else
831 if (msgspec <= 0)
832 k = _screen * size;
833 else
834 k = msgspec;
835 #endif
836 if (k >= msgCount)
837 k = msgCount - size;
838 if (k < 0)
839 k = 0;
841 if (mb.mb_threaded == 0) {
842 g = 0;
843 mq = message;
844 for (mp = message; PTRCMP(mp, <, message + msgCount); ++mp)
845 if (visible(mp)) {
846 if (g % size == 0)
847 mq = mp;
848 if (mp->m_flag & fl) {
849 lastg = g;
850 lastmq = mq;
852 if ((msgspec > 0 && PTRCMP(mp, ==, message + msgspec - 1)) ||
853 (msgspec == 0 && g == k) ||
854 (msgspec == -2 && g == k + size && lastmq) ||
855 (msgspec < 0 && g >= k && (mp->m_flag & fl) != 0))
856 break;
857 g++;
859 if (lastmq && (msgspec == -2 ||
860 (msgspec == -1 && PTRCMP(mp, ==, message + msgCount)))) {
861 g = lastg;
862 mq = lastmq;
864 _screen = g / size;
866 mp = mq;
867 mesg = (int)PTR2SIZE(mp - message);
868 if (PTRCMP(dot, !=, message + msgspec - 1)) { /* TODO really?? */
869 for (mq = mp; PTRCMP(mq, <, message + msgCount); ++mq)
870 if (visible(mq)) {
871 setdot(mq);
872 break;
876 srelax_hold();
877 isrelax = TRU1;
878 for (; PTRCMP(mp, <, message + msgCount); ++mp) {
879 ++mesg;
880 if (!visible(mp))
881 continue;
882 if (UICMP(32, flag++, >=, size))
883 break;
884 _print_head(0, mesg, stdout, 0);
885 srelax();
887 srelax_rele();
888 isrelax = FAL0;
889 } else { /* threaded */
890 g = 0;
891 mq = threadroot;
892 for (mp = threadroot; mp; mp = next_in_thread(mp))
893 if (visible(mp) &&
894 (mp->m_collapsed <= 0 ||
895 PTRCMP(mp, ==, message + msgspec - 1))) {
896 if (g % size == 0)
897 mq = mp;
898 if (mp->m_flag & fl) {
899 lastg = g;
900 lastmq = mq;
902 if ((msgspec > 0 && PTRCMP(mp, ==, message + msgspec - 1)) ||
903 (msgspec == 0 && g == k) ||
904 (msgspec == -2 && g == k + size && lastmq) ||
905 (msgspec < 0 && g >= k && (mp->m_flag & fl) != 0))
906 break;
907 g++;
909 if (lastmq && (msgspec == -2 ||
910 (msgspec == -1 && PTRCMP(mp, ==, message + msgCount)))) {
911 g = lastg;
912 mq = lastmq;
914 _screen = g / size;
915 mp = mq;
916 if (PTRCMP(dot, !=, message + msgspec - 1)) { /* TODO really?? */
917 for (mq = mp; mq; mq = next_in_thread(mq))
918 if (visible(mq) && mq->m_collapsed <= 0) {
919 setdot(mq);
920 break;
924 srelax_hold();
925 isrelax = TRU1;
926 while (mp) {
927 if (visible(mp) &&
928 (mp->m_collapsed <= 0 ||
929 PTRCMP(mp, ==, message + msgspec - 1))) {
930 if (UICMP(32, flag++, >=, size))
931 break;
932 _print_head(flag - 1, PTR2SIZE(mp - message + 1), stdout,
933 mb.mb_threaded);
934 srelax();
936 mp = next_in_thread(mp);
938 srelax_rele();
939 isrelax = FAL0;
942 if (!flag) {
943 printf(_("No more mail.\n"));
944 if (pstate & (PS_HOOK_MASK | PS_ROBOT))
945 flag = !flag;
948 n_sigman_cleanup_ping(&sm);
949 jleave:
950 if (isrelax)
951 srelax_rele();
952 n_COLOUR( n_colour_env_gut((sm.sm_signo != SIGPIPE) ? stdout : NULL); )
953 NYD_LEAVE;
954 n_sigman_leave(&sm, n_SIGMAN_VIPSIGS_NTTYOUT);
955 return !flag;
958 static int
959 _type1(int *msgvec, bool_t doign, bool_t dopage, bool_t dopipe,
960 bool_t dodecode, char *cmd, ui64_t *tstats)
962 struct n_sigman sm;
963 ui64_t mstats[1];
964 int rv = 1, *ip;
965 struct message *mp;
966 char const *cp;
967 FILE * volatile obuf;
968 bool_t volatile isrelax = FAL0;
969 NYD_ENTER;
970 {/* C89.. */
971 enum sendaction const action = ((dopipe && ok_blook(piperaw))
972 ? SEND_MBOX : dodecode
973 ? SEND_SHOW : doign
974 ? SEND_TODISP : SEND_TODISP_ALL);
975 bool_t const volatile formfeed = (dopipe && ok_blook(page));
976 obuf = stdout;
978 n_SIGMAN_ENTER_SWITCH(&sm, n_SIGMAN_ALL) {
979 case 0:
980 break;
981 default:
982 goto jleave;
985 if (dopipe) {
986 if ((obuf = Popen(cmd, "w", ok_vlook(SHELL), NULL, 1)) == NULL) {
987 n_perr(cmd, 0);
988 obuf = stdout;
990 } else if ((options & OPT_TTYOUT) && (dopage ||
991 ((options & OPT_INTERACTIVE) && (cp = ok_vlook(crt)) != NULL))) {
992 size_t nlines = 0;
994 if (!dopage) {
995 for (ip = msgvec; *ip && PTRCMP(ip - msgvec, <, msgCount); ++ip) {
996 mp = message + *ip - 1;
997 if (!(mp->m_have & HAVE_BODY))
998 if (get_body(mp) != OKAY)
999 goto jcleanup_leave;
1000 nlines += mp->m_lines + 1; /* Message info XXX and PARTS... */
1004 /* >= not <: we return to the prompt */
1005 if (dopage || UICMP(z, nlines, >=,
1006 (*cp != '\0' ? strtoul(cp, NULL, 0) : (size_t)realscreenheight))) {
1007 if ((obuf = n_pager_open()) == NULL)
1008 obuf = stdout;
1010 #ifdef HAVE_COLOUR
1011 if ((options & OPT_INTERACTIVE) &&
1012 (action == SEND_TODISP || action == SEND_TODISP_ALL ||
1013 action == SEND_SHOW))
1014 n_colour_env_create(n_COLOUR_CTX_VIEW, obuf != stdout);
1015 #endif
1017 #ifdef HAVE_COLOUR
1018 else if ((options & OPT_INTERACTIVE) &&
1019 (action == SEND_TODISP || action == SEND_TODISP_ALL))
1020 n_colour_env_create(n_COLOUR_CTX_VIEW, FAL0);
1021 #endif
1023 /*TODO unless we have our signal manager special care must be taken */
1024 srelax_hold();
1025 isrelax = TRU1;
1026 for (ip = msgvec; *ip && PTRCMP(ip - msgvec, <, msgCount); ++ip) {
1027 mp = message + *ip - 1;
1028 touch(mp);
1029 setdot(mp);
1030 uncollapse1(mp, 1);
1031 if (!dopipe && ip != msgvec)
1032 fprintf(obuf, "\n");
1033 if (action != SEND_MBOX)
1034 _show_msg_overview(obuf, mp, *ip);
1035 sendmp(mp, obuf, (doign ? ignore : NULL), NULL, action, mstats);
1036 srelax();
1037 if (formfeed) /* TODO a nicer way to separate piped messages! */
1038 putc('\f', obuf);
1039 if (tstats != NULL)
1040 tstats[0] += mstats[0];
1042 srelax_rele();
1043 isrelax = FAL0;
1045 rv = 0;
1046 jcleanup_leave:
1047 n_sigman_cleanup_ping(&sm);
1048 jleave:
1049 if (isrelax)
1050 srelax_rele();
1051 n_COLOUR( n_colour_env_gut((sm.sm_signo != SIGPIPE) ? obuf : NULL); )
1052 if (obuf != stdout)
1053 n_pager_close(obuf);
1055 NYD_LEAVE;
1056 n_sigman_leave(&sm, n_SIGMAN_VIPSIGS_NTTYOUT);
1057 return rv;
1060 static int
1061 _pipe1(char *str, int doign)
1063 ui64_t stats[1];
1064 char *cmd;
1065 int *msgvec, rv = 1;
1066 bool_t needs_list;
1067 NYD_ENTER;
1069 if ((cmd = laststring(str, &needs_list, TRU1)) == NULL) {
1070 cmd = ok_vlook(cmd);
1071 if (cmd == NULL || *cmd == '\0') {
1072 n_err(_("Variable *cmd* not set\n"));
1073 goto jleave;
1077 msgvec = salloc((msgCount + 2) * sizeof *msgvec);
1079 if (!needs_list) {
1080 *msgvec = first(0, MMNORM);
1081 if (*msgvec == 0) {
1082 if (pstate & (PS_HOOK_MASK | PS_ROBOT)) {
1083 rv = 0;
1084 goto jleave;
1086 puts(_("No messages to pipe."));
1087 goto jleave;
1089 msgvec[1] = 0;
1090 } else if (getmsglist(str, msgvec, 0) < 0)
1091 goto jleave;
1092 if (*msgvec == 0) {
1093 if (pstate & (PS_HOOK_MASK | PS_ROBOT)) {
1094 rv = 0;
1095 goto jleave;
1097 printf("No applicable messages.\n");
1098 goto jleave;
1101 printf(_("Pipe to: \"%s\"\n"), cmd);
1102 stats[0] = 0;
1103 if ((rv = _type1(msgvec, doign, FAL0, TRU1, FAL0, cmd, stats)) == 0)
1104 printf("\"%s\" %" PRIu64 " bytes\n", cmd, stats[0]);
1105 jleave:
1106 NYD_LEAVE;
1107 return rv;
1110 FL int
1111 c_cmdnotsupp(void *v) /* TODO -> lex.c */
1113 NYD_ENTER;
1114 UNUSED(v);
1115 n_err(_("The requested feature is not compiled in\n"));
1116 NYD_LEAVE;
1117 return 1;
1120 FL int
1121 c_headers(void *v)
1123 int rv;
1124 NYD_ENTER;
1126 rv = print_header_group((int*)v);
1127 NYD_LEAVE;
1128 return rv;
1131 FL int
1132 print_header_group(int *vector)
1134 int rv;
1135 NYD_ENTER;
1137 assert(vector != NULL && vector != (void*)-1);
1138 rv = _headers(vector[0]);
1139 NYD_LEAVE;
1140 return rv;
1143 FL int
1144 c_scroll(void *v)
1146 int rv;
1147 NYD_ENTER;
1149 rv = a_cmd_scroll(v, FAL0);
1150 NYD_LEAVE;
1151 return rv;
1154 FL int
1155 c_Scroll(void *v)
1157 int rv;
1158 NYD_ENTER;
1160 rv = a_cmd_scroll(v, TRU1);
1161 NYD_LEAVE;
1162 return rv;
1165 FL int
1166 c_from(void *v)
1168 struct n_sigman sm;
1169 int *msgvec = v, *ip, n;
1170 char *cp;
1171 FILE * volatile obuf;
1172 bool_t volatile isrelax;
1173 NYD_ENTER;
1175 time_current_update(&time_current, FAL0);
1177 obuf = stdout;
1178 isrelax = FAL0;
1179 n_SIGMAN_ENTER_SWITCH(&sm, n_SIGMAN_ALL) {
1180 case 0:
1181 break;
1182 default:
1183 goto jleave;
1186 if (options & OPT_INTERACTIVE) {
1187 if ((cp = ok_vlook(crt)) != NULL) {
1188 for (n = 0, ip = msgvec; *ip != 0; ++ip)
1189 ++n;
1190 if (UICMP(z, n, >, (*cp == '\0'
1191 ? (size_t)screensize() : strtoul(cp, NULL, 0)) + 3) &&
1192 (obuf = n_pager_open()) == NULL)
1193 obuf = stdout;
1195 n_COLOUR( n_colour_env_create(n_COLOUR_CTX_SUM, obuf != stdout); )
1198 /* Update dot before display so that the dotmark etc. are correct */
1199 for (ip = msgvec; *ip != 0; ++ip)
1201 if (--ip >= msgvec)
1202 setdot(message + *ip - 1);
1204 srelax_hold();
1205 isrelax = TRU1;
1206 for (n = 0, ip = msgvec; *ip != 0; ++ip) { /* TODO join into _print_head() */
1207 _print_head((size_t)n++, (size_t)*ip, obuf, mb.mb_threaded);
1208 srelax();
1210 srelax_rele();
1211 isrelax = FAL0;
1213 n_sigman_cleanup_ping(&sm);
1214 jleave:
1215 if (isrelax)
1216 srelax_rele();
1217 n_COLOUR( n_colour_env_gut((sm.sm_signo != SIGPIPE) ? obuf : NULL); )
1218 if (obuf != stdout)
1219 n_pager_close(obuf);
1220 NYD_LEAVE;
1221 n_sigman_leave(&sm, n_SIGMAN_VIPSIGS_NTTYOUT);
1222 return 0;
1225 FL void
1226 print_headers(size_t bottom, size_t topx, bool_t only_marked)
1228 struct n_sigman sm;
1229 bool_t volatile isrelax;
1230 size_t printed;
1231 NYD_ENTER;
1233 time_current_update(&time_current, FAL0);
1235 isrelax = FAL0;
1236 n_SIGMAN_ENTER_SWITCH(&sm, n_SIGMAN_ALL) {
1237 case 0:
1238 break;
1239 default:
1240 goto jleave;
1243 #ifdef HAVE_COLOUR
1244 if (options & OPT_INTERACTIVE)
1245 n_colour_env_create(n_COLOUR_CTX_SUM, FAL0);
1246 #endif
1248 srelax_hold();
1249 isrelax = TRU1;
1250 for (printed = 0; bottom <= topx; ++bottom) {
1251 struct message *mp = message + bottom - 1;
1252 if (only_marked) {
1253 if (!(mp->m_flag & MMARK))
1254 continue;
1255 } else if (!visible(mp))
1256 continue;
1257 _print_head(printed++, bottom, stdout, FAL0);
1258 srelax();
1260 srelax_rele();
1261 isrelax = FAL0;
1263 n_sigman_cleanup_ping(&sm);
1264 jleave:
1265 if (isrelax)
1266 srelax_rele();
1267 n_COLOUR( n_colour_env_gut((sm.sm_signo != SIGPIPE) ? stdout : NULL); )
1268 NYD_LEAVE;
1269 n_sigman_leave(&sm, n_SIGMAN_VIPSIGS_NTTYOUT);
1272 FL int
1273 c_pdot(void *v)
1275 NYD_ENTER;
1276 UNUSED(v);
1277 printf("%d\n", (int)PTR2SIZE(dot - message + 1));
1278 NYD_LEAVE;
1279 return 0;
1282 FL int
1283 c_more(void *v)
1285 int *msgvec = v, rv;
1286 NYD_ENTER;
1288 rv = _type1(msgvec, TRU1, TRU1, FAL0, FAL0, NULL, NULL);
1289 NYD_LEAVE;
1290 return rv;
1293 FL int
1294 c_More(void *v)
1296 int *msgvec = v, rv;
1297 NYD_ENTER;
1299 rv = _type1(msgvec, FAL0, TRU1, FAL0, FAL0, NULL, NULL);
1300 NYD_LEAVE;
1301 return rv;
1304 FL int
1305 c_type(void *v)
1307 int *msgvec = v, rv;
1308 NYD_ENTER;
1310 rv = _type1(msgvec, TRU1, FAL0, FAL0, FAL0, NULL, NULL);
1311 NYD_LEAVE;
1312 return rv;
1315 FL int
1316 c_Type(void *v)
1318 int *msgvec = v, rv;
1319 NYD_ENTER;
1321 rv = _type1(msgvec, FAL0, FAL0, FAL0, FAL0, NULL, NULL);
1322 NYD_LEAVE;
1323 return rv;
1326 FL int
1327 c_show(void *v)
1329 int *msgvec = v, rv;
1330 NYD_ENTER;
1332 rv = _type1(msgvec, FAL0, FAL0, FAL0, TRU1, NULL, NULL);
1333 NYD_LEAVE;
1334 return rv;
1337 FL int
1338 c_pipe(void *v)
1340 char *str = v;
1341 int rv;
1342 NYD_ENTER;
1344 rv = _pipe1(str, 1);
1345 NYD_LEAVE;
1346 return rv;
1349 FL int
1350 c_Pipe(void *v)
1352 char *str = v;
1353 int rv;
1354 NYD_ENTER;
1356 rv = _pipe1(str, 0);
1357 NYD_LEAVE;
1358 return rv;
1361 FL int
1362 c_top(void *v)
1364 int *msgvec = v, *ip, c, topl, lines, empty_last;
1365 struct message *mp;
1366 char *cp, *linebuf = NULL;
1367 size_t linesize = 0;
1368 FILE *ibuf;
1369 NYD_ENTER;
1371 topl = (int)strtol(ok_vlook(toplines), NULL, 0);
1373 /* XXX Colours of `top' only for message and part info lines */
1374 #ifdef HAVE_COLOUR
1375 if (options & OPT_INTERACTIVE)
1376 n_colour_env_create(n_COLOUR_CTX_VIEW, FAL0);
1377 #endif
1378 empty_last = 1;
1379 for (ip = msgvec; *ip != 0 && UICMP(z, PTR2SIZE(ip - msgvec), <, msgCount);
1380 ++ip) {
1381 mp = message + *ip - 1;
1382 touch(mp);
1383 setdot(mp);
1384 pstate |= PS_DID_PRINT_DOT;
1385 if (!empty_last)
1386 printf("\n");
1387 _show_msg_overview(stdout, mp, *ip);
1388 if (mp->m_flag & MNOFROM)
1389 /* XXX c_top(): coloured output? */
1390 printf("From %s %s\n", fakefrom(mp), fakedate(mp->m_time));
1391 if ((ibuf = setinput(&mb, mp, NEED_BODY)) == NULL) { /* XXX use TOP */
1392 v = NULL;
1393 break;
1395 c = mp->m_lines;
1396 /* TODO v15: in a filter-based implementation, simply "sendmp()" and hook
1397 * TODO the output, then stop after passing through *toplines* lines! */
1398 for (lines = 0; lines < c && UICMP(32, lines, <=, topl); ++lines) {
1399 if (readline_restart(ibuf, &linebuf, &linesize, 0) < 0)
1400 break;
1401 puts(linebuf);
1403 for (cp = linebuf; *cp != '\0' && blankchar(*cp); ++cp)
1405 empty_last = (*cp == '\0');
1409 n_COLOUR( n_colour_env_gut(stdout); )
1410 if (linebuf != NULL)
1411 free(linebuf);
1412 NYD_LEAVE;
1413 return (v != NULL);
1416 FL int
1417 c_stouch(void *v)
1419 int *msgvec = v, *ip;
1420 NYD_ENTER;
1422 for (ip = msgvec; *ip != 0; ++ip) {
1423 setdot(message + *ip - 1);
1424 dot->m_flag |= MTOUCH;
1425 dot->m_flag &= ~MPRESERVE;
1426 pstate |= PS_DID_PRINT_DOT;
1428 NYD_LEAVE;
1429 return 0;
1432 FL int
1433 c_mboxit(void *v)
1435 int *msgvec = v, *ip;
1436 NYD_ENTER;
1438 if (pstate & PS_EDIT) {
1439 n_err(_("`mbox' can only be used in a system mailbox\n")); /* TODO */
1440 goto jleave;
1443 for (ip = msgvec; *ip != 0; ++ip) {
1444 setdot(message + *ip - 1);
1445 dot->m_flag |= MTOUCH | MBOX;
1446 dot->m_flag &= ~MPRESERVE;
1447 pstate |= PS_DID_PRINT_DOT;
1449 jleave:
1450 NYD_LEAVE;
1451 return 0;
1454 FL int
1455 c_folders(void *v)
1457 char const *cp;
1458 char **argv;
1459 int rv;
1460 NYD_ENTER;
1462 rv = 1;
1464 if(*(argv = v) != NULL){
1465 if((cp = fexpand(*argv, FEXP_NSHELL | FEXP_LOCAL)) == NULL)
1466 goto jleave;
1467 }else
1468 cp = folder_query();
1470 run_command(ok_vlook(LISTER), 0, COMMAND_FD_PASS, COMMAND_FD_PASS, cp,
1471 NULL, NULL, NULL);
1472 jleave:
1473 NYD_LEAVE;
1474 return rv;
1477 /* s-it-mode */