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 * 4. Neither the name of the University nor the names of its contributors
141590Srgrimes *    may be used to endorse or promote products derived from this software
151590Srgrimes *    without specific prior written permission.
161590Srgrimes *
171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271590Srgrimes * SUCH DAMAGE.
281590Srgrimes */
291590Srgrimes
301590Srgrimes#ifndef lint
3174769Smikeh#if 0
3288150Smikehstatic char sccsid[] = "@(#)cmd1.c	8.2 (Berkeley) 4/20/95";
3374769Smikeh#endif
341590Srgrimes#endif /* not lint */
3599112Sobrien#include <sys/cdefs.h>
3699112Sobrien__FBSDID("$FreeBSD$");
371590Srgrimes
381590Srgrimes#include "rcv.h"
391590Srgrimes#include "extern.h"
401590Srgrimes
411590Srgrimes/*
421590Srgrimes * Mail -- a mail program
431590Srgrimes *
441590Srgrimes * User commands.
451590Srgrimes */
461590Srgrimes
4777274Smikehextern const struct cmd cmdtab[];
4877274Smikeh
491590Srgrimes/*
501590Srgrimes * Print the current active headings.
511590Srgrimes * Don't change dot if invoker didn't give an argument.
521590Srgrimes */
531590Srgrimes
541590Srgrimesstatic int screen;
551590Srgrimes
561590Srgrimesint
57216562Scharnierheaders(int *msgvec)
581590Srgrimes{
5977274Smikeh	int n, mesg, flag, size;
6077274Smikeh	struct message *mp;
611590Srgrimes
621590Srgrimes	size = screensize();
631590Srgrimes	n = msgvec[0];
641590Srgrimes	if (n != 0)
651590Srgrimes		screen = (n-1)/size;
661590Srgrimes	if (screen < 0)
671590Srgrimes		screen = 0;
681590Srgrimes	mp = &message[screen * size];
691590Srgrimes	if (mp >= &message[msgCount])
701590Srgrimes		mp = &message[msgCount - size];
711590Srgrimes	if (mp < &message[0])
721590Srgrimes		mp = &message[0];
731590Srgrimes	flag = 0;
741590Srgrimes	mesg = mp - &message[0];
751590Srgrimes	if (dot != &message[n-1])
761590Srgrimes		dot = mp;
771590Srgrimes	for (; mp < &message[msgCount]; mp++) {
781590Srgrimes		mesg++;
791590Srgrimes		if (mp->m_flag & MDELETED)
801590Srgrimes			continue;
811590Srgrimes		if (flag++ >= size)
821590Srgrimes			break;
831590Srgrimes		printhead(mesg);
841590Srgrimes	}
851590Srgrimes	if (flag == 0) {
861590Srgrimes		printf("No more mail.\n");
8777274Smikeh		return (1);
881590Srgrimes	}
8977274Smikeh	return (0);
901590Srgrimes}
911590Srgrimes
921590Srgrimes/*
931590Srgrimes * Scroll to the next/previous screen
941590Srgrimes */
951590Srgrimesint
96216562Scharnierscroll(char arg[])
971590Srgrimes{
9877274Smikeh	int s, size;
991590Srgrimes	int cur[1];
1001590Srgrimes
1011590Srgrimes	cur[0] = 0;
1021590Srgrimes	size = screensize();
1031590Srgrimes	s = screen;
1041590Srgrimes	switch (*arg) {
1051590Srgrimes	case 0:
1061590Srgrimes	case '+':
1071590Srgrimes		s++;
10888150Smikeh		if (s * size >= msgCount) {
1091590Srgrimes			printf("On last screenful of messages\n");
11077274Smikeh			return (0);
1111590Srgrimes		}
1121590Srgrimes		screen = s;
1131590Srgrimes		break;
1141590Srgrimes
1151590Srgrimes	case '-':
1161590Srgrimes		if (--s < 0) {
1171590Srgrimes			printf("On first screenful of messages\n");
11877274Smikeh			return (0);
1191590Srgrimes		}
1201590Srgrimes		screen = s;
1211590Srgrimes		break;
1221590Srgrimes
1231590Srgrimes	default:
1241590Srgrimes		printf("Unrecognized scrolling command \"%s\"\n", arg);
12577274Smikeh		return (1);
1261590Srgrimes	}
12777274Smikeh	return (headers(cur));
1281590Srgrimes}
1291590Srgrimes
1301590Srgrimes/*
1311590Srgrimes * Compute screen size.
1321590Srgrimes */
1331590Srgrimesint
134216562Scharnierscreensize(void)
1351590Srgrimes{
1361590Srgrimes	int s;
1371590Srgrimes	char *cp;
1381590Srgrimes
13977274Smikeh	if ((cp = value("screen")) != NULL && (s = atoi(cp)) > 0)
14077274Smikeh		return (s);
14177274Smikeh	return (screenheight - 4);
1421590Srgrimes}
1431590Srgrimes
1441590Srgrimes/*
1451590Srgrimes * Print out the headlines for each message
1461590Srgrimes * in the passed message list.
1471590Srgrimes */
1481590Srgrimesint
149216562Scharnierfrom(int *msgvec)
1501590Srgrimes{
15177274Smikeh	int *ip;
1521590Srgrimes
15329574Sphk	for (ip = msgvec; *ip != 0; ip++)
1541590Srgrimes		printhead(*ip);
1551590Srgrimes	if (--ip >= msgvec)
1561590Srgrimes		dot = &message[*ip - 1];
15777274Smikeh	return (0);
1581590Srgrimes}
1591590Srgrimes
1601590Srgrimes/*
1611590Srgrimes * Print out the header of a specific message.
1621590Srgrimes * This is a slight improvement to the standard one.
1631590Srgrimes */
1641590Srgrimesvoid
165216562Scharnierprinthead(int mesg)
1661590Srgrimes{
1671590Srgrimes	struct message *mp;
1681590Srgrimes	char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind;
1691590Srgrimes	char pbuf[BUFSIZ];
1701590Srgrimes	struct headline hl;
1711590Srgrimes	int subjlen;
1721590Srgrimes	char *name;
1731590Srgrimes
1741590Srgrimes	mp = &message[mesg-1];
17577274Smikeh	(void)readline(setinput(mp), headline, LINESIZE);
17677274Smikeh	if ((subjline = hfield("subject", mp)) == NULL)
1771590Srgrimes		subjline = hfield("subj", mp);
1781590Srgrimes	/*
1791590Srgrimes	 * Bletch!
1801590Srgrimes	 */
1811590Srgrimes	curind = dot == mp ? '>' : ' ';
1821590Srgrimes	dispc = ' ';
1831590Srgrimes	if (mp->m_flag & MSAVED)
1841590Srgrimes		dispc = '*';
1851590Srgrimes	if (mp->m_flag & MPRESERVE)
1861590Srgrimes		dispc = 'P';
1871590Srgrimes	if ((mp->m_flag & (MREAD|MNEW)) == MNEW)
1881590Srgrimes		dispc = 'N';
1891590Srgrimes	if ((mp->m_flag & (MREAD|MNEW)) == 0)
1901590Srgrimes		dispc = 'U';
1911590Srgrimes	if (mp->m_flag & MBOX)
1921590Srgrimes		dispc = 'M';
1931590Srgrimes	parse(headline, &hl, pbuf);
19437453Sbde	sprintf(wcount, "%3ld/%-5ld", mp->m_lines, mp->m_size);
1951590Srgrimes	subjlen = screenwidth - 50 - strlen(wcount);
19677274Smikeh	name = value("show-rcpt") != NULL ?
1971590Srgrimes		skin(hfield("to", mp)) : nameof(mp, 0);
19877274Smikeh	if (subjline == NULL || subjlen < 0)		/* pretty pathetic */
1991590Srgrimes		printf("%c%c%3d %-20.20s  %16.16s %s\n",
2001590Srgrimes			curind, dispc, mesg, name, hl.l_date, wcount);
2011590Srgrimes	else
2021590Srgrimes		printf("%c%c%3d %-20.20s  %16.16s %s \"%.*s\"\n",
2031590Srgrimes			curind, dispc, mesg, name, hl.l_date, wcount,
2041590Srgrimes			subjlen, subjline);
2051590Srgrimes}
2061590Srgrimes
2071590Srgrimes/*
2081590Srgrimes * Print out the value of dot.
2091590Srgrimes */
2101590Srgrimesint
211216562Scharnierpdot(void)
2121590Srgrimes{
213228647Sdim	printf("%td\n", dot - &message[0] + 1);
21477274Smikeh	return (0);
2151590Srgrimes}
2161590Srgrimes
2171590Srgrimes/*
2181590Srgrimes * Print out all the possible commands.
2191590Srgrimes */
2201590Srgrimesint
221216562Scharnierpcmdlist(void)
2221590Srgrimes{
22377274Smikeh	const struct cmd *cp;
22477274Smikeh	int cc;
2251590Srgrimes
2261590Srgrimes	printf("Commands are:\n");
2271590Srgrimes	for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) {
2281590Srgrimes		cc += strlen(cp->c_name) + 2;
2291590Srgrimes		if (cc > 72) {
2301590Srgrimes			printf("\n");
2311590Srgrimes			cc = strlen(cp->c_name) + 2;
2321590Srgrimes		}
23377274Smikeh		if ((cp+1)->c_name != NULL)
2341590Srgrimes			printf("%s, ", cp->c_name);
2351590Srgrimes		else
2361590Srgrimes			printf("%s\n", cp->c_name);
2371590Srgrimes	}
23877274Smikeh	return (0);
2391590Srgrimes}
2401590Srgrimes
2411590Srgrimes/*
2421590Srgrimes * Paginate messages, honor ignored fields.
2431590Srgrimes */
2441590Srgrimesint
245216562Scharniermore(int *msgvec)
2461590Srgrimes{
24777274Smikeh
2481590Srgrimes	return (type1(msgvec, 1, 1));
2491590Srgrimes}
2501590Srgrimes
2511590Srgrimes/*
2521590Srgrimes * Paginate messages, even printing ignored fields.
2531590Srgrimes */
2541590Srgrimesint
255216562ScharnierMore(int *msgvec)
2561590Srgrimes{
2571590Srgrimes
2581590Srgrimes	return (type1(msgvec, 0, 1));
2591590Srgrimes}
2601590Srgrimes
2611590Srgrimes/*
2621590Srgrimes * Type out messages, honor ignored fields.
2631590Srgrimes */
2641590Srgrimesint
265216562Scharniertype(int *msgvec)
2661590Srgrimes{
2671590Srgrimes
26877274Smikeh	return (type1(msgvec, 1, 0));
2691590Srgrimes}
2701590Srgrimes
2711590Srgrimes/*
2721590Srgrimes * Type out messages, even printing ignored fields.
2731590Srgrimes */
2741590Srgrimesint
275216562ScharnierType(int *msgvec)
2761590Srgrimes{
2771590Srgrimes
27877274Smikeh	return (type1(msgvec, 0, 0));
2791590Srgrimes}
2801590Srgrimes
2811590Srgrimes/*
2821590Srgrimes * Type out the messages requested.
2831590Srgrimes */
284173439Sddsstatic jmp_buf	pipestop;
2851590Srgrimesint
286216562Scharniertype1(int *msgvec, int doign, int page)
2871590Srgrimes{
28877274Smikeh	int nlines, *ip;
28977274Smikeh	struct message *mp;
29077274Smikeh	char *cp;
2911590Srgrimes	FILE *obuf;
2921590Srgrimes
2931590Srgrimes	obuf = stdout;
2941590Srgrimes	if (setjmp(pipestop))
2951590Srgrimes		goto close_pipe;
29677274Smikeh	if (value("interactive") != NULL &&
29777274Smikeh	    (page || (cp = value("crt")) != NULL)) {
2981590Srgrimes		nlines = 0;
2991590Srgrimes		if (!page) {
3001590Srgrimes			for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++)
3011590Srgrimes				nlines += message[*ip - 1].m_lines;
3021590Srgrimes		}
3031590Srgrimes		if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) {
3041590Srgrimes			cp = value("PAGER");
3051590Srgrimes			if (cp == NULL || *cp == '\0')
3061590Srgrimes				cp = _PATH_MORE;
3071590Srgrimes			obuf = Popen(cp, "w");
3081590Srgrimes			if (obuf == NULL) {
30974769Smikeh				warnx("%s", cp);
3101590Srgrimes				obuf = stdout;
3111590Srgrimes			} else
31277274Smikeh				(void)signal(SIGPIPE, brokpipe);
3131590Srgrimes		}
3141590Srgrimes	}
31577274Smikeh
31677274Smikeh	/*
31777274Smikeh	 * Send messages to the output.
31877274Smikeh	 *
31977274Smikeh	 */
3201590Srgrimes	for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) {
3211590Srgrimes		mp = &message[*ip - 1];
3221590Srgrimes		touch(mp);
3231590Srgrimes		dot = mp;
32477274Smikeh		if (value("quiet") == NULL)
3251590Srgrimes			fprintf(obuf, "Message %d:\n", *ip);
32677274Smikeh		(void)sendmessage(mp, obuf, doign ? ignore : 0, NULL);
3271590Srgrimes	}
32877274Smikeh
3291590Srgrimesclose_pipe:
3301590Srgrimes	if (obuf != stdout) {
3311590Srgrimes		/*
3321590Srgrimes		 * Ignore SIGPIPE so it can't cause a duplicate close.
3331590Srgrimes		 */
33477274Smikeh		(void)signal(SIGPIPE, SIG_IGN);
33577274Smikeh		(void)Pclose(obuf);
33677274Smikeh		(void)signal(SIGPIPE, SIG_DFL);
3371590Srgrimes	}
33877274Smikeh	return (0);
3391590Srgrimes}
3401590Srgrimes
3411590Srgrimes/*
3421590Srgrimes * Respond to a broken pipe signal --
3431590Srgrimes * probably caused by quitting more.
3441590Srgrimes */
34577274Smikeh/*ARGSUSED*/
3461590Srgrimesvoid
347216562Scharnierbrokpipe(int signo __unused)
3481590Srgrimes{
3491590Srgrimes	longjmp(pipestop, 1);
3501590Srgrimes}
3511590Srgrimes
3521590Srgrimes/*
3531590Srgrimes * Print the top so many lines of each desired message.
3541590Srgrimes * The number of lines is taken from the variable "toplines"
3551590Srgrimes * and defaults to 5.
3561590Srgrimes */
3571590Srgrimesint
358216562Scharniertop(int *msgvec)
3591590Srgrimes{
36077274Smikeh	int *ip;
36177274Smikeh	struct message *mp;
3621590Srgrimes	int c, topl, lines, lineb;
3631590Srgrimes	char *valtop, linebuf[LINESIZE];
3641590Srgrimes	FILE *ibuf;
3651590Srgrimes
3661590Srgrimes	topl = 5;
3671590Srgrimes	valtop = value("toplines");
36877274Smikeh	if (valtop != NULL) {
3691590Srgrimes		topl = atoi(valtop);
3701590Srgrimes		if (topl < 0 || topl > 10000)
3711590Srgrimes			topl = 5;
3721590Srgrimes	}
3731590Srgrimes	lineb = 1;
3741590Srgrimes	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
3751590Srgrimes		mp = &message[*ip - 1];
3761590Srgrimes		touch(mp);
3771590Srgrimes		dot = mp;
37877274Smikeh		if (value("quiet") == NULL)
3791590Srgrimes			printf("Message %d:\n", *ip);
3801590Srgrimes		ibuf = setinput(mp);
3811590Srgrimes		c = mp->m_lines;
3821590Srgrimes		if (!lineb)
3831590Srgrimes			printf("\n");
3841590Srgrimes		for (lines = 0; lines < c && lines <= topl; lines++) {
38574769Smikeh			if (readline(ibuf, linebuf, sizeof(linebuf)) < 0)
3861590Srgrimes				break;
3871590Srgrimes			puts(linebuf);
38874769Smikeh			lineb = strspn(linebuf, " \t") == strlen(linebuf);
3891590Srgrimes		}
3901590Srgrimes	}
39177274Smikeh	return (0);
3921590Srgrimes}
3931590Srgrimes
3941590Srgrimes/*
3951590Srgrimes * Touch all the given messages so that they will
3961590Srgrimes * get mboxed.
3971590Srgrimes */
3981590Srgrimesint
399216562Scharnierstouch(int msgvec[])
4001590Srgrimes{
40177274Smikeh	int *ip;
4021590Srgrimes
4031590Srgrimes	for (ip = msgvec; *ip != 0; ip++) {
4041590Srgrimes		dot = &message[*ip-1];
4051590Srgrimes		dot->m_flag |= MTOUCH;
4061590Srgrimes		dot->m_flag &= ~MPRESERVE;
4071590Srgrimes	}
40877274Smikeh	return (0);
4091590Srgrimes}
4101590Srgrimes
4111590Srgrimes/*
4121590Srgrimes * Make sure all passed messages get mboxed.
4131590Srgrimes */
4141590Srgrimesint
415216562Scharniermboxit(int msgvec[])
4161590Srgrimes{
41777274Smikeh	int *ip;
4181590Srgrimes
4191590Srgrimes	for (ip = msgvec; *ip != 0; ip++) {
4201590Srgrimes		dot = &message[*ip-1];
4211590Srgrimes		dot->m_flag |= MTOUCH|MBOX;
4221590Srgrimes		dot->m_flag &= ~MPRESERVE;
4231590Srgrimes	}
42477274Smikeh	return (0);
4251590Srgrimes}
4261590Srgrimes
4271590Srgrimes/*
4281590Srgrimes * List the folders the user currently has.
4291590Srgrimes */
4301590Srgrimesint
431216562Scharnierfolders(void)
4321590Srgrimes{
43374769Smikeh	char dirname[PATHSIZE];
4341590Srgrimes	char *cmd;
4351590Srgrimes
43674769Smikeh	if (getfold(dirname, sizeof(dirname)) < 0) {
4371590Srgrimes		printf("No value set for \"folder\"\n");
43877274Smikeh		return (1);
4391590Srgrimes	}
44077274Smikeh	if ((cmd = value("LISTER")) == NULL)
4411590Srgrimes		cmd = "ls";
44277274Smikeh	(void)run_command(cmd, 0, -1, -1, dirname, NULL, NULL);
44377274Smikeh	return (0);
4441590Srgrimes}
44588150Smikeh
44688150Smikeh/*
44788150Smikeh * Update the mail file with any new messages that have
44888150Smikeh * come in since we started reading mail.
44988150Smikeh */
45088150Smikehint
451216562Scharnierinc(void *v __unused)
45288150Smikeh{
45388150Smikeh	int nmsg, mdot;
45488150Smikeh
45588150Smikeh	nmsg = incfile();
45688150Smikeh
45788150Smikeh	if (nmsg == 0)
45888150Smikeh		printf("No new mail.\n");
45988150Smikeh	else if (nmsg > 0) {
46088150Smikeh		mdot = newfileinfo(msgCount - nmsg);
46188150Smikeh		dot = &message[mdot - 1];
46288150Smikeh	} else
46388150Smikeh		printf("\"inc\" command failed...\n");
46488150Smikeh
46588150Smikeh	return (0);
46688150Smikeh}
467