Merge commit 'b1e7e97d3b60469b243b3b2e22c7d8cbd11c7c90'
[unleashed.git] / usr / src / cmd / mailx / cmd1.c
blobfc4e1a5a1ed5b92023b15a52277ac070650261d9
1 /*
2 * CDDL HEADER START
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
7 * with the License.
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]
20 * CDDL HEADER END
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
38 * All Rights Reserved
40 * University Acknowledgment- Portions of this document are derived from
41 * software developed by the University of California, Berkeley, and its
42 * contributors.
45 #include <err.h>
46 #include "rcv.h"
47 #include <locale.h>
50 * mailx -- a modified version of a University of California at Berkeley
51 * mail program
53 * User commands.
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);
62 jmp_buf pipestop;
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;
71 int
72 headers(int *msgvec)
74 register int n, mesg, flag;
75 register struct message *mp;
76 int size;
78 size = screensize();
79 n = msgvec[0];
80 if (n != 0)
81 curscreen = (n-1)/size;
82 if (curscreen < 0)
83 curscreen = 0;
84 mp = &message[curscreen * size];
85 if (mp >= &message[msgCount])
86 mp = &message[msgCount - size];
87 if (mp < &message[0])
88 mp = &message[0];
89 flag = 0;
90 mesg = mp - &message[0];
91 if (dot != &message[n-1])
92 dot = mp;
93 if (Hflag)
94 mp = message;
95 for (; mp < &message[msgCount]; mp++) {
96 mesg++;
97 if (mp->m_flag & MDELETED)
98 continue;
99 if (flag++ >= size && !Hflag)
100 break;
101 printhead(mesg);
102 sreset();
104 if (flag == 0) {
105 printf(gettext("No more mail.\n"));
106 return (1);
108 return (0);
112 * Scroll to the next/previous screen
116 scroll(char arg[])
118 register int s, size;
119 int cur[1];
121 cur[0] = 0;
122 size = screensize();
123 s = curscreen;
124 switch (*arg) {
125 case 0:
126 case '+':
127 s++;
128 if (s * size > msgCount) {
129 printf(gettext("On last screenful of messages\n"));
130 return (0);
132 curscreen = s;
133 break;
135 case '-':
136 if (--s < 0) {
137 printf(gettext("On first screenful of messages\n"));
138 return (0);
140 curscreen = s;
141 break;
143 default:
144 printf(gettext("Unrecognized scrolling command \"%s\"\n"), arg);
145 return (1);
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
159 screensize(void)
161 register char *cp;
162 register int newscreensize, tmp;
163 #ifdef TIOCGWINSZ
164 struct winsize ws;
165 #endif
167 if ((cp = value("screen")) != NOSTR && (tmp = atoi(cp)) > 0)
168 newscreensize = tmp;
169 else if (baud < B1200)
170 newscreensize = 5;
171 else if (baud == B1200)
172 newscreensize = 10;
173 #ifdef TIOCGWINSZ
174 else if (ioctl(fileno(stdout), TIOCGWINSZ, &ws) == 0 && ws.ws_row > 4)
175 newscreensize = ws.ws_row - 4;
176 #endif
177 else
178 newscreensize = 20;
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.
193 from(int *msgvec)
195 register int *ip;
197 for (ip = msgvec; *ip != 0; ip++) {
198 printhead(*ip);
199 sreset();
201 if (--ip >= msgvec)
202 dot = &message[*ip - 1];
203 return (0);
207 * Print out the header of a specific message.
208 * This is a slight improvement to the standard one.
211 void
212 printhead(int mesg)
214 struct message *mp;
215 FILE *ibuf;
216 char headline[LINESIZE], *subjline, dispc, curind;
217 char *fromline;
218 char pbuf[LINESIZE];
219 char name[LINESIZE];
220 headline_t *hl;
221 register char *cp;
222 int showto;
224 if (headline_alloc(&hl) != 0) {
225 err(1, "could not allocate memory");
228 mp = &message[mesg-1];
229 ibuf = setinput(mp);
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)
234 subjline = "";
236 curind = (!Hflag && dot == mp) ? '>' : ' ';
237 dispc = ' ';
238 showto = 0;
239 if ((mp->m_flag & (MREAD|MNEW)) == (MREAD|MNEW))
240 dispc = 'R';
241 if (!(int)value("bsdcompat") && (mp->m_flag & (MREAD|MNEW)) == MREAD)
242 dispc = 'O';
243 if ((mp->m_flag & (MREAD|MNEW)) == MNEW)
244 dispc = 'N';
245 if ((mp->m_flag & (MREAD|MNEW)) == 0)
246 dispc = 'U';
247 if (mp->m_flag & MSAVED)
248 if ((int)value("bsdcompat"))
249 dispc = '*';
250 else
251 dispc = 'S';
252 if (mp->m_flag & MPRESERVE)
253 if ((int)value("bsdcompat"))
254 dispc = 'P';
255 else
256 dispc = 'H';
257 if (mp->m_flag & MBOX)
258 dispc = 'M';
259 if (parse_headline(headline, hl) == -1) {
260 headline_reset(hl);
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");
269 * Netnews interface?
272 if (newsflg) {
273 if ((fromline = hfield("newsgroups", mp, addone)) == NOSTR &&
274 (fromline = hfield("article-id", mp, addone)) == NOSTR)
275 fromline = "<>";
276 else
277 for (cp = fromline; *cp; cp++) { /* limit length */
278 if (any(*cp, " ,\n")) {
279 *cp = '\0';
280 break;
284 * else regular.
287 } else {
288 fromline = nameof(mp);
289 if (value("showto") &&
290 samebody(myname, skin(fromline), FALSE) &&
291 (cp = hfield("to", mp, addto))) {
292 showto = 1;
293 yankword(cp, fromline = name, sizeof (name),
294 docomma(cp));
296 if (value("showname"))
297 fromline = dispname(fromline);
298 else
299 fromline = skin(fromline);
301 printf("%c%c%3d ", curind, dispc, mesg);
302 if ((int)value("showfull")) {
303 if (showto)
304 printf("To %-15s ", fromline);
305 else
306 printf("%-18s ", fromline);
307 } else {
308 if (showto)
309 printf("To %-15.15s ", fromline);
310 else
311 printf("%-18.18s ", fromline);
313 if (mp->m_text) {
314 printf("%16.16s %4ld/%-5ld %-.25s\n",
315 custr_cstr(hl->hl_date), mp->m_lines, mp->m_size,
316 subjline);
317 } else {
318 printf("%16.16s binary/%-5ld %-.25s\n", custr_cstr(hl->hl_date),
319 mp->m_size, subjline);
322 headline_free(hl);
326 * Return the full name from an RFC-822 header line
327 * or the last two (or one) component of the address.
330 static char *
331 dispname(char *hdr)
333 char *cp, *cp2;
335 if (hdr == 0)
336 return (0);
337 if (((cp = strchr(hdr, '<')) != 0) && (cp > hdr)) {
338 *cp = 0;
339 if ((*hdr == '"') && ((cp = strrchr(++hdr, '"')) != 0))
340 *cp = 0;
341 return (hdr);
342 } else if ((cp = strchr(hdr, '(')) != 0) {
343 hdr = ++cp;
344 if ((cp = strchr(hdr, '+')) != 0)
345 *cp = 0;
346 if ((cp = strrchr(hdr, ')')) != 0)
347 *cp = 0;
348 return (hdr);
350 cp = skin(hdr);
351 if ((cp2 = strrchr(cp, '!')) != 0) {
352 while (cp2 >= cp && *--cp2 != '!');
353 cp = ++cp2;
355 return (cp);
359 * Print out the value of dot.
363 pdot(void)
365 printf("%d\n", dot - &message[0] + 1);
366 return (0);
370 * Print out all the possible commands.
374 pcmdlist(void)
376 register const struct cmd *cp;
377 register int cc;
379 printf("Commands are:\n");
380 for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) {
381 cc += strlen(cp->c_name) + 2;
382 if (cc > 72) {
383 printf("\n");
384 cc = strlen(cp->c_name) + 2;
386 if ((cp+1)->c_name != NOSTR)
387 printf("%s, ", cp->c_name);
388 else
389 printf("%s\n", cp->c_name);
391 return (0);
395 * Paginate messages, honor ignored fields.
398 more(int *msgvec)
400 return (type1(msgvec, 1, 1));
404 * Paginate messages, even printing ignored fields.
407 More(int *msgvec)
410 return (type1(msgvec, 0, 1));
414 * Type out messages, honor ignored fields.
417 type(int *msgvec)
420 return (type1(msgvec, 1, 0));
424 * Type out messages, even printing ignored fields.
427 Type(int *msgvec)
430 return (type1(msgvec, 0, 0));
434 * Type out the messages requested.
436 static int
437 type1(int *msgvec, int doign, int page)
439 int *ip;
440 register struct message *mp;
441 register int mesg;
442 register char *cp;
443 long nlines;
444 FILE *obuf;
445 void (*sigint)(int), (*sigpipe)(int);
446 int setsigs = 0;
448 obuf = stdout;
449 if (setjmp(pipestop)) {
450 if (obuf != stdout) {
451 pipef = NULL;
452 npclose(obuf);
454 goto ret0;
456 if (intty && outtty && (page || (cp = value("crt")) != NOSTR)) {
457 if (!page) {
458 nlines = 0;
459 for (ip = msgvec, nlines = 0;
460 *ip && ip-msgvec < msgCount; ip++)
461 nlines += message[*ip - 1].m_lines;
463 if (page ||
464 nlines > (*cp == '\0' ? screensize() - 2 : atoi(cp))) {
465 obuf = npopen(MORE, "w");
466 if (obuf == NULL) {
467 perror(MORE);
468 obuf = stdout;
469 } else {
470 pipef = obuf;
471 sigint = sigset(SIGINT, SIG_IGN);
472 sigpipe = sigset(SIGPIPE, brokpipe);
473 setsigs++;
477 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
478 mesg = *ip;
479 touch(mesg);
480 mp = &message[mesg-1];
481 dot = mp;
482 print(mp, obuf, doign);
484 if (obuf != stdout) {
485 pipef = NULL;
486 npclose(obuf);
488 ret0:
489 if (setsigs) {
490 sigset(SIGPIPE, sigpipe);
491 sigset(SIGINT, sigint);
493 return (0);
497 * Respond to a broken pipe signal --
498 * probably caused by user quitting more.
500 void
501 #ifdef __cplusplus
502 brokpipe(int)
503 #else
504 /* ARGSUSED */
505 brokpipe(int s)
506 #endif
508 #ifdef OLD_BSD_SIGS
509 sigrelse(SIGPIPE);
510 #endif
511 longjmp(pipestop, 1);
515 * Print the indicated message on standard output.
518 static void
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);
525 if (mp->m_text) {
526 (void) msend(mp, obuf, doign ? M_IGNORE : 0, fputs);
527 } else {
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"
535 * and defaults to 5.
538 static long top_linecount, top_maxlines, top_lineb;
539 static jmp_buf top_buf;
542 top(int *msgvec)
544 register int *ip;
545 register struct message *mp;
546 register int mesg;
547 char *valtop;
549 top_maxlines = 5;
550 valtop = value("toplines");
551 if (valtop != NOSTR) {
552 top_maxlines = atoi(valtop);
553 if (top_maxlines < 0 || top_maxlines > 10000)
554 top_maxlines = 5;
556 top_lineb = 1;
557 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
558 mesg = *ip;
559 touch(mesg);
560 mp = &message[mesg-1];
561 dot = mp;
562 if (value("quiet") == NOSTR)
563 printf("Message %2d:\n", mesg);
564 if (!top_lineb)
565 printf("\n");
566 top_linecount = 0;
567 if (setjmp(top_buf) == 0) {
568 if (mp->m_text) {
569 (void) msend(mp, stdout, M_IGNORE, topputs);
570 } else {
571 printf("\n%s\n", gettext(binmsg));
575 return (0);
579 topputs(const char *line, FILE *obuf)
581 if (top_linecount++ >= top_maxlines)
582 longjmp(top_buf, 1);
583 top_lineb = blankline(line);
584 return (fputs(line, obuf));
588 * Touch all the given messages so that they will
589 * get mboxed.
593 stouch(int msgvec[])
595 register int *ip;
597 for (ip = msgvec; *ip != 0; ip++) {
598 dot = &message[*ip-1];
599 dot->m_flag |= MTOUCH;
600 dot->m_flag &= ~MPRESERVE;
602 return (0);
606 * Make sure all passed messages get mboxed.
610 mboxit(int msgvec[])
612 register int *ip;
614 for (ip = msgvec; *ip != 0; ip++) {
615 dot = &message[*ip-1];
616 dot->m_flag |= MTOUCH|MBOX;
617 dot->m_flag &= ~MPRESERVE;
619 return (0);
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"));
632 return (-1);
634 if (*arglist) {
635 nstrcat(dirname, sizeof (dirname), "/");
636 nstrcat(dirname, sizeof (dirname), *arglist);
638 snprintf(cmd, sizeof (cmd), "%s %s", LS, dirname);
639 return (system(cmd));