cmd1.c revision 1590
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
351590Srgrimesstatic char sccsid[] = "@(#)cmd1.c	8.1 (Berkeley) 6/6/93";
361590Srgrimes#endif /* not lint */
371590Srgrimes
381590Srgrimes#include "rcv.h"
391590Srgrimes#include "extern.h"
401590Srgrimes
411590Srgrimes/*
421590Srgrimes * Mail -- a mail program
431590Srgrimes *
441590Srgrimes * User commands.
451590Srgrimes */
461590Srgrimes
471590Srgrimes/*
481590Srgrimes * Print the current active headings.
491590Srgrimes * Don't change dot if invoker didn't give an argument.
501590Srgrimes */
511590Srgrimes
521590Srgrimesstatic int screen;
531590Srgrimes
541590Srgrimesint
551590Srgrimesheaders(msgvec)
561590Srgrimes	int *msgvec;
571590Srgrimes{
581590Srgrimes	register int n, mesg, flag;
591590Srgrimes	register struct message *mp;
601590Srgrimes	int size;
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");
871590Srgrimes		return(1);
881590Srgrimes	}
891590Srgrimes	return(0);
901590Srgrimes}
911590Srgrimes
921590Srgrimes/*
931590Srgrimes * Scroll to the next/previous screen
941590Srgrimes */
951590Srgrimesint
961590Srgrimesscroll(arg)
971590Srgrimes	char arg[];
981590Srgrimes{
991590Srgrimes	register int s, size;
1001590Srgrimes	int cur[1];
1011590Srgrimes
1021590Srgrimes	cur[0] = 0;
1031590Srgrimes	size = screensize();
1041590Srgrimes	s = screen;
1051590Srgrimes	switch (*arg) {
1061590Srgrimes	case 0:
1071590Srgrimes	case '+':
1081590Srgrimes		s++;
1091590Srgrimes		if (s * size > msgCount) {
1101590Srgrimes			printf("On last screenful of messages\n");
1111590Srgrimes			return(0);
1121590Srgrimes		}
1131590Srgrimes		screen = s;
1141590Srgrimes		break;
1151590Srgrimes
1161590Srgrimes	case '-':
1171590Srgrimes		if (--s < 0) {
1181590Srgrimes			printf("On first screenful of messages\n");
1191590Srgrimes			return(0);
1201590Srgrimes		}
1211590Srgrimes		screen = s;
1221590Srgrimes		break;
1231590Srgrimes
1241590Srgrimes	default:
1251590Srgrimes		printf("Unrecognized scrolling command \"%s\"\n", arg);
1261590Srgrimes		return(1);
1271590Srgrimes	}
1281590Srgrimes	return(headers(cur));
1291590Srgrimes}
1301590Srgrimes
1311590Srgrimes/*
1321590Srgrimes * Compute screen size.
1331590Srgrimes */
1341590Srgrimesint
1351590Srgrimesscreensize()
1361590Srgrimes{
1371590Srgrimes	int s;
1381590Srgrimes	char *cp;
1391590Srgrimes
1401590Srgrimes	if ((cp = value("screen")) != NOSTR && (s = atoi(cp)) > 0)
1411590Srgrimes		return s;
1421590Srgrimes	return screenheight - 4;
1431590Srgrimes}
1441590Srgrimes
1451590Srgrimes/*
1461590Srgrimes * Print out the headlines for each message
1471590Srgrimes * in the passed message list.
1481590Srgrimes */
1491590Srgrimesint
1501590Srgrimesfrom(msgvec)
1511590Srgrimes	int *msgvec;
1521590Srgrimes{
1531590Srgrimes	register int *ip;
1541590Srgrimes
1551590Srgrimes	for (ip = msgvec; *ip != NULL; ip++)
1561590Srgrimes		printhead(*ip);
1571590Srgrimes	if (--ip >= msgvec)
1581590Srgrimes		dot = &message[*ip - 1];
1591590Srgrimes	return(0);
1601590Srgrimes}
1611590Srgrimes
1621590Srgrimes/*
1631590Srgrimes * Print out the header of a specific message.
1641590Srgrimes * This is a slight improvement to the standard one.
1651590Srgrimes */
1661590Srgrimesvoid
1671590Srgrimesprinthead(mesg)
1681590Srgrimes	int mesg;
1691590Srgrimes{
1701590Srgrimes	struct message *mp;
1711590Srgrimes	char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind;
1721590Srgrimes	char pbuf[BUFSIZ];
1731590Srgrimes	struct headline hl;
1741590Srgrimes	int subjlen;
1751590Srgrimes	char *name;
1761590Srgrimes
1771590Srgrimes	mp = &message[mesg-1];
1781590Srgrimes	(void) readline(setinput(mp), headline, LINESIZE);
1791590Srgrimes	if ((subjline = hfield("subject", mp)) == NOSTR)
1801590Srgrimes		subjline = hfield("subj", mp);
1811590Srgrimes	/*
1821590Srgrimes	 * Bletch!
1831590Srgrimes	 */
1841590Srgrimes	curind = dot == mp ? '>' : ' ';
1851590Srgrimes	dispc = ' ';
1861590Srgrimes	if (mp->m_flag & MSAVED)
1871590Srgrimes		dispc = '*';
1881590Srgrimes	if (mp->m_flag & MPRESERVE)
1891590Srgrimes		dispc = 'P';
1901590Srgrimes	if ((mp->m_flag & (MREAD|MNEW)) == MNEW)
1911590Srgrimes		dispc = 'N';
1921590Srgrimes	if ((mp->m_flag & (MREAD|MNEW)) == 0)
1931590Srgrimes		dispc = 'U';
1941590Srgrimes	if (mp->m_flag & MBOX)
1951590Srgrimes		dispc = 'M';
1961590Srgrimes	parse(headline, &hl, pbuf);
1971590Srgrimes	sprintf(wcount, "%3d/%-5ld", mp->m_lines, mp->m_size);
1981590Srgrimes	subjlen = screenwidth - 50 - strlen(wcount);
1991590Srgrimes	name = value("show-rcpt") != NOSTR ?
2001590Srgrimes		skin(hfield("to", mp)) : nameof(mp, 0);
2011590Srgrimes	if (subjline == NOSTR || subjlen < 0)		/* pretty pathetic */
2021590Srgrimes		printf("%c%c%3d %-20.20s  %16.16s %s\n",
2031590Srgrimes			curind, dispc, mesg, name, hl.l_date, wcount);
2041590Srgrimes	else
2051590Srgrimes		printf("%c%c%3d %-20.20s  %16.16s %s \"%.*s\"\n",
2061590Srgrimes			curind, dispc, mesg, name, hl.l_date, wcount,
2071590Srgrimes			subjlen, subjline);
2081590Srgrimes}
2091590Srgrimes
2101590Srgrimes/*
2111590Srgrimes * Print out the value of dot.
2121590Srgrimes */
2131590Srgrimesint
2141590Srgrimespdot()
2151590Srgrimes{
2161590Srgrimes	printf("%d\n", dot - &message[0] + 1);
2171590Srgrimes	return(0);
2181590Srgrimes}
2191590Srgrimes
2201590Srgrimes/*
2211590Srgrimes * Print out all the possible commands.
2221590Srgrimes */
2231590Srgrimesint
2241590Srgrimespcmdlist()
2251590Srgrimes{
2261590Srgrimes	register struct cmd *cp;
2271590Srgrimes	register int cc;
2281590Srgrimes	extern struct cmd cmdtab[];
2291590Srgrimes
2301590Srgrimes	printf("Commands are:\n");
2311590Srgrimes	for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) {
2321590Srgrimes		cc += strlen(cp->c_name) + 2;
2331590Srgrimes		if (cc > 72) {
2341590Srgrimes			printf("\n");
2351590Srgrimes			cc = strlen(cp->c_name) + 2;
2361590Srgrimes		}
2371590Srgrimes		if ((cp+1)->c_name != NOSTR)
2381590Srgrimes			printf("%s, ", cp->c_name);
2391590Srgrimes		else
2401590Srgrimes			printf("%s\n", cp->c_name);
2411590Srgrimes	}
2421590Srgrimes	return(0);
2431590Srgrimes}
2441590Srgrimes
2451590Srgrimes/*
2461590Srgrimes * Paginate messages, honor ignored fields.
2471590Srgrimes */
2481590Srgrimesint
2491590Srgrimesmore(msgvec)
2501590Srgrimes	int *msgvec;
2511590Srgrimes{
2521590Srgrimes	return (type1(msgvec, 1, 1));
2531590Srgrimes}
2541590Srgrimes
2551590Srgrimes/*
2561590Srgrimes * Paginate messages, even printing ignored fields.
2571590Srgrimes */
2581590Srgrimesint
2591590SrgrimesMore(msgvec)
2601590Srgrimes	int *msgvec;
2611590Srgrimes{
2621590Srgrimes
2631590Srgrimes	return (type1(msgvec, 0, 1));
2641590Srgrimes}
2651590Srgrimes
2661590Srgrimes/*
2671590Srgrimes * Type out messages, honor ignored fields.
2681590Srgrimes */
2691590Srgrimesint
2701590Srgrimestype(msgvec)
2711590Srgrimes	int *msgvec;
2721590Srgrimes{
2731590Srgrimes
2741590Srgrimes	return(type1(msgvec, 1, 0));
2751590Srgrimes}
2761590Srgrimes
2771590Srgrimes/*
2781590Srgrimes * Type out messages, even printing ignored fields.
2791590Srgrimes */
2801590Srgrimesint
2811590SrgrimesType(msgvec)
2821590Srgrimes	int *msgvec;
2831590Srgrimes{
2841590Srgrimes
2851590Srgrimes	return(type1(msgvec, 0, 0));
2861590Srgrimes}
2871590Srgrimes
2881590Srgrimes/*
2891590Srgrimes * Type out the messages requested.
2901590Srgrimes */
2911590Srgrimesjmp_buf	pipestop;
2921590Srgrimesint
2931590Srgrimestype1(msgvec, doign, page)
2941590Srgrimes	int *msgvec;
2951590Srgrimes	int doign, page;
2961590Srgrimes{
2971590Srgrimes	register *ip;
2981590Srgrimes	register struct message *mp;
2991590Srgrimes	register char *cp;
3001590Srgrimes	int nlines;
3011590Srgrimes	FILE *obuf;
3021590Srgrimes
3031590Srgrimes	obuf = stdout;
3041590Srgrimes	if (setjmp(pipestop))
3051590Srgrimes		goto close_pipe;
3061590Srgrimes	if (value("interactive") != NOSTR &&
3071590Srgrimes	    (page || (cp = value("crt")) != NOSTR)) {
3081590Srgrimes		nlines = 0;
3091590Srgrimes		if (!page) {
3101590Srgrimes			for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++)
3111590Srgrimes				nlines += message[*ip - 1].m_lines;
3121590Srgrimes		}
3131590Srgrimes		if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) {
3141590Srgrimes			cp = value("PAGER");
3151590Srgrimes			if (cp == NULL || *cp == '\0')
3161590Srgrimes				cp = _PATH_MORE;
3171590Srgrimes			obuf = Popen(cp, "w");
3181590Srgrimes			if (obuf == NULL) {
3191590Srgrimes				perror(cp);
3201590Srgrimes				obuf = stdout;
3211590Srgrimes			} else
3221590Srgrimes				signal(SIGPIPE, brokpipe);
3231590Srgrimes		}
3241590Srgrimes	}
3251590Srgrimes	for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) {
3261590Srgrimes		mp = &message[*ip - 1];
3271590Srgrimes		touch(mp);
3281590Srgrimes		dot = mp;
3291590Srgrimes		if (value("quiet") == NOSTR)
3301590Srgrimes			fprintf(obuf, "Message %d:\n", *ip);
3311590Srgrimes		(void) send(mp, obuf, doign ? ignore : 0, NOSTR);
3321590Srgrimes	}
3331590Srgrimesclose_pipe:
3341590Srgrimes	if (obuf != stdout) {
3351590Srgrimes		/*
3361590Srgrimes		 * Ignore SIGPIPE so it can't cause a duplicate close.
3371590Srgrimes		 */
3381590Srgrimes		signal(SIGPIPE, SIG_IGN);
3391590Srgrimes		Pclose(obuf);
3401590Srgrimes		signal(SIGPIPE, SIG_DFL);
3411590Srgrimes	}
3421590Srgrimes	return(0);
3431590Srgrimes}
3441590Srgrimes
3451590Srgrimes/*
3461590Srgrimes * Respond to a broken pipe signal --
3471590Srgrimes * probably caused by quitting more.
3481590Srgrimes */
3491590Srgrimesvoid
3501590Srgrimesbrokpipe(signo)
3511590Srgrimes	int signo;
3521590Srgrimes{
3531590Srgrimes	longjmp(pipestop, 1);
3541590Srgrimes}
3551590Srgrimes
3561590Srgrimes/*
3571590Srgrimes * Print the top so many lines of each desired message.
3581590Srgrimes * The number of lines is taken from the variable "toplines"
3591590Srgrimes * and defaults to 5.
3601590Srgrimes */
3611590Srgrimesint
3621590Srgrimestop(msgvec)
3631590Srgrimes	int *msgvec;
3641590Srgrimes{
3651590Srgrimes	register int *ip;
3661590Srgrimes	register struct message *mp;
3671590Srgrimes	int c, topl, lines, lineb;
3681590Srgrimes	char *valtop, linebuf[LINESIZE];
3691590Srgrimes	FILE *ibuf;
3701590Srgrimes
3711590Srgrimes	topl = 5;
3721590Srgrimes	valtop = value("toplines");
3731590Srgrimes	if (valtop != NOSTR) {
3741590Srgrimes		topl = atoi(valtop);
3751590Srgrimes		if (topl < 0 || topl > 10000)
3761590Srgrimes			topl = 5;
3771590Srgrimes	}
3781590Srgrimes	lineb = 1;
3791590Srgrimes	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
3801590Srgrimes		mp = &message[*ip - 1];
3811590Srgrimes		touch(mp);
3821590Srgrimes		dot = mp;
3831590Srgrimes		if (value("quiet") == NOSTR)
3841590Srgrimes			printf("Message %d:\n", *ip);
3851590Srgrimes		ibuf = setinput(mp);
3861590Srgrimes		c = mp->m_lines;
3871590Srgrimes		if (!lineb)
3881590Srgrimes			printf("\n");
3891590Srgrimes		for (lines = 0; lines < c && lines <= topl; lines++) {
3901590Srgrimes			if (readline(ibuf, linebuf, LINESIZE) < 0)
3911590Srgrimes				break;
3921590Srgrimes			puts(linebuf);
3931590Srgrimes			lineb = blankline(linebuf);
3941590Srgrimes		}
3951590Srgrimes	}
3961590Srgrimes	return(0);
3971590Srgrimes}
3981590Srgrimes
3991590Srgrimes/*
4001590Srgrimes * Touch all the given messages so that they will
4011590Srgrimes * get mboxed.
4021590Srgrimes */
4031590Srgrimesint
4041590Srgrimesstouch(msgvec)
4051590Srgrimes	int msgvec[];
4061590Srgrimes{
4071590Srgrimes	register int *ip;
4081590Srgrimes
4091590Srgrimes	for (ip = msgvec; *ip != 0; ip++) {
4101590Srgrimes		dot = &message[*ip-1];
4111590Srgrimes		dot->m_flag |= MTOUCH;
4121590Srgrimes		dot->m_flag &= ~MPRESERVE;
4131590Srgrimes	}
4141590Srgrimes	return(0);
4151590Srgrimes}
4161590Srgrimes
4171590Srgrimes/*
4181590Srgrimes * Make sure all passed messages get mboxed.
4191590Srgrimes */
4201590Srgrimesint
4211590Srgrimesmboxit(msgvec)
4221590Srgrimes	int msgvec[];
4231590Srgrimes{
4241590Srgrimes	register int *ip;
4251590Srgrimes
4261590Srgrimes	for (ip = msgvec; *ip != 0; ip++) {
4271590Srgrimes		dot = &message[*ip-1];
4281590Srgrimes		dot->m_flag |= MTOUCH|MBOX;
4291590Srgrimes		dot->m_flag &= ~MPRESERVE;
4301590Srgrimes	}
4311590Srgrimes	return(0);
4321590Srgrimes}
4331590Srgrimes
4341590Srgrimes/*
4351590Srgrimes * List the folders the user currently has.
4361590Srgrimes */
4371590Srgrimesint
4381590Srgrimesfolders()
4391590Srgrimes{
4401590Srgrimes	char dirname[BUFSIZ];
4411590Srgrimes	char *cmd;
4421590Srgrimes
4431590Srgrimes	if (getfold(dirname) < 0) {
4441590Srgrimes		printf("No value set for \"folder\"\n");
4451590Srgrimes		return 1;
4461590Srgrimes	}
4471590Srgrimes	if ((cmd = value("LISTER")) == NOSTR)
4481590Srgrimes		cmd = "ls";
4491590Srgrimes	(void) run_command(cmd, 0, -1, -1, dirname, NOSTR, NOSTR);
4501590Srgrimes	return 0;
4511590Srgrimes}
452