1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ Header display, search, etc., related user commands.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2017 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
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
36 #define n_FILE cmd_headers
38 #ifndef HAVE_AMALGAMATION
44 /* ... And place the extracted date in `date' */
45 static void _parse_from_(struct message
*mp
, char date
[n_FROM_DATEBUF
]);
47 /* Print out the header of a specific message
48 * __hprf: handle *headline*
49 * __subject: return -1 if Subject: yet seen, otherwise smalloc()d Subject:
50 * __putindent: print out the indenting in threaded display */
51 static void _print_head(size_t yetprinted
, size_t msgno
, FILE *f
,
53 static void __hprf(size_t yetprinted
, char const *fmt
, size_t msgno
,
54 FILE *f
, bool_t threaded
, char const *attrlist
);
55 static char * __subject(struct message
*mp
, bool_t threaded
,
57 static int __putindent(FILE *fp
, struct message
*mp
, int maxwidth
);
59 static int _dispc(struct message
*mp
, char const *a
);
61 /* Shared `z' implementation */
62 static int a_cmd_scroll(char const *arg
, bool_t onlynew
);
64 /* Shared `headers' implementation */
65 static int _headers(int msgspec
);
68 _parse_from_(struct message
*mp
, char date
[n_FROM_DATEBUF
]) /* TODO line pool */
76 if ((ibuf
= setinput(&mb
, mp
, NEED_HEADER
)) != NULL
&&
77 (hlen
= readline_restart(ibuf
, &hline
, &hsize
, 0)) > 0)
78 extract_date_from_from_(hline
, hlen
, date
);
85 _print_head(size_t yetprinted
, size_t msgno
, FILE *f
, bool_t threaded
)
88 char attrlist
[attrlen
+1], *cp
;
92 if ((cp
= ok_vlook(attrlist
)) != NULL
) {
93 if (strlen(cp
) == attrlen
) {
94 memcpy(attrlist
, cp
, attrlen
+1);
97 n_err(_("*attrlist* is not of the correct length, using built-in\n"));
100 if (ok_blook(bsdcompat
) || ok_blook(bsdflags
)) {
101 char const bsdattr
[attrlen
+1] = "NU *HMFAT+-$~";
102 memcpy(attrlist
, bsdattr
, sizeof bsdattr
);
103 } else if (ok_blook(SYSV3
)) {
104 char const bsdattr
[attrlen
+1] = "NU *HMFAT+-$~";
105 memcpy(attrlist
, bsdattr
, sizeof bsdattr
);
106 n_OBSOLETE(_("*SYSV3*: please use *bsdcompat* or *bsdflags*, "
107 "or set *attrlist*"));
109 char const pattr
[attrlen
+1] = "NUROSPMFAT+-$~";
110 memcpy(attrlist
, pattr
, sizeof pattr
);
114 if ((fmt
= ok_vlook(headline
)) == NULL
) {
115 fmt
= ((ok_blook(bsdcompat
) || ok_blook(bsdheadline
))
116 ? "%>%a%m %-20f %16d %4l/%-5o %i%-S"
117 : "%>%a%m %-18f %-16d %4l/%-5o %i%-s");
120 __hprf(yetprinted
, fmt
, msgno
, f
, threaded
, attrlist
);
125 __hprf(size_t yetprinted
, char const *fmt
, size_t msgno
, FILE *f
,
126 bool_t threaded
, char const *attrlist
)
128 char buf
[16], datebuf
[n_FROM_DATEBUF
], cbuf
[8], *cp
, *subjline
;
129 char const *datefmt
, *date
, *name
, *fp
n_COLOUR( COMMA
*colo_tag
);
130 int i
, n
, s
, wleft
, subjlen
;
133 n_COLOUR( struct n_colour_pen
*cpen_new COMMA
*cpen_cur COMMA
*cpen_bas
; )
140 _LOOP_MASK
= (1<<4) - 1,
141 _SFMT
= 1<<4, /* It is 'S' */
142 /* For the simple byte-based counts in wleft and n we sometimes need
143 * adjustments to compensate for additional bytes of UTF-8 sequences */
144 _PUTCB_UTF8_SHIFT
= 5,
145 _PUTCB_UTF8_MASK
= 3<<5
150 if ((mp
= message
+ msgno
- 1) == dot
)
154 n_COLOUR( colo_tag
= NULL
; )
156 datefmt
= ok_vlook(datefield
);
158 if (datefmt
!= NULL
) {
159 fp
= hfield1("date", mp
);/* TODO use m_date field! */
165 date
= fakedate(datet
);
166 fp
= ok_vlook(datefield_markout_older
);
167 i
= (*datefmt
!= '\0');
169 i
|= (*fp
!= '\0') ? 2 | 4 : 2; /* XXX no magics */
171 /* May we strftime(3)? */
173 memcpy(&time_current
.tc_local
, localtime(&datet
),
174 sizeof time_current
.tc_local
);
177 (UICMP(64,datet
, >, time_current
.tc_time
+ n_DATE_SECSDAY
) ||
178 #define _6M ((n_DATE_DAYSYEAR / 2) * n_DATE_SECSDAY)
179 UICMP(64,datet
+ _6M
, <, time_current
.tc_time
))) {
181 if ((datefmt
= (i
& 4) ? fp
: NULL
) == NULL
) {
182 memset(datebuf
, ' ', n_FROM_DATEBUF
); /* xxx ur */
183 memcpy(datebuf
+ 4, date
+ 4, 7);
184 datebuf
[4 + 7] = ' ';
185 memcpy(datebuf
+ 4 + 7 + 1, date
+ 20, 4);
186 datebuf
[4 + 7 + 1 + 4] = '\0';
189 n_COLOUR( colo_tag
= n_COLOUR_TAG_SUM_OLDER
; )
190 } else if ((i
& 1) == 0)
192 } else if (datet
== (time_t)0 && !(mp
->m_flag
& MNOFROM
)) {
193 /* TODO eliminate this path, query the FROM_ date in setptr(),
194 * TODO all other codepaths do so by themselves ALREADY ?????
195 * TODO assert(mp->m_time != 0);, then
196 * TODO ALSO changes behaviour of datefield_markout_older */
197 _parse_from_(mp
, datebuf
);
200 date
= fakedate(datet
);
204 if (name
!= NULL
&& ok_blook(showto
) && n_is_myname(skin(name
))) {
205 if ((cp
= hfield1("to", mp
)) != NULL
) {
215 name
= ok_blook(showname
) ? realname(name
) : prstr(skin(name
));
219 /* Detect the width of the non-format characters in *headline*;
220 * like that we can simply use putc() in the next loop, since we have
221 * already calculated their column widths (TODO it's sick) */
222 wleft
= subjlen
= n_scrnwidth
;
224 for (fp
= fmt
; *fp
!= '\0'; ++fp
) {
230 if (digitchar(*fp
)) {
233 n
= 10*n
+ *fp
- '0';
234 while (++fp
, digitchar(*fp
));
244 if (n_mb_cur_max
> 1) {
246 if ((s
= mbtowc(&wc
, fp
, n_mb_cur_max
)) == -1)
248 else if ((n
= wcwidth(wc
)) == -1)
260 /* Walk *headline*, producing output TODO not (really) MB safe */
262 if(n_COLOUR_IS_ACTIVE()){
264 colo_tag
= n_COLOUR_TAG_SUM_DOT
;
265 cpen_bas
= n_colour_pen_create(n_COLOUR_ID_SUM_HEADER
, colo_tag
);
266 n_colour_pen_put(cpen_new
= cpen_cur
= cpen_bas
);
268 cpen_new
= cpen_bas
= cpen_cur
= NULL
;
271 for (fp
= fmt
; *fp
!= '\0'; ++fp
) {
274 if ((c
= *fp
& 0xFF) != '%') {
276 if(n_COLOUR_IS_ACTIVE() && (cpen_new
= cpen_bas
) != cpen_cur
)
277 n_colour_pen_put(cpen_cur
= cpen_new
);
286 if ((c
= *++fp
) == '-') {
291 if (digitchar(*fp
)) {
293 n
= 10*n
+ *fp
- '0';
294 while (++fp
, digitchar(*fp
));
297 if ((c
= *fp
& 0xFF) == '\0')
307 if (flags
& _ISDOT
) {
309 if(n_COLOUR_IS_ACTIVE())
310 cpen_new
= n_colour_pen_create(n_COLOUR_ID_SUM_DOTMARK
,
313 if (n_psonce
& n_PSO_UNICODE
) {
315 /* 25B8;BLACK RIGHT-POINTING SMALL TRIANGLE: â–¸ */
316 cbuf
[1] = (char)0x96, cbuf
[2] = (char)0xB8;
318 /* 25C2;BLACK LEFT-POINTING SMALL TRIANGLE: â—‚ */
319 cbuf
[1] = (char)0x97, cbuf
[2] = (char)0x82;
322 flags
|= 2 << _PUTCB_UTF8_SHIFT
;
331 if (UICMP(32, n_ABS(n
), >, wleft
))
332 n
= (n
< 0) ? -wleft
: wleft
;
333 snprintf(buf
, sizeof buf
, "%u.%02u",
334 (mp
->m_spamscore
>> 8), (mp
->m_spamscore
& 0xFF));
335 n
= fprintf(f
, "%*s", n
, buf
);
336 wleft
= (n
>= 0) ? wleft
- n
: 0;
343 c
= _dispc(mp
, attrlist
);
346 if(n_COLOUR_IS_ACTIVE()){
347 if(cpen_new
== cpen_cur
)
349 if(cpen_new
!= cpen_cur
)
350 n_colour_pen_put(cpen_cur
= cpen_new
);
353 if (UICMP(32, n_ABS(n
), >, wleft
))
354 n
= (n
< 0) ? -wleft
: wleft
;
356 n
= fprintf(f
, "%*s", n
, cbuf
);
359 if ((n
= (flags
& _PUTCB_UTF8_MASK
)) != 0) {
360 n
>>= _PUTCB_UTF8_SHIFT
;
364 wleft
= 0; /* TODO I/O error.. ? break? */
367 if(n_COLOUR_IS_ACTIVE() && (cpen_new
= cpen_bas
) != cpen_cur
)
368 n_colour_pen_put(cpen_cur
= cpen_new
);
372 if (datefmt
!= NULL
) {
373 i
= strftime(datebuf
, sizeof datebuf
, datefmt
,
374 &time_current
.tc_local
);
378 n_err(_("Ignored date format, it excesses the target "
379 "buffer (%lu bytes)\n"), (ul_i
)sizeof(datebuf
));
384 if (UICMP(32, n_ABS(n
), >, wleft
))
385 n
= (n
< 0) ? -wleft
: wleft
;
386 n
= fprintf(f
, "%*.*s", n
, n_ABS(n
), date
);
387 wleft
= (n
>= 0) ? wleft
- n
: 0;
392 if (UICMP(32, n_ABS(n
), >, wleft
))
393 n
= (n
< 0) ? -wleft
: wleft
;
394 n
= fprintf(f
, "%*u", n
, (threaded
== 1 ? mp
->m_level
: 0));
395 wleft
= (n
>= 0) ? wleft
- n
: 0;
406 n
= (n
< 0) ? -wleft
: wleft
;
408 if (flags
& _ISTO
) /* XXX tr()! */
410 n
= fprintf(f
, "%s%s", ((flags
& _ISTO
) ? "To " : n_empty
),
411 colalign(name
, i
, n
, &wleft
));
414 else if (flags
& _ISTO
)
420 if(n_COLOUR_IS_ACTIVE()){
421 cpen_new
= n_colour_pen_create(n_COLOUR_ID_SUM_THREAD
, colo_tag
);
422 if(cpen_new
!= cpen_cur
)
423 n_colour_pen_put(cpen_cur
= cpen_new
);
426 n
= __putindent(f
, mp
, n_MIN(wleft
, (int)n_scrnwidth
- 60));
427 wleft
= (n
>= 0) ? wleft
- n
: 0;
429 if(n_COLOUR_IS_ACTIVE() && (cpen_new
= cpen_bas
) != cpen_cur
)
430 n_colour_pen_put(cpen_cur
= cpen_new
);
437 if (UICMP(32, n_ABS(n
), >, wleft
))
438 n
= (n
< 0) ? -wleft
: wleft
;
440 n
= fprintf(f
, "%*ld", n
, mp
->m_xlines
);
441 wleft
= (n
>= 0) ? wleft
- n
: 0;
453 for (i
= msgCount
; i
> 999; i
/= 10)
456 if (UICMP(32, n_ABS(n
), >, wleft
))
457 n
= (n
< 0) ? -wleft
: wleft
;
458 n
= fprintf(f
, "%*lu", n
, (ul_i
)msgno
);
459 wleft
= (n
>= 0) ? wleft
- n
: 0;
464 if (UICMP(32, n_ABS(n
), >, wleft
))
465 n
= (n
< 0) ? -wleft
: wleft
;
466 n
= fprintf(f
, "%*lu", n
, (ul_i
)mp
->m_xsize
);
467 wleft
= (n
>= 0) ? wleft
- n
: 0;
479 if (UICMP(32, n_ABS(n
), >, subjlen
))
480 n
= (n
< 0) ? -subjlen
: subjlen
;
482 n
-= (n
< 0) ? -2 : 2;
485 if (subjline
== NULL
)
486 subjline
= __subject(mp
, (threaded
&& (flags
& _IFMT
)), yetprinted
);
487 if (subjline
== (char*)-1) {
488 n
= fprintf(f
, "%*s", n
, n_empty
);
489 wleft
= (n
>= 0) ? wleft
- n
: 0;
491 n
= fprintf(f
, ((flags
& _SFMT
) ? "\"%s\"" : "%s"),
492 colalign(subjline
, n_ABS(n
), n
, &wleft
));
497 case 'T': { /* Message recipient flags */
498 /* We never can reuse "name" since it's the full name */
499 struct name
const *np
= lextract(hfield1("to", mp
), GTO
| GSKIN
);
503 for (; np
!= NULL
; np
= np
->n_flink
) {
504 switch (is_mlist(np
->n_name
, FAL0
)) {
505 case MLIST_SUBSCRIBED
: c
= 'S'; goto jputcb
;
506 case MLIST_KNOWN
: c
= 'L'; goto jputcb
;
514 np
= lextract(hfield1("cc", mp
), GCC
| GSKIN
);
521 for (i
= msgCount
; i
> 999; i
/= 10)
524 if (UICMP(32, n_ABS(n
), >, wleft
))
525 n
= (n
< 0) ? -wleft
: wleft
;
526 n
= fprintf(f
, "%*lu",
527 n
, (threaded
? (ul_i
)mp
->m_threadpos
: (ul_i
)msgno
));
528 wleft
= (n
>= 0) ? wleft
- n
: 0;
534 if (UICMP(32, n_ABS(n
), >, wleft
))
535 n
= (n
< 0) ? -wleft
: wleft
;
536 n
= fprintf(f
, "%*lu", n
, mp
->m_uid
);
537 wleft
= (n
>= 0) ? wleft
- n
: 0;
544 if (n_poption
& n_PO_D_V
)
545 n_err(_("Unkown *headline* format: %%%c\n"), c
);
554 n_COLOUR( n_colour_reset(); )
557 if (subjline
!= NULL
&& subjline
!= (char*)-1)
563 __subject(struct message
*mp
, bool_t threaded
, size_t yetprinted
)
571 if ((ms
= hfield1("subject", mp
)) == NULL
)
574 in
.l
= strlen(in
.s
= ms
);
575 mime_fromhdr(&in
, &out
, TD_ICONV
| TD_ISPR
);
578 if (!threaded
|| mp
->m_level
== 0)
581 /* In a display thread - check whether this message uses the same
582 * Subject: as it's parent or elder neighbour, suppress printing it if
583 * this is the case. To extend this a bit, ignore any leading Re: or
584 * Fwd: plus follow-up WS. Ignore invisible messages along the way */
585 ms
= n_UNCONST(subject_re_trim(n_UNCONST(ms
)));
587 for (; (mp
= prev_in_thread(mp
)) != NULL
&& yetprinted
-- > 0;) {
590 if (visible(mp
) && (os
= hfield1("subject", mp
)) != NULL
) {
594 in
.l
= strlen(in
.s
= os
);
595 mime_fromhdr(&in
, &oout
, TD_ICONV
| TD_ISPR
);
596 x
= asccasecmp(ms
, subject_re_trim(oout
.s
));
612 __putindent(FILE *fp
, struct message
*mp
, int maxwidth
)/* XXX no magic consts */
615 int *us
, indlvl
, indw
, i
, important
= MNEW
| MFLAGGED
;
619 if (mp
->m_level
== 0 || maxwidth
== 0) {
624 cs
= ac_alloc(mp
->m_level
);
625 us
= ac_alloc(mp
->m_level
* sizeof *us
);
628 if (mp
->m_younger
&& UICMP(32, i
+ 1, ==, mp
->m_younger
->m_level
)) {
629 if (mp
->m_parent
&& mp
->m_parent
->m_flag
& important
)
630 us
[i
] = mp
->m_flag
& important
? 0x2523 : 0x2520;
632 us
[i
] = mp
->m_flag
& important
? 0x251D : 0x251C;
635 if (mp
->m_parent
&& mp
->m_parent
->m_flag
& important
)
636 us
[i
] = mp
->m_flag
& important
? 0x2517 : 0x2516;
638 us
[i
] = mp
->m_flag
& important
? 0x2515 : 0x2514;
643 for (i
= mp
->m_level
- 2; i
>= 0; --i
) {
645 if (UICMP(32, i
, >, mq
->m_level
- 1)) {
650 if (mq
->m_parent
&& (mq
->m_parent
->m_flag
& important
))
663 for (indlvl
= indw
= 0; (ui8_t
)indlvl
< mp
->m_level
&& indw
< maxwidth
;
665 if (indw
< maxwidth
- 1)
666 indw
+= (int)putuc(us
[indlvl
], cs
[indlvl
] & 0xFF, fp
);
668 indw
+= (int)putuc(0x21B8, '^', fp
);
670 indw
+= putuc(0x25B8, '>', fp
);
680 _dispc(struct message
*mp
, char const *a
)
685 if ((mp
->m_flag
& (MREAD
| MNEW
)) == MREAD
)
687 if ((mp
->m_flag
& (MREAD
| MNEW
)) == (MREAD
| MNEW
))
689 if (mp
->m_flag
& MANSWERED
)
691 if (mp
->m_flag
& MDRAFTED
)
693 if ((mp
->m_flag
& (MREAD
| MNEW
)) == MNEW
)
695 if (!(mp
->m_flag
& (MREAD
| MNEW
)))
697 if (mp
->m_flag
& MSPAM
)
699 if (mp
->m_flag
& MSPAMUNSURE
)
701 if (mp
->m_flag
& MSAVED
)
703 if (mp
->m_flag
& MPRESERVE
)
705 if (mp
->m_flag
& (MBOX
| MBOXED
))
707 if (mp
->m_flag
& MFLAGGED
)
709 if (mb
.mb_threaded
== 1 && mp
->m_collapsed
> 0)
711 if (mb
.mb_threaded
== 1 && mp
->m_collapsed
< 0)
718 a_cmd_scroll(char const *arg
, bool_t onlynew
){
721 int msgspec
, size
, maxs
;
724 /* TODO scroll problem: we do not know whether + and $ have already reached
725 * TODO the last screen in threaded mode */
726 msgspec
= onlynew
? -1 : 0;
727 size
= (int)/*TODO*/n_screensize();
728 if((maxs
= msgCount
/ size
) > 0 && msgCount
% size
== 0)
759 case '1': case '2': case '3': case '4': case '5':
760 case '6': case '7': case '8': case '9': case '0':
763 if((n_idec_siz_cp(&l
, arg
, 0, NULL
764 ) & (n_IDEC_STATE_EMASK
| n_IDEC_STATE_CONSUMED
)
765 ) != n_IDEC_STATE_CONSUMED
)
767 if(l
> maxs
- (isabs
? 0 : _screen
))
769 _screen
= isabs
? (int)l
: _screen
+ l
;
775 fprintf(n_stdout
, _("On last screenful of messages\n"));
783 if((n_idec_siz_cp(&l
, ++arg
, 0, NULL
784 ) & (n_IDEC_STATE_EMASK
| n_IDEC_STATE_CONSUMED
)
785 ) != n_IDEC_STATE_CONSUMED
)
794 fprintf(n_stdout
, _("On first screenful of messages\n"));
801 n_err(_("Unrecognized scrolling command: %s\n"), arg
);
806 size
= _headers(msgspec
);
813 _headers(int msgspec
) /* TODO rework v15 */
815 ui32_t
volatile flag
;
816 int g
, k
, mesg
, size
;
817 int volatile lastg
= 1;
818 struct message
*mp
, *mq
, *lastmq
= NULL
;
819 enum mflag fl
= MNEW
| MFLAGGED
;
822 time_current_update(&time_current
, FAL0
);
825 size
= (int)/*TODO*/n_screensize();
828 #if 0 /* FIXME original code path */
841 if (mb
.mb_threaded
== 0) {
844 for (mp
= message
; PTRCMP(mp
, <, message
+ msgCount
); ++mp
)
848 if (mp
->m_flag
& fl
) {
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))
859 if (lastmq
&& (msgspec
== -2 ||
860 (msgspec
== -1 && PTRCMP(mp
, ==, message
+ msgCount
)))) {
867 mesg
= (int)PTR2SIZE(mp
- message
);
868 if (PTRCMP(dot
, !=, message
+ msgspec
- 1)) { /* TODO really?? */
869 for (mq
= mp
; PTRCMP(mq
, <, message
+ msgCount
); ++mq
)
877 if (mb
.mb_type
== MB_IMAP
)
878 imap_getheaders(mesg
+ 1, mesg
+ size
);
880 n_COLOUR( n_colour_env_create(n_COLOUR_CTX_SUM
, n_stdout
, FAL0
); )
882 for (; PTRCMP(mp
, <, message
+ msgCount
); ++mp
) {
886 if (UICMP(32, flag
++, >=, size
))
888 _print_head(0, mesg
, n_stdout
, 0);
892 n_COLOUR( n_colour_env_gut(); )
893 } else { /* threaded */
896 for (mp
= threadroot
; mp
; mp
= next_in_thread(mp
))
898 (mp
->m_collapsed
<= 0 ||
899 PTRCMP(mp
, ==, message
+ msgspec
- 1))) {
902 if (mp
->m_flag
& fl
) {
906 if ((msgspec
> 0 && PTRCMP(mp
, ==, message
+ msgspec
- 1)) ||
907 (msgspec
== 0 && g
== k
) ||
908 (msgspec
== -2 && g
== k
+ size
&& lastmq
) ||
909 (msgspec
< 0 && g
>= k
&& (mp
->m_flag
& fl
) != 0))
913 if (lastmq
&& (msgspec
== -2 ||
914 (msgspec
== -1 && PTRCMP(mp
, ==, message
+ msgCount
)))) {
920 if (PTRCMP(dot
, !=, message
+ msgspec
- 1)) { /* TODO really?? */
921 for (mq
= mp
; mq
; mq
= next_in_thread(mq
))
922 if (visible(mq
) && mq
->m_collapsed
<= 0) {
928 n_COLOUR( n_colour_env_create(n_COLOUR_CTX_SUM
, n_stdout
, FAL0
); )
932 (mp
->m_collapsed
<= 0 ||
933 PTRCMP(mp
, ==, message
+ msgspec
- 1))) {
934 if (UICMP(32, flag
++, >=, size
))
936 _print_head(flag
- 1, PTR2SIZE(mp
- message
+ 1), n_stdout
,
940 mp
= next_in_thread(mp
);
943 n_COLOUR( n_colour_env_gut(); )
947 fprintf(n_stdout
, _("No more mail.\n"));
948 if (n_pstate
& (n_PS_ROBOT
| n_PS_HOOK_MASK
))
961 rv
= print_header_group((int*)v
);
967 print_header_group(int *vector
)
972 assert(vector
!= NULL
&& vector
!= (void*)-1);
973 rv
= _headers(vector
[0]);
984 rv
= a_cmd_scroll(*(char const**)v
, FAL0
);
995 rv
= a_cmd_scroll(*(char const**)v
, TRU1
);
1007 if (*(args
= v
) == '\0' || args
[1] != '\0') {
1009 n_err(_("Synopsis: dotmove: up <-> or down <+> by one message\n"));
1011 } else switch (args
[0]) {
1014 if (msgCount
== 0) {
1015 fprintf(n_stdout
, _("At EOF\n"));
1017 } else if (getmsglist(n_UNCONST(/*TODO*/ args
), msgvec
, 0) > 0) {
1018 setdot(message
+ msgvec
[0] - 1);
1020 rv
= c_headers(msgvec
);
1034 int *msgvec
= v
, *ip
, n
;
1036 FILE * volatile obuf
;
1039 time_current_update(&time_current
, FAL0
);
1043 if (n_psonce
& n_PSO_INTERACTIVE
) {
1044 if ((cp
= ok_vlook(crt
)) != NULL
) {
1047 for (n
= 0, ip
= msgvec
; *ip
!= 0; ++ip
)
1051 ib
= n_screensize();
1053 n_idec_uiz_cp(&ib
, cp
, 0, NULL
);
1054 if (UICMP(z
, n
, >, ib
) && (obuf
= n_pager_open()) == NULL
)
1059 /* Update dot before display so that the dotmark etc. are correct */
1060 for (ip
= msgvec
; *ip
!= 0; ++ip
)
1063 setdot(message
+ *ip
- 1);
1065 n_COLOUR( n_colour_env_create(n_COLOUR_CTX_SUM
, obuf
, obuf
!= n_stdout
); )
1067 for (n
= 0, ip
= msgvec
; *ip
!= 0; ++ip
) { /* TODO join into _print_head() */
1068 _print_head((size_t)n
++, (size_t)*ip
, obuf
, mb
.mb_threaded
);
1072 n_COLOUR( n_colour_env_gut(); )
1074 if (obuf
!= n_stdout
)
1075 n_pager_close(obuf
);
1081 print_headers(size_t bottom
, size_t topx
, bool_t only_marked
)
1087 if (mb
.mb_type
== MB_IMAP
)
1088 imap_getheaders(bottom
, topx
);
1090 time_current_update(&time_current
, FAL0
);
1092 n_COLOUR( n_colour_env_create(n_COLOUR_CTX_SUM
, n_stdout
, FAL0
); )
1094 for (printed
= 0; bottom
<= topx
; ++bottom
) {
1095 struct message
*mp
= message
+ bottom
- 1;
1097 if (!(mp
->m_flag
& MMARK
))
1099 } else if (!visible(mp
))
1101 _print_head(printed
++, bottom
, n_stdout
, FAL0
);
1105 n_COLOUR( n_colour_env_gut(); )