4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
24 * Copyright 2014 Joyent, Inc.
28 * Copyright 2001 Sun Microsystems, Inc. All rights reserved.
29 * Use is subject to license terms.
32 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
33 /* All Rights Reserved */
36 * University Copyright- Copyright (c) 1982, 1986, 1988
37 * The Regents of the University of California
40 * University Acknowledgment- Portions of this document are derived from
41 * software developed by the University of California, Berkeley, and its
50 * mailx -- a modified version of a University of California at Berkeley
56 static char *dispname(char *hdr
);
57 static void print(register struct message
*mp
, FILE *obuf
, int doign
);
58 static int type1(int *msgvec
, int doign
, int page
);
59 static int topputs(const char *line
, FILE *obuf
);
61 void brokpipe(int sig
);
65 * Print the current active headings.
66 * Don't change dot if invoker didn't give an argument.
69 static int curscreen
= 0, oldscreensize
= 0;
74 register int n
, mesg
, flag
;
75 register struct message
*mp
;
81 curscreen
= (n
-1)/size
;
84 mp
= &message
[curscreen
* size
];
85 if (mp
>= &message
[msgCount
])
86 mp
= &message
[msgCount
- size
];
90 mesg
= mp
- &message
[0];
91 if (dot
!= &message
[n
-1])
95 for (; mp
< &message
[msgCount
]; mp
++) {
97 if (mp
->m_flag
& MDELETED
)
99 if (flag
++ >= size
&& !Hflag
)
105 printf(gettext("No more mail.\n"));
112 * Scroll to the next/previous screen
118 register int s
, size
;
128 if (s
* size
> msgCount
) {
129 printf(gettext("On last screenful of messages\n"));
137 printf(gettext("On first screenful of messages\n"));
144 printf(gettext("Unrecognized scrolling command \"%s\"\n"), arg
);
147 return (headers(cur
));
151 * Compute what the screen size should be.
152 * We use the following algorithm:
153 * If user specifies with screen option, use that.
154 * If baud rate < 1200, use 5
155 * If baud rate = 1200, use 10
156 * If baud rate > 1200, use 20
162 register int newscreensize
, tmp
;
167 if ((cp
= value("screen")) != NOSTR
&& (tmp
= atoi(cp
)) > 0)
169 else if (baud
< B1200
)
171 else if (baud
== B1200
)
174 else if (ioctl(fileno(stdout
), TIOCGWINSZ
, &ws
) == 0 && ws
.ws_row
> 4)
175 newscreensize
= ws
.ws_row
- 4;
179 /* renormalize the value of curscreen */
180 if (newscreensize
!= oldscreensize
) {
181 curscreen
= curscreen
* oldscreensize
/ newscreensize
;
182 oldscreensize
= newscreensize
;
184 return (newscreensize
);
188 * Print out the headlines for each message
189 * in the passed message list.
197 for (ip
= msgvec
; *ip
!= NULL
; ip
++) {
202 dot
= &message
[*ip
- 1];
207 * Print out the header of a specific message.
208 * This is a slight improvement to the standard one.
216 char headline
[LINESIZE
], *subjline
, dispc
, curind
;
224 if (headline_alloc(&hl
) != 0) {
225 err(1, "could not allocate memory");
228 mp
= &message
[mesg
-1];
230 readline(ibuf
, headline
);
231 if ((subjline
= hfield("subject", mp
, addone
)) == NOSTR
&&
232 (subjline
= hfield("subj", mp
, addone
)) == NOSTR
&&
233 (subjline
= hfield("message-status", mp
, addone
)) == NOSTR
)
236 curind
= (!Hflag
&& dot
== mp
) ? '>' : ' ';
239 if ((mp
->m_flag
& (MREAD
|MNEW
)) == (MREAD
|MNEW
))
241 if (!(int)value("bsdcompat") && (mp
->m_flag
& (MREAD
|MNEW
)) == MREAD
)
243 if ((mp
->m_flag
& (MREAD
|MNEW
)) == MNEW
)
245 if ((mp
->m_flag
& (MREAD
|MNEW
)) == 0)
247 if (mp
->m_flag
& MSAVED
)
248 if ((int)value("bsdcompat"))
252 if (mp
->m_flag
& MPRESERVE
)
253 if ((int)value("bsdcompat"))
257 if (mp
->m_flag
& MBOX
)
259 if (parse_headline(headline
, hl
) == -1) {
262 if (custr_len(hl
->hl_date
) == 0) {
263 if (custr_append(hl
->hl_date
, "<Unknown date>") != 0) {
264 err(1, "could not print header");
273 if ((fromline
= hfield("newsgroups", mp
, addone
)) == NOSTR
&&
274 (fromline
= hfield("article-id", mp
, addone
)) == NOSTR
)
277 for (cp
= fromline
; *cp
; cp
++) { /* limit length */
278 if (any(*cp
, " ,\n")) {
288 fromline
= nameof(mp
);
289 if (value("showto") &&
290 samebody(myname
, skin(fromline
), FALSE
) &&
291 (cp
= hfield("to", mp
, addto
))) {
293 yankword(cp
, fromline
= name
, sizeof (name
),
296 if (value("showname"))
297 fromline
= dispname(fromline
);
299 fromline
= skin(fromline
);
301 printf("%c%c%3d ", curind
, dispc
, mesg
);
302 if ((int)value("showfull")) {
304 printf("To %-15s ", fromline
);
306 printf("%-18s ", fromline
);
309 printf("To %-15.15s ", fromline
);
311 printf("%-18.18s ", fromline
);
314 printf("%16.16s %4ld/%-5ld %-.25s\n",
315 custr_cstr(hl
->hl_date
), mp
->m_lines
, mp
->m_size
,
318 printf("%16.16s binary/%-5ld %-.25s\n", custr_cstr(hl
->hl_date
),
319 mp
->m_size
, subjline
);
326 * Return the full name from an RFC-822 header line
327 * or the last two (or one) component of the address.
337 if (((cp
= strchr(hdr
, '<')) != 0) && (cp
> hdr
)) {
339 if ((*hdr
== '"') && ((cp
= strrchr(++hdr
, '"')) != 0))
342 } else if ((cp
= strchr(hdr
, '(')) != 0) {
344 if ((cp
= strchr(hdr
, '+')) != 0)
346 if ((cp
= strrchr(hdr
, ')')) != 0)
351 if ((cp2
= strrchr(cp
, '!')) != 0) {
352 while (cp2
>= cp
&& *--cp2
!= '!');
359 * Print out the value of dot.
365 printf("%d\n", dot
- &message
[0] + 1);
370 * Print out all the possible commands.
376 register const struct cmd
*cp
;
379 printf("Commands are:\n");
380 for (cc
= 0, cp
= cmdtab
; cp
->c_name
!= NULL
; cp
++) {
381 cc
+= strlen(cp
->c_name
) + 2;
384 cc
= strlen(cp
->c_name
) + 2;
386 if ((cp
+1)->c_name
!= NOSTR
)
387 printf("%s, ", cp
->c_name
);
389 printf("%s\n", cp
->c_name
);
395 * Paginate messages, honor ignored fields.
400 return (type1(msgvec
, 1, 1));
404 * Paginate messages, even printing ignored fields.
410 return (type1(msgvec
, 0, 1));
414 * Type out messages, honor ignored fields.
420 return (type1(msgvec
, 1, 0));
424 * Type out messages, even printing ignored fields.
430 return (type1(msgvec
, 0, 0));
434 * Type out the messages requested.
437 type1(int *msgvec
, int doign
, int page
)
440 register struct message
*mp
;
445 void (*sigint
)(int), (*sigpipe
)(int);
449 if (setjmp(pipestop
)) {
450 if (obuf
!= stdout
) {
456 if (intty
&& outtty
&& (page
|| (cp
= value("crt")) != NOSTR
)) {
459 for (ip
= msgvec
, nlines
= 0;
460 *ip
&& ip
-msgvec
< msgCount
; ip
++)
461 nlines
+= message
[*ip
- 1].m_lines
;
464 nlines
> (*cp
== '\0' ? screensize() - 2 : atoi(cp
))) {
465 obuf
= npopen(MORE
, "w");
471 sigint
= sigset(SIGINT
, SIG_IGN
);
472 sigpipe
= sigset(SIGPIPE
, brokpipe
);
477 for (ip
= msgvec
; *ip
&& ip
-msgvec
< msgCount
; ip
++) {
480 mp
= &message
[mesg
-1];
482 print(mp
, obuf
, doign
);
484 if (obuf
!= stdout
) {
490 sigset(SIGPIPE
, sigpipe
);
491 sigset(SIGINT
, sigint
);
497 * Respond to a broken pipe signal --
498 * probably caused by user quitting more.
511 longjmp(pipestop
, 1);
515 * Print the indicated message on standard output.
519 print(register struct message
*mp
, FILE *obuf
, int doign
)
522 if (value("quiet") == NOSTR
&& (!doign
|| !isign("message", 0)))
523 fprintf(obuf
, "Message %2d:\n", mp
- &message
[0] + 1);
524 touch(mp
- &message
[0] + 1);
526 (void) msend(mp
, obuf
, doign
? M_IGNORE
: 0, fputs
);
528 fprintf(obuf
, "\n%s\n", gettext(binmsg
));
533 * Print the top so many lines of each desired message.
534 * The number of lines is taken from the variable "toplines"
538 static long top_linecount
, top_maxlines
, top_lineb
;
539 static jmp_buf top_buf
;
545 register struct message
*mp
;
550 valtop
= value("toplines");
551 if (valtop
!= NOSTR
) {
552 top_maxlines
= atoi(valtop
);
553 if (top_maxlines
< 0 || top_maxlines
> 10000)
557 for (ip
= msgvec
; *ip
&& ip
-msgvec
< msgCount
; ip
++) {
560 mp
= &message
[mesg
-1];
562 if (value("quiet") == NOSTR
)
563 printf("Message %2d:\n", mesg
);
567 if (setjmp(top_buf
) == 0) {
569 (void) msend(mp
, stdout
, M_IGNORE
, topputs
);
571 printf("\n%s\n", gettext(binmsg
));
579 topputs(const char *line
, FILE *obuf
)
581 if (top_linecount
++ >= top_maxlines
)
583 top_lineb
= blankline(line
);
584 return (fputs(line
, obuf
));
588 * Touch all the given messages so that they will
597 for (ip
= msgvec
; *ip
!= 0; ip
++) {
598 dot
= &message
[*ip
-1];
599 dot
->m_flag
|= MTOUCH
;
600 dot
->m_flag
&= ~MPRESERVE
;
606 * Make sure all passed messages get mboxed.
614 for (ip
= msgvec
; *ip
!= 0; ip
++) {
615 dot
= &message
[*ip
-1];
616 dot
->m_flag
|= MTOUCH
|MBOX
;
617 dot
->m_flag
&= ~MPRESERVE
;
623 * List the folders the user currently has.
626 folders(char **arglist
)
628 char dirname
[BUFSIZ
], cmd
[BUFSIZ
];
630 if (getfold(dirname
) < 0) {
631 printf(gettext("No value set for \"folder\"\n"));
635 nstrcat(dirname
, sizeof (dirname
), "/");
636 nstrcat(dirname
, sizeof (dirname
), *arglist
);
638 snprintf(cmd
, sizeof (cmd
), "%s %s", LS
, dirname
);
639 return (system(cmd
));