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 - 2013 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 * Print the current active headings.
46 * Don't change dot if invoker didn't give an argument.
51 /* Prepare and print "[Message: xy]:" intro */
52 static void _show_msg_overview(struct message
*mp
, int msg_no
, FILE *obuf
);
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
, int msgno
, FILE *f
,
63 static void __hprf(size_t yetprinted
, const char *fmt
, int mesg
, FILE *f
,
64 bool_t threaded
, const char *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 void _cmd1_onpipe(int signo
);
71 static int _dispc(struct message
*mp
, const char *a
);
72 static int scroll1(char *arg
, int onlynew
);
74 static int _type1(int *msgvec
, bool_t doign
, bool_t dopage
, bool_t dopipe
,
75 bool_t dodecode
, char *cmd
, off_t
*tstats
);
76 static int pipe1(char *str
, int doign
);
79 _show_msg_overview(struct message
*mp
, int msg_no
, FILE *obuf
)
81 fprintf(obuf
, tr(17, "[-- Message %2d -- %lu lines, %lu bytes --]:\n"),
82 msg_no
, (ul_it
)mp
->m_lines
, (ul_it
)mp
->m_size
);
86 _parse_from_(struct message
*mp
, char date
[FROM_DATEBUF
])
93 if ((ibuf
= setinput(&mb
, mp
, NEED_HEADER
)) != NULL
&&
94 (hlen
= readline_restart(ibuf
, &hline
, &hsize
, 0)) > 0)
95 (void)extract_date_from_from_(hline
, hlen
, date
);
101 _print_head(size_t yetprinted
, int msgno
, FILE *f
, bool_t threaded
)
103 char attrlist
[30], *cp
;
106 if ((cp
= voption("attrlist")) != NULL
) {
107 size_t i
= strlen(cp
);
108 if (UICMP(32, i
, >, sizeof attrlist
- 1))
109 i
= (int)sizeof attrlist
- 1;
110 memcpy(attrlist
, cp
, i
);
111 } else if (boption("bsdcompat") || boption("bsdflags") ||
112 getenv("SYSV3") != NULL
) {
113 char const bsdattr
[] = "NU *HMFAT+-$";
114 memcpy(attrlist
, bsdattr
, sizeof bsdattr
- 1);
116 char const pattr
[] = "NUROSPMFAT+-$";
117 memcpy(attrlist
, pattr
, sizeof pattr
- 1);
120 if ((fmt
= voption("headline")) == NULL
) {
121 fmt
= ((boption("bsdcompat") || boption("bsdheadline"))
122 ? "%>%a%m %-20f %16d %3l/%-5o %i%-S"
123 : "%>%a%m %-18f %16d %4l/%-5o %i%-s");
126 __hprf(yetprinted
, fmt
, msgno
, f
, threaded
, attrlist
);
130 __hprf(size_t yetprinted
, char const *fmt
, int msgno
, FILE *f
, bool_t threaded
,
131 char const *attrlist
)
133 char datebuf
[FROM_DATEBUF
], *cp
, *subjline
;
134 char const *datefmt
, *date
, *name
, *fp
;
135 int B
, c
, i
, n
, s
, wleft
, subjlen
, isto
= 0, isaddr
= 0;
136 struct message
*mp
= &message
[msgno
- 1];
137 time_t datet
= mp
->m_time
;
140 if ((datefmt
= value("datefield")) != NULL
) {
141 fp
= hfield1("date", mp
);/* TODO use m_date field! */
147 date
= fakedate(datet
);
148 fp
= value("datefield-markout-older");
149 i
= (*datefmt
!= '\0');
151 i
|= (*fp
!= '\0') ? 2 | 4 : 2;
152 /* May we strftime(3)? */
154 memcpy(&time_current
.tc_local
, localtime(&datet
),
155 sizeof time_current
.tc_local
);
157 /* TODO *datefield-markout-older* we accept
158 * TODO one day in the future, should be UTC
159 * TODO offset only? and Stephen Isard had
160 * TODO one week once he proposed the patch! */
161 (datet
> time_current
.tc_time
+ DATE_SECSDAY
||
162 #define _6M ((DATE_DAYSYEAR / 2) * DATE_SECSDAY)
163 (datet
+ _6M
< time_current
.tc_time
))) {
165 if ((datefmt
= (i
& 4) ? fp
: NULL
) == NULL
) {
166 memset(datebuf
, ' ', FROM_DATEBUF
); /* xxx ur */
167 memcpy(datebuf
+ 4, date
+ 4, 7);
168 datebuf
[4 + 7] = ' ';
169 memcpy(datebuf
+ 4 + 7 + 1, date
+ 20, 4);
170 datebuf
[4 + 7 + 1 + 4] = '\0';
173 } else if ((i
& 1) == 0)
175 } else if (datet
== (time_t)0 && (mp
->m_flag
& MNOFROM
) == 0) {
176 /* TODO eliminate this path, query the FROM_ date in setptr(),
177 * TODO all other codepaths do so by themselves ALREADY ?????
178 * TODO assert(mp->m_time != 0);, then
179 * TODO ALSO changes behaviour of markout-non-current */
180 _parse_from_(mp
, datebuf
);
184 date
= fakedate(datet
);
189 if (name
!= NULL
&& value("showto") && is_myname(skin(name
))) {
190 if ((cp
= hfield1("to", mp
)) != NULL
) {
200 if (value("showname"))
201 name
= realname(name
);
203 name
= prstr(skin(name
));
209 /* Detect the width of the non-format characters in *headline*;
210 * like that we can simply use putc() in the next loop, since we have
211 * already calculated their column widths (TODO it's sick) */
215 for (fp
= fmt
; *fp
; ++fp
) {
219 } else if (*fp
== '+')
221 if (digitchar(*fp
)) {
224 n
= 10*n
+ *fp
- '0';
225 while (++fp
, digitchar(*fp
));
233 if (mb_cur_max
> 1) {
235 if ((s
= mbtowc(&wc
, fp
, mb_cur_max
)) < 0)
237 else if ((n
= wcwidth(wc
)) < 0)
249 /* Walk *headline*, producing output */
250 for (fp
= fmt
; *fp
; ++fp
) {
251 if ((c
= *fp
& 0xFF) == '%') {
258 } else if (*fp
== '+')
260 if (digitchar(*fp
)) {
262 n
= 10*n
+ *fp
- '0';
263 while (++fp
, digitchar(*fp
));
269 switch ((c
= *fp
& 0xFF)) {
278 c
= _dispc(mp
, attrlist
);
280 if (UICMP(32, ABS(n
), >, wleft
))
281 n
= (n
< 0) ? -wleft
: wleft
;
282 n
= fprintf(f
, "%*c", n
, c
);
283 wleft
= (n
>= 0) ? wleft
- n
: 0;
289 for (i
=msgCount
; i
>999; i
/=10)
292 if (UICMP(32, ABS(n
), >, wleft
))
293 n
= (n
< 0) ? -wleft
: wleft
;
294 n
= fprintf(f
, "%*d", n
, msgno
);
295 wleft
= (n
>= 0) ? wleft
- n
: 0;
306 n
= (n
< 0) ? -wleft
: wleft
;
308 if (isto
) /* XXX tr()! */
310 n
= fprintf(f
, "%s%s", (isto
? "To " : ""),
311 colalign(name
, i
, n
, &wleft
));
318 if (datefmt
!= NULL
) {
319 i
= strftime(datebuf
, sizeof datebuf
,
321 &time_current
.tc_local
);
325 fprintf(stderr
, tr(174,
326 "Ignored date format, "
330 (ul_it
)sizeof datebuf
);
335 if (UICMP(32, ABS(n
), >, wleft
))
336 n
= (n
< 0) ? -wleft
: wleft
;
337 n
= fprintf(f
, "%*.*s", n
, n
, date
);
338 wleft
= (n
>= 0) ? wleft
- n
: 0;
343 if (UICMP(32, ABS(n
), >, wleft
))
344 n
= (n
< 0) ? -wleft
: wleft
;
346 n
= fprintf(f
, "%*ld", n
, mp
->m_xlines
);
347 wleft
= (n
>= 0) ? wleft
- n
: 0;
358 if (UICMP(32, ABS(n
), >, wleft
))
359 n
= (n
< 0) ? -wleft
: wleft
;
360 n
= fprintf(f
, "%*lu", n
, (long)mp
->m_xsize
);
361 wleft
= (n
>= 0) ? wleft
- n
: 0;
365 n
= __putindent(f
, mp
, MIN(wleft
,
367 wleft
= (n
>= 0) ? wleft
- n
: 0;
380 if (UICMP(32, ABS(n
), >, subjlen
))
381 n
= (n
< 0) ? -subjlen
: subjlen
;
383 n
-= (n
< 0) ? -2 : 2;
386 if (subjline
== NULL
)
387 subjline
= __subject(mp
, threaded
,
389 if (subjline
== (char*)-1) {
390 n
= fprintf(f
, "%*s", n
, "");
391 wleft
= (n
>= 0) ? wleft
-n
: 0;
393 n
= fprintf(f
, (B
? "\"%s\"" : "%s"),
394 colalign(subjline
, ABS(n
), n
,
404 if (UICMP(32, ABS(n
), >, wleft
))
405 n
= (n
< 0) ? -wleft
: wleft
;
406 n
= fprintf(f
, "%*lu", n
, mp
->m_uid
);
407 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
,
419 threaded
== 1 ? mp
->m_level
: 0);
420 wleft
= (n
>= 0) ? wleft
- n
: 0;
426 for (i
=msgCount
; i
>999; i
/=10)
429 if (UICMP(32, ABS(n
), >, wleft
))
430 n
= (n
< 0) ? -wleft
: wleft
;
431 n
= fprintf(f
, "%*ld", n
,
432 threaded
? mp
->m_threadpos
: msgno
);
433 wleft
= (n
>= 0) ? wleft
- n
: 0;
439 if (UICMP(32, ABS(n
), >, wleft
))
440 n
= (n
< 0) ? -wleft
: wleft
;
442 snprintf(buf
, sizeof buf
, "%u.%u",
443 (mp
->m_spamscore
>> 8),
444 (mp
->m_spamscore
& 0xFF));
445 n
= fprintf(f
, "%*s", n
, buf
);
446 wleft
= (n
>= 0) ? wleft
- n
: 0;
461 if (subjline
!= NULL
&& subjline
!= (char*)-1)
466 __subject_trim(char *s
)
471 } const *pp
, ignored
[] = { /* TODO make ignore list configurable */
472 { 3, "re:" }, { 4, "fwd:" },
473 { 3, "aw:" }, { 5, "antw:" },
478 while (spacechar(*s
))
480 /* TODO While it is maybe ok not to MIME decode these, we
481 * TODO should skip =?..?= at the beginning? */
482 for (pp
= ignored
; pp
->len
> 0; ++pp
)
483 if (is_asccaseprefix(pp
->dat
, s
)) {
493 __subject(struct message
*mp
, bool_t threaded
, size_t yetprinted
)
495 /* XXX NOTE: because of efficiency reasons we simply ignore any encoded
496 * XXX parts and use ASCII case-insensitive comparison */
499 char *rv
= (char*)-1, *ms
, *mso
, *os
;
501 if ((ms
= hfield1("subject", mp
)) == NULL
)
504 if (!threaded
|| mp
->m_level
== 0)
507 /* In a display thread - check wether this message uses the same
508 * Subject: as it's parent or elder neighbour, suppress printing it if
509 * this is the case. To extend this a bit, ignore any leading Re: or
510 * Fwd: plus follow-up WS. Ignore invisible messages along the way */
511 mso
= __subject_trim(ms
);
512 for (xmp
= mp
; (xmp
= prev_in_thread(xmp
)) != NULL
&& yetprinted
-- > 0;)
513 if (visible(xmp
) && (os
= hfield1("subject", xmp
)) != NULL
&&
514 asccasecmp(mso
, __subject_trim(os
)) == 0)
519 mime_fromhdr(&in
, &out
, TD_ICONV
| TD_ISPR
);
526 __putindent(FILE *fp
, struct message
*mp
, int maxwidth
)/* XXX no magic consts */
529 int *us
, indlvl
, indw
, i
, important
= MNEW
|MFLAGGED
;
532 if (mp
->m_level
== 0 || maxwidth
== 0)
534 cs
= ac_alloc(mp
->m_level
);
535 us
= ac_alloc(mp
->m_level
* sizeof *us
);
538 if (mp
->m_younger
&& UICMP(32, i
+ 1, ==, mp
->m_younger
->m_level
)) {
539 if (mp
->m_parent
&& mp
->m_parent
->m_flag
& important
)
540 us
[i
] = mp
->m_flag
& important
? 0x2523 : 0x2520;
542 us
[i
] = mp
->m_flag
& important
? 0x251D : 0x251C;
545 if (mp
->m_parent
&& mp
->m_parent
->m_flag
& important
)
546 us
[i
] = mp
->m_flag
& important
? 0x2517 : 0x2516;
548 us
[i
] = mp
->m_flag
& important
? 0x2515 : 0x2514;
553 for (i
= mp
->m_level
- 2; i
>= 0; i
--) {
555 if (UICMP(32, i
, >, mq
->m_level
- 1)) {
561 mq
->m_parent
->m_flag
&important
)
574 for (indlvl
= indw
= 0; (uc_it
)indlvl
< mp
->m_level
&&
575 indw
< maxwidth
; ++indlvl
) {
576 if (indw
< maxwidth
- 1)
577 indw
+= (int)putuc(us
[indlvl
], cs
[indlvl
] & 0377, fp
);
579 indw
+= (int)putuc(0x21B8, '^', fp
);
581 indw
+= /*putuc(0x261E, fp)*/putc('>', fp
) != EOF
;
589 ccmdnotsupp(void *v
) /* TODO -> lex.c */
592 fprintf(stderr
, tr(10, "The requested feature is not compiled in\n"));
602 if (cp
== NULL
|| *cp
== '\0')
611 int *msgvec
= v
, g
, k
, n
, mesg
, size
, lastg
= 1;
612 struct message
*mp
, *mq
, *lastmq
= NULL
;
613 enum mflag fl
= MNEW
|MFLAGGED
;
615 time_current_update(&time_current
, FAL0
);
619 n
= msgvec
[0]; /* n == {-2, -1, 0}: called from scroll() */
628 if (mb
.mb_threaded
== 0) {
631 for (mp
= &message
[0]; mp
< &message
[msgCount
]; mp
++)
639 if ((n
> 0 && mp
== &message
[n
-1]) ||
640 (n
== 0 && g
== k
) ||
641 (n
== -2 && g
== k
+ size
&&
644 (mp
->m_flag
& fl
) != 0))
648 if (lastmq
&& (n
==-2 || (n
==-1 && mp
== &message
[msgCount
]))) {
654 mesg
= mp
- &message
[0];
655 if (dot
!= &message
[n
-1]) {
656 for (mq
= mp
; mq
< &message
[msgCount
]; mq
++)
663 if (mb
.mb_type
== MB_IMAP
)
664 imap_getheaders(mesg
+1, mesg
+ size
);
667 for (; mp
< &message
[msgCount
]; mp
++) {
671 if (UICMP(32, flag
++, >=, size
))
673 _print_head(0, mesg
, stdout
, 0);
677 } else { /* threaded */
680 for (mp
= threadroot
; mp
; mp
= next_in_thread(mp
))
681 if (visible(mp
) && (mp
->m_collapsed
<= 0 ||
682 mp
== &message
[n
-1])) {
689 if ((n
> 0 && mp
== &message
[n
-1]) ||
690 (n
== 0 && g
== k
) ||
691 (n
== -2 && g
== k
+ size
&&
694 (mp
->m_flag
& fl
) != 0))
698 if (lastmq
&& (n
==-2 || (n
==-1 && mp
==&message
[msgCount
]))) {
704 if (dot
!= &message
[n
-1]) {
705 for (mq
= mp
; mq
; mq
= next_in_thread(mq
))
706 if (visible(mq
) && mq
->m_collapsed
<= 0) {
713 if (visible(mp
) && (mp
->m_collapsed
<= 0 ||
714 mp
== &message
[n
-1])) {
715 if (UICMP(32, flag
++, >=, size
))
717 _print_head(flag
- 1, mp
- &message
[0] + 1,
718 stdout
, mb
.mb_threaded
);
721 mp
= next_in_thread(mp
);
726 printf(tr(6, "No more mail.\n"));
731 * Scroll to the next/previous screen
736 return scroll1(v
, 0);
742 return scroll1(v
, 1);
746 scroll1(char *arg
, int onlynew
)
751 cur
[0] = onlynew
? -1 : 0;
754 case '1': case '2': case '3': case '4': case '5':
755 case '6': case '7': case '8': case '9': case '0':
762 screen
= msgCount
/ size
;
768 screen
+= atoi(arg
+ 1);
770 if (screen
* size
> msgCount
) {
771 screen
= msgCount
/ size
;
772 printf(tr(7, "On last screenful of messages\n"));
780 screen
-= atoi(arg
+ 1);
783 printf(tr(8, "On first screenful of messages\n"));
790 printf(tr(9, "Unrecognized scrolling command \"%s\"\n"), arg
);
793 return(headers(cur
));
797 * Compute screen size.
805 if ((cp
= value("screen")) != NULL
&& (s
= atoi(cp
)) > 0)
807 return scrnheight
- 4;
810 static sigjmp_buf _cmd1_pipejmp
;
814 _cmd1_onpipe(int signo
)
817 siglongjmp(_cmd1_pipejmp
, 1);
821 * Print out the headlines for each message
822 * in the passed message list.
827 int *msgvec
= v
, *ip
, n
;
829 FILE *volatile obuf
= stdout
;
831 time_current_update(&time_current
, FAL0
);
833 /* TODO unfixable memory leaks still */
834 if (IS_TTY_SESSION() && (cp
= value("crt")) != NULL
) {
835 for (n
= 0, ip
= msgvec
; *ip
; ip
++)
837 if (n
> (*cp
== '\0' ? screensize() : atoi((char*)cp
)) + 3) {
839 if (sigsetjmp(_cmd1_pipejmp
, 1))
842 if ((obuf
= Popen(p
, "w", NULL
, 1)) == NULL
) {
847 safe_signal(SIGPIPE
, _cmd1_onpipe
);
850 for (n
= 0, ip
= msgvec
; *ip
!= 0; ip
++)
851 _print_head((size_t)n
++, *ip
, obuf
, mb
.mb_threaded
);
853 setdot(&message
[*ip
- 1]);
855 if (obuf
!= stdout
) {
856 safe_signal(SIGPIPE
, SIG_IGN
);
858 safe_signal(SIGPIPE
, dflpipe
);
864 _dispc(struct message
*mp
, const char *a
)
871 if ((mp
->m_flag
& (MREAD
|MNEW
)) == MREAD
)
873 if ((mp
->m_flag
& (MREAD
|MNEW
)) == (MREAD
|MNEW
))
875 if (mp
->m_flag
& MANSWERED
)
877 if (mp
->m_flag
& MDRAFTED
)
879 if ((mp
->m_flag
& (MREAD
|MNEW
)) == MNEW
)
881 if ((mp
->m_flag
& (MREAD
|MNEW
)) == 0)
883 if (mp
->m_flag
& MSPAM
)
885 if (mp
->m_flag
& MSAVED
)
887 if (mp
->m_flag
& MPRESERVE
)
889 if (mp
->m_flag
& (MBOX
|MBOXED
))
891 if (mp
->m_flag
& MFLAGGED
)
893 if (mb
.mb_threaded
== 1 && mp
->m_collapsed
> 0)
895 if (mb
.mb_threaded
== 1 && mp
->m_collapsed
< 0)
901 print_headers(size_t bottom
, size_t topx
)
906 if (mb
.mb_type
== MB_IMAP
)
907 imap_getheaders(bottom
, topx
);
909 time_current_update(&time_current
, FAL0
);
911 for (printed
= 0; bottom
<= topx
; ++bottom
)
912 if (visible(&message
[bottom
- 1]))
913 _print_head(printed
++, bottom
, stdout
, 0);
917 * Print out the value of dot.
924 printf("%d\n", (int)(dot
- &message
[0] + 1));
929 * Type out the messages requested.
931 static sigjmp_buf pipestop
;
938 siglongjmp(pipestop
, 1);
942 _type1(int *msgvec
, bool_t doign
, bool_t dopage
, bool_t dopipe
,
943 bool_t dodecode
, char *cmd
, off_t
*tstats
)
949 FILE * volatile obuf
;
952 if (sigsetjmp(pipestop
, 1))
955 if ((cp
= value("SHELL")) == NULL
)
957 if ((obuf
= Popen(cmd
, "w", cp
, 1)) == NULL
) {
961 safe_signal(SIGPIPE
, brokpipe
);
962 } else if ((options
& OPT_TTYOUT
) &&
963 (dopage
|| (cp
= value("crt")) != NULL
)) {
966 for (ip
= msgvec
; *ip
&&
967 PTRCMP(ip
- msgvec
, <, msgCount
);
969 if (!(message
[*ip
- 1].m_have
& HAVE_BODY
)) {
970 if ((get_body(&message
[*ip
- 1])) !=
974 nlines
+= message
[*ip
- 1].m_lines
;
977 if (dopage
|| nlines
> (*cp
? atoi(cp
) : realscreenheight
)) {
978 char const *p
= get_pager();
979 if ((obuf
= Popen(p
, "w", NULL
, 1)) == NULL
) {
983 safe_signal(SIGPIPE
, brokpipe
);
987 /* This may jump, in which case srelax_rele() wouldn't be called, but
988 * it shouldn't matter, because we -- then -- directly reenter the
989 * lex.c:commands() loop, which sreset()s */
991 for (ip
= msgvec
; *ip
&& PTRCMP(ip
- msgvec
, <, msgCount
); ++ip
) {
992 mp
= &message
[*ip
- 1];
996 if (!dopipe
&& ip
!= msgvec
)
998 _show_msg_overview(mp
, *ip
, obuf
);
999 sendmp(mp
, obuf
, (doign
? ignore
: 0), NULL
,
1000 ((dopipe
&& boption("piperaw"))
1001 ? SEND_MBOX
: dodecode
1003 ? SEND_TODISP
: SEND_TODISP_ALL
),
1006 if (dopipe
&& boption("page"))
1009 tstats
[0] += mstats
[0];
1010 tstats
[1] += mstats
[1];
1015 if (obuf
!= stdout
) {
1016 /* Ignore SIGPIPE so it can't cause a duplicate close */
1017 safe_signal(SIGPIPE
, SIG_IGN
);
1019 safe_signal(SIGPIPE
, dflpipe
);
1025 * Pipe the messages requested.
1028 pipe1(char *str
, int doign
)
1036 msgvec
= (int *)salloc((msgCount
+ 2) * sizeof *msgvec
);
1037 if ((cmd
= laststring(str
, &f
, 1)) == NULL
) {
1039 if (cmd
== NULL
|| *cmd
== '\0') {
1040 fputs(tr(16, "variable cmd not set\n"), stderr
);
1045 *msgvec
= first(0, MMNORM
);
1049 puts(tr(18, "No messages to pipe."));
1053 } else if (getmsglist(str
, msgvec
, 0) < 0)
1058 printf("No applicable messages.\n");
1061 printf(tr(268, "Pipe to: \"%s\"\n"), cmd
);
1062 stats
[0] = stats
[1] = 0;
1063 if ((ret
= _type1(msgvec
, doign
, FAL0
, TRU1
, FAL0
, cmd
, stats
)) == 0) {
1064 printf("\"%s\" ", cmd
);
1066 printf("%lu", (long)stats
[0]);
1068 printf(tr(27, "binary"));
1069 printf("/%lu\n", (long)stats
[1]);
1075 * Paginate messages, honor ignored fields.
1082 return _type1(msgvec
, TRU1
, TRU1
, FAL0
, FAL0
, NULL
, NULL
);
1086 * Paginate messages, even printing ignored fields.
1093 return _type1(msgvec
, FAL0
, TRU1
, FAL0
, FAL0
, NULL
, NULL
);
1097 * Type out messages, honor ignored fields.
1104 return _type1(msgvec
, TRU1
, FAL0
, FAL0
, FAL0
, NULL
, NULL
);
1108 * Type out messages, even printing ignored fields.
1115 return _type1(msgvec
, FAL0
, FAL0
, FAL0
, FAL0
, NULL
, NULL
);
1119 * Show MIME-encoded message text, including all fields.
1126 return _type1(msgvec
, FAL0
, FAL0
, FAL0
, TRU1
, NULL
, NULL
);
1130 * Pipe messages, honor ignored fields.
1136 return(pipe1(str
, 1));
1139 * Pipe messages, not respecting ignored fields.
1145 return(pipe1(str
, 0));
1149 * Print the top so many lines of each desired message.
1150 * The number of lines is taken from the variable "toplines"
1151 * and defaults to 5.
1156 int *msgvec
= v
, *ip
, c
, topl
, lines
, empty_last
;
1158 char *cp
, *linebuf
= NULL
;
1159 size_t linesize
= 0;
1163 cp
= value("toplines");
1166 if (topl
< 0 || topl
> 10000)
1170 for (ip
= msgvec
; *ip
&& ip
-msgvec
< msgCount
; ip
++) {
1171 mp
= &message
[*ip
- 1];
1174 did_print_dot
= TRU1
;
1177 _show_msg_overview(mp
, *ip
, stdout
);
1178 if (mp
->m_flag
& MNOFROM
)
1179 printf("From %s %s\n", fakefrom(mp
),
1180 fakedate(mp
->m_time
));
1181 if ((ibuf
= setinput(&mb
, mp
, NEED_BODY
)) == NULL
) { /* XXX could use TOP */
1186 for (lines
= 0; lines
< c
&& UICMP(32, lines
, <=, topl
);
1188 if (readline_restart(ibuf
, &linebuf
, &linesize
, 0) < 0)
1192 for (cp
= linebuf
; *cp
&& blankchar(*cp
); ++cp
)
1194 empty_last
= (*cp
== '\0');
1198 if (linebuf
!= NULL
)
1204 * Touch all the given messages so that they will
1213 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1214 setdot(&message
[*ip
-1]);
1215 dot
->m_flag
|= MTOUCH
;
1216 dot
->m_flag
&= ~MPRESERVE
;
1218 * POSIX interpretation necessary.
1220 did_print_dot
= TRU1
;
1226 * Make sure all passed messages get mboxed.
1234 for (ip
= msgvec
; *ip
!= 0; ip
++) {
1235 setdot(&message
[*ip
-1]);
1236 dot
->m_flag
|= MTOUCH
|MBOX
;
1237 dot
->m_flag
&= ~MPRESERVE
;
1239 * POSIX interpretation necessary.
1241 did_print_dot
= TRU1
;
1247 * List the folders the user currently has.
1252 char dirname
[MAXPATHLEN
], *name
, **argv
= v
;
1256 name
= expand(*argv
);
1259 } else if (! getfold(dirname
, sizeof dirname
)) {
1260 fprintf(stderr
, tr(20, "No value set for \"folder\"\n"));
1265 if (which_protocol(name
) == PROTO_IMAP
) {
1267 imap_folders(name
, *argv
== NULL
);
1269 return ccmdnotsupp(NULL
);
1272 if ((cmd
= value("LISTER")) == NULL
)
1274 run_command(cmd
, 0, -1, -1, name
, NULL
, NULL
);