cmd1.c revision 99112
11590Srgrimes/*-
21590Srgrimes * Copyright (c) 1980, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 3. All advertising materials mentioning features or use of this software
141590Srgrimes *    must display the following acknowledgement:
151590Srgrimes *	This product includes software developed by the University of
161590Srgrimes *	California, Berkeley and its contributors.
171590Srgrimes * 4. Neither the name of the University nor the names of its contributors
181590Srgrimes *    may be used to endorse or promote products derived from this software
191590Srgrimes *    without specific prior written permission.
201590Srgrimes *
211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311590Srgrimes * SUCH DAMAGE.
321590Srgrimes */
331590Srgrimes
341590Srgrimes#ifndef lint
3574769Smikeh#if 0
3688150Smikehstatic char sccsid[] = "@(#)cmd1.c	8.2 (Berkeley) 4/20/95";
3774769Smikeh#endif
381590Srgrimes#endif /* not lint */
3999112Sobrien#include <sys/cdefs.h>
4099112Sobrien__FBSDID("$FreeBSD: head/usr.bin/mail/cmd1.c 99112 2002-06-30 05:25:07Z obrien $");
411590Srgrimes
421590Srgrimes#include "rcv.h"
431590Srgrimes#include "extern.h"
441590Srgrimes
451590Srgrimes/*
461590Srgrimes * Mail -- a mail program
471590Srgrimes *
481590Srgrimes * User commands.
491590Srgrimes */
501590Srgrimes
5177274Smikehextern const struct cmd cmdtab[];
5277274Smikeh
531590Srgrimes/*
541590Srgrimes * Print the current active headings.
551590Srgrimes * Don't change dot if invoker didn't give an argument.
561590Srgrimes */
571590Srgrimes
581590Srgrimesstatic int screen;
591590Srgrimes
601590Srgrimesint
611590Srgrimesheaders(msgvec)
621590Srgrimes	int *msgvec;
631590Srgrimes{
6477274Smikeh	int n, mesg, flag, size;
6577274Smikeh	struct message *mp;
661590Srgrimes
671590Srgrimes	size = screensize();
681590Srgrimes	n = msgvec[0];
691590Srgrimes	if (n != 0)
701590Srgrimes		screen = (n-1)/size;
711590Srgrimes	if (screen < 0)
721590Srgrimes		screen = 0;
731590Srgrimes	mp = &message[screen * size];
741590Srgrimes	if (mp >= &message[msgCount])
751590Srgrimes		mp = &message[msgCount - size];
761590Srgrimes	if (mp < &message[0])
771590Srgrimes		mp = &message[0];
781590Srgrimes	flag = 0;
791590Srgrimes	mesg = mp - &message[0];
801590Srgrimes	if (dot != &message[n-1])
811590Srgrimes		dot = mp;
821590Srgrimes	for (; mp < &message[msgCount]; mp++) {
831590Srgrimes		mesg++;
841590Srgrimes		if (mp->m_flag & MDELETED)
851590Srgrimes			continue;
861590Srgrimes		if (flag++ >= size)
871590Srgrimes			break;
881590Srgrimes		printhead(mesg);
891590Srgrimes	}
901590Srgrimes	if (flag == 0) {
911590Srgrimes		printf("No more mail.\n");
9277274Smikeh		return (1);
931590Srgrimes	}
9477274Smikeh	return (0);
951590Srgrimes}
961590Srgrimes
971590Srgrimes/*
981590Srgrimes * Scroll to the next/previous screen
991590Srgrimes */
1001590Srgrimesint
1011590Srgrimesscroll(arg)
1021590Srgrimes	char arg[];
1031590Srgrimes{
10477274Smikeh	int s, size;
1051590Srgrimes	int cur[1];
1061590Srgrimes
1071590Srgrimes	cur[0] = 0;
1081590Srgrimes	size = screensize();
1091590Srgrimes	s = screen;
1101590Srgrimes	switch (*arg) {
1111590Srgrimes	case 0:
1121590Srgrimes	case '+':
1131590Srgrimes		s++;
11488150Smikeh		if (s * size >= msgCount) {
1151590Srgrimes			printf("On last screenful of messages\n");
11677274Smikeh			return (0);
1171590Srgrimes		}
1181590Srgrimes		screen = s;
1191590Srgrimes		break;
1201590Srgrimes
1211590Srgrimes	case '-':
1221590Srgrimes		if (--s < 0) {
1231590Srgrimes			printf("On first screenful of messages\n");
12477274Smikeh			return (0);
1251590Srgrimes		}
1261590Srgrimes		screen = s;
1271590Srgrimes		break;
1281590Srgrimes
1291590Srgrimes	default:
1301590Srgrimes		printf("Unrecognized scrolling command \"%s\"\n", arg);
13177274Smikeh		return (1);
1321590Srgrimes	}
13377274Smikeh	return (headers(cur));
1341590Srgrimes}
1351590Srgrimes
1361590Srgrimes/*
1371590Srgrimes * Compute screen size.
1381590Srgrimes */
1391590Srgrimesint
1401590Srgrimesscreensize()
1411590Srgrimes{
1421590Srgrimes	int s;
1431590Srgrimes	char *cp;
1441590Srgrimes
14577274Smikeh	if ((cp = value("screen")) != NULL && (s = atoi(cp)) > 0)
14677274Smikeh		return (s);
14777274Smikeh	return (screenheight - 4);
1481590Srgrimes}
1491590Srgrimes
1501590Srgrimes/*
1511590Srgrimes * Print out the headlines for each message
1521590Srgrimes * in the passed message list.
1531590Srgrimes */
1541590Srgrimesint
1551590Srgrimesfrom(msgvec)
1561590Srgrimes	int *msgvec;
1571590Srgrimes{
15877274Smikeh	int *ip;
1591590Srgrimes
16029574Sphk	for (ip = msgvec; *ip != 0; ip++)
1611590Srgrimes		printhead(*ip);
1621590Srgrimes	if (--ip >= msgvec)
1631590Srgrimes		dot = &message[*ip - 1];
16477274Smikeh	return (0);
1651590Srgrimes}
1661590Srgrimes
1671590Srgrimes/*
1681590Srgrimes * Print out the header of a specific message.
1691590Srgrimes * This is a slight improvement to the standard one.
1701590Srgrimes */
1711590Srgrimesvoid
1721590Srgrimesprinthead(mesg)
1731590Srgrimes	int mesg;
1741590Srgrimes{
1751590Srgrimes	struct message *mp;
1761590Srgrimes	char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind;
1771590Srgrimes	char pbuf[BUFSIZ];
1781590Srgrimes	struct headline hl;
1791590Srgrimes	int subjlen;
1801590Srgrimes	char *name;
1811590Srgrimes
1821590Srgrimes	mp = &message[mesg-1];
18377274Smikeh	(void)readline(setinput(mp), headline, LINESIZE);
18477274Smikeh	if ((subjline = hfield("subject", mp)) == NULL)
1851590Srgrimes		subjline = hfield("subj", mp);
1861590Srgrimes	/*
1871590Srgrimes	 * Bletch!
1881590Srgrimes	 */
1891590Srgrimes	curind = dot == mp ? '>' : ' ';
1901590Srgrimes	dispc = ' ';
1911590Srgrimes	if (mp->m_flag & MSAVED)
1921590Srgrimes		dispc = '*';
1931590Srgrimes	if (mp->m_flag & MPRESERVE)
1941590Srgrimes		dispc = 'P';
1951590Srgrimes	if ((mp->m_flag & (MREAD|MNEW)) == MNEW)
1961590Srgrimes		dispc = 'N';
1971590Srgrimes	if ((mp->m_flag & (MREAD|MNEW)) == 0)
1981590Srgrimes		dispc = 'U';
1991590Srgrimes	if (mp->m_flag & MBOX)
2001590Srgrimes		dispc = 'M';
2011590Srgrimes	parse(headline, &hl, pbuf);
20237453Sbde	sprintf(wcount, "%3ld/%-5ld", mp->m_lines, mp->m_size);
2031590Srgrimes	subjlen = screenwidth - 50 - strlen(wcount);
20477274Smikeh	name = value("show-rcpt") != NULL ?
2051590Srgrimes		skin(hfield("to", mp)) : nameof(mp, 0);
20677274Smikeh	if (subjline == NULL || subjlen < 0)		/* pretty pathetic */
2071590Srgrimes		printf("%c%c%3d %-20.20s  %16.16s %s\n",
2081590Srgrimes			curind, dispc, mesg, name, hl.l_date, wcount);
2091590Srgrimes	else
2101590Srgrimes		printf("%c%c%3d %-20.20s  %16.16s %s \"%.*s\"\n",
2111590Srgrimes			curind, dispc, mesg, name, hl.l_date, wcount,
2121590Srgrimes			subjlen, subjline);
2131590Srgrimes}
2141590Srgrimes
2151590Srgrimes/*
2161590Srgrimes * Print out the value of dot.
2171590Srgrimes */
2181590Srgrimesint
2191590Srgrimespdot()
2201590Srgrimes{
2211590Srgrimes	printf("%d\n", dot - &message[0] + 1);
22277274Smikeh	return (0);
2231590Srgrimes}
2241590Srgrimes
2251590Srgrimes/*
2261590Srgrimes * Print out all the possible commands.
2271590Srgrimes */
2281590Srgrimesint
2291590Srgrimespcmdlist()
2301590Srgrimes{
23177274Smikeh	const struct cmd *cp;
23277274Smikeh	int cc;
2331590Srgrimes
2341590Srgrimes	printf("Commands are:\n");
2351590Srgrimes	for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) {
2361590Srgrimes		cc += strlen(cp->c_name) + 2;
2371590Srgrimes		if (cc > 72) {
2381590Srgrimes			printf("\n");
2391590Srgrimes			cc = strlen(cp->c_name) + 2;
2401590Srgrimes		}
24177274Smikeh		if ((cp+1)->c_name != NULL)
2421590Srgrimes			printf("%s, ", cp->c_name);
2431590Srgrimes		else
2441590Srgrimes			printf("%s\n", cp->c_name);
2451590Srgrimes	}
24677274Smikeh	return (0);
2471590Srgrimes}
2481590Srgrimes
2491590Srgrimes/*
2501590Srgrimes * Paginate messages, honor ignored fields.
2511590Srgrimes */
2521590Srgrimesint
2531590Srgrimesmore(msgvec)
2541590Srgrimes	int *msgvec;
2551590Srgrimes{
25677274Smikeh
2571590Srgrimes	return (type1(msgvec, 1, 1));
2581590Srgrimes}
2591590Srgrimes
2601590Srgrimes/*
2611590Srgrimes * Paginate messages, even printing ignored fields.
2621590Srgrimes */
2631590Srgrimesint
2641590SrgrimesMore(msgvec)
2651590Srgrimes	int *msgvec;
2661590Srgrimes{
2671590Srgrimes
2681590Srgrimes	return (type1(msgvec, 0, 1));
2691590Srgrimes}
2701590Srgrimes
2711590Srgrimes/*
2721590Srgrimes * Type out messages, honor ignored fields.
2731590Srgrimes */
2741590Srgrimesint
2751590Srgrimestype(msgvec)
2761590Srgrimes	int *msgvec;
2771590Srgrimes{
2781590Srgrimes
27977274Smikeh	return (type1(msgvec, 1, 0));
2801590Srgrimes}
2811590Srgrimes
2821590Srgrimes/*
2831590Srgrimes * Type out messages, even printing ignored fields.
2841590Srgrimes */
2851590Srgrimesint
2861590SrgrimesType(msgvec)
2871590Srgrimes	int *msgvec;
2881590Srgrimes{
2891590Srgrimes
29077274Smikeh	return (type1(msgvec, 0, 0));
2911590Srgrimes}
2921590Srgrimes
2931590Srgrimes/*
2941590Srgrimes * Type out the messages requested.
2951590Srgrimes */
2961590Srgrimesjmp_buf	pipestop;
2971590Srgrimesint
2981590Srgrimestype1(msgvec, doign, page)
2991590Srgrimes	int *msgvec;
3001590Srgrimes	int doign, page;
3011590Srgrimes{
30277274Smikeh	int nlines, *ip;
30377274Smikeh	struct message *mp;
30477274Smikeh	char *cp;
3051590Srgrimes	FILE *obuf;
3061590Srgrimes
3071590Srgrimes	obuf = stdout;
3081590Srgrimes	if (setjmp(pipestop))
3091590Srgrimes		goto close_pipe;
31077274Smikeh	if (value("interactive") != NULL &&
31177274Smikeh	    (page || (cp = value("crt")) != NULL)) {
3121590Srgrimes		nlines = 0;
3131590Srgrimes		if (!page) {
3141590Srgrimes			for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++)
3151590Srgrimes				nlines += message[*ip - 1].m_lines;
3161590Srgrimes		}
3171590Srgrimes		if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) {
3181590Srgrimes			cp = value("PAGER");
3191590Srgrimes			if (cp == NULL || *cp == '\0')
3201590Srgrimes				cp = _PATH_MORE;
3211590Srgrimes			obuf = Popen(cp, "w");
3221590Srgrimes			if (obuf == NULL) {
32374769Smikeh				warnx("%s", cp);
3241590Srgrimes				obuf = stdout;
3251590Srgrimes			} else
32677274Smikeh				(void)signal(SIGPIPE, brokpipe);
3271590Srgrimes		}
3281590Srgrimes	}
32977274Smikeh
33077274Smikeh	/*
33177274Smikeh	 * Send messages to the output.
33277274Smikeh	 *
33377274Smikeh	 */
3341590Srgrimes	for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) {
3351590Srgrimes		mp = &message[*ip - 1];
3361590Srgrimes		touch(mp);
3371590Srgrimes		dot = mp;
33877274Smikeh		if (value("quiet") == NULL)
3391590Srgrimes			fprintf(obuf, "Message %d:\n", *ip);
34077274Smikeh		(void)sendmessage(mp, obuf, doign ? ignore : 0, NULL);
3411590Srgrimes	}
34277274Smikeh
3431590Srgrimesclose_pipe:
3441590Srgrimes	if (obuf != stdout) {
3451590Srgrimes		/*
3461590Srgrimes		 * Ignore SIGPIPE so it can't cause a duplicate close.
3471590Srgrimes		 */
34877274Smikeh		(void)signal(SIGPIPE, SIG_IGN);
34977274Smikeh		(void)Pclose(obuf);
35077274Smikeh		(void)signal(SIGPIPE, SIG_DFL);
3511590Srgrimes	}
35277274Smikeh	return (0);
3531590Srgrimes}
3541590Srgrimes
3551590Srgrimes/*
3561590Srgrimes * Respond to a broken pipe signal --
3571590Srgrimes * probably caused by quitting more.
3581590Srgrimes */
35977274Smikeh/*ARGSUSED*/
3601590Srgrimesvoid
3611590Srgrimesbrokpipe(signo)
3621590Srgrimes	int signo;
3631590Srgrimes{
3641590Srgrimes	longjmp(pipestop, 1);
3651590Srgrimes}
3661590Srgrimes
3671590Srgrimes/*
3681590Srgrimes * Print the top so many lines of each desired message.
3691590Srgrimes * The number of lines is taken from the variable "toplines"
3701590Srgrimes * and defaults to 5.
3711590Srgrimes */
3721590Srgrimesint
3731590Srgrimestop(msgvec)
3741590Srgrimes	int *msgvec;
3751590Srgrimes{
37677274Smikeh	int *ip;
37777274Smikeh	struct message *mp;
3781590Srgrimes	int c, topl, lines, lineb;
3791590Srgrimes	char *valtop, linebuf[LINESIZE];
3801590Srgrimes	FILE *ibuf;
3811590Srgrimes
3821590Srgrimes	topl = 5;
3831590Srgrimes	valtop = value("toplines");
38477274Smikeh	if (valtop != NULL) {
3851590Srgrimes		topl = atoi(valtop);
3861590Srgrimes		if (topl < 0 || topl > 10000)
3871590Srgrimes			topl = 5;
3881590Srgrimes	}
3891590Srgrimes	lineb = 1;
3901590Srgrimes	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
3911590Srgrimes		mp = &message[*ip - 1];
3921590Srgrimes		touch(mp);
3931590Srgrimes		dot = mp;
39477274Smikeh		if (value("quiet") == NULL)
3951590Srgrimes			printf("Message %d:\n", *ip);
3961590Srgrimes		ibuf = setinput(mp);
3971590Srgrimes		c = mp->m_lines;
3981590Srgrimes		if (!lineb)
3991590Srgrimes			printf("\n");
4001590Srgrimes		for (lines = 0; lines < c && lines <= topl; lines++) {
40174769Smikeh			if (readline(ibuf, linebuf, sizeof(linebuf)) < 0)
4021590Srgrimes				break;
4031590Srgrimes			puts(linebuf);
40474769Smikeh			lineb = strspn(linebuf, " \t") == strlen(linebuf);
4051590Srgrimes		}
4061590Srgrimes	}
40777274Smikeh	return (0);
4081590Srgrimes}
4091590Srgrimes
4101590Srgrimes/*
4111590Srgrimes * Touch all the given messages so that they will
4121590Srgrimes * get mboxed.
4131590Srgrimes */
4141590Srgrimesint
4151590Srgrimesstouch(msgvec)
4161590Srgrimes	int msgvec[];
4171590Srgrimes{
41877274Smikeh	int *ip;
4191590Srgrimes
4201590Srgrimes	for (ip = msgvec; *ip != 0; ip++) {
4211590Srgrimes		dot = &message[*ip-1];
4221590Srgrimes		dot->m_flag |= MTOUCH;
4231590Srgrimes		dot->m_flag &= ~MPRESERVE;
4241590Srgrimes	}
42577274Smikeh	return (0);
4261590Srgrimes}
4271590Srgrimes
4281590Srgrimes/*
4291590Srgrimes * Make sure all passed messages get mboxed.
4301590Srgrimes */
4311590Srgrimesint
4321590Srgrimesmboxit(msgvec)
4331590Srgrimes	int msgvec[];
4341590Srgrimes{
43577274Smikeh	int *ip;
4361590Srgrimes
4371590Srgrimes	for (ip = msgvec; *ip != 0; ip++) {
4381590Srgrimes		dot = &message[*ip-1];
4391590Srgrimes		dot->m_flag |= MTOUCH|MBOX;
4401590Srgrimes		dot->m_flag &= ~MPRESERVE;
4411590Srgrimes	}
44277274Smikeh	return (0);
4431590Srgrimes}
4441590Srgrimes
4451590Srgrimes/*
4461590Srgrimes * List the folders the user currently has.
4471590Srgrimes */
4481590Srgrimesint
4491590Srgrimesfolders()
4501590Srgrimes{
45174769Smikeh	char dirname[PATHSIZE];
4521590Srgrimes	char *cmd;
4531590Srgrimes
45474769Smikeh	if (getfold(dirname, sizeof(dirname)) < 0) {
4551590Srgrimes		printf("No value set for \"folder\"\n");
45677274Smikeh		return (1);
4571590Srgrimes	}
45877274Smikeh	if ((cmd = value("LISTER")) == NULL)
4591590Srgrimes		cmd = "ls";
46077274Smikeh	(void)run_command(cmd, 0, -1, -1, dirname, NULL, NULL);
46177274Smikeh	return (0);
4621590Srgrimes}
46388150Smikeh
46488150Smikeh/*
46588150Smikeh * Update the mail file with any new messages that have
46688150Smikeh * come in since we started reading mail.
46788150Smikeh */
46888150Smikehint
46988150Smikehinc(v)
47088150Smikeh	void *v;
47188150Smikeh{
47288150Smikeh	int nmsg, mdot;
47388150Smikeh
47488150Smikeh	nmsg = incfile();
47588150Smikeh
47688150Smikeh	if (nmsg == 0)
47788150Smikeh		printf("No new mail.\n");
47888150Smikeh	else if (nmsg > 0) {
47988150Smikeh		mdot = newfileinfo(msgCount - nmsg);
48088150Smikeh		dot = &message[mdot - 1];
48188150Smikeh	} else
48288150Smikeh		printf("\"inc\" command failed...\n");
48388150Smikeh
48488150Smikeh	return (0);
48588150Smikeh}
486