xref: /titanic_51/usr/src/cmd/mailx/cmd2.c (revision 6c83d09f819e9de7126c8539546eca2e276df44a)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate 
237c478bd9Sstevel@tonic-gate /*
24*6c83d09fSrobbin  * Copyright 2002 Sun Microsystems, Inc.  All rights reserved.
257c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
28*6c83d09fSrobbin /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29*6c83d09fSrobbin /*	  All Rights Reserved  	*/
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
337c478bd9Sstevel@tonic-gate  * The Regents of the University of California
347c478bd9Sstevel@tonic-gate  * All Rights Reserved
357c478bd9Sstevel@tonic-gate  *
367c478bd9Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
377c478bd9Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
387c478bd9Sstevel@tonic-gate  * contributors.
397c478bd9Sstevel@tonic-gate  */
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #include "rcv.h"
447c478bd9Sstevel@tonic-gate #include <locale.h>
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate /*
477c478bd9Sstevel@tonic-gate  * mailx -- a modified version of a University of California at Berkeley
487c478bd9Sstevel@tonic-gate  *	mail program
497c478bd9Sstevel@tonic-gate  *
507c478bd9Sstevel@tonic-gate  * More user commands.
517c478bd9Sstevel@tonic-gate  */
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate static int	igshow(void);
547c478bd9Sstevel@tonic-gate static int	igcomp(const void *l, const void *r);
557c478bd9Sstevel@tonic-gate static int	save1(char str[], int mark);
567c478bd9Sstevel@tonic-gate static int	Save1(int *msgvec, int mark);
577c478bd9Sstevel@tonic-gate static void	savemsglist(char *file, int *msgvec, int flag);
587c478bd9Sstevel@tonic-gate static int	put1(char str[], int doign);
597c478bd9Sstevel@tonic-gate static int	svputs(const char *line, FILE *obuf);
607c478bd9Sstevel@tonic-gate static int	wrputs(const char *line, FILE *obuf);
617c478bd9Sstevel@tonic-gate static int	retshow(void);
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate /* flags for savemsglist() */
647c478bd9Sstevel@tonic-gate #define	S_MARK		1		/* mark the message as saved */
657c478bd9Sstevel@tonic-gate #define	S_NOHEADER	2		/* don't write out the header */
667c478bd9Sstevel@tonic-gate #define	S_SAVING	4		/* doing save/copy */
677c478bd9Sstevel@tonic-gate #define	S_NOIGNORE	8		/* don't do ignore processing */
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate /*
707c478bd9Sstevel@tonic-gate  * If any arguments were given, go to the next applicable argument
717c478bd9Sstevel@tonic-gate  * following dot, otherwise, go to the next applicable message.
727c478bd9Sstevel@tonic-gate  * If given as first command with no arguments, print first message.
737c478bd9Sstevel@tonic-gate  */
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate int
767c478bd9Sstevel@tonic-gate next(int *msgvec)
777c478bd9Sstevel@tonic-gate {
787c478bd9Sstevel@tonic-gate 	register struct message *mp;
797c478bd9Sstevel@tonic-gate 	register int *ip, *ip2;
807c478bd9Sstevel@tonic-gate 	int list[2], mdot;
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 	if (*msgvec != NULL) {
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 		/*
857c478bd9Sstevel@tonic-gate 		 * If some messages were supplied, find the
867c478bd9Sstevel@tonic-gate 		 * first applicable one following dot using
877c478bd9Sstevel@tonic-gate 		 * wrap around.
887c478bd9Sstevel@tonic-gate 		 */
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 		mdot = dot - &message[0] + 1;
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate 		/*
937c478bd9Sstevel@tonic-gate 		 * Find the first message in the supplied
947c478bd9Sstevel@tonic-gate 		 * message list which follows dot.
957c478bd9Sstevel@tonic-gate 		 */
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 		for (ip = msgvec; *ip != NULL; ip++)
987c478bd9Sstevel@tonic-gate 			if (*ip > mdot)
997c478bd9Sstevel@tonic-gate 				break;
1007c478bd9Sstevel@tonic-gate 		if (*ip == NULL)
1017c478bd9Sstevel@tonic-gate 			ip = msgvec;
1027c478bd9Sstevel@tonic-gate 		ip2 = ip;
1037c478bd9Sstevel@tonic-gate 		do {
1047c478bd9Sstevel@tonic-gate 			mp = &message[*ip2 - 1];
1057c478bd9Sstevel@tonic-gate 			if ((mp->m_flag & MDELETED) == 0) {
1067c478bd9Sstevel@tonic-gate 				dot = mp;
1077c478bd9Sstevel@tonic-gate 				goto hitit;
1087c478bd9Sstevel@tonic-gate 			}
1097c478bd9Sstevel@tonic-gate 			if (*ip2 != NULL)
1107c478bd9Sstevel@tonic-gate 				ip2++;
1117c478bd9Sstevel@tonic-gate 			if (*ip2 == NULL)
1127c478bd9Sstevel@tonic-gate 				ip2 = msgvec;
1137c478bd9Sstevel@tonic-gate 		} while (ip2 != ip);
1147c478bd9Sstevel@tonic-gate 		printf(gettext("No messages applicable\n"));
1157c478bd9Sstevel@tonic-gate 		return(1);
1167c478bd9Sstevel@tonic-gate 	}
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 	/*
1197c478bd9Sstevel@tonic-gate 	 * If this is the first command, select message 1.
1207c478bd9Sstevel@tonic-gate 	 * Note that this must exist for us to get here at all.
1217c478bd9Sstevel@tonic-gate 	 */
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	if (!sawcom)
1247c478bd9Sstevel@tonic-gate 		goto hitit;
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	/*
1277c478bd9Sstevel@tonic-gate 	 * Just find the next good message after dot, no
1287c478bd9Sstevel@tonic-gate 	 * wraparound.
1297c478bd9Sstevel@tonic-gate 	 */
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	for (mp = dot+1; mp < &message[msgCount]; mp++)
1327c478bd9Sstevel@tonic-gate 		if ((mp->m_flag & (MDELETED|MSAVED)) == 0)
1337c478bd9Sstevel@tonic-gate 			break;
1347c478bd9Sstevel@tonic-gate 	if (mp >= &message[msgCount]) {
1357c478bd9Sstevel@tonic-gate 		printf(gettext("At EOF\n"));
1367c478bd9Sstevel@tonic-gate 		return(0);
1377c478bd9Sstevel@tonic-gate 	}
1387c478bd9Sstevel@tonic-gate 	dot = mp;
1397c478bd9Sstevel@tonic-gate hitit:
1407c478bd9Sstevel@tonic-gate 	/*
1417c478bd9Sstevel@tonic-gate 	 * Print dot.
1427c478bd9Sstevel@tonic-gate 	 */
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	list[0] = dot - &message[0] + 1;
1457c478bd9Sstevel@tonic-gate 	list[1] = NULL;
1467c478bd9Sstevel@tonic-gate 	return(type(list));
1477c478bd9Sstevel@tonic-gate }
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate /*
1507c478bd9Sstevel@tonic-gate  * Save a message in a file.  Mark the message as saved
1517c478bd9Sstevel@tonic-gate  * so we can discard when the user quits.
1527c478bd9Sstevel@tonic-gate  */
1537c478bd9Sstevel@tonic-gate int
1547c478bd9Sstevel@tonic-gate save(char str[])
1557c478bd9Sstevel@tonic-gate {
1567c478bd9Sstevel@tonic-gate 	return(save1(str, S_MARK));
1577c478bd9Sstevel@tonic-gate }
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate /*
1607c478bd9Sstevel@tonic-gate  * Copy a message to a file without affected its saved-ness
1617c478bd9Sstevel@tonic-gate  */
1627c478bd9Sstevel@tonic-gate int
1637c478bd9Sstevel@tonic-gate copycmd(char str[])
1647c478bd9Sstevel@tonic-gate {
1657c478bd9Sstevel@tonic-gate 	return(save1(str, 0));
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate /*
1697c478bd9Sstevel@tonic-gate  * Save/copy the indicated messages at the end of the passed file name.
1707c478bd9Sstevel@tonic-gate  * If mark is true, mark the message "saved."
1717c478bd9Sstevel@tonic-gate  */
1727c478bd9Sstevel@tonic-gate static int
1737c478bd9Sstevel@tonic-gate save1(char str[], int mark)
1747c478bd9Sstevel@tonic-gate {
1757c478bd9Sstevel@tonic-gate 	char *file, *cmd;
1767c478bd9Sstevel@tonic-gate 	int f, *msgvec;
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	cmd = mark ? "save" : "copy";
1797c478bd9Sstevel@tonic-gate 	msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec);
1807c478bd9Sstevel@tonic-gate 	if ((file = snarf(str, &f, 0)) == NOSTR)
1817c478bd9Sstevel@tonic-gate 		file = Getf("MBOX");
1827c478bd9Sstevel@tonic-gate 	if (f==-1)
1837c478bd9Sstevel@tonic-gate 		return(1);
1847c478bd9Sstevel@tonic-gate 	if (!f) {
1857c478bd9Sstevel@tonic-gate 		*msgvec = first(0, MMNORM);
1867c478bd9Sstevel@tonic-gate 		if (*msgvec == NULL) {
1877c478bd9Sstevel@tonic-gate 			printf(gettext("No messages to %s.\n"), cmd);
1887c478bd9Sstevel@tonic-gate 			return(1);
1897c478bd9Sstevel@tonic-gate 		}
1907c478bd9Sstevel@tonic-gate 		msgvec[1] = NULL;
1917c478bd9Sstevel@tonic-gate 	}
1927c478bd9Sstevel@tonic-gate 	if (f && getmsglist(str, msgvec, 0) < 0)
1937c478bd9Sstevel@tonic-gate 		return(1);
1947c478bd9Sstevel@tonic-gate 	if ((file = expand(file)) == NOSTR)
1957c478bd9Sstevel@tonic-gate 		return(1);
1967c478bd9Sstevel@tonic-gate 	savemsglist(file, msgvec, mark | S_SAVING);
1977c478bd9Sstevel@tonic-gate 	return(0);
1987c478bd9Sstevel@tonic-gate }
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate int
2017c478bd9Sstevel@tonic-gate Save(int *msgvec)
2027c478bd9Sstevel@tonic-gate {
2037c478bd9Sstevel@tonic-gate 	return(Save1(msgvec, S_MARK));
2047c478bd9Sstevel@tonic-gate }
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate int
2077c478bd9Sstevel@tonic-gate Copy(int *msgvec)
2087c478bd9Sstevel@tonic-gate {
2097c478bd9Sstevel@tonic-gate 	return(Save1(msgvec, 0));
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate /*
2137c478bd9Sstevel@tonic-gate  * save/copy the indicated messages at the end of a file named
2147c478bd9Sstevel@tonic-gate  * by the sender of the first message in the msglist.
2157c478bd9Sstevel@tonic-gate  */
2167c478bd9Sstevel@tonic-gate static int
2177c478bd9Sstevel@tonic-gate Save1(int *msgvec, int mark)
2187c478bd9Sstevel@tonic-gate {
2197c478bd9Sstevel@tonic-gate 	register char *from;
2207c478bd9Sstevel@tonic-gate 	char recfile[BUFSIZ];
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate #ifdef notdef
2237c478bd9Sstevel@tonic-gate 	from = striphosts(nameof(&message[*msgvec-1], 0));
2247c478bd9Sstevel@tonic-gate #else
2257c478bd9Sstevel@tonic-gate 	from = nameof(&message[*msgvec-1]);
2267c478bd9Sstevel@tonic-gate #endif
2277c478bd9Sstevel@tonic-gate 	getrecf(from, recfile, 1, sizeof (recfile));
2287c478bd9Sstevel@tonic-gate 	if (*recfile != '\0')
2297c478bd9Sstevel@tonic-gate 		savemsglist(safeexpand(recfile), msgvec, mark | S_SAVING);
2307c478bd9Sstevel@tonic-gate 	return(0);
2317c478bd9Sstevel@tonic-gate }
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate int
2347c478bd9Sstevel@tonic-gate sput(char str[])
2357c478bd9Sstevel@tonic-gate {
2367c478bd9Sstevel@tonic-gate 	return(put1(str, 0));
2377c478bd9Sstevel@tonic-gate }
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate int
2407c478bd9Sstevel@tonic-gate Sput(char str[])
2417c478bd9Sstevel@tonic-gate {
2427c478bd9Sstevel@tonic-gate 	return(put1(str, S_NOIGNORE));
2437c478bd9Sstevel@tonic-gate }
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate /*
2467c478bd9Sstevel@tonic-gate  * Put the indicated messages at the end of the passed file name.
2477c478bd9Sstevel@tonic-gate  */
2487c478bd9Sstevel@tonic-gate static int
2497c478bd9Sstevel@tonic-gate put1(char str[], int doign)
2507c478bd9Sstevel@tonic-gate {
2517c478bd9Sstevel@tonic-gate 	char *file;
2527c478bd9Sstevel@tonic-gate 	int f, *msgvec;
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec);
2557c478bd9Sstevel@tonic-gate 	if ((file = snarf(str, &f, 0)) == NOSTR)
2567c478bd9Sstevel@tonic-gate 		file = Getf("MBOX");
2577c478bd9Sstevel@tonic-gate 	if (f==-1)
2587c478bd9Sstevel@tonic-gate 		return(1);
2597c478bd9Sstevel@tonic-gate 	if (!f) {
2607c478bd9Sstevel@tonic-gate 		*msgvec = first(0, MMNORM);
2617c478bd9Sstevel@tonic-gate 		if (*msgvec == NULL) {
2627c478bd9Sstevel@tonic-gate 			printf(gettext("No messages to put.\n"));
2637c478bd9Sstevel@tonic-gate 			return(1);
2647c478bd9Sstevel@tonic-gate 		}
2657c478bd9Sstevel@tonic-gate 		msgvec[1] = NULL;
2667c478bd9Sstevel@tonic-gate 	}
2677c478bd9Sstevel@tonic-gate 	if (f && getmsglist(str, msgvec, 0) < 0)
2687c478bd9Sstevel@tonic-gate 		return(1);
2697c478bd9Sstevel@tonic-gate 	if ((file = expand(file)) == NOSTR)
2707c478bd9Sstevel@tonic-gate 		return(1);
2717c478bd9Sstevel@tonic-gate 	savemsglist(file, msgvec, doign);
2727c478bd9Sstevel@tonic-gate 	return(0);
2737c478bd9Sstevel@tonic-gate }
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate /*
2767c478bd9Sstevel@tonic-gate  * save a message list in a file.
2777c478bd9Sstevel@tonic-gate  * if wr set, doing "write" instead
2787c478bd9Sstevel@tonic-gate  * of "save" or "copy" so don't put
2797c478bd9Sstevel@tonic-gate  * out header.
2807c478bd9Sstevel@tonic-gate  */
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate static	int wr_linecount;		/* count of lines written */
2837c478bd9Sstevel@tonic-gate static	int wr_charcount;		/* char count of lines written */
2847c478bd9Sstevel@tonic-gate static	int wr_inlines;			/* count of lines read */
2857c478bd9Sstevel@tonic-gate static	long wr_maxlines;		/* total lines in message */
2867c478bd9Sstevel@tonic-gate static	int wr_inhead;			/* in header of message */
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate static void
2897c478bd9Sstevel@tonic-gate savemsglist(char *file, int *msgvec, int flag)
2907c478bd9Sstevel@tonic-gate {
2917c478bd9Sstevel@tonic-gate 	register int *ip, mesg;
2927c478bd9Sstevel@tonic-gate 	register struct message *mp;
2937c478bd9Sstevel@tonic-gate 	char *disp;
2947c478bd9Sstevel@tonic-gate 	FILE *obuf;
2957c478bd9Sstevel@tonic-gate 	struct stat statb;
2967c478bd9Sstevel@tonic-gate 	long lc, cc, t;
2977c478bd9Sstevel@tonic-gate 	int bnry, mflag;
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	printf("\"%s\" ", file);
3007c478bd9Sstevel@tonic-gate 	flush();
3017c478bd9Sstevel@tonic-gate 	if (stat(file, &statb) >= 0)
3027c478bd9Sstevel@tonic-gate 		disp = "[Appended]";
3037c478bd9Sstevel@tonic-gate 	else
3047c478bd9Sstevel@tonic-gate 		disp = "[New file]";
3057c478bd9Sstevel@tonic-gate 	if ((obuf = fopen(file, "a")) == NULL) {
3067c478bd9Sstevel@tonic-gate 		perror("");
3077c478bd9Sstevel@tonic-gate 		return;
3087c478bd9Sstevel@tonic-gate 	}
3097c478bd9Sstevel@tonic-gate 	lc = cc = 0;
3107c478bd9Sstevel@tonic-gate 	bnry = 0;
3117c478bd9Sstevel@tonic-gate 	if (flag & S_SAVING)
3127c478bd9Sstevel@tonic-gate 		mflag = (int)value("alwaysignore")?(M_IGNORE|M_SAVING):M_SAVING;
3137c478bd9Sstevel@tonic-gate 	else if (flag & S_NOIGNORE)
3147c478bd9Sstevel@tonic-gate 		mflag = 0;
3157c478bd9Sstevel@tonic-gate 	else
3167c478bd9Sstevel@tonic-gate 		mflag = M_IGNORE;
3177c478bd9Sstevel@tonic-gate 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
3187c478bd9Sstevel@tonic-gate 		mesg = *ip;
3197c478bd9Sstevel@tonic-gate 		mp = &message[mesg-1];
3207c478bd9Sstevel@tonic-gate 		if (!mp->m_text) {
3217c478bd9Sstevel@tonic-gate 			bnry = 1;
3227c478bd9Sstevel@tonic-gate 		}
3237c478bd9Sstevel@tonic-gate 		wr_linecount = 0;
3247c478bd9Sstevel@tonic-gate 		wr_charcount = 0;
3257c478bd9Sstevel@tonic-gate 		if (flag & S_NOHEADER) {
3267c478bd9Sstevel@tonic-gate 			wr_inhead = 1;
3277c478bd9Sstevel@tonic-gate 			wr_maxlines = mp->m_lines;
3287c478bd9Sstevel@tonic-gate 			wr_inlines = 0;
3297c478bd9Sstevel@tonic-gate 			t = msend(mp, obuf, 0, wrputs);
3307c478bd9Sstevel@tonic-gate 		} else {
3317c478bd9Sstevel@tonic-gate 			t = msend(mp, obuf, mflag, svputs);
3327c478bd9Sstevel@tonic-gate 		}
3337c478bd9Sstevel@tonic-gate 		if (t < 0) {
3347c478bd9Sstevel@tonic-gate 			perror(file);
3357c478bd9Sstevel@tonic-gate 			fclose(obuf);
3367c478bd9Sstevel@tonic-gate 			return;
3377c478bd9Sstevel@tonic-gate 		}
3387c478bd9Sstevel@tonic-gate 		touch(mesg);
3397c478bd9Sstevel@tonic-gate 		dot = mp;
3407c478bd9Sstevel@tonic-gate 		lc += wr_linecount;
3417c478bd9Sstevel@tonic-gate 		cc += wr_charcount;
3427c478bd9Sstevel@tonic-gate 		if (flag & S_MARK)
3437c478bd9Sstevel@tonic-gate 			mp->m_flag |= MSAVED;
3447c478bd9Sstevel@tonic-gate 	}
3457c478bd9Sstevel@tonic-gate 	fflush(obuf);
3467c478bd9Sstevel@tonic-gate 	if (fferror(obuf))
3477c478bd9Sstevel@tonic-gate 		perror(file);
3487c478bd9Sstevel@tonic-gate 	fclose(obuf);
3497c478bd9Sstevel@tonic-gate 	if (!bnry) {
3507c478bd9Sstevel@tonic-gate 		printf("%s %ld/%ld\n", disp, lc, cc);
3517c478bd9Sstevel@tonic-gate 	} else {
3527c478bd9Sstevel@tonic-gate 		printf("%s binary/%ld\n", disp, cc);
3537c478bd9Sstevel@tonic-gate 	}
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate static int
3577c478bd9Sstevel@tonic-gate svputs(const char *line, FILE *obuf)
3587c478bd9Sstevel@tonic-gate {
3597c478bd9Sstevel@tonic-gate 	wr_linecount++;
3607c478bd9Sstevel@tonic-gate 	wr_charcount += strlen(line);
3617c478bd9Sstevel@tonic-gate 	return(fputs(line, obuf));
3627c478bd9Sstevel@tonic-gate }
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate static int
3657c478bd9Sstevel@tonic-gate wrputs(const char *line, FILE *obuf)
3667c478bd9Sstevel@tonic-gate {
3677c478bd9Sstevel@tonic-gate 	/*
3687c478bd9Sstevel@tonic-gate 	 * If this is a header line or
3697c478bd9Sstevel@tonic-gate 	 * the last line, don't write it out.  Since we may add a
3707c478bd9Sstevel@tonic-gate 	 * "Status" line the line count may be off by one so insist
3717c478bd9Sstevel@tonic-gate 	 * that the last line is blank before we skip it.
3727c478bd9Sstevel@tonic-gate 	 */
3737c478bd9Sstevel@tonic-gate 	wr_inlines++;
3747c478bd9Sstevel@tonic-gate 	if (wr_inhead) {
3757c478bd9Sstevel@tonic-gate 		if (strcmp(line, "\n") == 0)
3767c478bd9Sstevel@tonic-gate 			wr_inhead = 0;
3777c478bd9Sstevel@tonic-gate 		return(0);
3787c478bd9Sstevel@tonic-gate 	}
3797c478bd9Sstevel@tonic-gate 	if (wr_inlines >= wr_maxlines && strcmp(line, "\n") == 0)
3807c478bd9Sstevel@tonic-gate 		return(0);
3817c478bd9Sstevel@tonic-gate 	wr_linecount++;
3827c478bd9Sstevel@tonic-gate 	wr_charcount += strlen(line);
3837c478bd9Sstevel@tonic-gate 	return(fputs(line, obuf));
3847c478bd9Sstevel@tonic-gate }
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate /*
3877c478bd9Sstevel@tonic-gate  * Write the indicated messages at the end of the passed
3887c478bd9Sstevel@tonic-gate  * file name, minus header and trailing blank line.
3897c478bd9Sstevel@tonic-gate  */
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate int
3927c478bd9Sstevel@tonic-gate swrite(char str[])
3937c478bd9Sstevel@tonic-gate {
3947c478bd9Sstevel@tonic-gate 	register char *file;
3957c478bd9Sstevel@tonic-gate 	int f, *msgvec;
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec);
3987c478bd9Sstevel@tonic-gate 	if ((file = snarf(str, &f, 1)) == NOSTR)
3997c478bd9Sstevel@tonic-gate 		return(1);
4007c478bd9Sstevel@tonic-gate 	if (f==-1)
4017c478bd9Sstevel@tonic-gate 		return(1);
4027c478bd9Sstevel@tonic-gate 	if ((file = expand(file)) == NOSTR)
4037c478bd9Sstevel@tonic-gate 		return(1);
4047c478bd9Sstevel@tonic-gate 	if (!f) {
4057c478bd9Sstevel@tonic-gate 		*msgvec = first(0, MMNORM);
4067c478bd9Sstevel@tonic-gate 		if (*msgvec == NULL) {
4077c478bd9Sstevel@tonic-gate 			printf(gettext("No messages to write.\n"));
4087c478bd9Sstevel@tonic-gate 			return(1);
4097c478bd9Sstevel@tonic-gate 		}
4107c478bd9Sstevel@tonic-gate 		msgvec[1] = NULL;
4117c478bd9Sstevel@tonic-gate 	}
4127c478bd9Sstevel@tonic-gate 	if (f && getmsglist(str, msgvec, 0) < 0)
4137c478bd9Sstevel@tonic-gate 		return(1);
4147c478bd9Sstevel@tonic-gate 	savemsglist(file, msgvec, S_MARK|S_NOHEADER);
4157c478bd9Sstevel@tonic-gate 	return(0);
4167c478bd9Sstevel@tonic-gate }
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate /*
4197c478bd9Sstevel@tonic-gate  * Snarf the file from the end of the command line and
4207c478bd9Sstevel@tonic-gate  * return a pointer to it.  If there is no file attached,
4217c478bd9Sstevel@tonic-gate  * just return NOSTR.  Put a null in front of the file
4227c478bd9Sstevel@tonic-gate  * name so that the message list processing won't see it,
4237c478bd9Sstevel@tonic-gate  * unless the file name is the only thing on the line, in
4247c478bd9Sstevel@tonic-gate  * which case, return 0 in the reference flag variable.
4257c478bd9Sstevel@tonic-gate  */
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate /*
4287c478bd9Sstevel@tonic-gate  * The following definitions are used to characterize the syntactic
4297c478bd9Sstevel@tonic-gate  * category of the preceding character in the following parse procedure.
4307c478bd9Sstevel@tonic-gate  * The variable pc_type assumes these values.
4317c478bd9Sstevel@tonic-gate  */
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate #define	SN_DELIM	1	/* Delimiter (<blank> or line beginning) */
4347c478bd9Sstevel@tonic-gate #define	SN_TOKEN	2	/* A part of a token */
4357c478bd9Sstevel@tonic-gate #define	SN_QUOTE	4	/* An entire quoted string (ie, "...") */
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate char *
4387c478bd9Sstevel@tonic-gate snarf(char linebuf[], int *flag, int erf)
4397c478bd9Sstevel@tonic-gate {
4407c478bd9Sstevel@tonic-gate 	register char *p;		/* utility pointer */
4417c478bd9Sstevel@tonic-gate 	register char qc;		/* quotation character to match */
4427c478bd9Sstevel@tonic-gate 	register unsigned int  pc_type;	/* preceding character type */
4437c478bd9Sstevel@tonic-gate 	register char *tok_beg;		/* beginning of last token */
4447c478bd9Sstevel@tonic-gate 	register char *tok_end;		/* end of last token */
4457c478bd9Sstevel@tonic-gate 	char *line_beg;			/* beginning of line, after */
4467c478bd9Sstevel@tonic-gate 					/* leading whitespace */
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	/*
4497c478bd9Sstevel@tonic-gate 	 * Skip leading whitespace.
4507c478bd9Sstevel@tonic-gate 	 */
4517c478bd9Sstevel@tonic-gate 	for (line_beg = linebuf;
4527c478bd9Sstevel@tonic-gate 	     *line_beg && any(*line_beg, " \t");
4537c478bd9Sstevel@tonic-gate 	     line_beg++) {
4547c478bd9Sstevel@tonic-gate 		/* empty body */
4557c478bd9Sstevel@tonic-gate 	}
4567c478bd9Sstevel@tonic-gate 	if (!*line_beg) {
4577c478bd9Sstevel@tonic-gate 		if (erf) {
4587c478bd9Sstevel@tonic-gate 			printf(gettext("No file specified\n."));
4597c478bd9Sstevel@tonic-gate 		}
4607c478bd9Sstevel@tonic-gate 		*flag = 0;
4617c478bd9Sstevel@tonic-gate 		return(NOSTR);
4627c478bd9Sstevel@tonic-gate 	}
4637c478bd9Sstevel@tonic-gate 	/*
4647c478bd9Sstevel@tonic-gate 	 * Process line from left-to-right, 1 char at a time.
4657c478bd9Sstevel@tonic-gate 	 */
4667c478bd9Sstevel@tonic-gate 	for (pc_type = SN_DELIM, tok_beg = tok_end = NOSTR, p = line_beg;
4677c478bd9Sstevel@tonic-gate 	     *p != '\0'; ) {
4687c478bd9Sstevel@tonic-gate 		if (any(*p, " \t")) {
4697c478bd9Sstevel@tonic-gate 			/* This character is a DELIMITER */
4707c478bd9Sstevel@tonic-gate 			if (pc_type & (SN_TOKEN|SN_QUOTE)) {
4717c478bd9Sstevel@tonic-gate 				tok_end = p - 1;
4727c478bd9Sstevel@tonic-gate 			}
4737c478bd9Sstevel@tonic-gate 			pc_type = SN_DELIM;
4747c478bd9Sstevel@tonic-gate 			p++;
4757c478bd9Sstevel@tonic-gate 		} else if ((qc = *p) == '"' || qc == '\'') {
4767c478bd9Sstevel@tonic-gate 			/* This character is a QUOTE character */
4777c478bd9Sstevel@tonic-gate 			if (pc_type == SN_TOKEN) {
4787c478bd9Sstevel@tonic-gate 				/* embedded quotation symbols are simply */
4797c478bd9Sstevel@tonic-gate 				/* token characters. */
4807c478bd9Sstevel@tonic-gate 				p++;
4817c478bd9Sstevel@tonic-gate 				continue;
4827c478bd9Sstevel@tonic-gate 			}
4837c478bd9Sstevel@tonic-gate 			/* Search for the matching QUOTE character */
4847c478bd9Sstevel@tonic-gate 			for (tok_beg = p, tok_end = NOSTR, p++;
4857c478bd9Sstevel@tonic-gate 			     *p != '\0' && *p != qc;
4867c478bd9Sstevel@tonic-gate 			     p++) {
4877c478bd9Sstevel@tonic-gate 				if (*p == '\\' && *(p+1) == qc) {
4887c478bd9Sstevel@tonic-gate 					p++;
4897c478bd9Sstevel@tonic-gate 				}
4907c478bd9Sstevel@tonic-gate 			}
4917c478bd9Sstevel@tonic-gate 			if (*p == '\0') {
4927c478bd9Sstevel@tonic-gate 				printf(gettext("Syntax error: missing "
4937c478bd9Sstevel@tonic-gate 					       "%c.\n"), qc);
4947c478bd9Sstevel@tonic-gate 				*flag = -1;
4957c478bd9Sstevel@tonic-gate 				return(NOSTR);
4967c478bd9Sstevel@tonic-gate 			}
4977c478bd9Sstevel@tonic-gate 			tok_end = p;
4987c478bd9Sstevel@tonic-gate 			pc_type = SN_QUOTE;
4997c478bd9Sstevel@tonic-gate 			p++;
5007c478bd9Sstevel@tonic-gate 		} else {
5017c478bd9Sstevel@tonic-gate 			/* This character should be a TOKEN character */
5027c478bd9Sstevel@tonic-gate 			if (pc_type & (SN_DELIM|SN_TOKEN)) {
5037c478bd9Sstevel@tonic-gate 				if (pc_type & SN_DELIM) {
5047c478bd9Sstevel@tonic-gate 					tok_beg = p;
5057c478bd9Sstevel@tonic-gate 					tok_end = NOSTR;
5067c478bd9Sstevel@tonic-gate 				}
5077c478bd9Sstevel@tonic-gate 			} else {
5087c478bd9Sstevel@tonic-gate 				printf(gettext("improper quotes"
5097c478bd9Sstevel@tonic-gate 					       " at \"%s\".\n"), p);
5107c478bd9Sstevel@tonic-gate 				*flag = -1;
5117c478bd9Sstevel@tonic-gate 				return(NOSTR);
5127c478bd9Sstevel@tonic-gate 			}
5137c478bd9Sstevel@tonic-gate 			if (*p == '\\' && *++p == '\0') {
5147c478bd9Sstevel@tonic-gate 				printf(gettext("\'\\\' at "
5157c478bd9Sstevel@tonic-gate 					       "end of line.\n"));
5167c478bd9Sstevel@tonic-gate 				*flag = -1;
5177c478bd9Sstevel@tonic-gate 				return(NOSTR);
5187c478bd9Sstevel@tonic-gate 			}
5197c478bd9Sstevel@tonic-gate 			pc_type = SN_TOKEN;
5207c478bd9Sstevel@tonic-gate 			p++;
5217c478bd9Sstevel@tonic-gate 		}
5227c478bd9Sstevel@tonic-gate 	}
5237c478bd9Sstevel@tonic-gate 	if (pc_type == SN_TOKEN) {
5247c478bd9Sstevel@tonic-gate 		tok_end = p - 1;
5257c478bd9Sstevel@tonic-gate 	}
5267c478bd9Sstevel@tonic-gate 	if (tok_beg != NOSTR && tok_end != NOSTR) {
5277c478bd9Sstevel@tonic-gate 		if (tok_beg == line_beg) {
5287c478bd9Sstevel@tonic-gate 			*flag = 0;
5297c478bd9Sstevel@tonic-gate 		} else {
5307c478bd9Sstevel@tonic-gate 			tok_beg[-1] = '\0';
5317c478bd9Sstevel@tonic-gate 			*flag = 1;
5327c478bd9Sstevel@tonic-gate 		}
5337c478bd9Sstevel@tonic-gate 		tok_end[1] = '\0';
5347c478bd9Sstevel@tonic-gate 		return(tok_beg);
5357c478bd9Sstevel@tonic-gate 	} else {
5367c478bd9Sstevel@tonic-gate 		if (erf) {
5377c478bd9Sstevel@tonic-gate 			printf(gettext("No file specified\n."));
5387c478bd9Sstevel@tonic-gate 		}
5397c478bd9Sstevel@tonic-gate 		*flag = 0;
5407c478bd9Sstevel@tonic-gate 		return(NOSTR);
5417c478bd9Sstevel@tonic-gate 	}
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate /*
5457c478bd9Sstevel@tonic-gate  * Delete messages, then type the new dot.
5467c478bd9Sstevel@tonic-gate  */
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate int
5497c478bd9Sstevel@tonic-gate deltype(int msgvec[])
5507c478bd9Sstevel@tonic-gate {
5517c478bd9Sstevel@tonic-gate 	int list[2];
5527c478bd9Sstevel@tonic-gate 	int lastdot;
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 	lastdot = dot - &message[0] + 1;
5557c478bd9Sstevel@tonic-gate 	if (delm(msgvec) >= 0) {
5567c478bd9Sstevel@tonic-gate 		list[0] = dot - &message[0];
5577c478bd9Sstevel@tonic-gate 		list[0]++;
5587c478bd9Sstevel@tonic-gate 		if (list[0] > lastdot) {
5597c478bd9Sstevel@tonic-gate 			touch(list[0]);
5607c478bd9Sstevel@tonic-gate 			list[1] = NULL;
5617c478bd9Sstevel@tonic-gate 			return(type(list));
5627c478bd9Sstevel@tonic-gate 		}
5637c478bd9Sstevel@tonic-gate 		printf(gettext("At EOF\n"));
5647c478bd9Sstevel@tonic-gate 		return(0);
5657c478bd9Sstevel@tonic-gate 	}
5667c478bd9Sstevel@tonic-gate 	else {
5677c478bd9Sstevel@tonic-gate 		printf(gettext("No more messages\n"));
5687c478bd9Sstevel@tonic-gate 		return(0);
5697c478bd9Sstevel@tonic-gate 	}
5707c478bd9Sstevel@tonic-gate }
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate /*
5737c478bd9Sstevel@tonic-gate  * Delete the indicated messages.
5747c478bd9Sstevel@tonic-gate  * Set dot to some nice place afterwards.
5757c478bd9Sstevel@tonic-gate  */
5767c478bd9Sstevel@tonic-gate int
5777c478bd9Sstevel@tonic-gate delm(int *msgvec)
5787c478bd9Sstevel@tonic-gate {
5797c478bd9Sstevel@tonic-gate 	register struct message *mp;
580*6c83d09fSrobbin 	int *ip, mesg;
5817c478bd9Sstevel@tonic-gate 	int last;
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	last = NULL;
5847c478bd9Sstevel@tonic-gate 	for (ip = msgvec; *ip != NULL; ip++) {
5857c478bd9Sstevel@tonic-gate 		mesg = *ip;
5867c478bd9Sstevel@tonic-gate 		touch(mesg);
5877c478bd9Sstevel@tonic-gate 		mp = &message[mesg-1];
5887c478bd9Sstevel@tonic-gate 		mp->m_flag |= MDELETED|MTOUCH;
5897c478bd9Sstevel@tonic-gate 		mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
5907c478bd9Sstevel@tonic-gate 		last = mesg;
5917c478bd9Sstevel@tonic-gate 	}
5927c478bd9Sstevel@tonic-gate 	if (last != NULL) {
5937c478bd9Sstevel@tonic-gate 		dot = &message[last-1];
5947c478bd9Sstevel@tonic-gate 		last = first(0, MDELETED);
5957c478bd9Sstevel@tonic-gate 		if (last != NULL) {
5967c478bd9Sstevel@tonic-gate 			dot = &message[last-1];
5977c478bd9Sstevel@tonic-gate 			return(0);
5987c478bd9Sstevel@tonic-gate 		}
5997c478bd9Sstevel@tonic-gate 		else {
6007c478bd9Sstevel@tonic-gate 			dot = &message[0];
6017c478bd9Sstevel@tonic-gate 			return(-1);
6027c478bd9Sstevel@tonic-gate 		}
6037c478bd9Sstevel@tonic-gate 	}
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 	/*
6067c478bd9Sstevel@tonic-gate 	 * Following can't happen -- it keeps lint happy
6077c478bd9Sstevel@tonic-gate 	 */
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	return(-1);
6107c478bd9Sstevel@tonic-gate }
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate /*
6137c478bd9Sstevel@tonic-gate  * Undelete the indicated messages.
6147c478bd9Sstevel@tonic-gate  */
6157c478bd9Sstevel@tonic-gate int
6167c478bd9Sstevel@tonic-gate undelete(int *msgvec)
6177c478bd9Sstevel@tonic-gate {
6187c478bd9Sstevel@tonic-gate 	register struct message *mp;
619*6c83d09fSrobbin 	int *ip, mesg;
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	for (ip = msgvec; ip-msgvec < msgCount; ip++) {
6227c478bd9Sstevel@tonic-gate 		mesg = *ip;
6237c478bd9Sstevel@tonic-gate 		if (mesg == 0)
6247c478bd9Sstevel@tonic-gate 			return(0);
6257c478bd9Sstevel@tonic-gate 		touch(mesg);
6267c478bd9Sstevel@tonic-gate 		mp = &message[mesg-1];
6277c478bd9Sstevel@tonic-gate 		dot = mp;
6287c478bd9Sstevel@tonic-gate 		mp->m_flag &= ~MDELETED;
6297c478bd9Sstevel@tonic-gate 	}
6307c478bd9Sstevel@tonic-gate 	return(0);
6317c478bd9Sstevel@tonic-gate }
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate /*
6347c478bd9Sstevel@tonic-gate  * Add the given header fields to the retained list.
6357c478bd9Sstevel@tonic-gate  * If no arguments, print the current list of retained fields.
6367c478bd9Sstevel@tonic-gate  */
6377c478bd9Sstevel@tonic-gate int
6387c478bd9Sstevel@tonic-gate retfield(char *list[])
6397c478bd9Sstevel@tonic-gate {
6407c478bd9Sstevel@tonic-gate 	char field[BUFSIZ];
6417c478bd9Sstevel@tonic-gate 	register int h;
6427c478bd9Sstevel@tonic-gate 	register struct ignore *igp;
6437c478bd9Sstevel@tonic-gate 	char **ap;
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	if (argcount(list) == 0)
6467c478bd9Sstevel@tonic-gate 		return(retshow());
6477c478bd9Sstevel@tonic-gate 	for (ap = list; *ap != 0; ap++) {
6487c478bd9Sstevel@tonic-gate 		istrcpy(field, sizeof (field), *ap);
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 		if (member(field, retain))
6517c478bd9Sstevel@tonic-gate 			continue;
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 		h = hash(field);
6547c478bd9Sstevel@tonic-gate 		if ((igp = (struct ignore *)
6557c478bd9Sstevel@tonic-gate 		    calloc(1, sizeof (struct ignore))) == NULL) {
6567c478bd9Sstevel@tonic-gate 			panic("Couldn't allocate memory");
6577c478bd9Sstevel@tonic-gate 		}
6587c478bd9Sstevel@tonic-gate 		if ((igp->i_field = (char *)
6597c478bd9Sstevel@tonic-gate 		    calloc(strlen(field) + 1, sizeof (char))) == NULL) {
6607c478bd9Sstevel@tonic-gate 			panic("Couldn't allocate memory");
6617c478bd9Sstevel@tonic-gate 		}
6627c478bd9Sstevel@tonic-gate 		strcpy(igp->i_field, field);
6637c478bd9Sstevel@tonic-gate 		igp->i_link = retain[h];
6647c478bd9Sstevel@tonic-gate 		retain[h] = igp;
6657c478bd9Sstevel@tonic-gate 		nretained++;
6667c478bd9Sstevel@tonic-gate 	}
6677c478bd9Sstevel@tonic-gate 	return(0);
6687c478bd9Sstevel@tonic-gate }
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate /*
6717c478bd9Sstevel@tonic-gate  * Print out all currently retained fields.
6727c478bd9Sstevel@tonic-gate  */
6737c478bd9Sstevel@tonic-gate static int
6747c478bd9Sstevel@tonic-gate retshow(void)
6757c478bd9Sstevel@tonic-gate {
6767c478bd9Sstevel@tonic-gate 	register int h, count;
6777c478bd9Sstevel@tonic-gate 	struct ignore *igp;
6787c478bd9Sstevel@tonic-gate 	char **ap, **ring;
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	count = 0;
6817c478bd9Sstevel@tonic-gate 	for (h = 0; h < HSHSIZE; h++)
6827c478bd9Sstevel@tonic-gate 		for (igp = retain[h]; igp != 0; igp = igp->i_link)
6837c478bd9Sstevel@tonic-gate 			count++;
6847c478bd9Sstevel@tonic-gate 	if (count == 0) {
6857c478bd9Sstevel@tonic-gate 		printf(gettext("No fields currently being retained.\n"));
6867c478bd9Sstevel@tonic-gate 		return(0);
6877c478bd9Sstevel@tonic-gate 	}
6887c478bd9Sstevel@tonic-gate 	ring = (char **) salloc((count + 1) * sizeof (char *));
6897c478bd9Sstevel@tonic-gate 	ap = ring;
6907c478bd9Sstevel@tonic-gate 	for (h = 0; h < HSHSIZE; h++)
6917c478bd9Sstevel@tonic-gate 		for (igp = retain[h]; igp != 0; igp = igp->i_link)
6927c478bd9Sstevel@tonic-gate 			*ap++ = igp->i_field;
6937c478bd9Sstevel@tonic-gate 	*ap = 0;
6947c478bd9Sstevel@tonic-gate 	qsort(ring, count, sizeof (char *), igcomp);
6957c478bd9Sstevel@tonic-gate 	for (ap = ring; *ap != 0; ap++)
6967c478bd9Sstevel@tonic-gate 		printf("%s\n", *ap);
6977c478bd9Sstevel@tonic-gate 	return(0);
6987c478bd9Sstevel@tonic-gate }
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate /*
7017c478bd9Sstevel@tonic-gate  * Remove a list of fields from the retain list.
7027c478bd9Sstevel@tonic-gate  */
7037c478bd9Sstevel@tonic-gate int
7047c478bd9Sstevel@tonic-gate unretfield(char *list[])
7057c478bd9Sstevel@tonic-gate {
7067c478bd9Sstevel@tonic-gate 	char **ap, field[BUFSIZ];
7077c478bd9Sstevel@tonic-gate 	register int h, count = 0;
7087c478bd9Sstevel@tonic-gate 	register struct ignore *ig1, *ig2;
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	if (argcount(list) == 0) {
7117c478bd9Sstevel@tonic-gate 		for (h = 0; h < HSHSIZE; h++) {
7127c478bd9Sstevel@tonic-gate 			ig1 = retain[h];
7137c478bd9Sstevel@tonic-gate 			while (ig1) {
7147c478bd9Sstevel@tonic-gate 				free(ig1->i_field);
7157c478bd9Sstevel@tonic-gate 				ig2 = ig1->i_link;
7167c478bd9Sstevel@tonic-gate 				free((char *) ig1);
7177c478bd9Sstevel@tonic-gate 				ig1 = ig2;
7187c478bd9Sstevel@tonic-gate 				count++;
7197c478bd9Sstevel@tonic-gate 			}
7207c478bd9Sstevel@tonic-gate 			retain[h] = NULL;
7217c478bd9Sstevel@tonic-gate 		}
7227c478bd9Sstevel@tonic-gate 		if (count == 0)
7237c478bd9Sstevel@tonic-gate 			printf(gettext(
7247c478bd9Sstevel@tonic-gate 			    "No fields currently being retained.\n"));
7257c478bd9Sstevel@tonic-gate 		nretained = 0;
7267c478bd9Sstevel@tonic-gate 		return 0;
7277c478bd9Sstevel@tonic-gate 	}
7287c478bd9Sstevel@tonic-gate 	for (ap = list; *ap; ap++) {
7297c478bd9Sstevel@tonic-gate 		istrcpy(field, sizeof (field), *ap);
7307c478bd9Sstevel@tonic-gate 		h = hash(field);
7317c478bd9Sstevel@tonic-gate 		for (ig1 = retain[h]; ig1; ig2 = ig1, ig1 = ig1->i_link)
7327c478bd9Sstevel@tonic-gate 			if (strcmp(ig1->i_field, field) == 0) {
7337c478bd9Sstevel@tonic-gate 				if (ig1 == retain[h])
7347c478bd9Sstevel@tonic-gate 					retain[h] = ig1->i_link;
7357c478bd9Sstevel@tonic-gate 				else
7367c478bd9Sstevel@tonic-gate 					ig2->i_link = ig1->i_link;
7377c478bd9Sstevel@tonic-gate 				free(ig1->i_field);
7387c478bd9Sstevel@tonic-gate 				free((char *) ig1);
7397c478bd9Sstevel@tonic-gate 				nretained--;
7407c478bd9Sstevel@tonic-gate 				break;
7417c478bd9Sstevel@tonic-gate 			}
7427c478bd9Sstevel@tonic-gate 	}
7437c478bd9Sstevel@tonic-gate 	return 0;
7447c478bd9Sstevel@tonic-gate }
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate /*
7477c478bd9Sstevel@tonic-gate  * Add the given header fields to the ignored list.
7487c478bd9Sstevel@tonic-gate  * If no arguments, print the current list of ignored fields.
7497c478bd9Sstevel@tonic-gate  */
7507c478bd9Sstevel@tonic-gate int
7517c478bd9Sstevel@tonic-gate igfield(char *list[])
7527c478bd9Sstevel@tonic-gate {
7537c478bd9Sstevel@tonic-gate 	char field[BUFSIZ];
7547c478bd9Sstevel@tonic-gate 	register int h;
7557c478bd9Sstevel@tonic-gate 	register struct ignore *igp;
7567c478bd9Sstevel@tonic-gate 	char **ap;
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	if (argcount(list) == 0)
7597c478bd9Sstevel@tonic-gate 		return(igshow());
7607c478bd9Sstevel@tonic-gate 	for (ap = list; *ap != 0; ap++) {
7617c478bd9Sstevel@tonic-gate 		if (isign(*ap, 0))
7627c478bd9Sstevel@tonic-gate 			continue;
7637c478bd9Sstevel@tonic-gate 		istrcpy(field, sizeof (field), *ap);
7647c478bd9Sstevel@tonic-gate 		h = hash(field);
7657c478bd9Sstevel@tonic-gate 		if ((igp = (struct ignore *)
7667c478bd9Sstevel@tonic-gate 		    calloc(1, sizeof (struct ignore))) == NULL) {
7677c478bd9Sstevel@tonic-gate 			panic("Couldn't allocate memory");
7687c478bd9Sstevel@tonic-gate 		}
7697c478bd9Sstevel@tonic-gate 		if ((igp->i_field = (char *)
7707c478bd9Sstevel@tonic-gate 		    calloc((unsigned)strlen(field) + 1,
7717c478bd9Sstevel@tonic-gate 		    sizeof (char))) == NULL) {
7727c478bd9Sstevel@tonic-gate 			panic("Couldn't allocate memory");
7737c478bd9Sstevel@tonic-gate 		}
7747c478bd9Sstevel@tonic-gate 		strcpy(igp->i_field, field);
7757c478bd9Sstevel@tonic-gate 		igp->i_link = ignore[h];
7767c478bd9Sstevel@tonic-gate 		ignore[h] = igp;
7777c478bd9Sstevel@tonic-gate 	}
7787c478bd9Sstevel@tonic-gate 	return(0);
7797c478bd9Sstevel@tonic-gate }
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate /*
7827c478bd9Sstevel@tonic-gate  * Print out all currently ignored fields.
7837c478bd9Sstevel@tonic-gate  */
7847c478bd9Sstevel@tonic-gate static int
7857c478bd9Sstevel@tonic-gate igshow(void)
7867c478bd9Sstevel@tonic-gate {
7877c478bd9Sstevel@tonic-gate 	register int h, count;
7887c478bd9Sstevel@tonic-gate 	struct ignore *igp;
7897c478bd9Sstevel@tonic-gate 	char **ap, **ring;
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 	count = 0;
7927c478bd9Sstevel@tonic-gate 	for (h = 0; h < HSHSIZE; h++)
7937c478bd9Sstevel@tonic-gate 		for (igp = ignore[h]; igp != 0; igp = igp->i_link)
7947c478bd9Sstevel@tonic-gate 			count++;
7957c478bd9Sstevel@tonic-gate 	if (count == 0) {
7967c478bd9Sstevel@tonic-gate 		printf(gettext("No fields currently being ignored.\n"));
7977c478bd9Sstevel@tonic-gate 		return(0);
7987c478bd9Sstevel@tonic-gate 	}
7997c478bd9Sstevel@tonic-gate 	ring = (char **) salloc((count + 1) * sizeof (char *));
8007c478bd9Sstevel@tonic-gate 	ap = ring;
8017c478bd9Sstevel@tonic-gate 	for (h = 0; h < HSHSIZE; h++)
8027c478bd9Sstevel@tonic-gate 		for (igp = ignore[h]; igp != 0; igp = igp->i_link)
8037c478bd9Sstevel@tonic-gate 			*ap++ = igp->i_field;
8047c478bd9Sstevel@tonic-gate 	*ap = 0;
8057c478bd9Sstevel@tonic-gate 	qsort((char *) ring, (unsigned) count, sizeof (char *), igcomp);
8067c478bd9Sstevel@tonic-gate 	for (ap = ring; *ap != 0; ap++)
8077c478bd9Sstevel@tonic-gate 		printf("%s\n", *ap);
8087c478bd9Sstevel@tonic-gate 	return(0);
8097c478bd9Sstevel@tonic-gate }
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate /*
8127c478bd9Sstevel@tonic-gate  * Compare two names for sorting ignored field list.
8137c478bd9Sstevel@tonic-gate  */
8147c478bd9Sstevel@tonic-gate static int
8157c478bd9Sstevel@tonic-gate igcomp(const void *l, const void *r)
8167c478bd9Sstevel@tonic-gate {
8177c478bd9Sstevel@tonic-gate 	return(strcmp(*(char **)l, *(char **)r));
8187c478bd9Sstevel@tonic-gate }
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate /*
8217c478bd9Sstevel@tonic-gate  * Remove a list of fields from the ignore list.
8227c478bd9Sstevel@tonic-gate  */
8237c478bd9Sstevel@tonic-gate int
8247c478bd9Sstevel@tonic-gate unigfield(char *list[])
8257c478bd9Sstevel@tonic-gate {
8267c478bd9Sstevel@tonic-gate 	char **ap, field[BUFSIZ];
8277c478bd9Sstevel@tonic-gate 	register int h, count = 0;
8287c478bd9Sstevel@tonic-gate 	register struct ignore *ig1, *ig2;
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 	if (argcount(list) == 0) {
8317c478bd9Sstevel@tonic-gate 		for (h = 0; h < HSHSIZE; h++) {
8327c478bd9Sstevel@tonic-gate 			ig1 = ignore[h];
8337c478bd9Sstevel@tonic-gate 			while (ig1) {
8347c478bd9Sstevel@tonic-gate 				free(ig1->i_field);
8357c478bd9Sstevel@tonic-gate 				ig2 = ig1->i_link;
8367c478bd9Sstevel@tonic-gate 				free((char *) ig1);
8377c478bd9Sstevel@tonic-gate 				ig1 = ig2;
8387c478bd9Sstevel@tonic-gate 				count++;
8397c478bd9Sstevel@tonic-gate 			}
8407c478bd9Sstevel@tonic-gate 			ignore[h] = NULL;
8417c478bd9Sstevel@tonic-gate 		}
8427c478bd9Sstevel@tonic-gate 		if (count == 0)
8437c478bd9Sstevel@tonic-gate 			printf(gettext("No fields currently being ignored.\n"));
8447c478bd9Sstevel@tonic-gate 		return 0;
8457c478bd9Sstevel@tonic-gate 	}
8467c478bd9Sstevel@tonic-gate 	for (ap = list; *ap; ap++) {
8477c478bd9Sstevel@tonic-gate 		istrcpy(field, sizeof (field), *ap);
8487c478bd9Sstevel@tonic-gate 		h = hash(field);
8497c478bd9Sstevel@tonic-gate 		for (ig1 = ignore[h]; ig1; ig2 = ig1, ig1 = ig1->i_link)
8507c478bd9Sstevel@tonic-gate 			if (strcmp(ig1->i_field, field) == 0) {
8517c478bd9Sstevel@tonic-gate 				if (ig1 == ignore[h])
8527c478bd9Sstevel@tonic-gate 					ignore[h] = ig1->i_link;
8537c478bd9Sstevel@tonic-gate 				else
8547c478bd9Sstevel@tonic-gate 					ig2->i_link = ig1->i_link;
8557c478bd9Sstevel@tonic-gate 				free(ig1->i_field);
8567c478bd9Sstevel@tonic-gate 				free((char *) ig1);
8577c478bd9Sstevel@tonic-gate 				break;
8587c478bd9Sstevel@tonic-gate 			}
8597c478bd9Sstevel@tonic-gate 	}
8607c478bd9Sstevel@tonic-gate 	return 0;
8617c478bd9Sstevel@tonic-gate }
862