1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2015 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
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
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
38 #ifndef HAVE_AMALGAMATION
43 static sigjmp_buf _cmd1_pipejmp
;
45 static void _cmd1_onpipe(int signo
);
47 /* Prepare and print "[Message: xy]:" intro */
48 static void _show_msg_overview(FILE *obuf
, struct message
*mp
, int msg_no
);
50 /* ... And place the extracted date in `date' */
51 static void _parse_from_(struct message
*mp
, char date
[FROM_DATEBUF
]);
53 /* Print out the header of a specific message
54 * __hprf: handle *headline*
55 * __subject: return -1 if Subject: yet seen, otherwise smalloc()d Subject:
56 * __putindent: print out the indenting in threaded display */
57 static void _print_head(size_t yetprinted
, size_t msgno
, FILE *f
,
59 static void __hprf(size_t yetprinted
, char const *fmt
, size_t msgno
,
60 FILE *f
, bool_t threaded
, char const *attrlist
);
61 static char * __subject(struct message
*mp
, bool_t threaded
,
63 static int __putindent(FILE *fp
, struct message
*mp
, int maxwidth
);
65 static int _dispc(struct message
*mp
, char const *a
);
67 /* Shared `z' implementation */
68 static int a_cmd_scroll(char const *arg
, bool_t onlynew
);
70 /* Shared `headers' implementation */
71 static int _headers(int msgspec
);
73 /* Show the requested messages */
74 static int _type1(int *msgvec
, bool_t doign
, bool_t dopage
, bool_t dopipe
,
75 bool_t dodecode
, char *cmd
, ui64_t
*tstats
);
77 /* Pipe the requested messages */
78 static int _pipe1(char *str
, int doign
);
81 _cmd1_onpipe(int signo
)
83 NYD_X
; /* Signal handler */
85 siglongjmp(_cmd1_pipejmp
, 1);
89 _show_msg_overview(FILE *obuf
, struct message
*mp
, int msg_no
)
91 char const *cpre
= "", *csuf
= "";
95 if (pstate
& PS_COLOUR_ACTIVE
) {
96 struct n_colour_pen
*cpen
;
98 if ((cpen
= n_colour_pen_create(n_COLOUR_ID_VIEW_MSGINFO
, NULL
)) != NULL
){
101 if ((sp
= n_colour_pen_to_str(cpen
)) != NULL
)
103 if ((sp
= n_colour_reset_to_str()) != NULL
)
108 fprintf(obuf
, _("%s[-- Message %2d -- %lu lines, %lu bytes --]:%s\n"),
109 cpre
, msg_no
, (ul_i
)mp
->m_lines
, (ul_i
)mp
->m_size
, csuf
);
114 _parse_from_(struct message
*mp
, char date
[FROM_DATEBUF
]) /* TODO line pool */
122 if ((ibuf
= setinput(&mb
, mp
, NEED_HEADER
)) != NULL
&&
123 (hlen
= readline_restart(ibuf
, &hline
, &hsize
, 0)) > 0)
124 extract_date_from_from_(hline
, hlen
, date
);
131 _print_head(size_t yetprinted
, size_t msgno
, FILE *f
, bool_t threaded
)
134 char attrlist
[attrlen
+1], *cp
;
138 if ((cp
= ok_vlook(attrlist
)) != NULL
) {
139 if (strlen(cp
) == attrlen
) {
140 memcpy(attrlist
, cp
, attrlen
+1);
143 n_err(_("*attrlist* is not of the correct length, using builtin\n"));
146 if (ok_blook(bsdcompat
) || ok_blook(bsdflags
)) {
147 char const bsdattr
[attrlen
+1] = "NU *HMFAT+-$~";
148 memcpy(attrlist
, bsdattr
, sizeof bsdattr
);
149 } else if (env_blook("SYSV3", FAL0
)) {
150 char const bsdattr
[attrlen
+1] = "NU *HMFAT+-$~";
151 memcpy(attrlist
, bsdattr
, sizeof bsdattr
);
152 OBSOLETE(_("*SYSV3*: please use *bsdcompat* or *bsdflags*, "
153 "or set *attrlist*"));
155 char const pattr
[attrlen
+1] = "NUROSPMFAT+-$~";
156 memcpy(attrlist
, pattr
, sizeof pattr
);
160 if ((fmt
= ok_vlook(headline
)) == NULL
) {
161 fmt
= ((ok_blook(bsdcompat
) || ok_blook(bsdheadline
))
162 ? "%>%a%m %-20f %16d %3l/%-5o %i%-S"
163 : "%>%a%m %-18f %16d %4l/%-5o %i%-s");
166 __hprf(yetprinted
, fmt
, msgno
, f
, threaded
, attrlist
);
171 __hprf(size_t yetprinted
, char const *fmt
, size_t msgno
, FILE *f
,
172 bool_t threaded
, char const *attrlist
)
174 char buf
[16], datebuf
[FROM_DATEBUF
], cbuf
[8], *cp
, *subjline
;
175 char const *datefmt
, *date
, *name
, *fp
n_COLOUR( COMMA
*colo_tag
);
176 int i
, n
, s
, wleft
, subjlen
;
179 n_COLOUR( struct n_colour_pen
*cpen_new COMMA
*cpen_cur COMMA
*cpen_bas
; )
186 _LOOP_MASK
= (1<<4) - 1,
192 if ((mp
= message
+ msgno
- 1) == dot
)
196 n_COLOUR( colo_tag
= NULL
; )
198 datefmt
= ok_vlook(datefield
);
200 if (datefmt
!= NULL
) {
201 fp
= hfield1("date", mp
);/* TODO use m_date field! */
207 date
= fakedate(datet
);
208 fp
= ok_vlook(datefield_markout_older
);
209 i
= (*datefmt
!= '\0');
211 i
|= (*fp
!= '\0') ? 2 | 4 : 2; /* XXX no magics */
213 /* May we strftime(3)? */
215 memcpy(&time_current
.tc_local
, localtime(&datet
),
216 sizeof time_current
.tc_local
);
218 if ((i
& 2) && (datet
> time_current
.tc_time
+ DATE_SECSDAY
||
219 #define _6M ((DATE_DAYSYEAR / 2) * DATE_SECSDAY)
220 (datet
+ _6M
< time_current
.tc_time
))) {
222 if ((datefmt
= (i
& 4) ? fp
: NULL
) == NULL
) {
223 memset(datebuf
, ' ', FROM_DATEBUF
); /* xxx ur */
224 memcpy(datebuf
+ 4, date
+ 4, 7);
225 datebuf
[4 + 7] = ' ';
226 memcpy(datebuf
+ 4 + 7 + 1, date
+ 20, 4);
227 datebuf
[4 + 7 + 1 + 4] = '\0';
230 n_COLOUR( colo_tag
= n_COLOUR_TAG_SUM_OLDER
; )
231 } else if ((i
& 1) == 0)
233 } else if (datet
== (time_t)0 && !(mp
->m_flag
& MNOFROM
)) {
234 /* TODO eliminate this path, query the FROM_ date in setptr(),
235 * TODO all other codepaths do so by themselves ALREADY ?????
236 * TODO assert(mp->m_time != 0);, then
237 * TODO ALSO changes behaviour of datefield_markout_older */
238 _parse_from_(mp
, datebuf
);
241 date
= fakedate(datet
);
245 if (name
!= NULL
&& ok_blook(showto
) && is_myname(skin(name
))) {
246 if ((cp
= hfield1("to", mp
)) != NULL
) {
256 name
= ok_blook(showname
) ? realname(name
) : prstr(skin(name
));
260 /* Detect the width of the non-format characters in *headline*;
261 * like that we can simply use putc() in the next loop, since we have
262 * already calculated their column widths (TODO it's sick) */
263 wleft
= subjlen
= scrnwidth
;
265 for (fp
= fmt
; *fp
!= '\0'; ++fp
) {
271 if (digitchar(*fp
)) {
274 n
= 10*n
+ *fp
- '0';
275 while (++fp
, digitchar(*fp
));
285 if (mb_cur_max
> 1) {
287 if ((s
= mbtowc(&wc
, fp
, mb_cur_max
)) == -1)
289 else if ((n
= wcwidth(wc
)) == -1)
301 /* Walk *headline*, producing output TODO not (really) MB safe */
304 colo_tag
= n_COLOUR_TAG_SUM_DOT
;
305 cpen_bas
= n_colour_pen_create(n_COLOUR_ID_SUM_HEADER
, colo_tag
);
306 n_colour_pen_put(cpen_new
= cpen_cur
= cpen_bas
, f
);
309 for (fp
= fmt
; *fp
!= '\0'; ++fp
) {
312 if ((c
= *fp
& 0xFF) != '%') {
314 if ((cpen_new
= cpen_bas
) != cpen_cur
)
315 n_colour_pen_put(cpen_cur
= cpen_new
, f
);
324 if ((c
= *++fp
) == '-') {
329 if (digitchar(*fp
)) {
331 n
= 10*n
+ *fp
- '0';
332 while (++fp
, digitchar(*fp
));
335 if ((c
= *fp
& 0xFF) == '\0')
345 if (flags
& _ISDOT
) {
346 n_COLOUR( cpen_new
= n_colour_pen_create(n_COLOUR_ID_SUM_DOTMARK
,
348 if (options
& OPT_UNICODE
) {
350 /* 25B8;BLACK RIGHT-POINTING SMALL TRIANGLE: â–¸ */
351 cbuf
[1] = (char)0x96, cbuf
[2] = (char)0xB8;
353 /* 25C2;BLACK LEFT-POINTING SMALL TRIANGLE: â—‚ */
354 cbuf
[1] = (char)0x97, cbuf
[2] = (char)0x82;
365 if (UICMP(32, ABS(n
), >, wleft
))
366 n
= (n
< 0) ? -wleft
: wleft
;
367 snprintf(buf
, sizeof buf
, "%u.%02u",
368 (mp
->m_spamscore
>> 8), (mp
->m_spamscore
& 0xFF));
369 n
= fprintf(f
, "%*s", n
, buf
);
370 wleft
= (n
>= 0) ? wleft
- n
: 0;
377 c
= _dispc(mp
, attrlist
);
380 if (cpen_new
== cpen_cur
)
382 if (cpen_new
!= cpen_cur
)
383 n_colour_pen_put(cpen_cur
= cpen_new
, f
);
385 if (UICMP(32, ABS(n
), >, wleft
))
386 n
= (n
< 0) ? -wleft
: wleft
;
388 n
= fprintf(f
, "%*s", n
, cbuf
);
389 wleft
= (n
>= 0) ? wleft
- n
: 0;
391 if ((cpen_new
= cpen_bas
) != cpen_cur
)
392 n_colour_pen_put(cpen_cur
= cpen_new
, f
);
396 if (datefmt
!= NULL
) {
397 i
= strftime(datebuf
, sizeof datebuf
, datefmt
,
398 &time_current
.tc_local
);
402 n_err(_("Ignored date format, it excesses the target "
403 "buffer (%lu bytes)\n"), (ul_i
)sizeof(datebuf
));
408 if (UICMP(32, ABS(n
), >, wleft
))
409 n
= (n
< 0) ? -wleft
: wleft
;
410 n
= fprintf(f
, "%*.*s", n
, n
, date
);
411 wleft
= (n
>= 0) ? wleft
- n
: 0;
416 if (UICMP(32, ABS(n
), >, wleft
))
417 n
= (n
< 0) ? -wleft
: wleft
;
418 n
= fprintf(f
, "%*u", n
, (threaded
== 1 ? mp
->m_level
: 0));
419 wleft
= (n
>= 0) ? wleft
- n
: 0;
430 n
= (n
< 0) ? -wleft
: wleft
;
432 if (flags
& _ISTO
) /* XXX tr()! */
434 n
= fprintf(f
, "%s%s", ((flags
& _ISTO
) ? "To " : ""),
435 colalign(name
, i
, n
, &wleft
));
438 else if (flags
& _ISTO
)
444 cpen_new
= n_colour_pen_create(n_COLOUR_ID_SUM_THREAD
, colo_tag
);
445 if (cpen_new
!= cpen_cur
)
446 n_colour_pen_put(cpen_cur
= cpen_new
, f
);
448 n
= __putindent(f
, mp
, MIN(wleft
, scrnwidth
- 60));
449 wleft
= (n
>= 0) ? wleft
- n
: 0;
451 if ((cpen_new
= cpen_bas
) != cpen_cur
)
452 n_colour_pen_put(cpen_cur
= cpen_new
, f
);
459 if (UICMP(32, ABS(n
), >, wleft
))
460 n
= (n
< 0) ? -wleft
: wleft
;
462 n
= fprintf(f
, "%*ld", n
, mp
->m_xlines
);
463 wleft
= (n
>= 0) ? wleft
- n
: 0;
475 for (i
= msgCount
; i
> 999; i
/= 10)
478 if (UICMP(32, ABS(n
), >, wleft
))
479 n
= (n
< 0) ? -wleft
: wleft
;
480 n
= fprintf(f
, "%*lu", n
, (ul_i
)msgno
);
481 wleft
= (n
>= 0) ? wleft
- n
: 0;
486 if (UICMP(32, ABS(n
), >, wleft
))
487 n
= (n
< 0) ? -wleft
: wleft
;
488 n
= fprintf(f
, "%*lu", n
, (ul_i
)mp
->m_xsize
);
489 wleft
= (n
>= 0) ? wleft
- n
: 0;
501 if (UICMP(32, ABS(n
), >, subjlen
))
502 n
= (n
< 0) ? -subjlen
: subjlen
;
504 n
-= (n
< 0) ? -2 : 2;
507 if (subjline
== NULL
)
508 subjline
= __subject(mp
, (threaded
&& (flags
& _IFMT
)), yetprinted
);
509 if (subjline
== (char*)-1) {
510 n
= fprintf(f
, "%*s", n
, "");
511 wleft
= (n
>= 0) ? wleft
- n
: 0;
513 n
= fprintf(f
, ((flags
& _SFMT
) ? "\"%s\"" : "%s"),
514 colalign(subjline
, ABS(n
), n
, &wleft
));
519 case 'T': { /* Message recipient flags */
520 /* We never can reuse "name" since it's the full name */
521 struct name
const *np
= lextract(hfield1("to", mp
), GTO
| GSKIN
);
525 for (; np
!= NULL
; np
= np
->n_flink
) {
526 switch (is_mlist(np
->n_name
, FAL0
)) {
527 case MLIST_SUBSCRIBED
: c
= 'S'; goto jputcb
;
528 case MLIST_KNOWN
: c
= 'L'; goto jputcb
;
536 np
= lextract(hfield1("cc", mp
), GCC
| GSKIN
);
543 for (i
= msgCount
; i
> 999; i
/= 10)
546 if (UICMP(32, ABS(n
), >, wleft
))
547 n
= (n
< 0) ? -wleft
: wleft
;
548 n
= fprintf(f
, "%*lu",
549 n
, (threaded
? (ul_i
)mp
->m_threadpos
: (ul_i
)msgno
));
550 wleft
= (n
>= 0) ? wleft
- n
: 0;
553 if (options
& OPT_D_V
)
554 n_err(_("Unkown *headline* format: \"%%%c\"\n"), c
);
568 if (subjline
!= NULL
&& subjline
!= (char*)-1)
574 __subject(struct message
*mp
, bool_t threaded
, size_t yetprinted
)
577 char *rv
= (char*)-1, *ms
;
580 if ((ms
= hfield1("subject", mp
)) == NULL
)
583 in
.l
= strlen(in
.s
= ms
);
584 mime_fromhdr(&in
, &out
, TD_ICONV
| TD_ISPR
);
587 if (!threaded
|| mp
->m_level
== 0)
590 /* In a display thread - check wether this message uses the same
591 * Subject: as it's parent or elder neighbour, suppress printing it if
592 * this is the case. To extend this a bit, ignore any leading Re: or
593 * Fwd: plus follow-up WS. Ignore invisible messages along the way */
594 ms
= subject_re_trim(ms
);
596 for (; (mp
= prev_in_thread(mp
)) != NULL
&& yetprinted
-- > 0;) {
599 if (visible(mp
) && (os
= hfield1("subject", mp
)) != NULL
) {
603 in
.l
= strlen(in
.s
= os
);
604 mime_fromhdr(&in
, &oout
, TD_ICONV
| TD_ISPR
);
605 x
= asccasecmp(ms
, subject_re_trim(oout
.s
));
621 __putindent(FILE *fp
, struct message
*mp
, int maxwidth
)/* XXX no magic consts */
624 int *us
, indlvl
, indw
, i
, important
= MNEW
| MFLAGGED
;
628 if (mp
->m_level
== 0 || maxwidth
== 0) {
633 cs
= ac_alloc(mp
->m_level
);
634 us
= ac_alloc(mp
->m_level
* sizeof *us
);
637 if (mp
->m_younger
&& UICMP(32, i
+ 1, ==, mp
->m_younger
->m_level
)) {
638 if (mp
->m_parent
&& mp
->m_parent
->m_flag
& important
)
639 us
[i
] = mp
->m_flag
& important
? 0x2523 : 0x2520;
641 us
[i
] = mp
->m_flag
& important
? 0x251D : 0x251C;
644 if (mp
->m_parent
&& mp
->m_parent
->m_flag
& important
)
645 us
[i
] = mp
->m_flag
& important
? 0x2517 : 0x2516;
647 us
[i
] = mp
->m_flag
& important
? 0x2515 : 0x2514;
652 for (i
= mp
->m_level
- 2; i
>= 0; --i
) {
654 if (UICMP(32, i
, >, mq
->m_level
- 1)) {
659 if (mq
->m_parent
&& (mq
->m_parent
->m_flag
& important
))
672 for (indlvl
= indw
= 0; (ui8_t
)indlvl
< mp
->m_level
&& indw
< maxwidth
;
674 if (indw
< maxwidth
- 1)
675 indw
+= (int)putuc(us
[indlvl
], cs
[indlvl
] & 0xFF, fp
);
677 indw
+= (int)putuc(0x21B8, '^', fp
);
679 indw
+= putuc(0x25B8, '>', fp
);
689 _dispc(struct message
*mp
, char const *a
)
694 if ((mp
->m_flag
& (MREAD
| MNEW
)) == MREAD
)
696 if ((mp
->m_flag
& (MREAD
| MNEW
)) == (MREAD
| MNEW
))
698 if (mp
->m_flag
& MANSWERED
)
700 if (mp
->m_flag
& MDRAFTED
)
702 if ((mp
->m_flag
& (MREAD
| MNEW
)) == MNEW
)
704 if (!(mp
->m_flag
& (MREAD
| MNEW
)))
706 if (mp
->m_flag
& MSPAM
)
708 if (mp
->m_flag
& MSPAMUNSURE
)
710 if (mp
->m_flag
& MSAVED
)
712 if (mp
->m_flag
& MPRESERVE
)
714 if (mp
->m_flag
& (MBOX
| MBOXED
))
716 if (mp
->m_flag
& MFLAGGED
)
718 if (mb
.mb_threaded
== 1 && mp
->m_collapsed
> 0)
720 if (mb
.mb_threaded
== 1 && mp
->m_collapsed
< 0)
727 a_cmd_scroll(char const *arg
, bool_t onlynew
){
731 int msgspec
, size
, maxs
;
734 msgspec
= onlynew
? -1 : 0;
736 maxs
= msgCount
/ size
;
757 case '1': case '2': case '3': case '4': case '5':
758 case '6': case '7': case '8': case '9': case '0':
761 l
= strtol(arg
, &eptr
, 10);
764 if(l
> maxs
- (isabs
? 0 : _screen
))
766 _screen
= isabs
? (int)l
: _screen
+ l
;
772 printf(_("On last screenful of messages\n"));
781 l
= strtol(arg
, &eptr
, 10);
791 printf(_("On first screenful of messages\n"));
798 n_err(_("Unrecognized scrolling command \"%s\"\n"), arg
);
803 size
= _headers(msgspec
);
810 _headers(int msgspec
) /* TODO rework v15 */
812 bool_t
volatile isrelax
;
813 sighandler_type
volatile opipe
;
814 ui32_t
volatile flag
;
815 int g
, k
, mesg
, size
, lastg
= 1;
816 struct message
*mp
, *mq
, *lastmq
= NULL
;
817 enum mflag fl
= MNEW
| MFLAGGED
;
820 time_current_update(&time_current
, FAL0
);
825 if (sigsetjmp(_cmd1_pipejmp
, 1))
827 opipe
= safe_signal(SIGPIPE
, &_cmd1_onpipe
);
830 if (options
& OPT_INTERACTIVE
)
831 n_colour_env_create(n_COLOUR_GROUP_SUM
, FAL0
);
837 #if 0 /* FIXME original code path */
850 if (mb
.mb_threaded
== 0) {
853 for (mp
= message
; PTRCMP(mp
, <, message
+ msgCount
); ++mp
)
857 if (mp
->m_flag
& fl
) {
861 if ((msgspec
> 0 && PTRCMP(mp
, ==, message
+ msgspec
- 1)) ||
862 (msgspec
== 0 && g
== k
) ||
863 (msgspec
== -2 && g
== k
+ size
&& lastmq
) ||
864 (msgspec
< 0 && g
>= k
&& (mp
->m_flag
& fl
) != 0))
868 if (lastmq
&& (msgspec
== -2 ||
869 (msgspec
== -1 && PTRCMP(mp
, ==, message
+ msgCount
)))) {
876 mesg
= (int)PTR2SIZE(mp
- message
);
877 if (PTRCMP(dot
, !=, message
+ msgspec
- 1)) { /* TODO really?? */
878 for (mq
= mp
; PTRCMP(mq
, <, message
+ msgCount
); ++mq
)
887 for (; PTRCMP(mp
, <, message
+ msgCount
); ++mp
) {
891 if (UICMP(32, flag
++, >=, size
))
893 _print_head(0, mesg
, stdout
, 0);
898 } else { /* threaded */
901 for (mp
= threadroot
; mp
; mp
= next_in_thread(mp
))
903 (mp
->m_collapsed
<= 0 ||
904 PTRCMP(mp
, ==, message
+ msgspec
- 1))) {
907 if (mp
->m_flag
& fl
) {
911 if ((msgspec
> 0 && PTRCMP(mp
, ==, message
+ msgspec
- 1)) ||
912 (msgspec
== 0 && g
== k
) ||
913 (msgspec
== -2 && g
== k
+ size
&& lastmq
) ||
914 (msgspec
< 0 && g
>= k
&& (mp
->m_flag
& fl
) != 0))
918 if (lastmq
&& (msgspec
== -2 ||
919 (msgspec
== -1 && PTRCMP(mp
, ==, message
+ msgCount
)))) {
925 if (PTRCMP(dot
, !=, message
+ msgspec
- 1)) { /* TODO really?? */
926 for (mq
= mp
; mq
; mq
= next_in_thread(mq
))
927 if (visible(mq
) && mq
->m_collapsed
<= 0) {
937 (mp
->m_collapsed
<= 0 ||
938 PTRCMP(mp
, ==, message
+ msgspec
- 1))) {
939 if (UICMP(32, flag
++, >=, size
))
941 _print_head(flag
- 1, PTR2SIZE(mp
- message
+ 1), stdout
,
945 mp
= next_in_thread(mp
);
952 printf(_("No more mail.\n"));
956 n_COLOUR( n_colour_env_gut(stdout
); )
958 safe_signal(SIGPIPE
, opipe
);
964 _type1(int *msgvec
, bool_t doign
, bool_t dopage
, bool_t dopipe
,
965 bool_t dodecode
, char *cmd
, ui64_t
*tstats
)
971 FILE * volatile obuf
;
972 bool_t
volatile isrelax
= FAL0
;
973 sighandler_type opipe
= NULL
;
976 enum sendaction
const action
= ((dopipe
&& ok_blook(piperaw
))
977 ? SEND_MBOX
: dodecode
979 ? SEND_TODISP
: SEND_TODISP_ALL
);
980 bool_t
const volatile formfeed
= (dopipe
&& ok_blook(page
));
983 if (sigsetjmp(_cmd1_pipejmp
, 1))
985 opipe
= safe_signal(SIGPIPE
, &_cmd1_onpipe
);
988 if ((cp
= ok_vlook(SHELL
)) == NULL
)
990 if ((obuf
= Popen(cmd
, "w", cp
, NULL
, 1)) == NULL
) {
994 } else if ((options
& OPT_TTYOUT
) && (dopage
||
995 ((options
& OPT_INTERACTIVE
) && (cp
= ok_vlook(crt
)) != NULL
))) {
999 for (ip
= msgvec
; *ip
&& PTRCMP(ip
- msgvec
, <, msgCount
); ++ip
) {
1000 mp
= message
+ *ip
- 1;
1001 if (!(mp
->m_have
& HAVE_BODY
))
1002 if (get_body(mp
) != OKAY
)
1004 nlines
+= mp
->m_lines
+ 1; /* Message info XXX and PARTS... */
1008 /* >= not <: we return to the prompt */
1009 if (dopage
|| UICMP(z
, nlines
, >=,
1010 (*cp
!= '\0' ? atoi(cp
) : realscreenheight
))) {
1011 char const *env_add
[2], *pager
= get_pager(env_add
+ 0);
1013 obuf
= Popen(pager
, "w", NULL
, env_add
, 1);
1020 if ((options
& OPT_INTERACTIVE
) &&
1021 (action
== SEND_TODISP
|| action
== SEND_TODISP_ALL
||
1022 action
== SEND_SHOW
))
1023 n_colour_env_create(n_COLOUR_GROUP_VIEW
, obuf
!= stdout
);
1027 else if ((options
& OPT_INTERACTIVE
) &&
1028 (action
== SEND_TODISP
|| action
== SEND_TODISP_ALL
))
1029 n_colour_env_create(n_COLOUR_GROUP_VIEW
, FAL0
);
1032 /*TODO unless we have our signal manager special care must be taken */
1035 for (ip
= msgvec
; *ip
&& PTRCMP(ip
- msgvec
, <, msgCount
); ++ip
) {
1036 mp
= message
+ *ip
- 1;
1040 if (!dopipe
&& ip
!= msgvec
)
1041 fprintf(obuf
, "\n");
1042 if (action
!= SEND_MBOX
)
1043 _show_msg_overview(obuf
, mp
, *ip
);
1044 sendmp(mp
, obuf
, (doign
? ignore
: NULL
), NULL
, action
, mstats
);
1046 if (formfeed
) /* TODO a nicer way to separate piped messages! */
1049 tstats
[0] += mstats
[0];
1057 /* Ignore SIGPIPE so it can't cause a duplicate close */
1058 safe_signal(SIGPIPE
, SIG_IGN
);
1061 n_COLOUR( n_colour_env_gut(obuf
); )
1065 safe_signal(SIGPIPE
, dflpipe
);
1072 _pipe1(char *str
, int doign
)
1076 int *msgvec
, rv
= 1;
1080 if ((cmd
= laststring(str
, &needs_list
, TRU1
)) == NULL
) {
1081 cmd
= ok_vlook(cmd
);
1082 if (cmd
== NULL
|| *cmd
== '\0') {
1083 n_err(_("Variable *cmd* not set\n"));
1088 msgvec
= salloc((msgCount
+ 2) * sizeof *msgvec
);
1091 *msgvec
= first(0, MMNORM
);
1093 if (pstate
& PS_HOOK_MASK
) {
1097 puts(_("No messages to pipe."));
1101 } else if (getmsglist(str
, msgvec
, 0) < 0)
1104 if (pstate
& PS_HOOK_MASK
) {
1108 printf("No applicable messages.\n");
1112 printf(_("Pipe to: \"%s\"\n"), cmd
);
1114 if ((rv
= _type1(msgvec
, doign
, FAL0
, TRU1
, FAL0
, cmd
, stats
)) == 0)
1115 printf("\"%s\" %" PRIu64
" bytes\n", cmd
, stats
[0]);
1122 c_cmdnotsupp(void *v
) /* TODO -> lex.c */
1126 n_err(_("The requested feature is not compiled in\n"));
1137 rv
= print_header_group((int*)v
);
1143 print_header_group(int *vector
)
1148 assert(vector
!= NULL
&& vector
!= (void*)-1);
1149 rv
= _headers(vector
[0]);
1160 rv
= a_cmd_scroll(v
, FAL0
);
1171 rv
= a_cmd_scroll(v
, TRU1
);
1179 int *msgvec
= v
, *ip
, n
;
1181 FILE * volatile obuf
;
1182 bool_t
volatile isrelax
;
1183 sighandler_type
volatile opipe
;
1186 time_current_update(&time_current
, FAL0
);
1191 if (sigsetjmp(_cmd1_pipejmp
, 1))
1193 opipe
= safe_signal(SIGPIPE
, &_cmd1_onpipe
);
1195 if (options
& OPT_INTERACTIVE
) {
1196 if ((cp
= ok_vlook(crt
)) != NULL
) {
1197 for (n
= 0, ip
= msgvec
; *ip
!= 0; ++ip
)
1199 if (n
> (*cp
== '\0' ? screensize() : atoi(cp
)) + 3) {
1200 char const *p
= get_pager(NULL
);
1201 if ((obuf
= Popen(p
, "w", NULL
, NULL
, 1)) == NULL
) {
1207 n_COLOUR( n_colour_env_create(n_COLOUR_GROUP_SUM
, obuf
!= stdout
); )
1210 /* Update dot before display so that the dotmark etc. are correct */
1211 for (ip
= msgvec
; *ip
!= 0; ++ip
)
1214 setdot(message
+ *ip
- 1);
1218 for (n
= 0, ip
= msgvec
; *ip
!= 0; ++ip
) { /* TODO join into _print_head() */
1219 _print_head((size_t)n
++, (size_t)*ip
, obuf
, mb
.mb_threaded
);
1227 /* Ignore SIGPIPE so it can't cause a duplicate close */
1228 safe_signal(SIGPIPE
, SIG_IGN
);
1231 n_COLOUR( n_colour_env_gut(obuf
); )
1235 safe_signal(SIGPIPE
, opipe
);
1241 print_headers(size_t bottom
, size_t topx
, bool_t only_marked
)
1243 bool_t
volatile isrelax
;
1244 sighandler_type
volatile opipe
;
1248 time_current_update(&time_current
, FAL0
);
1252 if (sigsetjmp(_cmd1_pipejmp
, 1))
1254 opipe
= safe_signal(SIGPIPE
, &_cmd1_onpipe
);
1257 if (options
& OPT_INTERACTIVE
)
1258 n_colour_env_create(n_COLOUR_GROUP_SUM
, FAL0
);
1263 for (printed
= 0; bottom
<= topx
; ++bottom
) {
1264 struct message
*mp
= message
+ bottom
- 1;
1266 if (!(mp
->m_flag
& MMARK
))
1268 } else if (!visible(mp
))
1270 _print_head(printed
++, bottom
, stdout
, FAL0
);
1279 n_COLOUR( n_colour_env_gut(stdout
); )
1281 safe_signal(SIGPIPE
, opipe
);
1290 printf("%d\n", (int)PTR2SIZE(dot
- message
+ 1));
1298 int *msgvec
= v
, rv
;
1301 rv
= _type1(msgvec
, TRU1
, TRU1
, FAL0
, FAL0
, NULL
, NULL
);
1309 int *msgvec
= v
, rv
;
1312 rv
= _type1(msgvec
, FAL0
, TRU1
, FAL0
, FAL0
, NULL
, NULL
);
1320 int *msgvec
= v
, rv
;
1323 rv
= _type1(msgvec
, TRU1
, FAL0
, FAL0
, FAL0
, NULL
, NULL
);
1331 int *msgvec
= v
, rv
;
1334 rv
= _type1(msgvec
, FAL0
, FAL0
, FAL0
, FAL0
, NULL
, NULL
);
1342 int *msgvec
= v
, rv
;
1345 rv
= _type1(msgvec
, FAL0
, FAL0
, FAL0
, TRU1
, NULL
, NULL
);
1357 rv
= _pipe1(str
, 1);
1369 rv
= _pipe1(str
, 0);
1377 int *msgvec
= v
, *ip
, c
, topl
, lines
, empty_last
;
1379 char *cp
, *linebuf
= NULL
;
1380 size_t linesize
= 0;
1385 cp
= ok_vlook(toplines
);
1388 if (topl
< 0 || topl
> 10000)
1392 /* XXX Colours of `top' only for message and part info lines */
1394 if (options
& OPT_INTERACTIVE
)
1395 n_colour_env_create(n_COLOUR_GROUP_VIEW
, FAL0
);
1398 for (ip
= msgvec
; *ip
!= 0 && UICMP(z
, PTR2SIZE(ip
- msgvec
), <, msgCount
);
1400 mp
= message
+ *ip
- 1;
1403 pstate
|= PS_DID_PRINT_DOT
;
1406 _show_msg_overview(stdout
, mp
, *ip
);
1407 if (mp
->m_flag
& MNOFROM
)
1408 /* XXX c_top(): coloured output? */
1409 printf("From %s %s\n", fakefrom(mp
), fakedate(mp
->m_time
));
1410 if ((ibuf
= setinput(&mb
, mp
, NEED_BODY
)) == NULL
) { /* XXX use TOP */
1415 for (lines
= 0; lines
< c
&& UICMP(32, lines
, <=, topl
); ++lines
) {
1416 if (readline_restart(ibuf
, &linebuf
, &linesize
, 0) < 0)
1420 for (cp
= linebuf
; *cp
!= '\0' && blankchar(*cp
); ++cp
)
1422 empty_last
= (*cp
== '\0');
1426 n_COLOUR( n_colour_env_gut(stdout
); )
1427 if (linebuf
!= NULL
)
1436 int *msgvec
= v
, *ip
;
1439 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1440 setdot(message
+ *ip
- 1);
1441 dot
->m_flag
|= MTOUCH
;
1442 dot
->m_flag
&= ~MPRESERVE
;
1443 pstate
|= PS_DID_PRINT_DOT
;
1452 int *msgvec
= v
, *ip
;
1455 if (pstate
& PS_EDIT
) {
1456 n_err(_("`mbox' can only be used in a system mailbox\n")); /* TODO */
1460 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1461 setdot(message
+ *ip
- 1);
1462 dot
->m_flag
|= MTOUCH
| MBOX
;
1463 dot
->m_flag
&= ~MPRESERVE
;
1464 pstate
|= PS_DID_PRINT_DOT
;
1474 char dirname
[PATH_MAX
], *name
, **argv
= v
;
1480 name
= expand(*argv
);
1483 } else if (!getfold(dirname
, sizeof dirname
)) {
1484 n_err(_("No value set for \"folder\"\n"));
1489 if ((cmd
= ok_vlook(LISTER
)) == NULL
)
1491 run_command(cmd
, 0, COMMAND_FD_PASS
, COMMAND_FD_PASS
, name
, NULL
, NULL
,