xref: /csrg-svn/usr.bin/mail/cmd1.c (revision 68818)
143105Sedward /*-
262083Sbostic  * Copyright (c) 1980, 1993
362083Sbostic  *	The Regents of the University of California.  All rights reserved.
433499Sbostic  *
543105Sedward  * %sccs.include.redist.c%
622644Sdist  */
722644Sdist 
834905Sbostic #ifndef lint
9*68818Sdab static char sccsid[] = "@(#)cmd1.c	8.2 (Berkeley) 04/20/95";
1034905Sbostic #endif /* not lint */
1114523Ssam 
121223Skas #include "rcv.h"
1354505Sbostic #include "extern.h"
141223Skas 
151223Skas /*
161223Skas  * Mail -- a mail program
171223Skas  *
181223Skas  * User commands.
191223Skas  */
201223Skas 
211223Skas /*
221223Skas  * Print the current active headings.
232214Skas  * Don't change dot if invoker didn't give an argument.
241223Skas  */
251223Skas 
261223Skas static int screen;
271223Skas 
2854505Sbostic int
headers(msgvec)291223Skas headers(msgvec)
301223Skas 	int *msgvec;
311223Skas {
321223Skas 	register int n, mesg, flag;
331223Skas 	register struct message *mp;
346224Skurt 	int size;
351223Skas 
366224Skurt 	size = screensize();
371223Skas 	n = msgvec[0];
381223Skas 	if (n != 0)
396224Skurt 		screen = (n-1)/size;
401223Skas 	if (screen < 0)
411223Skas 		screen = 0;
426224Skurt 	mp = &message[screen * size];
431223Skas 	if (mp >= &message[msgCount])
446224Skurt 		mp = &message[msgCount - size];
451223Skas 	if (mp < &message[0])
461223Skas 		mp = &message[0];
471223Skas 	flag = 0;
481223Skas 	mesg = mp - &message[0];
492214Skas 	if (dot != &message[n-1])
502214Skas 		dot = mp;
511223Skas 	for (; mp < &message[msgCount]; mp++) {
521223Skas 		mesg++;
531223Skas 		if (mp->m_flag & MDELETED)
541223Skas 			continue;
556224Skurt 		if (flag++ >= size)
561223Skas 			break;
571223Skas 		printhead(mesg);
581223Skas 	}
591223Skas 	if (flag == 0) {
601223Skas 		printf("No more mail.\n");
611223Skas 		return(1);
621223Skas 	}
631223Skas 	return(0);
641223Skas }
651223Skas 
661223Skas /*
671223Skas  * Scroll to the next/previous screen
681223Skas  */
6954505Sbostic int
scroll(arg)701223Skas scroll(arg)
711223Skas 	char arg[];
721223Skas {
736224Skurt 	register int s, size;
741223Skas 	int cur[1];
751223Skas 
761223Skas 	cur[0] = 0;
776224Skurt 	size = screensize();
781223Skas 	s = screen;
791223Skas 	switch (*arg) {
801223Skas 	case 0:
811223Skas 	case '+':
821223Skas 		s++;
836224Skurt 		if (s * size > msgCount) {
841223Skas 			printf("On last screenful of messages\n");
851223Skas 			return(0);
861223Skas 		}
871223Skas 		screen = s;
881223Skas 		break;
891223Skas 
901223Skas 	case '-':
911223Skas 		if (--s < 0) {
921223Skas 			printf("On first screenful of messages\n");
931223Skas 			return(0);
941223Skas 		}
951223Skas 		screen = s;
961223Skas 		break;
971223Skas 
981223Skas 	default:
991223Skas 		printf("Unrecognized scrolling command \"%s\"\n", arg);
1001223Skas 		return(1);
1011223Skas 	}
1021223Skas 	return(headers(cur));
1031223Skas }
1041223Skas 
1056224Skurt /*
10631142Sedward  * Compute screen size.
1076224Skurt  */
10854505Sbostic int
screensize()1096224Skurt screensize()
1106224Skurt {
11131142Sedward 	int s;
11231142Sedward 	char *cp;
1131223Skas 
11431142Sedward 	if ((cp = value("screen")) != NOSTR && (s = atoi(cp)) > 0)
11531142Sedward 		return s;
11631142Sedward 	return screenheight - 4;
1176224Skurt }
1186224Skurt 
1191223Skas /*
1201223Skas  * Print out the headlines for each message
1211223Skas  * in the passed message list.
1221223Skas  */
12354505Sbostic int
from(msgvec)1241223Skas from(msgvec)
1251223Skas 	int *msgvec;
1261223Skas {
1271223Skas 	register int *ip;
1281223Skas 
12934968Sedward 	for (ip = msgvec; *ip != NULL; ip++)
1301223Skas 		printhead(*ip);
1311223Skas 	if (--ip >= msgvec)
1321223Skas 		dot = &message[*ip - 1];
1331223Skas 	return(0);
1341223Skas }
1351223Skas 
1361223Skas /*
1371223Skas  * Print out the header of a specific message.
1381223Skas  * This is a slight improvement to the standard one.
1391223Skas  */
14054505Sbostic void
printhead(mesg)1411223Skas printhead(mesg)
14254505Sbostic 	int mesg;
1431223Skas {
1441223Skas 	struct message *mp;
14524755Sserge 	char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind;
1461223Skas 	char pbuf[BUFSIZ];
1471223Skas 	struct headline hl;
14831142Sedward 	int subjlen;
14943105Sedward 	char *name;
1501223Skas 
1511223Skas 	mp = &message[mesg-1];
15236478Sedward 	(void) readline(setinput(mp), headline, LINESIZE);
15331142Sedward 	if ((subjline = hfield("subject", mp)) == NOSTR)
1541223Skas 		subjline = hfield("subj", mp);
1551223Skas 	/*
1561223Skas 	 * Bletch!
1571223Skas 	 */
1582214Skas 	curind = dot == mp ? '>' : ' ';
1591223Skas 	dispc = ' ';
1601223Skas 	if (mp->m_flag & MSAVED)
1611223Skas 		dispc = '*';
1621223Skas 	if (mp->m_flag & MPRESERVE)
1631223Skas 		dispc = 'P';
1641480Skas 	if ((mp->m_flag & (MREAD|MNEW)) == MNEW)
1651480Skas 		dispc = 'N';
1661480Skas 	if ((mp->m_flag & (MREAD|MNEW)) == 0)
1671473Skas 		dispc = 'U';
1683318Skas 	if (mp->m_flag & MBOX)
1693318Skas 		dispc = 'M';
1701223Skas 	parse(headline, &hl, pbuf);
17143105Sedward 	sprintf(wcount, "%3d/%-5ld", mp->m_lines, mp->m_size);
17231142Sedward 	subjlen = screenwidth - 50 - strlen(wcount);
17343105Sedward 	name = value("show-rcpt") != NOSTR ?
17443105Sedward 		skin(hfield("to", mp)) : nameof(mp, 0);
17531142Sedward 	if (subjline == NOSTR || subjlen < 0)		/* pretty pathetic */
17631142Sedward 		printf("%c%c%3d %-20.20s  %16.16s %s\n",
17743105Sedward 			curind, dispc, mesg, name, hl.l_date, wcount);
1781223Skas 	else
17931142Sedward 		printf("%c%c%3d %-20.20s  %16.16s %s \"%.*s\"\n",
18043105Sedward 			curind, dispc, mesg, name, hl.l_date, wcount,
18131142Sedward 			subjlen, subjline);
1821223Skas }
1831223Skas 
1841223Skas /*
1851223Skas  * Print out the value of dot.
1861223Skas  */
18754505Sbostic int
pdot()1881223Skas pdot()
1891223Skas {
1901223Skas 	printf("%d\n", dot - &message[0] + 1);
1911223Skas 	return(0);
1921223Skas }
1931223Skas 
1941223Skas /*
1951223Skas  * Print out all the possible commands.
1961223Skas  */
19754505Sbostic int
pcmdlist()1981223Skas pcmdlist()
1991223Skas {
2001223Skas 	register struct cmd *cp;
2011223Skas 	register int cc;
2021223Skas 	extern struct cmd cmdtab[];
2031223Skas 
2041223Skas 	printf("Commands are:\n");
2051223Skas 	for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) {
2061223Skas 		cc += strlen(cp->c_name) + 2;
2071223Skas 		if (cc > 72) {
2081223Skas 			printf("\n");
2091223Skas 			cc = strlen(cp->c_name) + 2;
2101223Skas 		}
2111223Skas 		if ((cp+1)->c_name != NOSTR)
2121223Skas 			printf("%s, ", cp->c_name);
2131223Skas 		else
2141223Skas 			printf("%s\n", cp->c_name);
2151223Skas 	}
2161223Skas 	return(0);
2171223Skas }
2181223Skas 
2191223Skas /*
22022604Sserge  * Paginate messages, honor ignored fields.
22122604Sserge  */
22254505Sbostic int
more(msgvec)22322604Sserge more(msgvec)
22422604Sserge 	int *msgvec;
22522604Sserge {
22622604Sserge 	return (type1(msgvec, 1, 1));
22722604Sserge }
22822604Sserge 
22922604Sserge /*
23022604Sserge  * Paginate messages, even printing ignored fields.
23122604Sserge  */
23254505Sbostic int
More(msgvec)23322604Sserge More(msgvec)
23422604Sserge 	int *msgvec;
23522604Sserge {
23622604Sserge 
23722604Sserge 	return (type1(msgvec, 0, 1));
23822604Sserge }
23922604Sserge 
24022604Sserge /*
2417572Skurt  * Type out messages, honor ignored fields.
2427572Skurt  */
24354505Sbostic int
type(msgvec)2447572Skurt type(msgvec)
2457572Skurt 	int *msgvec;
2467572Skurt {
2477572Skurt 
24822604Sserge 	return(type1(msgvec, 1, 0));
2497572Skurt }
2507572Skurt 
2517572Skurt /*
2527572Skurt  * Type out messages, even printing ignored fields.
2537572Skurt  */
25454505Sbostic int
Type(msgvec)2557572Skurt Type(msgvec)
2567572Skurt 	int *msgvec;
2577572Skurt {
2587572Skurt 
25922604Sserge 	return(type1(msgvec, 0, 0));
2607572Skurt }
2617572Skurt 
2627572Skurt /*
2631223Skas  * Type out the messages requested.
2641223Skas  */
2651307Skas jmp_buf	pipestop;
26654505Sbostic int
type1(msgvec,doign,page)26722604Sserge type1(msgvec, doign, page)
2681223Skas 	int *msgvec;
26954505Sbostic 	int doign, page;
2701223Skas {
2711223Skas 	register *ip;
2721223Skas 	register struct message *mp;
2731307Skas 	register char *cp;
27431142Sedward 	int nlines;
27531142Sedward 	FILE *obuf;
2761223Skas 
2771307Skas 	obuf = stdout;
27843865Sedward 	if (setjmp(pipestop))
27943865Sedward 		goto close_pipe;
28034751Sedward 	if (value("interactive") != NOSTR &&
28134751Sedward 	    (page || (cp = value("crt")) != NOSTR)) {
28224755Sserge 		nlines = 0;
28322604Sserge 		if (!page) {
28422604Sserge 			for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++)
28522604Sserge 				nlines += message[*ip - 1].m_lines;
28622604Sserge 		}
28734749Sedward 		if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) {
28824755Sserge 			cp = value("PAGER");
28924755Sserge 			if (cp == NULL || *cp == '\0')
29037870Sbostic 				cp = _PATH_MORE;
29134877Sedward 			obuf = Popen(cp, "w");
2921307Skas 			if (obuf == NULL) {
29324755Sserge 				perror(cp);
2941307Skas 				obuf = stdout;
29543865Sedward 			} else
29631142Sedward 				signal(SIGPIPE, brokpipe);
2971307Skas 		}
2981307Skas 	}
29931142Sedward 	for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) {
30034987Sedward 		mp = &message[*ip - 1];
30134987Sedward 		touch(mp);
3021223Skas 		dot = mp;
30331142Sedward 		if (value("quiet") == NOSTR)
30434987Sedward 			fprintf(obuf, "Message %d:\n", *ip);
30534969Sedward 		(void) send(mp, obuf, doign ? ignore : 0, NOSTR);
3061223Skas 	}
30743865Sedward close_pipe:
3081307Skas 	if (obuf != stdout) {
30943865Sedward 		/*
31043865Sedward 		 * Ignore SIGPIPE so it can't cause a duplicate close.
31143865Sedward 		 */
31243865Sedward 		signal(SIGPIPE, SIG_IGN);
31334877Sedward 		Pclose(obuf);
31443865Sedward 		signal(SIGPIPE, SIG_DFL);
3151307Skas 	}
3161223Skas 	return(0);
3171223Skas }
3181223Skas 
3191223Skas /*
3201307Skas  * Respond to a broken pipe signal --
32143865Sedward  * probably caused by quitting more.
3221307Skas  */
32347709Sbostic void
brokpipe(signo)32454505Sbostic brokpipe(signo)
32554505Sbostic 	int signo;
3261307Skas {
3271307Skas 	longjmp(pipestop, 1);
3281307Skas }
3291307Skas 
3301307Skas /*
3311223Skas  * Print the top so many lines of each desired message.
3321223Skas  * The number of lines is taken from the variable "toplines"
3331223Skas  * and defaults to 5.
3341223Skas  */
33554505Sbostic int
top(msgvec)3361223Skas top(msgvec)
3371223Skas 	int *msgvec;
3381223Skas {
3391223Skas 	register int *ip;
3401223Skas 	register struct message *mp;
3411223Skas 	int c, topl, lines, lineb;
3421223Skas 	char *valtop, linebuf[LINESIZE];
3431223Skas 	FILE *ibuf;
3441223Skas 
3451223Skas 	topl = 5;
3461223Skas 	valtop = value("toplines");
3471223Skas 	if (valtop != NOSTR) {
3481223Skas 		topl = atoi(valtop);
3491223Skas 		if (topl < 0 || topl > 10000)
3501223Skas 			topl = 5;
3511223Skas 	}
3521223Skas 	lineb = 1;
3531223Skas 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
35434987Sedward 		mp = &message[*ip - 1];
35534987Sedward 		touch(mp);
3561223Skas 		dot = mp;
3571223Skas 		if (value("quiet") == NOSTR)
35834987Sedward 			printf("Message %d:\n", *ip);
3591223Skas 		ibuf = setinput(mp);
3601223Skas 		c = mp->m_lines;
3611223Skas 		if (!lineb)
3621223Skas 			printf("\n");
3631223Skas 		for (lines = 0; lines < c && lines <= topl; lines++) {
36436478Sedward 			if (readline(ibuf, linebuf, LINESIZE) < 0)
3651223Skas 				break;
3661223Skas 			puts(linebuf);
3671223Skas 			lineb = blankline(linebuf);
3681223Skas 		}
3691223Skas 	}
3701223Skas 	return(0);
3711223Skas }
3721223Skas 
3731223Skas /*
3741223Skas  * Touch all the given messages so that they will
3751223Skas  * get mboxed.
3761223Skas  */
37754505Sbostic int
stouch(msgvec)3781223Skas stouch(msgvec)
3791223Skas 	int msgvec[];
3801223Skas {
3811223Skas 	register int *ip;
3821223Skas 
3831223Skas 	for (ip = msgvec; *ip != 0; ip++) {
3841223Skas 		dot = &message[*ip-1];
3851480Skas 		dot->m_flag |= MTOUCH;
3861223Skas 		dot->m_flag &= ~MPRESERVE;
3871223Skas 	}
3881223Skas 	return(0);
3891223Skas }
3903318Skas 
3913318Skas /*
3923318Skas  * Make sure all passed messages get mboxed.
3933318Skas  */
39454505Sbostic int
mboxit(msgvec)3953318Skas mboxit(msgvec)
3963318Skas 	int msgvec[];
3973318Skas {
3983318Skas 	register int *ip;
3993318Skas 
4003318Skas 	for (ip = msgvec; *ip != 0; ip++) {
4013318Skas 		dot = &message[*ip-1];
4023318Skas 		dot->m_flag |= MTOUCH|MBOX;
4033318Skas 		dot->m_flag &= ~MPRESERVE;
4043318Skas 	}
4053318Skas 	return(0);
4063318Skas }
4076224Skurt 
4086224Skurt /*
4096224Skurt  * List the folders the user currently has.
4106224Skurt  */
41154505Sbostic int
folders()4126224Skurt folders()
4136224Skurt {
41431142Sedward 	char dirname[BUFSIZ];
41534963Sedward 	char *cmd;
4166224Skurt 
4176224Skurt 	if (getfold(dirname) < 0) {
4186224Skurt 		printf("No value set for \"folder\"\n");
41936554Sedward 		return 1;
4206224Skurt 	}
42134963Sedward 	if ((cmd = value("LISTER")) == NOSTR)
42234963Sedward 		cmd = "ls";
42354505Sbostic 	(void) run_command(cmd, 0, -1, -1, dirname, NOSTR, NOSTR);
42434963Sedward 	return 0;
4256224Skurt }
426*68818Sdab 
427*68818Sdab /*
428*68818Sdab  * Update the mail file with any new messages that have
429*68818Sdab  * come in since we started reading mail.
430*68818Sdab  */
inc()431*68818Sdab inc()
432*68818Sdab {
433*68818Sdab 	int nmsg, mdot;
434*68818Sdab 
435*68818Sdab 	nmsg = incfile();
436*68818Sdab 
437*68818Sdab 	if (nmsg == 0) {
438*68818Sdab 		printf("No new mail.\n");
439*68818Sdab 	} else if (nmsg > 0) {
440*68818Sdab 		mdot = newfileinfo(msgCount - nmsg);
441*68818Sdab 		dot = &message[mdot - 1];
442*68818Sdab 	} else {
443*68818Sdab 		printf("\"inc\" command failed...\n");
444*68818Sdab 	}
445*68818Sdab 
446*68818Sdab 	return 0;
447*68818Sdab }
448