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 - 2014 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. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 #ifndef HAVE_AMALGAMATION
45 static sigjmp_buf _cmd1_pipestop
;
46 static sigjmp_buf _cmd1_pipejmp
;
48 static void _cmd1_onpipe(int signo
);
49 static void _cmd1_brokpipe(int signo
);
51 /* Prepare and print "[Message: xy]:" intro */
52 static void _show_msg_overview(FILE *obuf
, struct message
*mp
, int msg_no
);
54 /* ... And place the extracted date in `date' */
55 static void _parse_from_(struct message
*mp
, char date
[FROM_DATEBUF
]);
57 /* Print out the header of a specific message
58 * __hprf: handle *headline*
59 * __subject: Subject:, but return NULL if threaded and Subject: yet seen
60 * __putindent: print out the indenting in threaded display */
61 static void _print_head(size_t yetprinted
, size_t msgno
, FILE *f
,
63 static void __hprf(size_t yetprinted
, char const *fmt
, size_t msgno
,
64 FILE *f
, bool_t threaded
, char const *attrlist
);
65 static char * __subject(struct message
*mp
, bool_t threaded
,
67 static char * __subject_trim(char *s
);
68 static int __putindent(FILE *fp
, struct message
*mp
, int maxwidth
);
70 static int _dispc(struct message
*mp
, char const *a
);
71 static int _scroll1(char *arg
, int onlynew
);
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
, off_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 _cmd1_brokpipe(int signo
)
91 NYD_X
; /* Signal handler */
93 siglongjmp(_cmd1_pipestop
, 1);
97 _show_msg_overview(FILE *obuf
, struct message
*mp
, int msg_no
)
99 char const *cpre
= "", *csuf
= "";
103 if (colour_table
!= NULL
) {
104 struct str
const *sp
;
106 if ((sp
= colour_get(COLOURSPEC_MSGINFO
)) != NULL
)
108 csuf
= colour_get(COLOURSPEC_RESET
)->s
;
111 fprintf(obuf
, tr(17, "%s[-- Message %2d -- %lu lines, %lu bytes --]:%s\n"),
112 cpre
, msg_no
, (ul_it
)mp
->m_lines
, (ul_it
)mp
->m_size
, csuf
);
117 _parse_from_(struct message
*mp
, char date
[FROM_DATEBUF
]) /* TODO line pool */
125 if ((ibuf
= setinput(&mb
, mp
, NEED_HEADER
)) != NULL
&&
126 (hlen
= readline_restart(ibuf
, &hline
, &hsize
, 0)) > 0)
127 extract_date_from_from_(hline
, hlen
, date
);
134 _print_head(size_t yetprinted
, size_t msgno
, FILE *f
, bool_t threaded
)
137 char attrlist
[attrlen
+1], *cp
;
141 if ((cp
= ok_vlook(attrlist
)) != NULL
) {
142 if (strlen(cp
) == attrlen
) {
143 memcpy(attrlist
, cp
, attrlen
+1);
146 fprintf(stderr
, tr(570,
147 "The value of *attrlist* is not of the correct length\n"));
149 if (ok_blook(bsdcompat
) || ok_blook(bsdflags
) ||
150 getenv("SYSV3") != NULL
) {
151 char const bsdattr
[attrlen
+1] = "NU *HMFAT+-$";
152 memcpy(attrlist
, bsdattr
, sizeof bsdattr
);
154 char const pattr
[attrlen
+1] = "NUROSPMFAT+-$";
155 memcpy(attrlist
, pattr
, sizeof pattr
);
158 if ((fmt
= ok_vlook(headline
)) == NULL
) {
159 fmt
= ((ok_blook(bsdcompat
) || ok_blook(bsdheadline
))
160 ? "%>%a%m %-20f %16d %3l/%-5o %i%-S"
161 : "%>%a%m %-18f %16d %4l/%-5o %i%-s");
164 __hprf(yetprinted
, fmt
, msgno
, f
, threaded
, attrlist
);
169 __hprf(size_t yetprinted
, char const *fmt
, size_t msgno
, FILE *f
,
170 bool_t threaded
, char const *attrlist
)
172 char datebuf
[FROM_DATEBUF
], *cp
, *subjline
;
173 char const *datefmt
, *date
, *name
, *fp
;
174 int B
, c
, i
, n
, s
, wleft
, subjlen
, isto
= 0, isaddr
= 0;
179 mp
= message
+ msgno
- 1;
183 datefmt
= ok_vlook(datefield
);
185 if (datefmt
!= NULL
) {
186 fp
= hfield1("date", mp
);/* TODO use m_date field! */
192 date
= fakedate(datet
);
193 fp
= ok_vlook(datefield_markout_older
);
194 i
= (*datefmt
!= '\0');
196 i
|= (*fp
!= '\0') ? 2 | 4 : 2; /* XXX no magics */
198 /* May we strftime(3)? */
200 memcpy(&time_current
.tc_local
, localtime(&datet
),
201 sizeof time_current
.tc_local
);
203 if ((i
& 2) && (datet
> time_current
.tc_time
+ DATE_SECSDAY
||
204 #define _6M ((DATE_DAYSYEAR / 2) * DATE_SECSDAY)
205 (datet
+ _6M
< time_current
.tc_time
))) {
207 if ((datefmt
= (i
& 4) ? fp
: NULL
) == NULL
) {
208 memset(datebuf
, ' ', FROM_DATEBUF
); /* xxx ur */
209 memcpy(datebuf
+ 4, date
+ 4, 7);
210 datebuf
[4 + 7] = ' ';
211 memcpy(datebuf
+ 4 + 7 + 1, date
+ 20, 4);
212 datebuf
[4 + 7 + 1 + 4] = '\0';
215 } else if ((i
& 1) == 0)
217 } else if (datet
== (time_t)0 && !(mp
->m_flag
& MNOFROM
)) {
218 /* TODO eliminate this path, query the FROM_ date in setptr(),
219 * TODO all other codepaths do so by themselves ALREADY ?????
220 * TODO assert(mp->m_time != 0);, then
221 * TODO ALSO changes behaviour of datefield_markout_older */
222 _parse_from_(mp
, datebuf
);
225 date
= fakedate(datet
);
229 if (name
!= NULL
&& ok_blook(showto
) && is_myname(skin(name
))) {
230 if ((cp
= hfield1("to", mp
)) != NULL
) {
240 name
= ok_blook(showname
) ? realname(name
) : prstr(skin(name
));
244 /* Detect the width of the non-format characters in *headline*;
245 * like that we can simply use putc() in the next loop, since we have
246 * already calculated their column widths (TODO it's sick) */
247 wleft
= subjlen
= scrnwidth
;
249 for (fp
= fmt
; *fp
!= '\0'; ++fp
) {
255 if (digitchar(*fp
)) {
258 n
= 10*n
+ *fp
- '0';
259 while (++fp
, digitchar(*fp
));
267 if (mb_cur_max
> 1) {
269 if ((s
= mbtowc(&wc
, fp
, mb_cur_max
)) == -1)
271 else if ((n
= wcwidth(wc
)) == -1)
283 /* Walk *headline*, producing output TODO not (really) MB safe */
284 for (fp
= fmt
; *fp
!= '\0'; ++fp
) {
285 if ((c
= *fp
& 0xFF) != '%')
294 } else if (*fp
== '+')
296 if (digitchar(*fp
)) {
298 n
= 10*n
+ *fp
- '0';
299 while (++fp
, digitchar(*fp
));
305 switch ((c
= *fp
& 0xFF)) {
317 if (UICMP(32, ABS(n
), >, wleft
))
318 n
= (n
< 0) ? -wleft
: wleft
;
320 snprintf(buf
, sizeof buf
, "%u.%u",
321 (mp
->m_spamscore
>> 8), (mp
->m_spamscore
& 0xFF));
322 n
= fprintf(f
, "%*s", n
, buf
);
323 wleft
= (n
>= 0) ? wleft
- n
: 0;
330 c
= _dispc(mp
, attrlist
);
332 if (UICMP(32, ABS(n
), >, wleft
))
333 n
= (n
< 0) ? -wleft
: wleft
;
334 n
= fprintf(f
, "%*c", n
, c
);
335 wleft
= (n
>= 0) ? wleft
- n
: 0;
338 if (datefmt
!= NULL
) {
339 i
= strftime(datebuf
, sizeof datebuf
, datefmt
,
340 &time_current
.tc_local
);
344 fprintf(stderr
, tr(174,
345 "Ignored date format, it excesses the target buffer "
346 "(%lu bytes)\n"), (ul_it
)sizeof datebuf
);
351 if (UICMP(32, ABS(n
), >, wleft
))
352 n
= (n
< 0) ? -wleft
: wleft
;
353 n
= fprintf(f
, "%*.*s", n
, n
, date
);
354 wleft
= (n
>= 0) ? wleft
- n
: 0;
359 if (UICMP(32, ABS(n
), >, wleft
))
360 n
= (n
< 0) ? -wleft
: wleft
;
361 n
= fprintf(f
, "%*u", n
, (threaded
== 1 ? mp
->m_level
: 0));
362 wleft
= (n
>= 0) ? wleft
- n
: 0;
373 n
= (n
< 0) ? -wleft
: wleft
;
375 if (isto
) /* XXX tr()! */
377 n
= fprintf(f
, "%s%s", (isto
? "To " : ""),
378 colalign(name
, i
, n
, &wleft
));
386 n
= __putindent(f
, mp
, MIN(wleft
, scrnwidth
- 60));
387 wleft
= (n
>= 0) ? wleft
- n
: 0;
393 if (UICMP(32, ABS(n
), >, wleft
))
394 n
= (n
< 0) ? -wleft
: wleft
;
396 n
= fprintf(f
, "%*ld", n
, mp
->m_xlines
);
397 wleft
= (n
>= 0) ? wleft
- n
: 0;
409 for (i
= msgCount
; i
> 999; i
/= 10)
412 if (UICMP(32, ABS(n
), >, wleft
))
413 n
= (n
< 0) ? -wleft
: wleft
;
414 n
= fprintf(f
, "%*lu", n
, (ul_it
)msgno
);
415 wleft
= (n
>= 0) ? wleft
- n
: 0;
420 if (UICMP(32, ABS(n
), >, wleft
))
421 n
= (n
< 0) ? -wleft
: wleft
;
422 n
= fprintf(f
, "%*lu", n
, (long)mp
->m_xsize
);
423 wleft
= (n
>= 0) ? wleft
- n
: 0;
435 if (UICMP(32, ABS(n
), >, subjlen
))
436 n
= (n
< 0) ? -subjlen
: subjlen
;
438 n
-= (n
< 0) ? -2 : 2;
441 if (subjline
== NULL
)
442 subjline
= __subject(mp
, threaded
, yetprinted
);
443 if (subjline
== (char*)-1) {
444 n
= fprintf(f
, "%*s", n
, "");
445 wleft
= (n
>= 0) ? wleft
- n
: 0;
447 n
= fprintf(f
, (B
? "\"%s\"" : "%s"),
448 colalign(subjline
, ABS(n
), n
, &wleft
));
457 for (i
= msgCount
; i
> 999; i
/= 10)
460 if (UICMP(32, ABS(n
), >, wleft
))
461 n
= (n
< 0) ? -wleft
: wleft
;
462 n
= fprintf(f
, "%*lu", n
,
463 (threaded
? (ul_it
)mp
->m_threadpos
: (ul_it
)msgno
));
464 wleft
= (n
>= 0) ? wleft
- n
: 0;
470 if (UICMP(32, ABS(n
), >, wleft
))
471 n
= (n
< 0) ? -wleft
: wleft
;
472 n
= fprintf(f
, "%*lu", n
, mp
->m_uid
);
473 wleft
= (n
>= 0) ? wleft
- n
: 0;
487 if (subjline
!= NULL
&& subjline
!= (char*)-1)
493 __subject_trim(char *s
)
498 } const *pp
, ignored
[] = { /* TODO make ignore list configurable */
499 { 3, "re:" }, { 4, "fwd:" },
500 { 3, "aw:" }, { 5, "antw:" },
507 while (spacechar(*s
))
509 /* TODO While it is maybe ok not to MIME decode these (for purpose), we
510 * TODO should skip =?..?= at the beginning? */
511 for (pp
= ignored
; pp
->len
> 0; ++pp
)
512 if (is_asccaseprefix(pp
->dat
, s
)) {
523 __subject(struct message
*mp
, bool_t threaded
, size_t yetprinted
)
525 /* XXX NOTE: because of efficiency reasons we simply ignore any encoded
526 * XXX parts and use ASCII case-insensitive comparison */
529 char *rv
= (char*)-1, *ms
, *mso
, *os
;
532 if ((ms
= hfield1("subject", mp
)) == NULL
)
535 if (!threaded
|| mp
->m_level
== 0)
538 /* In a display thread - check wether this message uses the same
539 * Subject: as it's parent or elder neighbour, suppress printing it if
540 * this is the case. To extend this a bit, ignore any leading Re: or
541 * Fwd: plus follow-up WS. Ignore invisible messages along the way */
542 mso
= __subject_trim(ms
);
543 for (xmp
= mp
; (xmp
= prev_in_thread(xmp
)) != NULL
&& yetprinted
-- > 0;)
544 if (visible(xmp
) && (os
= hfield1("subject", xmp
)) != NULL
&&
545 !asccasecmp(mso
, __subject_trim(os
)))
550 mime_fromhdr(&in
, &out
, TD_ICONV
| TD_ISPR
);
558 __putindent(FILE *fp
, struct message
*mp
, int maxwidth
)/* XXX no magic consts */
561 int *us
, indlvl
, indw
, i
, important
= MNEW
| MFLAGGED
;
565 if (mp
->m_level
== 0 || maxwidth
== 0) {
570 cs
= ac_alloc(mp
->m_level
);
571 us
= ac_alloc(mp
->m_level
* sizeof *us
);
574 if (mp
->m_younger
&& UICMP(32, i
+ 1, ==, mp
->m_younger
->m_level
)) {
575 if (mp
->m_parent
&& mp
->m_parent
->m_flag
& important
)
576 us
[i
] = mp
->m_flag
& important
? 0x2523 : 0x2520;
578 us
[i
] = mp
->m_flag
& important
? 0x251D : 0x251C;
581 if (mp
->m_parent
&& mp
->m_parent
->m_flag
& important
)
582 us
[i
] = mp
->m_flag
& important
? 0x2517 : 0x2516;
584 us
[i
] = mp
->m_flag
& important
? 0x2515 : 0x2514;
589 for (i
= mp
->m_level
- 2; i
>= 0; --i
) {
591 if (UICMP(32, i
, >, mq
->m_level
- 1)) {
596 if (mq
->m_parent
&& (mq
->m_parent
->m_flag
& important
))
609 for (indlvl
= indw
= 0; (ui8_t
)indlvl
< mp
->m_level
&& indw
< maxwidth
;
611 if (indw
< maxwidth
- 1)
612 indw
+= (int)putuc(us
[indlvl
], cs
[indlvl
] & 0xFF, fp
);
614 indw
+= (int)putuc(0x21B8, '^', fp
);
616 indw
+= (/*putuc(0x261E, fp)*/putc('>', fp
) != EOF
);
626 _dispc(struct message
*mp
, char const *a
)
631 if ((mp
->m_flag
& (MREAD
| MNEW
)) == MREAD
)
633 if ((mp
->m_flag
& (MREAD
| MNEW
)) == (MREAD
| MNEW
))
635 if (mp
->m_flag
& MANSWERED
)
637 if (mp
->m_flag
& MDRAFTED
)
639 if ((mp
->m_flag
& (MREAD
| MNEW
)) == MNEW
)
641 if (!(mp
->m_flag
& (MREAD
| MNEW
)))
643 if (mp
->m_flag
& MSPAM
)
645 if (mp
->m_flag
& MSAVED
)
647 if (mp
->m_flag
& MPRESERVE
)
649 if (mp
->m_flag
& (MBOX
| MBOXED
))
651 if (mp
->m_flag
& MFLAGGED
)
653 if (mb
.mb_threaded
== 1 && mp
->m_collapsed
> 0)
655 if (mb
.mb_threaded
== 1 && mp
->m_collapsed
< 0)
662 _scroll1(char *arg
, int onlynew
)
667 cur
[0] = onlynew
? -1 : 0;
670 case '1': case '2': case '3': case '4': case '5':
671 case '6': case '7': case '8': case '9': case '0':
673 goto jscroll_forward
;
676 goto jscroll_forward
;
678 _screen
= msgCount
/ size
;
679 goto jscroll_forward
;
684 _screen
+= atoi(arg
+ 1);
686 if (_screen
* size
> msgCount
) {
687 _screen
= msgCount
/ size
;
688 printf(tr(7, "On last screenful of messages\n"));
696 _screen
-= atoi(arg
+ 1);
699 printf(tr(8, "On first screenful of messages\n"));
706 fprintf(stderr
, tr(9, "Unrecognized scrolling command \"%s\"\n"), arg
);
710 size
= c_headers(cur
);
717 _type1(int *msgvec
, bool_t doign
, bool_t dopage
, bool_t dopipe
,
718 bool_t dodecode
, char *cmd
, off_t
*tstats
)
724 FILE * volatile obuf
;
727 enum sendaction
const action
= ((dopipe
&& ok_blook(piperaw
))
728 ? SEND_MBOX
: dodecode
730 ? SEND_TODISP
: SEND_TODISP_ALL
);
731 bool_t
const volatile formfeed
= (dopipe
&& ok_blook(page
));
734 if (sigsetjmp(_cmd1_pipestop
, 1))
737 if ((cp
= ok_vlook(SHELL
)) == NULL
)
739 if ((obuf
= Popen(cmd
, "w", cp
, 1)) == NULL
) {
743 safe_signal(SIGPIPE
, &_cmd1_brokpipe
);
744 } else if ((options
& OPT_TTYOUT
) &&
745 (dopage
|| (cp
= ok_vlook(crt
)) != NULL
)) {
746 char const *pager
= NULL
;
750 for (ip
= msgvec
; *ip
&& PTRCMP(ip
- msgvec
, <, msgCount
); ++ip
) {
751 mp
= message
+ *ip
- 1;
752 if (!(mp
->m_have
& HAVE_BODY
))
753 if (get_body(mp
) != OKAY
) {
757 nlines
+= mp
->m_lines
+ 1; /* Message info XXX and PARTS... */
761 /* `>=' not `<': we return to the prompt */
762 if (dopage
|| UICMP(z
, nlines
, >=,
763 (*cp
!= '\0' ? atoi(cp
) : realscreenheight
))) {
765 obuf
= Popen(pager
, "w", NULL
, 1);
771 safe_signal(SIGPIPE
, &_cmd1_brokpipe
);
774 if (action
!= SEND_MBOX
)
775 colour_table_create(pager
); /* (salloc()s!) */
779 else if ((options
& OPT_TTYOUT
) && action
!= SEND_MBOX
)
780 colour_table_create(NULL
); /* (salloc()s!) */
783 /* This may jump, in which case srelax_rele() wouldn't be called, but
784 * it shouldn't matter, because we -- then -- directly reenter the
785 * lex.c:commands() loop, which sreset()s */
787 for (ip
= msgvec
; *ip
&& PTRCMP(ip
- msgvec
, <, msgCount
); ++ip
) {
788 mp
= message
+ *ip
- 1;
795 if (action
!= SEND_MBOX
)
796 _show_msg_overview(obuf
, mp
, *ip
);
798 sendmp(mp
, obuf
, (doign
? ignore
: NULL
), NULL
, action
, mstats
);
800 if (formfeed
) /* TODO a nicer way to separate piped messages! */
803 tstats
[0] += mstats
[0];
804 tstats
[1] += mstats
[1];
810 if (obuf
!= stdout
) {
811 /* Ignore SIGPIPE so it can't cause a duplicate close */
812 safe_signal(SIGPIPE
, SIG_IGN
);
813 colour_reset(obuf
); /* XXX hacky; only here because we still jump */
815 safe_signal(SIGPIPE
, dflpipe
);
825 _pipe1(char *str
, int doign
)
833 if ((cmd
= laststring(str
, &needs_list
, 1)) == NULL
) {
835 if (cmd
== NULL
|| *cmd
== '\0') {
836 fputs(tr(16, "variable cmd not set\n"), stderr
);
841 msgvec
= salloc((msgCount
+ 2) * sizeof *msgvec
);
844 *msgvec
= first(0, MMNORM
);
850 puts(tr(18, "No messages to pipe."));
854 } else if (getmsglist(str
, msgvec
, 0) < 0)
861 printf("No applicable messages.\n");
865 printf(tr(268, "Pipe to: \"%s\"\n"), cmd
);
866 stats
[0] = stats
[1] = 0;
867 if ((rv
= _type1(msgvec
, doign
, FAL0
, TRU1
, FAL0
, cmd
, stats
)) == 0) {
868 printf("\"%s\" ", cmd
);
870 printf("%lu", (long)stats
[0]);
872 printf(tr(27, "binary"));
873 printf("/%lu\n", (long)stats
[1]);
881 c_cmdnotsupp(void *v
) /* TODO -> lex.c */
885 fprintf(stderr
, tr(10, "The requested feature is not compiled in\n"));
894 int *msgvec
= v
, g
, k
, n
, mesg
, size
, lastg
= 1;
895 struct message
*mp
, *mq
, *lastmq
= NULL
;
896 enum mflag fl
= MNEW
| MFLAGGED
;
899 time_current_update(&time_current
, FAL0
);
903 n
= msgvec
[0]; /* n == {-2, -1, 0}: called from scroll() */
912 if (mb
.mb_threaded
== 0) {
915 for (mp
= message
; PTRCMP(mp
, <, message
+ msgCount
); ++mp
)
919 if (mp
->m_flag
& fl
) {
923 if ((n
> 0 && PTRCMP(mp
, ==, message
+ n
- 1)) ||
924 (n
== 0 && g
== k
) || (n
== -2 && g
== k
+ size
&& lastmq
) ||
925 (n
< 0 && g
>= k
&& (mp
->m_flag
& fl
) != 0))
929 if (lastmq
&& (n
== -2 ||
930 (n
== -1 && PTRCMP(mp
, ==, message
+ msgCount
)))) {
936 mesg
= (int)PTR2SIZE(mp
- message
);
937 if (PTRCMP(dot
, !=, message
+ n
- 1)) {
938 for (mq
= mp
; PTRCMP(mq
, <, message
+ msgCount
); ++mq
)
945 if (mb
.mb_type
== MB_IMAP
)
946 imap_getheaders(mesg
+ 1, mesg
+ size
);
949 for (; PTRCMP(mp
, <, message
+ msgCount
); ++mp
) {
953 if (UICMP(32, flag
++, >=, size
))
955 _print_head(0, mesg
, stdout
, 0);
959 } else { /* threaded */
962 for (mp
= threadroot
; mp
; mp
= next_in_thread(mp
))
964 (mp
->m_collapsed
<= 0 || PTRCMP(mp
, ==, message
+ n
- 1))) {
967 if (mp
->m_flag
& fl
) {
971 if ((n
> 0 && PTRCMP(mp
, ==, message
+ n
- 1)) ||
972 (n
== 0 && g
== k
) || (n
== -2 && g
== k
+ size
&& lastmq
) ||
973 (n
< 0 && g
>= k
&& (mp
->m_flag
& fl
) != 0))
977 if (lastmq
&& (n
== -2 ||
978 (n
== -1 && PTRCMP(mp
, ==, message
+ msgCount
)))) {
984 if (PTRCMP(dot
, !=, message
+ n
- 1)) {
985 for (mq
= mp
; mq
; mq
= next_in_thread(mq
))
986 if (visible(mq
) && mq
->m_collapsed
<= 0) {
994 (mp
->m_collapsed
<= 0 || PTRCMP(mp
, ==, message
+ n
- 1))) {
995 if (UICMP(32, flag
++, >=, size
))
997 _print_head(flag
- 1, PTR2SIZE(mp
- message
+ 1), stdout
,
1001 mp
= next_in_thread(mp
);
1007 printf(tr(6, "No more mail.\n"));
1018 rv
= _scroll1(v
, 0);
1029 rv
= _scroll1(v
, 1);
1037 int *msgvec
= v
, *ip
, n
;
1039 FILE * volatile obuf
;
1042 time_current_update(&time_current
, FAL0
);
1045 /* TODO unfixable memory leaks still */
1046 if (IS_TTY_SESSION() && (cp
= ok_vlook(crt
)) != NULL
) {
1047 for (n
= 0, ip
= msgvec
; *ip
!= 0; ++ip
)
1049 if (n
> (*cp
== '\0' ? screensize() : atoi(cp
)) + 3) {
1051 if (sigsetjmp(_cmd1_pipejmp
, 1))
1054 if ((obuf
= Popen(p
, "w", NULL
, 1)) == NULL
) {
1059 safe_signal(SIGPIPE
, &_cmd1_onpipe
);
1063 for (n
= 0, ip
= msgvec
; *ip
!= 0; ++ip
) /* TODO join into _print_head() */
1064 _print_head((size_t)n
++, (size_t)*ip
, obuf
, mb
.mb_threaded
);
1066 setdot(message
+ *ip
- 1);
1069 if (obuf
!= stdout
) {
1070 safe_signal(SIGPIPE
, SIG_IGN
);
1072 safe_signal(SIGPIPE
, dflpipe
);
1079 print_headers(size_t bottom
, size_t topx
, bool_t only_marked
)
1085 if (mb
.mb_type
== MB_IMAP
)
1086 imap_getheaders(bottom
, topx
);
1088 time_current_update(&time_current
, FAL0
);
1090 for (printed
= 0; bottom
<= topx
; ++bottom
) {
1091 struct message
*mp
= message
+ bottom
- 1;
1093 if (!(mp
->m_flag
& MMARK
))
1095 } else if (!visible(mp
))
1097 _print_head(printed
++, bottom
, stdout
, FAL0
);
1107 printf("%d\n", (int)PTR2SIZE(dot
- message
+ 1));
1115 int *msgvec
= v
, rv
;
1118 rv
= _type1(msgvec
, TRU1
, TRU1
, FAL0
, FAL0
, NULL
, NULL
);
1126 int *msgvec
= v
, rv
;
1129 rv
= _type1(msgvec
, FAL0
, TRU1
, FAL0
, FAL0
, NULL
, NULL
);
1137 int *msgvec
= v
, rv
;
1140 rv
= _type1(msgvec
, TRU1
, FAL0
, FAL0
, FAL0
, NULL
, NULL
);
1148 int *msgvec
= v
, rv
;
1151 rv
= _type1(msgvec
, FAL0
, FAL0
, FAL0
, FAL0
, NULL
, NULL
);
1159 int *msgvec
= v
, rv
;
1162 rv
= _type1(msgvec
, FAL0
, FAL0
, FAL0
, TRU1
, NULL
, NULL
);
1174 rv
= _pipe1(str
, 1);
1186 rv
= _pipe1(str
, 0);
1194 int *msgvec
= v
, *ip
, c
, topl
, lines
, empty_last
;
1196 char *cp
, *linebuf
= NULL
;
1197 size_t linesize
= 0;
1202 cp
= ok_vlook(toplines
);
1205 if (topl
< 0 || topl
> 10000)
1210 if (options
& OPT_TTYOUT
)
1211 colour_table_create(NULL
); /* (salloc()s) */
1214 for (ip
= msgvec
; *ip
!= 0 && UICMP(z
, PTR2SIZE(ip
- msgvec
), <, msgCount
);
1216 mp
= message
+ *ip
- 1;
1219 did_print_dot
= TRU1
;
1222 _show_msg_overview(stdout
, mp
, *ip
);
1223 if (mp
->m_flag
& MNOFROM
)
1224 /* XXX c_top(): coloured output? */
1225 printf("From %s %s\n", fakefrom(mp
), fakedate(mp
->m_time
));
1226 if ((ibuf
= setinput(&mb
, mp
, NEED_BODY
)) == NULL
) { /* XXX could use TOP */
1231 for (lines
= 0; lines
< c
&& UICMP(32, lines
, <=, topl
); ++lines
) {
1232 if (readline_restart(ibuf
, &linebuf
, &linesize
, 0) < 0)
1236 for (cp
= linebuf
; *cp
!= '\0' && blankchar(*cp
); ++cp
)
1238 empty_last
= (*cp
== '\0');
1242 if (linebuf
!= NULL
)
1251 int *msgvec
= v
, *ip
;
1254 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1255 setdot(message
+ *ip
- 1);
1256 dot
->m_flag
|= MTOUCH
;
1257 dot
->m_flag
&= ~MPRESERVE
;
1258 did_print_dot
= TRU1
;
1267 int *msgvec
= v
, *ip
;
1270 for (ip
= msgvec
; *ip
!= 0; ++ip
) {
1271 setdot(message
+ *ip
- 1);
1272 dot
->m_flag
|= MTOUCH
| MBOX
;
1273 dot
->m_flag
&= ~MPRESERVE
;
1274 did_print_dot
= TRU1
;
1283 char dirname
[PATH_MAX
], *name
, **argv
= v
;
1289 name
= expand(*argv
);
1292 } else if (!getfold(dirname
, sizeof dirname
)) {
1293 fprintf(stderr
, tr(20, "No value set for \"folder\"\n"));
1298 if (which_protocol(name
) == PROTO_IMAP
) {
1300 imap_folders(name
, *argv
== NULL
);
1302 rv
= c_cmdnotsupp(NULL
);
1305 if ((cmd
= ok_vlook(LISTER
)) == NULL
)
1307 run_command(cmd
, 0, -1, -1, name
, NULL
, NULL
);
1314 /* vim:set fenc=utf-8:s-it-mode */