xref: /illumos-gate/usr/src/cmd/mailx/cmd2.c (revision 46d64c14)
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
5eb2b0a61Sas  * Common Development and Distribution License (the "License").
6eb2b0a61Sas  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate 
227c478bd9Sstevel@tonic-gate /*
232f72c445SViswanathan Kannappan  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
276c83d09fSrobbin /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
286c83d09fSrobbin /*	  All Rights Reserved  	*/
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
327c478bd9Sstevel@tonic-gate  * The Regents of the University of California
337c478bd9Sstevel@tonic-gate  * All Rights Reserved
347c478bd9Sstevel@tonic-gate  *
357c478bd9Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
367c478bd9Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
377c478bd9Sstevel@tonic-gate  * contributors.
387c478bd9Sstevel@tonic-gate  */
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate #include "rcv.h"
417c478bd9Sstevel@tonic-gate #include <locale.h>
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /*
447c478bd9Sstevel@tonic-gate  * mailx -- a modified version of a University of California at Berkeley
457c478bd9Sstevel@tonic-gate  *	mail program
467c478bd9Sstevel@tonic-gate  *
477c478bd9Sstevel@tonic-gate  * More user commands.
487c478bd9Sstevel@tonic-gate  */
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate static int	igshow(void);
517c478bd9Sstevel@tonic-gate static int	igcomp(const void *l, const void *r);
527c478bd9Sstevel@tonic-gate static int	save1(char str[], int mark);
537c478bd9Sstevel@tonic-gate static int	Save1(int *msgvec, int mark);
547c478bd9Sstevel@tonic-gate static void	savemsglist(char *file, int *msgvec, int flag);
557c478bd9Sstevel@tonic-gate static int	put1(char str[], int doign);
567c478bd9Sstevel@tonic-gate static int	svputs(const char *line, FILE *obuf);
577c478bd9Sstevel@tonic-gate static int	wrputs(const char *line, FILE *obuf);
587c478bd9Sstevel@tonic-gate static int	retshow(void);
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate /* flags for savemsglist() */
617c478bd9Sstevel@tonic-gate #define	S_MARK		1		/* mark the message as saved */
627c478bd9Sstevel@tonic-gate #define	S_NOHEADER	2		/* don't write out the header */
637c478bd9Sstevel@tonic-gate #define	S_SAVING	4		/* doing save/copy */
647c478bd9Sstevel@tonic-gate #define	S_NOIGNORE	8		/* don't do ignore processing */
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate /*
67eb2b0a61Sas  * If any arguments were given, print the first message
68eb2b0a61Sas  * identified by the first argument. If no arguments are given,
69eb2b0a61Sas  * print the next applicable message after dot.
707c478bd9Sstevel@tonic-gate  */
717c478bd9Sstevel@tonic-gate 
72eb2b0a61Sas int
next(int * msgvec)737c478bd9Sstevel@tonic-gate next(int *msgvec)
747c478bd9Sstevel@tonic-gate {
757c478bd9Sstevel@tonic-gate 	register struct message *mp;
76eb2b0a61Sas 	int list[2];
777c478bd9Sstevel@tonic-gate 
78*46d64c14SToomas Soome 	if (*msgvec != 0) {
79eb2b0a61Sas 		if (*msgvec < 0) {
80eb2b0a61Sas 			printf((gettext("Negative message given\n")));
81eb2b0a61Sas 			return (1);
82eb2b0a61Sas 		}
83eb2b0a61Sas 		mp = &message[*msgvec - 1];
84eb2b0a61Sas 		if ((mp->m_flag & MDELETED) == 0) {
85eb2b0a61Sas 			dot = mp;
86eb2b0a61Sas 			goto hitit;
87eb2b0a61Sas 		}
88eb2b0a61Sas 		printf(gettext("No applicable message\n"));
89eb2b0a61Sas 		return (1);
907c478bd9Sstevel@tonic-gate 	}
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate 	/*
937c478bd9Sstevel@tonic-gate 	 * If this is the first command, select message 1.
947c478bd9Sstevel@tonic-gate 	 * Note that this must exist for us to get here at all.
957c478bd9Sstevel@tonic-gate 	 */
967c478bd9Sstevel@tonic-gate 	if (!sawcom)
977c478bd9Sstevel@tonic-gate 		goto hitit;
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	/*
1007c478bd9Sstevel@tonic-gate 	 * Just find the next good message after dot, no
1017c478bd9Sstevel@tonic-gate 	 * wraparound.
1027c478bd9Sstevel@tonic-gate 	 */
1037c478bd9Sstevel@tonic-gate 	for (mp = dot+1; mp < &message[msgCount]; mp++)
1047c478bd9Sstevel@tonic-gate 		if ((mp->m_flag & (MDELETED|MSAVED)) == 0)
1057c478bd9Sstevel@tonic-gate 			break;
1067c478bd9Sstevel@tonic-gate 	if (mp >= &message[msgCount]) {
1077c478bd9Sstevel@tonic-gate 		printf(gettext("At EOF\n"));
108eb2b0a61Sas 		return (0);
1097c478bd9Sstevel@tonic-gate 	}
1107c478bd9Sstevel@tonic-gate 	dot = mp;
1117c478bd9Sstevel@tonic-gate hitit:
1127c478bd9Sstevel@tonic-gate 	/*
1137c478bd9Sstevel@tonic-gate 	 * Print dot.
1147c478bd9Sstevel@tonic-gate 	 */
1157c478bd9Sstevel@tonic-gate 	list[0] = dot - &message[0] + 1;
116*46d64c14SToomas Soome 	list[1] = 0;
117eb2b0a61Sas 	return (type(list));
1187c478bd9Sstevel@tonic-gate }
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate /*
1217c478bd9Sstevel@tonic-gate  * Save a message in a file.  Mark the message as saved
1227c478bd9Sstevel@tonic-gate  * so we can discard when the user quits.
1237c478bd9Sstevel@tonic-gate  */
124eb2b0a61Sas int
save(char str[])1257c478bd9Sstevel@tonic-gate save(char str[])
1267c478bd9Sstevel@tonic-gate {
127eb2b0a61Sas 	return (save1(str, S_MARK));
1287c478bd9Sstevel@tonic-gate }
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate /*
1317c478bd9Sstevel@tonic-gate  * Copy a message to a file without affected its saved-ness
1327c478bd9Sstevel@tonic-gate  */
133eb2b0a61Sas int
copycmd(char str[])1347c478bd9Sstevel@tonic-gate copycmd(char str[])
1357c478bd9Sstevel@tonic-gate {
136eb2b0a61Sas 	return (save1(str, 0));
1377c478bd9Sstevel@tonic-gate }
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate /*
1407c478bd9Sstevel@tonic-gate  * Save/copy the indicated messages at the end of the passed file name.
1417c478bd9Sstevel@tonic-gate  * If mark is true, mark the message "saved."
1427c478bd9Sstevel@tonic-gate  */
143eb2b0a61Sas static int
save1(char str[],int mark)1447c478bd9Sstevel@tonic-gate save1(char str[], int mark)
1457c478bd9Sstevel@tonic-gate {
1467c478bd9Sstevel@tonic-gate 	char *file, *cmd;
1477c478bd9Sstevel@tonic-gate 	int f, *msgvec;
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	cmd = mark ? "save" : "copy";
150eb2b0a61Sas 	msgvec = (int *)salloc((msgCount + 2) * sizeof (*msgvec));
1517c478bd9Sstevel@tonic-gate 	if ((file = snarf(str, &f, 0)) == NOSTR)
1527c478bd9Sstevel@tonic-gate 		file = Getf("MBOX");
153eb2b0a61Sas 	if (f == -1)
154eb2b0a61Sas 		return (1);
1557c478bd9Sstevel@tonic-gate 	if (!f) {
1567c478bd9Sstevel@tonic-gate 		*msgvec = first(0, MMNORM);
157*46d64c14SToomas Soome 		if (*msgvec == 0) {
1587c478bd9Sstevel@tonic-gate 			printf(gettext("No messages to %s.\n"), cmd);
159eb2b0a61Sas 			return (1);
1607c478bd9Sstevel@tonic-gate 		}
161*46d64c14SToomas Soome 		msgvec[1] = 0;
1627c478bd9Sstevel@tonic-gate 	}
1637c478bd9Sstevel@tonic-gate 	if (f && getmsglist(str, msgvec, 0) < 0)
164eb2b0a61Sas 		return (1);
1657c478bd9Sstevel@tonic-gate 	if ((file = expand(file)) == NOSTR)
166eb2b0a61Sas 		return (1);
1677c478bd9Sstevel@tonic-gate 	savemsglist(file, msgvec, mark | S_SAVING);
168eb2b0a61Sas 	return (0);
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate 
171eb2b0a61Sas int
Save(int * msgvec)1727c478bd9Sstevel@tonic-gate Save(int *msgvec)
1737c478bd9Sstevel@tonic-gate {
174eb2b0a61Sas 	return (Save1(msgvec, S_MARK));
1757c478bd9Sstevel@tonic-gate }
1767c478bd9Sstevel@tonic-gate 
177eb2b0a61Sas int
Copy(int * msgvec)1787c478bd9Sstevel@tonic-gate Copy(int *msgvec)
1797c478bd9Sstevel@tonic-gate {
180eb2b0a61Sas 	return (Save1(msgvec, 0));
1817c478bd9Sstevel@tonic-gate }
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate /*
1847c478bd9Sstevel@tonic-gate  * save/copy the indicated messages at the end of a file named
1857c478bd9Sstevel@tonic-gate  * by the sender of the first message in the msglist.
1867c478bd9Sstevel@tonic-gate  */
187eb2b0a61Sas static int
Save1(int * msgvec,int mark)1887c478bd9Sstevel@tonic-gate Save1(int *msgvec, int mark)
1897c478bd9Sstevel@tonic-gate {
1907c478bd9Sstevel@tonic-gate 	register char *from;
1917c478bd9Sstevel@tonic-gate 	char recfile[BUFSIZ];
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate #ifdef notdef
1947c478bd9Sstevel@tonic-gate 	from = striphosts(nameof(&message[*msgvec-1], 0));
1957c478bd9Sstevel@tonic-gate #else
1967c478bd9Sstevel@tonic-gate 	from = nameof(&message[*msgvec-1]);
1977c478bd9Sstevel@tonic-gate #endif
1987c478bd9Sstevel@tonic-gate 	getrecf(from, recfile, 1, sizeof (recfile));
1997c478bd9Sstevel@tonic-gate 	if (*recfile != '\0')
2007c478bd9Sstevel@tonic-gate 		savemsglist(safeexpand(recfile), msgvec, mark | S_SAVING);
201eb2b0a61Sas 	return (0);
2027c478bd9Sstevel@tonic-gate }
2037c478bd9Sstevel@tonic-gate 
204eb2b0a61Sas int
sput(char str[])2057c478bd9Sstevel@tonic-gate sput(char str[])
2067c478bd9Sstevel@tonic-gate {
207eb2b0a61Sas 	return (put1(str, 0));
2087c478bd9Sstevel@tonic-gate }
2097c478bd9Sstevel@tonic-gate 
210eb2b0a61Sas int
Sput(char str[])2117c478bd9Sstevel@tonic-gate Sput(char str[])
2127c478bd9Sstevel@tonic-gate {
213eb2b0a61Sas 	return (put1(str, S_NOIGNORE));
2147c478bd9Sstevel@tonic-gate }
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate /*
2177c478bd9Sstevel@tonic-gate  * Put the indicated messages at the end of the passed file name.
2187c478bd9Sstevel@tonic-gate  */
219eb2b0a61Sas static int
put1(char str[],int doign)2207c478bd9Sstevel@tonic-gate put1(char str[], int doign)
2217c478bd9Sstevel@tonic-gate {
2227c478bd9Sstevel@tonic-gate 	char *file;
2237c478bd9Sstevel@tonic-gate 	int f, *msgvec;
2247c478bd9Sstevel@tonic-gate 
225eb2b0a61Sas 	msgvec = (int *)salloc((msgCount + 2) * sizeof (*msgvec));
2267c478bd9Sstevel@tonic-gate 	if ((file = snarf(str, &f, 0)) == NOSTR)
2277c478bd9Sstevel@tonic-gate 		file = Getf("MBOX");
228eb2b0a61Sas 	if (f == -1)
229eb2b0a61Sas 		return (1);
2307c478bd9Sstevel@tonic-gate 	if (!f) {
2317c478bd9Sstevel@tonic-gate 		*msgvec = first(0, MMNORM);
232*46d64c14SToomas Soome 		if (*msgvec == 0) {
2337c478bd9Sstevel@tonic-gate 			printf(gettext("No messages to put.\n"));
234eb2b0a61Sas 			return (1);
2357c478bd9Sstevel@tonic-gate 		}
236*46d64c14SToomas Soome 		msgvec[1] = 0;
2377c478bd9Sstevel@tonic-gate 	}
2387c478bd9Sstevel@tonic-gate 	if (f && getmsglist(str, msgvec, 0) < 0)
239eb2b0a61Sas 		return (1);
2407c478bd9Sstevel@tonic-gate 	if ((file = expand(file)) == NOSTR)
241eb2b0a61Sas 		return (1);
2427c478bd9Sstevel@tonic-gate 	savemsglist(file, msgvec, doign);
243eb2b0a61Sas 	return (0);
2447c478bd9Sstevel@tonic-gate }
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate /*
2477c478bd9Sstevel@tonic-gate  * save a message list in a file.
2487c478bd9Sstevel@tonic-gate  * if wr set, doing "write" instead
2497c478bd9Sstevel@tonic-gate  * of "save" or "copy" so don't put
2507c478bd9Sstevel@tonic-gate  * out header.
2517c478bd9Sstevel@tonic-gate  */
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate static	int wr_linecount;		/* count of lines written */
2547c478bd9Sstevel@tonic-gate static	int wr_charcount;		/* char count of lines written */
2557c478bd9Sstevel@tonic-gate static	int wr_inlines;			/* count of lines read */
2567c478bd9Sstevel@tonic-gate static	long wr_maxlines;		/* total lines in message */
2577c478bd9Sstevel@tonic-gate static	int wr_inhead;			/* in header of message */
2587c478bd9Sstevel@tonic-gate 
259eb2b0a61Sas static void
savemsglist(char * file,int * msgvec,int flag)2607c478bd9Sstevel@tonic-gate savemsglist(char *file, int *msgvec, int flag)
2617c478bd9Sstevel@tonic-gate {
2627c478bd9Sstevel@tonic-gate 	register int *ip, mesg;
2637c478bd9Sstevel@tonic-gate 	register struct message *mp;
2647c478bd9Sstevel@tonic-gate 	char *disp;
2657c478bd9Sstevel@tonic-gate 	FILE *obuf;
2667c478bd9Sstevel@tonic-gate 	struct stat statb;
2677c478bd9Sstevel@tonic-gate 	long lc, cc, t;
2687c478bd9Sstevel@tonic-gate 	int bnry, mflag;
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	printf("\"%s\" ", file);
2717c478bd9Sstevel@tonic-gate 	flush();
2727c478bd9Sstevel@tonic-gate 	if (stat(file, &statb) >= 0)
2737c478bd9Sstevel@tonic-gate 		disp = "[Appended]";
2747c478bd9Sstevel@tonic-gate 	else
2757c478bd9Sstevel@tonic-gate 		disp = "[New file]";
2767c478bd9Sstevel@tonic-gate 	if ((obuf = fopen(file, "a")) == NULL) {
2777c478bd9Sstevel@tonic-gate 		perror("");
2787c478bd9Sstevel@tonic-gate 		return;
2797c478bd9Sstevel@tonic-gate 	}
2807c478bd9Sstevel@tonic-gate 	lc = cc = 0;
2817c478bd9Sstevel@tonic-gate 	bnry = 0;
2827c478bd9Sstevel@tonic-gate 	if (flag & S_SAVING)
2837c478bd9Sstevel@tonic-gate 		mflag = (int)value("alwaysignore")?(M_IGNORE|M_SAVING):M_SAVING;
2847c478bd9Sstevel@tonic-gate 	else if (flag & S_NOIGNORE)
2857c478bd9Sstevel@tonic-gate 		mflag = 0;
2867c478bd9Sstevel@tonic-gate 	else
2877c478bd9Sstevel@tonic-gate 		mflag = M_IGNORE;
2887c478bd9Sstevel@tonic-gate 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
2897c478bd9Sstevel@tonic-gate 		mesg = *ip;
2907c478bd9Sstevel@tonic-gate 		mp = &message[mesg-1];
2917c478bd9Sstevel@tonic-gate 		if (!mp->m_text) {
2927c478bd9Sstevel@tonic-gate 			bnry = 1;
2937c478bd9Sstevel@tonic-gate 		}
2947c478bd9Sstevel@tonic-gate 		wr_linecount = 0;
2957c478bd9Sstevel@tonic-gate 		wr_charcount = 0;
2967c478bd9Sstevel@tonic-gate 		if (flag & S_NOHEADER) {
2977c478bd9Sstevel@tonic-gate 			wr_inhead = 1;
2987c478bd9Sstevel@tonic-gate 			wr_maxlines = mp->m_lines;
2997c478bd9Sstevel@tonic-gate 			wr_inlines = 0;
3007c478bd9Sstevel@tonic-gate 			t = msend(mp, obuf, 0, wrputs);
3017c478bd9Sstevel@tonic-gate 		} else {
3027c478bd9Sstevel@tonic-gate 			t = msend(mp, obuf, mflag, svputs);
3037c478bd9Sstevel@tonic-gate 		}
3047c478bd9Sstevel@tonic-gate 		if (t < 0) {
3057c478bd9Sstevel@tonic-gate 			perror(file);
3067c478bd9Sstevel@tonic-gate 			fclose(obuf);
3077c478bd9Sstevel@tonic-gate 			return;
3087c478bd9Sstevel@tonic-gate 		}
3097c478bd9Sstevel@tonic-gate 		touch(mesg);
3107c478bd9Sstevel@tonic-gate 		dot = mp;
3117c478bd9Sstevel@tonic-gate 		lc += wr_linecount;
3127c478bd9Sstevel@tonic-gate 		cc += wr_charcount;
3137c478bd9Sstevel@tonic-gate 		if (flag & S_MARK)
3147c478bd9Sstevel@tonic-gate 			mp->m_flag |= MSAVED;
3157c478bd9Sstevel@tonic-gate 	}
3167c478bd9Sstevel@tonic-gate 	fflush(obuf);
3177c478bd9Sstevel@tonic-gate 	if (fferror(obuf))
3187c478bd9Sstevel@tonic-gate 		perror(file);
3197c478bd9Sstevel@tonic-gate 	fclose(obuf);
3207c478bd9Sstevel@tonic-gate 	if (!bnry) {
3217c478bd9Sstevel@tonic-gate 		printf("%s %ld/%ld\n", disp, lc, cc);
3227c478bd9Sstevel@tonic-gate 	} else {
3237c478bd9Sstevel@tonic-gate 		printf("%s binary/%ld\n", disp, cc);
3247c478bd9Sstevel@tonic-gate 	}
3257c478bd9Sstevel@tonic-gate }
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate static int
svputs(const char * line,FILE * obuf)3287c478bd9Sstevel@tonic-gate svputs(const char *line, FILE *obuf)
3297c478bd9Sstevel@tonic-gate {
3307c478bd9Sstevel@tonic-gate 	wr_linecount++;
3317c478bd9Sstevel@tonic-gate 	wr_charcount += strlen(line);
332eb2b0a61Sas 	return (fputs(line, obuf));
3337c478bd9Sstevel@tonic-gate }
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate static int
wrputs(const char * line,FILE * obuf)3367c478bd9Sstevel@tonic-gate wrputs(const char *line, FILE *obuf)
3377c478bd9Sstevel@tonic-gate {
3387c478bd9Sstevel@tonic-gate 	/*
3397c478bd9Sstevel@tonic-gate 	 * If this is a header line or
3407c478bd9Sstevel@tonic-gate 	 * the last line, don't write it out.  Since we may add a
3417c478bd9Sstevel@tonic-gate 	 * "Status" line the line count may be off by one so insist
3427c478bd9Sstevel@tonic-gate 	 * that the last line is blank before we skip it.
3437c478bd9Sstevel@tonic-gate 	 */
3447c478bd9Sstevel@tonic-gate 	wr_inlines++;
3457c478bd9Sstevel@tonic-gate 	if (wr_inhead) {
3467c478bd9Sstevel@tonic-gate 		if (strcmp(line, "\n") == 0)
3477c478bd9Sstevel@tonic-gate 			wr_inhead = 0;
348eb2b0a61Sas 		return (0);
3497c478bd9Sstevel@tonic-gate 	}
3507c478bd9Sstevel@tonic-gate 	if (wr_inlines >= wr_maxlines && strcmp(line, "\n") == 0)
351eb2b0a61Sas 		return (0);
3527c478bd9Sstevel@tonic-gate 	wr_linecount++;
3537c478bd9Sstevel@tonic-gate 	wr_charcount += strlen(line);
354eb2b0a61Sas 	return (fputs(line, obuf));
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate /*
3587c478bd9Sstevel@tonic-gate  * Write the indicated messages at the end of the passed
3597c478bd9Sstevel@tonic-gate  * file name, minus header and trailing blank line.
3607c478bd9Sstevel@tonic-gate  */
3617c478bd9Sstevel@tonic-gate 
362eb2b0a61Sas int
swrite(char str[])3637c478bd9Sstevel@tonic-gate swrite(char str[])
3647c478bd9Sstevel@tonic-gate {
3657c478bd9Sstevel@tonic-gate 	register char *file;
3667c478bd9Sstevel@tonic-gate 	int f, *msgvec;
3677c478bd9Sstevel@tonic-gate 
368eb2b0a61Sas 	msgvec = (int *)salloc((msgCount + 2) * sizeof (*msgvec));
3697c478bd9Sstevel@tonic-gate 	if ((file = snarf(str, &f, 1)) == NOSTR)
370eb2b0a61Sas 		return (1);
371eb2b0a61Sas 	if (f == -1)
372eb2b0a61Sas 		return (1);
3737c478bd9Sstevel@tonic-gate 	if ((file = expand(file)) == NOSTR)
374eb2b0a61Sas 		return (1);
3757c478bd9Sstevel@tonic-gate 	if (!f) {
3767c478bd9Sstevel@tonic-gate 		*msgvec = first(0, MMNORM);
377*46d64c14SToomas Soome 		if (*msgvec == 0) {
3787c478bd9Sstevel@tonic-gate 			printf(gettext("No messages to write.\n"));
379eb2b0a61Sas 			return (1);
3807c478bd9Sstevel@tonic-gate 		}
381*46d64c14SToomas Soome 		msgvec[1] = 0;
3827c478bd9Sstevel@tonic-gate 	}
3837c478bd9Sstevel@tonic-gate 	if (f && getmsglist(str, msgvec, 0) < 0)
384eb2b0a61Sas 		return (1);
3857c478bd9Sstevel@tonic-gate 	savemsglist(file, msgvec, S_MARK|S_NOHEADER);
386eb2b0a61Sas 	return (0);
3877c478bd9Sstevel@tonic-gate }
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate /*
3907c478bd9Sstevel@tonic-gate  * Snarf the file from the end of the command line and
3917c478bd9Sstevel@tonic-gate  * return a pointer to it.  If there is no file attached,
3927c478bd9Sstevel@tonic-gate  * just return NOSTR.  Put a null in front of the file
3937c478bd9Sstevel@tonic-gate  * name so that the message list processing won't see it,
3947c478bd9Sstevel@tonic-gate  * unless the file name is the only thing on the line, in
3957c478bd9Sstevel@tonic-gate  * which case, return 0 in the reference flag variable.
3967c478bd9Sstevel@tonic-gate  */
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate /*
3997c478bd9Sstevel@tonic-gate  * The following definitions are used to characterize the syntactic
4007c478bd9Sstevel@tonic-gate  * category of the preceding character in the following parse procedure.
4017c478bd9Sstevel@tonic-gate  * The variable pc_type assumes these values.
4027c478bd9Sstevel@tonic-gate  */
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate #define	SN_DELIM	1	/* Delimiter (<blank> or line beginning) */
4057c478bd9Sstevel@tonic-gate #define	SN_TOKEN	2	/* A part of a token */
4067c478bd9Sstevel@tonic-gate #define	SN_QUOTE	4	/* An entire quoted string (ie, "...") */
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate char *
snarf(char linebuf[],int * flag,int erf)4097c478bd9Sstevel@tonic-gate snarf(char linebuf[], int *flag, int erf)
4107c478bd9Sstevel@tonic-gate {
4117c478bd9Sstevel@tonic-gate 	register char *p;		/* utility pointer */
4127c478bd9Sstevel@tonic-gate 	register char qc;		/* quotation character to match */
4137c478bd9Sstevel@tonic-gate 	register unsigned int  pc_type;	/* preceding character type */
4147c478bd9Sstevel@tonic-gate 	register char *tok_beg;		/* beginning of last token */
4157c478bd9Sstevel@tonic-gate 	register char *tok_end;		/* end of last token */
4167c478bd9Sstevel@tonic-gate 	char *line_beg;			/* beginning of line, after */
4177c478bd9Sstevel@tonic-gate 					/* leading whitespace */
4187c478bd9Sstevel@tonic-gate 
419eb2b0a61Sas 	/*
4207c478bd9Sstevel@tonic-gate 	 * Skip leading whitespace.
4217c478bd9Sstevel@tonic-gate 	 */
4227c478bd9Sstevel@tonic-gate 	for (line_beg = linebuf;
4232f72c445SViswanathan Kannappan 	    *line_beg && any(*line_beg, " \t");
4242f72c445SViswanathan Kannappan 	    line_beg++) {
4257c478bd9Sstevel@tonic-gate 		/* empty body */
4267c478bd9Sstevel@tonic-gate 	}
4277c478bd9Sstevel@tonic-gate 	if (!*line_beg) {
4287c478bd9Sstevel@tonic-gate 		if (erf) {
4292f72c445SViswanathan Kannappan 			printf(gettext("No file specified.\n"));
4307c478bd9Sstevel@tonic-gate 		}
4317c478bd9Sstevel@tonic-gate 		*flag = 0;
432eb2b0a61Sas 		return (NOSTR);
4337c478bd9Sstevel@tonic-gate 	}
4347c478bd9Sstevel@tonic-gate 	/*
4357c478bd9Sstevel@tonic-gate 	 * Process line from left-to-right, 1 char at a time.
4367c478bd9Sstevel@tonic-gate 	 */
437eb2b0a61Sas 	pc_type = SN_DELIM;
438eb2b0a61Sas 	tok_beg = tok_end = NOSTR;
439eb2b0a61Sas 	p = line_beg;
440eb2b0a61Sas 	while (*p != '\0') {
4417c478bd9Sstevel@tonic-gate 		if (any(*p, " \t")) {
4427c478bd9Sstevel@tonic-gate 			/* This character is a DELIMITER */
4437c478bd9Sstevel@tonic-gate 			if (pc_type & (SN_TOKEN|SN_QUOTE)) {
4447c478bd9Sstevel@tonic-gate 				tok_end = p - 1;
4457c478bd9Sstevel@tonic-gate 			}
4467c478bd9Sstevel@tonic-gate 			pc_type = SN_DELIM;
4477c478bd9Sstevel@tonic-gate 			p++;
4487c478bd9Sstevel@tonic-gate 		} else if ((qc = *p) == '"' || qc == '\'') {
4497c478bd9Sstevel@tonic-gate 			/* This character is a QUOTE character */
4507c478bd9Sstevel@tonic-gate 			if (pc_type == SN_TOKEN) {
4517c478bd9Sstevel@tonic-gate 				/* embedded quotation symbols are simply */
4527c478bd9Sstevel@tonic-gate 				/* token characters. */
4537c478bd9Sstevel@tonic-gate 				p++;
4547c478bd9Sstevel@tonic-gate 				continue;
4557c478bd9Sstevel@tonic-gate 			}
4567c478bd9Sstevel@tonic-gate 			/* Search for the matching QUOTE character */
4577c478bd9Sstevel@tonic-gate 			for (tok_beg = p, tok_end = NOSTR, p++;
458eb2b0a61Sas 			    *p != '\0' && *p != qc;
4592f72c445SViswanathan Kannappan 			    p++) {
4607c478bd9Sstevel@tonic-gate 				if (*p == '\\' && *(p+1) == qc) {
4617c478bd9Sstevel@tonic-gate 					p++;
4627c478bd9Sstevel@tonic-gate 				}
4637c478bd9Sstevel@tonic-gate 			}
4647c478bd9Sstevel@tonic-gate 			if (*p == '\0') {
4657c478bd9Sstevel@tonic-gate 				printf(gettext("Syntax error: missing "
466eb2b0a61Sas 				    "%c.\n"), qc);
4677c478bd9Sstevel@tonic-gate 				*flag = -1;
468eb2b0a61Sas 				return (NOSTR);
4697c478bd9Sstevel@tonic-gate 			}
4707c478bd9Sstevel@tonic-gate 			tok_end = p;
4717c478bd9Sstevel@tonic-gate 			pc_type = SN_QUOTE;
4727c478bd9Sstevel@tonic-gate 			p++;
4737c478bd9Sstevel@tonic-gate 		} else {
4747c478bd9Sstevel@tonic-gate 			/* This character should be a TOKEN character */
4757c478bd9Sstevel@tonic-gate 			if (pc_type & (SN_DELIM|SN_TOKEN)) {
4767c478bd9Sstevel@tonic-gate 				if (pc_type & SN_DELIM) {
4777c478bd9Sstevel@tonic-gate 					tok_beg = p;
4787c478bd9Sstevel@tonic-gate 					tok_end = NOSTR;
4797c478bd9Sstevel@tonic-gate 				}
4807c478bd9Sstevel@tonic-gate 			} else {
4817c478bd9Sstevel@tonic-gate 				printf(gettext("improper quotes"
482eb2b0a61Sas 				    " at \"%s\".\n"), p);
4837c478bd9Sstevel@tonic-gate 				*flag = -1;
484eb2b0a61Sas 				return (NOSTR);
4857c478bd9Sstevel@tonic-gate 			}
4867c478bd9Sstevel@tonic-gate 			if (*p == '\\' && *++p == '\0') {
4877c478bd9Sstevel@tonic-gate 				printf(gettext("\'\\\' at "
488eb2b0a61Sas 				    "end of line.\n"));
4897c478bd9Sstevel@tonic-gate 				*flag = -1;
490eb2b0a61Sas 				return (NOSTR);
4917c478bd9Sstevel@tonic-gate 			}
4927c478bd9Sstevel@tonic-gate 			pc_type = SN_TOKEN;
4937c478bd9Sstevel@tonic-gate 			p++;
4947c478bd9Sstevel@tonic-gate 		}
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 	if (pc_type == SN_TOKEN) {
4977c478bd9Sstevel@tonic-gate 		tok_end = p - 1;
4987c478bd9Sstevel@tonic-gate 	}
4997c478bd9Sstevel@tonic-gate 	if (tok_beg != NOSTR && tok_end != NOSTR) {
5007c478bd9Sstevel@tonic-gate 		if (tok_beg == line_beg) {
5017c478bd9Sstevel@tonic-gate 			*flag = 0;
5027c478bd9Sstevel@tonic-gate 		} else {
5037c478bd9Sstevel@tonic-gate 			tok_beg[-1] = '\0';
5047c478bd9Sstevel@tonic-gate 			*flag = 1;
5057c478bd9Sstevel@tonic-gate 		}
5067c478bd9Sstevel@tonic-gate 		tok_end[1] = '\0';
507eb2b0a61Sas 		return (tok_beg);
5087c478bd9Sstevel@tonic-gate 	} else {
5097c478bd9Sstevel@tonic-gate 		if (erf) {
5102f72c445SViswanathan Kannappan 			printf(gettext("No file specified.\n"));
5117c478bd9Sstevel@tonic-gate 		}
5127c478bd9Sstevel@tonic-gate 		*flag = 0;
513eb2b0a61Sas 		return (NOSTR);
5147c478bd9Sstevel@tonic-gate 	}
5157c478bd9Sstevel@tonic-gate }
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate /*
5187c478bd9Sstevel@tonic-gate  * Delete messages, then type the new dot.
5197c478bd9Sstevel@tonic-gate  */
5207c478bd9Sstevel@tonic-gate 
521eb2b0a61Sas int
deltype(int msgvec[])5227c478bd9Sstevel@tonic-gate deltype(int msgvec[])
5237c478bd9Sstevel@tonic-gate {
5247c478bd9Sstevel@tonic-gate 	int list[2];
5257c478bd9Sstevel@tonic-gate 	int lastdot;
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	lastdot = dot - &message[0] + 1;
5287c478bd9Sstevel@tonic-gate 	if (delm(msgvec) >= 0) {
5297c478bd9Sstevel@tonic-gate 		list[0] = dot - &message[0];
5307c478bd9Sstevel@tonic-gate 		list[0]++;
5317c478bd9Sstevel@tonic-gate 		if (list[0] > lastdot) {
5327c478bd9Sstevel@tonic-gate 			touch(list[0]);
533*46d64c14SToomas Soome 			list[1] = 0;
534eb2b0a61Sas 			return (type(list));
5357c478bd9Sstevel@tonic-gate 		}
5367c478bd9Sstevel@tonic-gate 		printf(gettext("At EOF\n"));
537eb2b0a61Sas 		return (0);
538eb2b0a61Sas 	} else {
5397c478bd9Sstevel@tonic-gate 		printf(gettext("No more messages\n"));
540eb2b0a61Sas 		return (0);
5417c478bd9Sstevel@tonic-gate 	}
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate /*
5457c478bd9Sstevel@tonic-gate  * Delete the indicated messages.
5467c478bd9Sstevel@tonic-gate  * Set dot to some nice place afterwards.
5477c478bd9Sstevel@tonic-gate  */
548eb2b0a61Sas int
delm(int * msgvec)5497c478bd9Sstevel@tonic-gate delm(int *msgvec)
5507c478bd9Sstevel@tonic-gate {
5517c478bd9Sstevel@tonic-gate 	register struct message *mp;
5526c83d09fSrobbin 	int *ip, mesg;
5537c478bd9Sstevel@tonic-gate 	int last;
5547c478bd9Sstevel@tonic-gate 
555*46d64c14SToomas Soome 	last = 0;
556*46d64c14SToomas Soome 	for (ip = msgvec; *ip != 0; ip++) {
5577c478bd9Sstevel@tonic-gate 		mesg = *ip;
5587c478bd9Sstevel@tonic-gate 		touch(mesg);
5597c478bd9Sstevel@tonic-gate 		mp = &message[mesg-1];
5607c478bd9Sstevel@tonic-gate 		mp->m_flag |= MDELETED|MTOUCH;
5617c478bd9Sstevel@tonic-gate 		mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
5627c478bd9Sstevel@tonic-gate 		last = mesg;
5637c478bd9Sstevel@tonic-gate 	}
564*46d64c14SToomas Soome 	if (last != 0) {
5657c478bd9Sstevel@tonic-gate 		dot = &message[last-1];
5667c478bd9Sstevel@tonic-gate 		last = first(0, MDELETED);
567*46d64c14SToomas Soome 		if (last != 0) {
5687c478bd9Sstevel@tonic-gate 			dot = &message[last-1];
569eb2b0a61Sas 			return (0);
570eb2b0a61Sas 		} else {
5717c478bd9Sstevel@tonic-gate 			dot = &message[0];
572eb2b0a61Sas 			return (-1);
5737c478bd9Sstevel@tonic-gate 		}
5747c478bd9Sstevel@tonic-gate 	}
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	/*
5777c478bd9Sstevel@tonic-gate 	 * Following can't happen -- it keeps lint happy
5787c478bd9Sstevel@tonic-gate 	 */
5797c478bd9Sstevel@tonic-gate 
580eb2b0a61Sas 	return (-1);
5817c478bd9Sstevel@tonic-gate }
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate /*
5847c478bd9Sstevel@tonic-gate  * Undelete the indicated messages.
5857c478bd9Sstevel@tonic-gate  */
586eb2b0a61Sas int
undelete(int * msgvec)5877c478bd9Sstevel@tonic-gate undelete(int *msgvec)
5887c478bd9Sstevel@tonic-gate {
5897c478bd9Sstevel@tonic-gate 	register struct message *mp;
5906c83d09fSrobbin 	int *ip, mesg;
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	for (ip = msgvec; ip-msgvec < msgCount; ip++) {
5937c478bd9Sstevel@tonic-gate 		mesg = *ip;
5947c478bd9Sstevel@tonic-gate 		if (mesg == 0)
595eb2b0a61Sas 			return (0);
5967c478bd9Sstevel@tonic-gate 		touch(mesg);
5977c478bd9Sstevel@tonic-gate 		mp = &message[mesg-1];
5987c478bd9Sstevel@tonic-gate 		dot = mp;
5997c478bd9Sstevel@tonic-gate 		mp->m_flag &= ~MDELETED;
6007c478bd9Sstevel@tonic-gate 	}
601eb2b0a61Sas 	return (0);
6027c478bd9Sstevel@tonic-gate }
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate /*
6057c478bd9Sstevel@tonic-gate  * Add the given header fields to the retained list.
6067c478bd9Sstevel@tonic-gate  * If no arguments, print the current list of retained fields.
6077c478bd9Sstevel@tonic-gate  */
608eb2b0a61Sas int
retfield(char * list[])6097c478bd9Sstevel@tonic-gate retfield(char *list[])
6107c478bd9Sstevel@tonic-gate {
6117c478bd9Sstevel@tonic-gate 	char field[BUFSIZ];
6127c478bd9Sstevel@tonic-gate 	register int h;
6137c478bd9Sstevel@tonic-gate 	register struct ignore *igp;
6147c478bd9Sstevel@tonic-gate 	char **ap;
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 	if (argcount(list) == 0)
617eb2b0a61Sas 		return (retshow());
6187c478bd9Sstevel@tonic-gate 	for (ap = list; *ap != 0; ap++) {
6197c478bd9Sstevel@tonic-gate 		istrcpy(field, sizeof (field), *ap);
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 		if (member(field, retain))
6227c478bd9Sstevel@tonic-gate 			continue;
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 		h = hash(field);
6257c478bd9Sstevel@tonic-gate 		if ((igp = (struct ignore *)
6267c478bd9Sstevel@tonic-gate 		    calloc(1, sizeof (struct ignore))) == NULL) {
6277c478bd9Sstevel@tonic-gate 			panic("Couldn't allocate memory");
6287c478bd9Sstevel@tonic-gate 		}
6297c478bd9Sstevel@tonic-gate 		if ((igp->i_field = (char *)
6307c478bd9Sstevel@tonic-gate 		    calloc(strlen(field) + 1, sizeof (char))) == NULL) {
6317c478bd9Sstevel@tonic-gate 			panic("Couldn't allocate memory");
6327c478bd9Sstevel@tonic-gate 		}
6337c478bd9Sstevel@tonic-gate 		strcpy(igp->i_field, field);
6347c478bd9Sstevel@tonic-gate 		igp->i_link = retain[h];
6357c478bd9Sstevel@tonic-gate 		retain[h] = igp;
6367c478bd9Sstevel@tonic-gate 		nretained++;
6377c478bd9Sstevel@tonic-gate 	}
638eb2b0a61Sas 	return (0);
6397c478bd9Sstevel@tonic-gate }
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate /*
6427c478bd9Sstevel@tonic-gate  * Print out all currently retained fields.
6437c478bd9Sstevel@tonic-gate  */
644eb2b0a61Sas static int
retshow(void)6457c478bd9Sstevel@tonic-gate retshow(void)
6467c478bd9Sstevel@tonic-gate {
6477c478bd9Sstevel@tonic-gate 	register int h, count;
6487c478bd9Sstevel@tonic-gate 	struct ignore *igp;
6497c478bd9Sstevel@tonic-gate 	char **ap, **ring;
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	count = 0;
6527c478bd9Sstevel@tonic-gate 	for (h = 0; h < HSHSIZE; h++)
6537c478bd9Sstevel@tonic-gate 		for (igp = retain[h]; igp != 0; igp = igp->i_link)
6547c478bd9Sstevel@tonic-gate 			count++;
6557c478bd9Sstevel@tonic-gate 	if (count == 0) {
6567c478bd9Sstevel@tonic-gate 		printf(gettext("No fields currently being retained.\n"));
657eb2b0a61Sas 		return (0);
6587c478bd9Sstevel@tonic-gate 	}
659eb2b0a61Sas 	ring = (char **)salloc((count + 1) * sizeof (char *));
6607c478bd9Sstevel@tonic-gate 	ap = ring;
6617c478bd9Sstevel@tonic-gate 	for (h = 0; h < HSHSIZE; h++)
6627c478bd9Sstevel@tonic-gate 		for (igp = retain[h]; igp != 0; igp = igp->i_link)
6637c478bd9Sstevel@tonic-gate 			*ap++ = igp->i_field;
6647c478bd9Sstevel@tonic-gate 	*ap = 0;
6657c478bd9Sstevel@tonic-gate 	qsort(ring, count, sizeof (char *), igcomp);
6667c478bd9Sstevel@tonic-gate 	for (ap = ring; *ap != 0; ap++)
6677c478bd9Sstevel@tonic-gate 		printf("%s\n", *ap);
668eb2b0a61Sas 	return (0);
6697c478bd9Sstevel@tonic-gate }
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate /*
6727c478bd9Sstevel@tonic-gate  * Remove a list of fields from the retain list.
6737c478bd9Sstevel@tonic-gate  */
674eb2b0a61Sas int
unretfield(char * list[])6757c478bd9Sstevel@tonic-gate unretfield(char *list[])
6767c478bd9Sstevel@tonic-gate {
6777c478bd9Sstevel@tonic-gate 	char **ap, field[BUFSIZ];
6787c478bd9Sstevel@tonic-gate 	register int h, count = 0;
6797c478bd9Sstevel@tonic-gate 	register struct ignore *ig1, *ig2;
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	if (argcount(list) == 0) {
6827c478bd9Sstevel@tonic-gate 		for (h = 0; h < HSHSIZE; h++) {
6837c478bd9Sstevel@tonic-gate 			ig1 = retain[h];
6847c478bd9Sstevel@tonic-gate 			while (ig1) {
6857c478bd9Sstevel@tonic-gate 				free(ig1->i_field);
6867c478bd9Sstevel@tonic-gate 				ig2 = ig1->i_link;
687eb2b0a61Sas 				free((char *)ig1);
6887c478bd9Sstevel@tonic-gate 				ig1 = ig2;
6897c478bd9Sstevel@tonic-gate 				count++;
6907c478bd9Sstevel@tonic-gate 			}
6917c478bd9Sstevel@tonic-gate 			retain[h] = NULL;
6927c478bd9Sstevel@tonic-gate 		}
6937c478bd9Sstevel@tonic-gate 		if (count == 0)
6947c478bd9Sstevel@tonic-gate 			printf(gettext(
6957c478bd9Sstevel@tonic-gate 			    "No fields currently being retained.\n"));
6967c478bd9Sstevel@tonic-gate 		nretained = 0;
697eb2b0a61Sas 		return (0);
6987c478bd9Sstevel@tonic-gate 	}
6997c478bd9Sstevel@tonic-gate 	for (ap = list; *ap; ap++) {
7007c478bd9Sstevel@tonic-gate 		istrcpy(field, sizeof (field), *ap);
7017c478bd9Sstevel@tonic-gate 		h = hash(field);
7027c478bd9Sstevel@tonic-gate 		for (ig1 = retain[h]; ig1; ig2 = ig1, ig1 = ig1->i_link)
7037c478bd9Sstevel@tonic-gate 			if (strcmp(ig1->i_field, field) == 0) {
7047c478bd9Sstevel@tonic-gate 				if (ig1 == retain[h])
7057c478bd9Sstevel@tonic-gate 					retain[h] = ig1->i_link;
7067c478bd9Sstevel@tonic-gate 				else
7077c478bd9Sstevel@tonic-gate 					ig2->i_link = ig1->i_link;
7087c478bd9Sstevel@tonic-gate 				free(ig1->i_field);
709eb2b0a61Sas 				free((char *)ig1);
7107c478bd9Sstevel@tonic-gate 				nretained--;
7117c478bd9Sstevel@tonic-gate 				break;
7127c478bd9Sstevel@tonic-gate 			}
7137c478bd9Sstevel@tonic-gate 	}
714eb2b0a61Sas 	return (0);
7157c478bd9Sstevel@tonic-gate }
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate /*
7187c478bd9Sstevel@tonic-gate  * Add the given header fields to the ignored list.
7197c478bd9Sstevel@tonic-gate  * If no arguments, print the current list of ignored fields.
7207c478bd9Sstevel@tonic-gate  */
721eb2b0a61Sas int
igfield(char * list[])7227c478bd9Sstevel@tonic-gate igfield(char *list[])
7237c478bd9Sstevel@tonic-gate {
7247c478bd9Sstevel@tonic-gate 	char field[BUFSIZ];
7257c478bd9Sstevel@tonic-gate 	register int h;
7267c478bd9Sstevel@tonic-gate 	register struct ignore *igp;
7277c478bd9Sstevel@tonic-gate 	char **ap;
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	if (argcount(list) == 0)
730eb2b0a61Sas 		return (igshow());
7317c478bd9Sstevel@tonic-gate 	for (ap = list; *ap != 0; ap++) {
7327c478bd9Sstevel@tonic-gate 		if (isign(*ap, 0))
7337c478bd9Sstevel@tonic-gate 			continue;
7347c478bd9Sstevel@tonic-gate 		istrcpy(field, sizeof (field), *ap);
7357c478bd9Sstevel@tonic-gate 		h = hash(field);
7367c478bd9Sstevel@tonic-gate 		if ((igp = (struct ignore *)
7377c478bd9Sstevel@tonic-gate 		    calloc(1, sizeof (struct ignore))) == NULL) {
7387c478bd9Sstevel@tonic-gate 			panic("Couldn't allocate memory");
7397c478bd9Sstevel@tonic-gate 		}
7407c478bd9Sstevel@tonic-gate 		if ((igp->i_field = (char *)
7417c478bd9Sstevel@tonic-gate 		    calloc((unsigned)strlen(field) + 1,
7427c478bd9Sstevel@tonic-gate 		    sizeof (char))) == NULL) {
7437c478bd9Sstevel@tonic-gate 			panic("Couldn't allocate memory");
7447c478bd9Sstevel@tonic-gate 		}
7457c478bd9Sstevel@tonic-gate 		strcpy(igp->i_field, field);
7467c478bd9Sstevel@tonic-gate 		igp->i_link = ignore[h];
7477c478bd9Sstevel@tonic-gate 		ignore[h] = igp;
7487c478bd9Sstevel@tonic-gate 	}
749eb2b0a61Sas 	return (0);
7507c478bd9Sstevel@tonic-gate }
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate /*
7537c478bd9Sstevel@tonic-gate  * Print out all currently ignored fields.
7547c478bd9Sstevel@tonic-gate  */
755eb2b0a61Sas static int
igshow(void)7567c478bd9Sstevel@tonic-gate igshow(void)
7577c478bd9Sstevel@tonic-gate {
7587c478bd9Sstevel@tonic-gate 	register int h, count;
7597c478bd9Sstevel@tonic-gate 	struct ignore *igp;
7607c478bd9Sstevel@tonic-gate 	char **ap, **ring;
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 	count = 0;
7637c478bd9Sstevel@tonic-gate 	for (h = 0; h < HSHSIZE; h++)
7647c478bd9Sstevel@tonic-gate 		for (igp = ignore[h]; igp != 0; igp = igp->i_link)
7657c478bd9Sstevel@tonic-gate 			count++;
7667c478bd9Sstevel@tonic-gate 	if (count == 0) {
7677c478bd9Sstevel@tonic-gate 		printf(gettext("No fields currently being ignored.\n"));
768eb2b0a61Sas 		return (0);
7697c478bd9Sstevel@tonic-gate 	}
770eb2b0a61Sas 	ring = (char **)salloc((count + 1) * sizeof (char *));
7717c478bd9Sstevel@tonic-gate 	ap = ring;
7727c478bd9Sstevel@tonic-gate 	for (h = 0; h < HSHSIZE; h++)
7737c478bd9Sstevel@tonic-gate 		for (igp = ignore[h]; igp != 0; igp = igp->i_link)
7747c478bd9Sstevel@tonic-gate 			*ap++ = igp->i_field;
7757c478bd9Sstevel@tonic-gate 	*ap = 0;
776eb2b0a61Sas 	qsort((char *)ring, (unsigned)count, sizeof (char *), igcomp);
7777c478bd9Sstevel@tonic-gate 	for (ap = ring; *ap != 0; ap++)
7787c478bd9Sstevel@tonic-gate 		printf("%s\n", *ap);
779eb2b0a61Sas 	return (0);
7807c478bd9Sstevel@tonic-gate }
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate /*
7837c478bd9Sstevel@tonic-gate  * Compare two names for sorting ignored field list.
7847c478bd9Sstevel@tonic-gate  */
785eb2b0a61Sas static int
igcomp(const void * l,const void * r)7867c478bd9Sstevel@tonic-gate igcomp(const void *l, const void *r)
7877c478bd9Sstevel@tonic-gate {
788eb2b0a61Sas 	return (strcmp(*(char **)l, *(char **)r));
7897c478bd9Sstevel@tonic-gate }
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate /*
7927c478bd9Sstevel@tonic-gate  * Remove a list of fields from the ignore list.
7937c478bd9Sstevel@tonic-gate  */
794eb2b0a61Sas int
unigfield(char * list[])7957c478bd9Sstevel@tonic-gate unigfield(char *list[])
7967c478bd9Sstevel@tonic-gate {
7977c478bd9Sstevel@tonic-gate 	char **ap, field[BUFSIZ];
7987c478bd9Sstevel@tonic-gate 	register int h, count = 0;
7997c478bd9Sstevel@tonic-gate 	register struct ignore *ig1, *ig2;
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 	if (argcount(list) == 0) {
8027c478bd9Sstevel@tonic-gate 		for (h = 0; h < HSHSIZE; h++) {
8037c478bd9Sstevel@tonic-gate 			ig1 = ignore[h];
8047c478bd9Sstevel@tonic-gate 			while (ig1) {
8057c478bd9Sstevel@tonic-gate 				free(ig1->i_field);
8067c478bd9Sstevel@tonic-gate 				ig2 = ig1->i_link;
807eb2b0a61Sas 				free((char *)ig1);
8087c478bd9Sstevel@tonic-gate 				ig1 = ig2;
8097c478bd9Sstevel@tonic-gate 				count++;
8107c478bd9Sstevel@tonic-gate 			}
8117c478bd9Sstevel@tonic-gate 			ignore[h] = NULL;
8127c478bd9Sstevel@tonic-gate 		}
8137c478bd9Sstevel@tonic-gate 		if (count == 0)
8147c478bd9Sstevel@tonic-gate 			printf(gettext("No fields currently being ignored.\n"));
815eb2b0a61Sas 		return (0);
8167c478bd9Sstevel@tonic-gate 	}
8177c478bd9Sstevel@tonic-gate 	for (ap = list; *ap; ap++) {
8187c478bd9Sstevel@tonic-gate 		istrcpy(field, sizeof (field), *ap);
8197c478bd9Sstevel@tonic-gate 		h = hash(field);
8207c478bd9Sstevel@tonic-gate 		for (ig1 = ignore[h]; ig1; ig2 = ig1, ig1 = ig1->i_link)
8217c478bd9Sstevel@tonic-gate 			if (strcmp(ig1->i_field, field) == 0) {
8227c478bd9Sstevel@tonic-gate 				if (ig1 == ignore[h])
8237c478bd9Sstevel@tonic-gate 					ignore[h] = ig1->i_link;
8247c478bd9Sstevel@tonic-gate 				else
8257c478bd9Sstevel@tonic-gate 					ig2->i_link = ig1->i_link;
8267c478bd9Sstevel@tonic-gate 				free(ig1->i_field);
827eb2b0a61Sas 				free((char *)ig1);
8287c478bd9Sstevel@tonic-gate 				break;
8297c478bd9Sstevel@tonic-gate 			}
8307c478bd9Sstevel@tonic-gate 	}
831eb2b0a61Sas 	return (0);
8327c478bd9Sstevel@tonic-gate }
833