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
321590Srgrimesstatic char sccsid[] = "@(#)cmd2.c	8.1 (Berkeley) 6/6/93";
3374769Smikeh#endif
341590Srgrimes#endif /* not lint */
3599112Sobrien#include <sys/cdefs.h>
3699112Sobrien__FBSDID("$FreeBSD$");
371590Srgrimes
381590Srgrimes#include "rcv.h"
391590Srgrimes#include <sys/wait.h>
401590Srgrimes#include "extern.h"
411590Srgrimes
421590Srgrimes/*
431590Srgrimes * Mail -- a mail program
441590Srgrimes *
451590Srgrimes * More user commands.
461590Srgrimes */
471590Srgrimes
4877274Smikehextern int wait_status;
4977274Smikeh
501590Srgrimes/*
511590Srgrimes * If any arguments were given, go to the next applicable argument
521590Srgrimes * following dot, otherwise, go to the next applicable message.
531590Srgrimes * If given as first command with no arguments, print first message.
541590Srgrimes */
551590Srgrimesint
56216564Scharniernext(int *msgvec)
571590Srgrimes{
5877274Smikeh	struct message *mp;
5977274Smikeh	int *ip, *ip2, list[2], mdot;
601590Srgrimes
6129574Sphk	if (*msgvec != 0) {
621590Srgrimes
631590Srgrimes		/*
648874Srgrimes		 * If some messages were supplied, find the
651590Srgrimes		 * first applicable one following dot using
661590Srgrimes		 * wrap around.
671590Srgrimes		 */
681590Srgrimes
691590Srgrimes		mdot = dot - &message[0] + 1;
701590Srgrimes
711590Srgrimes		/*
721590Srgrimes		 * Find the first message in the supplied
731590Srgrimes		 * message list which follows dot.
741590Srgrimes		 */
751590Srgrimes
7629574Sphk		for (ip = msgvec; *ip != 0; ip++)
771590Srgrimes			if (*ip > mdot)
781590Srgrimes				break;
7929574Sphk		if (*ip == 0)
801590Srgrimes			ip = msgvec;
811590Srgrimes		ip2 = ip;
821590Srgrimes		do {
831590Srgrimes			mp = &message[*ip2 - 1];
841590Srgrimes			if ((mp->m_flag & MDELETED) == 0) {
851590Srgrimes				dot = mp;
861590Srgrimes				goto hitit;
871590Srgrimes			}
8829574Sphk			if (*ip2 != 0)
891590Srgrimes				ip2++;
9029574Sphk			if (*ip2 == 0)
911590Srgrimes				ip2 = msgvec;
921590Srgrimes		} while (ip2 != ip);
931590Srgrimes		printf("No messages applicable\n");
9477274Smikeh		return (1);
951590Srgrimes	}
961590Srgrimes
971590Srgrimes	/*
981590Srgrimes	 * If this is the first command, select message 1.
991590Srgrimes	 * Note that this must exist for us to get here at all.
1001590Srgrimes	 */
1011590Srgrimes
1021590Srgrimes	if (!sawcom)
1031590Srgrimes		goto hitit;
1041590Srgrimes
1051590Srgrimes	/*
1061590Srgrimes	 * Just find the next good message after dot, no
1071590Srgrimes	 * wraparound.
1081590Srgrimes	 */
1091590Srgrimes
1101590Srgrimes	for (mp = dot+1; mp < &message[msgCount]; mp++)
1111590Srgrimes		if ((mp->m_flag & (MDELETED|MSAVED)) == 0)
1121590Srgrimes			break;
1131590Srgrimes	if (mp >= &message[msgCount]) {
1141590Srgrimes		printf("At EOF\n");
11577274Smikeh		return (0);
1161590Srgrimes	}
1171590Srgrimes	dot = mp;
1181590Srgrimeshitit:
1191590Srgrimes	/*
1201590Srgrimes	 * Print dot.
1211590Srgrimes	 */
1221590Srgrimes
1231590Srgrimes	list[0] = dot - &message[0] + 1;
12429574Sphk	list[1] = 0;
12577274Smikeh	return (type(list));
1261590Srgrimes}
1271590Srgrimes
1281590Srgrimes/*
1291590Srgrimes * Save a message in a file.  Mark the message as saved
1301590Srgrimes * so we can discard when the user quits.
1311590Srgrimes */
1321590Srgrimesint
133216564Scharniersave(char str[])
1341590Srgrimes{
1351590Srgrimes
13677274Smikeh	return (save1(str, 1, "save", saveignore));
1371590Srgrimes}
1381590Srgrimes
1391590Srgrimes/*
1401590Srgrimes * Copy a message to a file without affected its saved-ness
1411590Srgrimes */
1421590Srgrimesint
143216564Scharniercopycmd(char str[])
1441590Srgrimes{
1451590Srgrimes
14677274Smikeh	return (save1(str, 0, "copy", saveignore));
1471590Srgrimes}
1481590Srgrimes
1491590Srgrimes/*
1501590Srgrimes * Save/copy the indicated messages at the end of the passed file name.
1511590Srgrimes * If mark is true, mark the message "saved."
1521590Srgrimes */
1531590Srgrimesint
154216564Scharniersave1(char str[], int mark, const char *cmd, struct ignoretab *ignore)
1551590Srgrimes{
15677274Smikeh	struct message *mp;
15777274Smikeh	char *file;
15877274Smikeh	const char *disp;
15977274Smikeh	int f, *msgvec, *ip;
1601590Srgrimes	FILE *obuf;
1611590Srgrimes
16277274Smikeh	msgvec = (int *)salloc((msgCount + 2) * sizeof(*msgvec));
16377274Smikeh	if ((file = snarf(str, &f)) == NULL)
16477274Smikeh		return (1);
1651590Srgrimes	if (!f) {
1661590Srgrimes		*msgvec = first(0, MMNORM);
16729574Sphk		if (*msgvec == 0) {
1681590Srgrimes			printf("No messages to %s.\n", cmd);
16977274Smikeh			return (1);
1701590Srgrimes		}
17129574Sphk		msgvec[1] = 0;
1721590Srgrimes	}
1731590Srgrimes	if (f && getmsglist(str, msgvec, 0) < 0)
17477274Smikeh		return (1);
17577274Smikeh	if ((file = expand(file)) == NULL)
17677274Smikeh		return (1);
1771590Srgrimes	printf("\"%s\" ", file);
17877274Smikeh	(void)fflush(stdout);
1791590Srgrimes	if (access(file, 0) >= 0)
1801590Srgrimes		disp = "[Appended]";
1811590Srgrimes	else
1821590Srgrimes		disp = "[New file]";
1831590Srgrimes	if ((obuf = Fopen(file, "a")) == NULL) {
18477274Smikeh		warn((char *)NULL);
18577274Smikeh		return (1);
1861590Srgrimes	}
1871590Srgrimes	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
1881590Srgrimes		mp = &message[*ip - 1];
1891590Srgrimes		touch(mp);
19077274Smikeh		if (sendmessage(mp, obuf, ignore, NULL) < 0) {
19174769Smikeh			warnx("%s", file);
19277274Smikeh			(void)Fclose(obuf);
19377274Smikeh			return (1);
1941590Srgrimes		}
1951590Srgrimes		if (mark)
1961590Srgrimes			mp->m_flag |= MSAVED;
1971590Srgrimes	}
19877274Smikeh	(void)fflush(obuf);
1991590Srgrimes	if (ferror(obuf))
20074769Smikeh		warn("%s", file);
20177274Smikeh	(void)Fclose(obuf);
2021590Srgrimes	printf("%s\n", disp);
20377274Smikeh	return (0);
2041590Srgrimes}
2051590Srgrimes
2061590Srgrimes/*
2071590Srgrimes * Write the indicated messages at the end of the passed
2081590Srgrimes * file name, minus header and trailing blank line.
2091590Srgrimes */
2101590Srgrimesint
211216564Scharnierswrite(char str[])
2121590Srgrimes{
2131590Srgrimes
21477274Smikeh	return (save1(str, 1, "write", ignoreall));
2151590Srgrimes}
2161590Srgrimes
2171590Srgrimes/*
2181590Srgrimes * Snarf the file from the end of the command line and
2191590Srgrimes * return a pointer to it.  If there is no file attached,
22077274Smikeh * just return NULL.  Put a null in front of the file
2211590Srgrimes * name so that the message list processing won't see it,
2221590Srgrimes * unless the file name is the only thing on the line, in
2231590Srgrimes * which case, return 0 in the reference flag variable.
2241590Srgrimes */
2251590Srgrimes
2261590Srgrimeschar *
227216564Scharniersnarf(char linebuf[], int *flag)
2281590Srgrimes{
22977274Smikeh	char *cp;
2301590Srgrimes
2311590Srgrimes	*flag = 1;
2321590Srgrimes	cp = strlen(linebuf) + linebuf - 1;
2331590Srgrimes
2341590Srgrimes	/*
2351590Srgrimes	 * Strip away trailing blanks.
2361590Srgrimes	 */
2371590Srgrimes
23888227Sache	while (cp > linebuf && isspace((unsigned char)*cp))
2391590Srgrimes		cp--;
24077274Smikeh	*++cp = '\0';
2411590Srgrimes
2421590Srgrimes	/*
2431590Srgrimes	 * Now search for the beginning of the file name.
2441590Srgrimes	 */
2451590Srgrimes
24688227Sache	while (cp > linebuf && !isspace((unsigned char)*cp))
2471590Srgrimes		cp--;
2481590Srgrimes	if (*cp == '\0') {
2491590Srgrimes		printf("No file specified.\n");
25077274Smikeh		return (NULL);
2511590Srgrimes	}
25288227Sache	if (isspace((unsigned char)*cp))
25377274Smikeh		*cp++ = '\0';
2541590Srgrimes	else
2551590Srgrimes		*flag = 0;
25677274Smikeh	return (cp);
2571590Srgrimes}
2581590Srgrimes
2591590Srgrimes/*
2601590Srgrimes * Delete messages.
2611590Srgrimes */
2621590Srgrimesint
263216564Scharnierdelete(int msgvec[])
2641590Srgrimes{
26577274Smikeh
2661590Srgrimes	delm(msgvec);
26777274Smikeh	return (0);
2681590Srgrimes}
2691590Srgrimes
2701590Srgrimes/*
2711590Srgrimes * Delete messages, then type the new dot.
2721590Srgrimes */
2731590Srgrimesint
274216564Scharnierdeltype(int msgvec[])
2751590Srgrimes{
2761590Srgrimes	int list[2];
2771590Srgrimes	int lastdot;
2781590Srgrimes
2791590Srgrimes	lastdot = dot - &message[0] + 1;
2801590Srgrimes	if (delm(msgvec) >= 0) {
2811590Srgrimes		list[0] = dot - &message[0] + 1;
2821590Srgrimes		if (list[0] > lastdot) {
2831590Srgrimes			touch(dot);
28429574Sphk			list[1] = 0;
28577274Smikeh			return (type(list));
2861590Srgrimes		}
2871590Srgrimes		printf("At EOF\n");
2881590Srgrimes	} else
2891590Srgrimes		printf("No more messages\n");
29077274Smikeh	return (0);
2911590Srgrimes}
2921590Srgrimes
2931590Srgrimes/*
2941590Srgrimes * Delete the indicated messages.
2951590Srgrimes * Set dot to some nice place afterwards.
2961590Srgrimes * Internal interface.
2971590Srgrimes */
2981590Srgrimesint
299216564Scharnierdelm(int *msgvec)
3001590Srgrimes{
30177274Smikeh	struct message *mp;
30277274Smikeh	int *ip, last;
3031590Srgrimes
30429574Sphk	last = 0;
30529574Sphk	for (ip = msgvec; *ip != 0; ip++) {
3061590Srgrimes		mp = &message[*ip - 1];
3071590Srgrimes		touch(mp);
3081590Srgrimes		mp->m_flag |= MDELETED|MTOUCH;
3091590Srgrimes		mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
3101590Srgrimes		last = *ip;
3111590Srgrimes	}
31229574Sphk	if (last != 0) {
3131590Srgrimes		dot = &message[last-1];
3141590Srgrimes		last = first(0, MDELETED);
31529574Sphk		if (last != 0) {
3161590Srgrimes			dot = &message[last-1];
31777274Smikeh			return (0);
3181590Srgrimes		}
3191590Srgrimes		else {
3201590Srgrimes			dot = &message[0];
32177274Smikeh			return (-1);
3221590Srgrimes		}
3231590Srgrimes	}
3241590Srgrimes
3251590Srgrimes	/*
3261590Srgrimes	 * Following can't happen -- it keeps lint happy
3271590Srgrimes	 */
3281590Srgrimes
32977274Smikeh	return (-1);
3301590Srgrimes}
3311590Srgrimes
3321590Srgrimes/*
3331590Srgrimes * Undelete the indicated messages.
3341590Srgrimes */
3351590Srgrimesint
336216564Scharnierundelete_messages(int *msgvec)
3371590Srgrimes{
33877274Smikeh	struct message *mp;
33977274Smikeh	int *ip;
3401590Srgrimes
3411590Srgrimes	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
3421590Srgrimes		mp = &message[*ip - 1];
3431590Srgrimes		touch(mp);
3441590Srgrimes		dot = mp;
3451590Srgrimes		mp->m_flag &= ~MDELETED;
3461590Srgrimes	}
34777274Smikeh	return (0);
3481590Srgrimes}
3491590Srgrimes
3501590Srgrimes/*
3511590Srgrimes * Interactively dump core on "core"
3521590Srgrimes */
3531590Srgrimesint
354216564Scharniercore(void)
3551590Srgrimes{
3561590Srgrimes	int pid;
3571590Srgrimes
35840189Sbde	switch (pid = fork()) {
3591590Srgrimes	case -1:
36074769Smikeh		warn("fork");
36177274Smikeh		return (1);
3621590Srgrimes	case 0:
3631590Srgrimes		abort();
3641590Srgrimes		_exit(1);
3651590Srgrimes	}
3661590Srgrimes	printf("Okie dokie");
36777274Smikeh	(void)fflush(stdout);
3681590Srgrimes	wait_child(pid);
36974769Smikeh	if (WIFSIGNALED(wait_status) && WCOREDUMP(wait_status))
3701590Srgrimes		printf(" -- Core dumped.\n");
3711590Srgrimes	else
3721590Srgrimes		printf(" -- Can't dump core.\n");
37377274Smikeh	return (0);
3741590Srgrimes}
3751590Srgrimes
3761590Srgrimes/*
3771590Srgrimes * Clobber as many bytes of stack as the user requests.
3781590Srgrimes */
3791590Srgrimesint
380216564Scharnierclobber(char **argv)
3811590Srgrimes{
38277274Smikeh	int times;
3831590Srgrimes
3841590Srgrimes	if (argv[0] == 0)
3851590Srgrimes		times = 1;
3861590Srgrimes	else
3871590Srgrimes		times = (atoi(argv[0]) + 511) / 512;
3881590Srgrimes	clob1(times);
38977274Smikeh	return (0);
3901590Srgrimes}
3911590Srgrimes
3921590Srgrimes/*
3931590Srgrimes * Clobber the stack.
3941590Srgrimes */
3951590Srgrimesvoid
396216564Scharnierclob1(int n)
3971590Srgrimes{
3981590Srgrimes	char buf[512];
39977274Smikeh	char *cp;
4001590Srgrimes
4011590Srgrimes	if (n <= 0)
4021590Srgrimes		return;
4031590Srgrimes	for (cp = buf; cp < &buf[512]; *cp++ = 0xFF)
4041590Srgrimes		;
4051590Srgrimes	clob1(n - 1);
4061590Srgrimes}
4071590Srgrimes
4081590Srgrimes/*
4091590Srgrimes * Add the given header fields to the retained list.
4101590Srgrimes * If no arguments, print the current list of retained fields.
4111590Srgrimes */
4121590Srgrimesint
413216564Scharnierretfield(char *list[])
4141590Srgrimes{
4151590Srgrimes
41677274Smikeh	return (ignore1(list, ignore + 1, "retained"));
4171590Srgrimes}
4181590Srgrimes
4191590Srgrimes/*
4201590Srgrimes * Add the given header fields to the ignored list.
4211590Srgrimes * If no arguments, print the current list of ignored fields.
4221590Srgrimes */
4231590Srgrimesint
424216564Scharnierigfield(char *list[])
4251590Srgrimes{
4261590Srgrimes
42777274Smikeh	return (ignore1(list, ignore, "ignored"));
4281590Srgrimes}
4291590Srgrimes
4301590Srgrimesint
431216564Scharniersaveretfield(char *list[])
4321590Srgrimes{
4331590Srgrimes
43477274Smikeh	return (ignore1(list, saveignore + 1, "retained"));
4351590Srgrimes}
4361590Srgrimes
4371590Srgrimesint
438216564Scharniersaveigfield(char *list[])
4391590Srgrimes{
4401590Srgrimes
44177274Smikeh	return (ignore1(list, saveignore, "ignored"));
4421590Srgrimes}
4431590Srgrimes
4441590Srgrimesint
445216564Scharnierignore1(char *list[], struct ignoretab *tab, const char *which)
4461590Srgrimes{
44774769Smikeh	char field[LINESIZE];
44877274Smikeh	int h;
44977274Smikeh	struct ignore *igp;
4501590Srgrimes	char **ap;
4511590Srgrimes
45277274Smikeh	if (*list == NULL)
45377274Smikeh		return (igshow(tab, which));
4541590Srgrimes	for (ap = list; *ap != 0; ap++) {
45574769Smikeh		istrncpy(field, *ap, sizeof(field));
4561590Srgrimes		if (member(field, tab))
4571590Srgrimes			continue;
4581590Srgrimes		h = hash(field);
45977274Smikeh		igp = calloc(1, sizeof(struct ignore));
46077274Smikeh		igp->i_field = calloc((unsigned)strlen(field) + 1,
46177274Smikeh		    sizeof(char));
4621590Srgrimes		strcpy(igp->i_field, field);
4631590Srgrimes		igp->i_link = tab->i_head[h];
4641590Srgrimes		tab->i_head[h] = igp;
4651590Srgrimes		tab->i_count++;
4661590Srgrimes	}
46777274Smikeh	return (0);
4681590Srgrimes}
4691590Srgrimes
4701590Srgrimes/*
4711590Srgrimes * Print out all currently retained fields.
4721590Srgrimes */
4731590Srgrimesint
474216564Scharnierigshow(struct ignoretab *tab, const char *which)
4751590Srgrimes{
47677274Smikeh	int h;
4771590Srgrimes	struct ignore *igp;
4781590Srgrimes	char **ap, **ring;
4791590Srgrimes
4801590Srgrimes	if (tab->i_count == 0) {
4811590Srgrimes		printf("No fields currently being %s.\n", which);
48277274Smikeh		return (0);
4831590Srgrimes	}
48477274Smikeh	ring = (char **)salloc((tab->i_count + 1) * sizeof(char *));
4851590Srgrimes	ap = ring;
4861590Srgrimes	for (h = 0; h < HSHSIZE; h++)
48777274Smikeh		for (igp = tab->i_head[h]; igp != NULL; igp = igp->i_link)
4881590Srgrimes			*ap++ = igp->i_field;
4891590Srgrimes	*ap = 0;
49077274Smikeh	qsort(ring, tab->i_count, sizeof(char *), igcomp);
4911590Srgrimes	for (ap = ring; *ap != 0; ap++)
4921590Srgrimes		printf("%s\n", *ap);
49377274Smikeh	return (0);
4941590Srgrimes}
4951590Srgrimes
4961590Srgrimes/*
4971590Srgrimes * Compare two names for sorting ignored field list.
4981590Srgrimes */
4991590Srgrimesint
500216564Scharnierigcomp(const void *l, const void *r)
5011590Srgrimes{
50277274Smikeh
50377274Smikeh	return (strcmp(*(const char **)l, *(const char **)r));
5041590Srgrimes}
505