[comp.sources.misc] v18i070: mush - Mail User's Shell, Part13/22

argv@zipcode.com (Dan Heller) (04/22/91)

Submitted-by: Dan Heller <argv@zipcode.com>
Posting-number: Volume 18, Issue 70
Archive-name: mush/part13
Supersedes: mush: Volume 12, Issue 28-47

#!/bin/sh
# do not concatenate these parts, unpack them in order with /bin/sh
# file makefile.sun continued
#
if test ! -r _shar_seq_.tmp; then
	echo 'Please unpack part 1 first!'
	exit 1
fi
(read Scheck
 if test "$Scheck" != 13; then
	echo Please unpack part "$Scheck" next!
	exit 1
 else
	exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
	echo 'x - still skipping makefile.sun'
else
echo 'x - continuing file makefile.sun'
sed 's/^X//' << 'SHAR_EOF' >> 'makefile.sun' &&
#
# Note that the default SunOS version for mush is 4.1.  If you have an
# older version of SunOS, you must explicitly define SUN_3_5 or SUN_4_0.
#
HDRS= mush.h config.h-dist strings.h bindings.h options.h version.h glob.h
X
SRCS= addrs.c bind.c commands.c curs_io.c curses.c dates.c doproc.c \
X      execute.c expr.c file.c fkeys.c folders.c glob.c hdrs.c init.c lock.c \
X      loop.c macros.c mail.c main.c malloc.c misc.c misc_frame.c msgs.c \
X      options.c panels.c pick.c print.c hdr_sw.c setopts.c signals.c sort.c \
X      strings.c tool.c tooledit.c viewopts.c command2.c
X
OBJS= addrs.o bind.o commands.o curs_io.o curses.o dates.o doproc.o \
X      execute.o expr.o file.o fkeys.o folders.o glob.o hdrs.o init.o lock.o \
X      loop.o macros.o mail.o main.o malloc.o misc.o misc_frame.o msgs.o \
X      options.o panels.o pick.o print.o hdr_sw.o setopts.o signals.o sort.o \
X      strings.o tool.o tooledit.o viewopts.o command2.o
X
IMAGES= mail.icon.1 mail.icon.2
X
HELP_FILES= README README-7.0 README-7.1 README-7.2.0 README-7.2.2 \
X            mush.1 cmd_help tool_help Mushrc Mailrc Gnurc \
X	    advanced.mushrc sample.mushrc digestify
X
MAKES= makefile.sun makefile.bsd makefile.sys.v makefile.xenix makefile.hpux
X
# If your SunOS version is 3.5, add -DSUN_3_5 to CFLAGS.
# If your SunOS version is 4.0, add -DSUN_4_0 to CFLAGS.
# If you are not using SUNTOOL, use makefile.bsd and add one of
#	-DSUN_3_5, -DSUN_4_0, or -DSUN_4_1 to CFLAGS there.
CFLAGS= -O -DSUNTOOL -DCURSES -DBSD
LDFLAGS=
LIBES= -lcurses -ltermlib -lsuntool -lsunwindow -lpixrect
OTHERLIBS=
# Use some variant of this one if you #define MMDF in config.h
#OTHERLIBS=/usr/src/mmdf/lib/libmmdf.a
LINTFLAGS= -bxah -Dlint
X
mush: $(OBJS)
X	@echo loading...
X	@cc $(LDFLAGS) $(OBJS) $(LIBES) $(OTHERLIBS) -o mush
X
$(OBJS): config.h mush.h
loop.o: version.h
X
lint:
X	lint $(LINTFLAGS) $(SRCS) -DSUNTOOL -DCURSES -DBSD
X
clean:
X	rm -f *.o core mush
X
BINDIR= /usr/local/bin
LIBDIR= /usr/local/lib
MRCDIR= /usr/lib
MANDIR= /usr/local/man/man1
MANEXT= 1
X
install: mush
X	mv mush $(BINDIR)
X	strip $(BINDIR)/mush
X	chmod 0755 $(BINDIR)/mush
X	rm -f $(BINDIR)/mushtool
X	ln -s $(BINDIR)/mush $(BINDIR)/mushtool
X	cp mush.1 $(MANDIR)/mush.$(MANEXT)
X	chmod 0644 $(MANDIR)/mush.$(MANEXT)
X	cp tool_help $(LIBDIR)
X	chmod 0644 $(LIBDIR)/tool_help
X	cp cmd_help $(LIBDIR)
X	chmod 0644 $(LIBDIR)/cmd_help
X	cp Mushrc $(MRCDIR)/Mushrc
X	chmod 0644 $(MRCDIR)/Mushrc
SHAR_EOF
echo 'File makefile.sun is complete' &&
chmod 0644 makefile.sun ||
echo 'restore of makefile.sun failed'
Wc_c="`wc -c < 'makefile.sun'`"
test 2454 -eq "$Wc_c" ||
	echo 'makefile.sun: original size 2454, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= makefile.sys.v ==============
if test -f 'makefile.sys.v' -a X"$1" != X"-c"; then
	echo 'x - skipping makefile.sys.v (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting makefile.sys.v (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'makefile.sys.v' &&
# Mush makefile for system V.  Note: SIGRET should return void for normal
# sys-v, but Att PC users should *not* have it defined.  See the README!!
#
HDRS1= mush.h config.h
HDRS2= strings.h options.h
HDRS3= bindings.h glob.h
HDRS4= version.h
SRCS1= commands.c dates.c execute.c expr.c folders.c \
X	hdrs.c init.c loop.c mail.c main.c misc.c msgs.c pick.c \
X	print.c setopts.c signals.c sort.c viewopts.c options.c lock.c
SRCS2= bind.c curs_io.c curses.c file.c strings.c macros.c \
X	addrs.c malloc.c glob.c command2.c
X
OBJS1= commands.o dates.o execute.o expr.o folders.o \
X	hdrs.o init.o loop.o mail.o main.o misc.o msgs.o pick.o \
X	print.o setopts.o signals.o sort.o viewopts.o options.o lock.o
OBJS2= bind.o curs_io.o curses.o file.o strings.o macros.o \
X	addrs.o malloc.o glob.o command2.o
X
HELP= README README-7.0 README-7.1 README-7.2.0 README-7.2.2 mush.1 \
X	cmd_help Mushrc Mailrc Gnurc sample.mushrc advanced.mushrc digestify
X
# Sun OS systems who wish to compile with sys-v options:
# CC= /usr/5bin/cc
# CFLAGS= 	-O -DSYSV -DCURSES -DUSG -DDIRECTORY
# LIBS= -L/usr/5lib -lcurses
X
# IRIX 3.2 systems (SGI Iris workstations) should add -DDIRECTORY to CFLAGS
# SCO UNIX 3.2 should add -DDIRECTORY -DSELECT and should avoid library -lx
X
CFLAGS= 	-O -DSYSV -DUSG -DCURSES -DREGCMP -DSIGRET=void
LDFLAGS=
LIBS= 		-lcurses -lPW
OTHERLIBS=
# Use some variant of this one if you #define MMDF in config.h
#OTHERLIBS=/usr/src/mmdf/lib/libmmdf.a
PROG=		mush
X
$(PROG): $(OBJS1) $(OBJS2)
X	@echo loading...
X	@$(CC) $(LDFLAGS) $(OBJS1) $(OBJS2) -o $(PROG) $(LIBS) $(OTHERLIBS)
X
$(OBJS1): $(HDRS1) $(HDRS2)
$(OBJS2): $(HDRS1) $(HDRS2) $(HDRS3)
loop.o: version.h
X
BINDIR= /usr/local/bin
LIBDIR= /usr/local/lib
MRCDIR= /usr/lib
MANDIR= /usr/local/man/man1
MANEXT= 1
X
install: mush
X	cp mush $(BINDIR)
X	strip $(BINDIR)/mush
X	chmod 0755 $(BINDIR)/mush
X	cp mush.1 $(MANDIR)/mush.$(MANEXT)
X	chmod 0644 $(MANDIR)/mush.$(MANEXT)
X	cp cmd_help $(LIBDIR)
X	chmod 0644 $(LIBDIR)/cmd_help
X	cp Mushrc $(MRCDIR)/Mushrc
X	chmod 0644 $(MRCDIR)/Mushrc
SHAR_EOF
chmod 0644 makefile.sys.v ||
echo 'restore of makefile.sys.v failed'
Wc_c="`wc -c < 'makefile.sys.v'`"
test 2023 -eq "$Wc_c" ||
	echo 'makefile.sys.v: original size 2023, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= makefile.xenix ==============
if test -f 'makefile.xenix' -a X"$1" != X"-c"; then
	echo 'x - skipping makefile.xenix (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting makefile.xenix (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'makefile.xenix' &&
#
# makefile for Xenix machines.  See "MODEL" below for your xenix type.
# some .c files may require the -LARGE compiler flag.  Examples below.
# This makefile assumes an 80386 machine.  If you have an 80286, see
# notes below.  This makefile was built for SCO/microsoft xenix --if you
# are running some other kind of xenix, you might need to change the
# CFLAGS and LDFLAGS options.
#
HDRS= mush.h config.h-dist strings.h bindings.h options.h version.h glob.h
SRCS1= main.c init.c misc.c execute.c
SRCS2= signals.c msgs.c pick.c viewopts.c
SRCS3= sort.c expr.c folders.c dates.c
SRCS4= loop.c bind.c options.c
SRCS5= commands.c commands2.c setopts.c hdrs.c
SRCS6= mail.c print.c
SRCS7= curses.c curs_io.c
SRCS8= file.c strings.c malloc.c
SRCS9= lock.c macros.c addrs.c glob.c
OBJS= main.o init.o misc.o mail.o hdrs.o execute.o commands.o print.o file.o \
X      signals.o setopts.o msgs.o pick.o sort.o expr.o strings.o \
X      folders.o dates.o loop.o viewopts.o bind.o curses.o curs_io.o \
X      lock.o macros.o options.o addrs.o malloc.o glob.o command2.o
HELP_FILES= README README-7.0 README-7.1 README-7.2.0 README-7.2.2 mush.1 \
X	cmd_help Mushrc Mailrc Gnurc sample.mushrc advanced.mushrc digestify
X
# Memory model.  Use -M3e for 80386 machines.
# Use -M2le -Mt32 -LARGE for 80286 machines.
MODEL= -M3e
X
#
# 80286 xenix may use this LDFLAGS define:
#LDFLAGS= -X -lx -M2le -Mt32 -F 8000 -SEG 256 -LARGE
LDFLAGS= -X -lx -M3
X
CFLAGS= $(MODEL) -O -DSYSV -DCURSES -DREGCMP -DUSG 
LIBES= -lcurses -ltermlib
OTHERLIBS=
# Use some variant of this one if you #define MMDF in config.h
#OTHERLIBS=/usr/src/mmdf/lib/libmmdf.a
X
mush: $(OBJS)
X	@echo loading...
X	@cc $(LDFLAGS) $(OBJS) $(LIBES) $(OTHERLIBS) -o mush
X
$(OBJS): config.h mush.h
loop.o: version.h
X
# For 80286 machines, use these two lines...
# misc.o:	misc.c
# 	cc $(CFLAGS) -LARGE -c misc.c
X
bind.o:	bind.c
X	cc $(CFLAGS) -LARGE -c bind.c
X
clean:
X	rm -f *.o core mush
X
BINDIR= /usr/local/bin
LIBDIR= /usr/local/lib
MRCDIR= /usr/lib
MANDIR= /usr/local/man/man1
MANEXT= 1
X
install: mush
X	cp mush $(BINDIR)
X	strip $(BINDIR)/mush
X	chmod 0755 $(BINDIR)/mush
X	cp mush.1 $(MANDIR)/mush.$(MANEXT)
X	chmod 0644 $(MANDIR)/mush.$(MANEXT)
X	cp cmd_help $(LIBDIR)
X	chmod 0644 $(LIBDIR)/cmd_help
X	cp Mushrc $(MRCDIR)/Mushrc
X	chmod 0644 $(MRCDIR)/Mushrc
SHAR_EOF
chmod 0644 makefile.xenix ||
echo 'restore of makefile.xenix failed'
Wc_c="`wc -c < 'makefile.xenix'`"
test 2293 -eq "$Wc_c" ||
	echo 'makefile.xenix: original size 2293, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= malloc.c ==============
if test -f 'malloc.c' -a X"$1" != X"-c"; then
	echo 'x - skipping malloc.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting malloc.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'malloc.c' &&
/*
X * This is a slightly modified version of the malloc.c distributed with
X * Larry Wall's perl 2.0 sources.  RCS and sccs information has been
X * retained, but modified so that it will not actually affect checkin
X * or checkout of this file if revision control is used for Mush.
X *
X * Other changes include:
X *	Removal of the ASSERT macro and other code related to the
X *	preprocessor definition "debug"
X *
X *	Replaced #include "perl.h" with #include "mush.h" (guess why)
X *
X *	Warning messages are now printed with the mush Debug macro,
X *	that is, they are normally suppressed
X *
X *	Added a calloc() function, using mush's bzero()
X *
X * Also, the mush xfree() and free_vec() functions have been moved here.
X */
X
#include "mush.h"
X
/*
X * Compile this portion only if configured for INTERNAL_MALLOC
X */
#ifdef INTERNAL_MALLOC
#ifdef SYSV
#include <memory.h>
#define bcopy(src,dst,len)	memcpy(dst,src,len)
#endif /* SYSV */
#define free xfree	/* rename free for mush purposes */
X
/* Begin modified perl malloc.c */
X
/* Header: malloc.c,v 2.0 88/06/05 00:09:16 root Exp
X *
X * Log:	malloc.c,v
X * Revision 2.0  88/06/05  00:09:16  root
X * Baseline version 2.0.
X * 
X */
X
#ifndef lint
static char sccsid[] = "malloc.c	4.3 (Berkeley) 9/16/83";
#endif /* !lint */
X
#define RCHECK
/*
X * malloc.c (Caltech) 2/21/82
X * Chris Kingsley, kingsley@cit-20.
X *
X * This is a very fast storage allocator.  It allocates blocks of a small 
X * number of different sizes, and keeps free lists of each size.  Blocks that
X * don't exactly fit are passed up to the next larger size.  In this 
X * implementation, the available sizes are 2^n-4 (or 2^n-12) bytes long.
X * This is designed for use in a program that uses vast quantities of memory,
X * but bombs when it runs out. 
X */
X
/* I don't much care whether these are defined in sys/types.h--LAW */
X
#undef u_char
#define u_char unsigned char
#undef u_int
#define u_int unsigned int
#undef u_short
#define u_short unsigned short
X
/*
X * The overhead on a block is at least 4 bytes.  When free, this space
X * contains a pointer to the next free block, and the bottom two bits must
X * be zero.  When in use, the first byte is set to MAGIC, and the second
X * byte is the size index.  The remaining bytes are for alignment.
X * If range checking is enabled and the size of the block fits
X * in two bytes, then the top two bytes hold the size of the requested block
X * plus the range checking words, and the header word MINUS ONE.
X */
union	overhead {
X	union	overhead *ov_next;	/* when free */
X	struct {
X		u_char	ovu_magic;	/* magic number */
X		u_char	ovu_index;	/* bucket # */
#ifdef RCHECK
X		u_short	ovu_size;	/* actual block size */
X		u_int	ovu_rmagic;	/* range magic number */
#endif /* RCHECK */
X	} ovu;
#define	ov_magic	ovu.ovu_magic
#define	ov_index	ovu.ovu_index
#define	ov_size		ovu.ovu_size
#define	ov_rmagic	ovu.ovu_rmagic
};
X
#define	MAGIC		0xff		/* magic # on accounting info */
#define OLDMAGIC	0x7f		/* same after a free() */
#define RMAGIC		0x55555555	/* magic # on range info */
#ifdef RCHECK
#define	RSLOP		sizeof (u_int)
#else /* !RCHECK */
#define	RSLOP		0
#endif /* RCHECK */
X
/*
X * nextf[i] is the pointer to the next free block of size 2^(i+3).  The
X * smallest allocatable block is 8 bytes.  The overhead information
X * precedes the data area returned to the user.
X */
#define	NBUCKETS 30
static	union overhead *nextf[NBUCKETS];
extern	char *sbrk();
X
#ifdef MSTATS
/*
X * nmalloc[i] is the difference between the number of mallocs and frees
X * for a given block size.
X */
static	u_int nmalloc[NBUCKETS];
#endif /* MSTATS */
X
char *
malloc(nbytes)
X	register unsigned nbytes;
{
X	register union overhead *p;
X	register int bucket = 0;
X	register unsigned shiftr;
X
X	if (nbytes == 0)
X	    return NULL;
X	/*
X	 * Convert amount of memory requested into
X	 * closest block size stored in hash buckets
X	 * which satisfies request.  Account for
X	 * space used per block for accounting.
X	 */
X	nbytes += sizeof (union overhead) + RSLOP;
X	nbytes = (nbytes + 3) &~ 3; 
X	shiftr = (nbytes - 1) >> 2;
X	/* apart from this loop, this is O(1) */
X	while (shiftr >>= 1)
X		bucket++;
X	/*
X	 * If nothing in hash bucket right now,
X	 * request more memory from the system.
X	 */
X	if (nextf[bucket] == (union overhead *)0)    
X		morecore(bucket);
X	if ((p = (union overhead *)nextf[bucket]) == (union overhead *)0)
X		return (NULL);
X	/* remove from linked list */
X	if (*((int*)p) > 0x10000000)
X	    Debug("Corrupt malloc ptr 0x%x at 0x%x\n",*((int*)p),p);
X	nextf[bucket] = nextf[bucket]->ov_next;
X	p->ov_magic = MAGIC;
X	p->ov_index= bucket;
#ifdef MSTATS
X	nmalloc[bucket]++;
#endif /* MSTATS */
#ifdef RCHECK
X	/*
X	 * Record allocated size of block and
X	 * bound space with magic numbers.
X	 */
X	if (nbytes <= 0x10000)
X		p->ov_size = nbytes - 1;
X	p->ov_rmagic = RMAGIC;
X	*((u_int *)((caddr_t)p + nbytes - RSLOP)) = RMAGIC;
#endif /* RCHECK */
X	return ((char *)(p + 1));
}
X
/*
X * Allocate more memory to the indicated bucket.
X */
static
morecore(bucket)
X	register bucket;
{
X	register union overhead *op;
X	register int rnu;       /* 2^rnu bytes will be requested */
X	register int nblks;     /* become nblks blocks of the desired size */
X	register int siz;
X
X	if (nextf[bucket])
X		return;
X	/*
X	 * Insure memory is allocated
X	 * on a page boundary.  Should
X	 * make getpageize call?
X	 */
X	op = (union overhead *)sbrk(0);
X	if ((long)op & 0x3ff)
X		sbrk(1024 - ((long)op & 0x3ff));
X	/* take 2k unless the block is bigger than that */
X	rnu = (bucket <= 8) ? 11 : bucket + 3;
X	nblks = 1 << (rnu - (bucket + 3));  /* how many blocks to get */
X	if (rnu < bucket)
X		rnu = bucket;
X	op = (union overhead *)sbrk(1 << rnu);
X	/* no more room! */
X	if ((long)op == -1)
X		return;
X	/*
X	 * Round up to minimum allocation size boundary
X	 * and deduct from block count to reflect.
X	 */
X	if ((long)op & 7) {
X		op = (union overhead *)(((long)op + 8) &~ 7);
X		nblks--;
X	}
X	/*
X	 * Add new memory allocated to that on
X	 * free list for this hash bucket.
X	 */
X	nextf[bucket] = op;
X	siz = 1 << (bucket + 3);
X	while (--nblks > 0) {
X		op->ov_next = (union overhead *)((caddr_t)op + siz);
X		op = (union overhead *)((caddr_t)op + siz);
X	}
}
X
void
free(cp)
X	char *cp;
{   
X	register int size;
X	register union overhead *op;
X
X	if (cp == NULL || debug > 4)
X		return;
X	op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
X	if (op->ov_magic != MAGIC) {
X		Debug("%s free() ignored\n",
X		    op->ov_magic == OLDMAGIC ? "Duplicate" : "Bad");
X		return;				/* sanity */
X	}
X	op->ov_magic = OLDMAGIC;
#ifdef RCHECK
X	if (op->ov_rmagic != RMAGIC) {
X		Debug("Range check failed, free() ignored\n");
X		return;
X	}
X	if (op->ov_index <= 13 &&
X	    *(u_int *)((caddr_t)op + op->ov_size + 1 - RSLOP) != RMAGIC) {
X		Debug("Range check failed, free() ignored\n");
X		return;
X	}
#endif /* RCHECK */
X	if (op->ov_index >= NBUCKETS)
X	    return;
X	size = op->ov_index;
X	op->ov_next = nextf[size];
X	nextf[size] = op;
#ifdef MSTATS
X	nmalloc[size]--;
#endif /* MSTATS */
}
X
/*
X * When a program attempts "storage compaction" as mentioned in the
X * old malloc man page, it realloc's an already freed block.  Usually
X * this is the last block it freed; occasionally it might be farther
X * back.  We have to search all the free lists for the block in order
X * to determine its bucket: 1st we make one pass thru the lists
X * checking only the first block in each; if that fails we search
X * ``reall_srchlen'' blocks in each list for a match (the variable
X * is extern so the caller can modify it).  If that fails we just copy
X * however many bytes was given to realloc() and hope it's not huge.
X */
int reall_srchlen = 4;	/* 4 should be plenty, -1 =>'s whole list */
X
char *
realloc(cp, nbytes)
X	char *cp;
X	unsigned nbytes;
{   
X	register u_int onb;
X	union overhead *op;
X	char *res;
X	register int i;
X	int was_alloced = 0;
X
X	if (cp == NULL)
X		return (malloc(nbytes));
X	op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
X	if (op->ov_magic == MAGIC) {
X		was_alloced++;
X		i = op->ov_index;
X	} else {
X		/*
X		 * Already free, doing "compaction".
X		 *
X		 * Search for the old block of memory on the
X		 * free list.  First, check the most common
X		 * case (last element free'd), then (this failing)
X		 * the last ``reall_srchlen'' items free'd.
X		 * If all lookups fail, then assume the size of
X		 * the memory block being realloc'd is the
X		 * smallest possible.
X		 */
X		if ((i = findbucket(op, 1)) < 0 &&
X		    (i = findbucket(op, reall_srchlen)) < 0)
X			i = 0;
X	}
X	onb = (1 << (i + 3)) - sizeof (*op) - RSLOP;
#ifdef RCHECK
X	/* There's something wrong with the "onb" size computation, above,
X	 * when RCHECK is defined.  If you see this comment and can figure
X	 * out exactly how "onb" is being used here, let me know.  Bart.
X	 */
X	if (was_alloced) {
X		free(cp);	/* Hack so there's some chance res == cp */
X		was_alloced = 0;
X	}
#else /* RCHECK */
X	/* avoid the copy if same size block */
X	if (was_alloced &&
X	    nbytes <= onb && nbytes > (onb >> 1) - sizeof(*op) - RSLOP)
X		return(cp);
#endif /* RCHECK */
X	if ((res = malloc(nbytes)) == NULL)
X		return (NULL);
X	if (cp != res)			/* common optimization */
X		bcopy(cp, res, (nbytes < onb) ? nbytes : onb);
X	if (was_alloced)
X		free(cp);
X	return (res);
}
X
/*
X * Search ``srchlen'' elements of each free list for a block whose
X * header starts at ``freep''.  If srchlen is -1 search the whole list.
X * Return bucket number, or -1 if not found.
X */
static
findbucket(freep, srchlen)
X	union overhead *freep;
X	int srchlen;
{
X	register union overhead *p;
X	register int i, j;
X
X	for (i = 0; i < NBUCKETS; i++) {
X		j = 0;
X		for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
X			if (p == freep)
X				return (i);
X			j++;
X		}
X	}
X	return (-1);
}
X
#ifdef MSTATS
/*
X * mstats - print out statistics about malloc
X * 
X * Prints two lines of numbers, one showing the length of the free list
X * for each size category, the second showing the number of mallocs -
X * frees for each size category.
X */
mstats(s)
X	char *s;
{
X	register int i, j;
X	register union overhead *p;
X	int totfree = 0,
X	totused = 0;
X
X	Debug("Memory allocation statistics %s\nfree:\t", s);
X	for (i = 0; i < NBUCKETS; i++) {
X		for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
X			;
X		Debug(" %d", j);
X		totfree += j * (1 << (i + 3));
X	}
X	Debug("\nused:\t");
X	for (i = 0; i < NBUCKETS; i++) {
X		Debug( " %d", nmalloc[i]);
X		totused += nmalloc[i] * (1 << (i + 3));
X	}
X	Debug("\n\tTotal in use: %d, total free: %d\n",
X	    totused, totfree);
}
#endif /* MSTATS */
X
/* End of modified perl malloc.c */
X
char *
calloc(nitems, itemsz)
u_int nitems, itemsz;
{
X    char *cp;
X
X    cp = malloc(nitems * itemsz);
X    bzero(cp, nitems * itemsz);
X    return cp;
}
X
/* These are needed for curses and other external linkage */
X
#undef free
X
char *
cfree(p, n, s)
char *p;
u_int n, s;
{
X    xfree(p);
X    return NULL;
}
X
char *
free(p)
char *p;
{
X    xfree(p);
X    return NULL;
}
X
#else /* INTERNAL_MALLOC */
X
char *stackbottom;	/* set first thing in main() */
X
void
xfree(cp)
char *cp;
{
X    extern char end[];
X
X    if (cp && cp >= end && cp < stackbottom && cp < (char *) &cp && debug < 5)
X	free(cp);
}
X
#endif /* INTERNAL_MALLOC */
X
void
free_elems(argv)
char **argv;
{
X    register int n;
X
X    if (!argv)
X	return;
X    for (n = 0; argv[n]; n++)
X	xfree(argv[n]);
}
X
void
free_vec(argv)
char **argv;
{
X    free_elems(argv);
X    xfree((char *)argv);
}
SHAR_EOF
chmod 0600 malloc.c ||
echo 'restore of malloc.c failed'
Wc_c="`wc -c < 'malloc.c'`"
test 11289 -eq "$Wc_c" ||
	echo 'malloc.c: original size 11289, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= misc.c ==============
if test -f 'misc.c' -a X"$1" != X"-c"; then
	echo 'x - skipping misc.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting misc.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'misc.c' &&
/* @(#)misc.c	(c) copyright 10/18/86 (Dan Heller) */
X
#include "mush.h"
X
/* check to see if a string describes a message that is within the range of
X * all messages; if invalid, return 0 and print error. else return msg number
X */
chk_msg(s)
register char *s;
{
X    register int n;
X
X    if ((n = atoi(s)) > 0 && n <= msg_cnt)
X	return n;
X    else if (*s == '^' && msg_cnt)
X	return 1;
X    else if (*s == '$' && msg_cnt)
X	return msg_cnt;
X    else if (*s == '.' && msg_cnt)
X	return current_msg+1;
X    print("Invalid message number: %s\n", s);
X    return 0;
}
X
/*
X * loop thru all msgs starting with current_msg and find next undeleted and
X * unsaved message.  If the variable "wrap" is set, wrap to the beginning of
X * the message list if we hit the end.  otherwise, stop at the end of the list.
X */
next_msg()
{
X    register int n = current_msg;
X    register int wrap = !!do_set(set_options, "wrap") ||
X	istool && !do_set(set_options, "show_deleted");
X
X    if (!msg_cnt)
X	return current_msg = 0;
X    for (n++; n != current_msg; n++)
X	if (n == msg_cnt)     /* hit the end, start back at the beginning */
X	    if (!wrap)
X		return current_msg;
X	    else
X		n = -1; /* increments to 0 in  loop  */
X	else if (isoff(msg[n].m_flags, DELETE) &&
X		 isoff(msg[n].m_flags, SAVED))
X	    return current_msg = n;
X    return current_msg = 0;
}
X
/* since print_help just prints help, always return help() */
print_help(argc, argv)
register char **argv;
{
X    int about = (argv && *argv && **argv == 'a');
X
X    if (!argc || !*++argv)
X	return help(0, about? "about": "general", cmd_help);
X    if (argv[0][0] == '-')
X	return help(0, about? "about": "help", cmd_help);
X    return help(0, *argv, cmd_help);
}
X
/* since this function does not affect messages, return -1 */
/*ARGSUSED*/
help(unused, str, file)
char *str, *file;
{
X    register char	*p, **text = (char **)str;
X    char		buf[BUFSIZ], help_str[32];
X    FILE		*fp;
X
X    /* If no file given, take "str" arg as message to print */
X    if (!file || !*file) {
#ifdef SUNTOOL
#ifdef SUN_4_0 /* SunOS 4.0+ */
X	/* SunOS 3.5 doesn't have enough file descriptors */
X	turnon(glob_flags, NEW_FRAME);
#endif /* SUN_4_0 */
X	strdup(more_prompt, "help");
#endif /* SUNTOOL */
X	/* use the pager on the args to the function */
X	(void) do_pager(NULL, TRUE);
X	while (*text) {
X	    (void) do_pager(*text++, FALSE);
X	    if (do_pager("\n", FALSE) == EOF)
X		break;
X	}
X	(void) do_pager(NULL, FALSE);
X	return 0;
X    } else {
X	int d = 0;
X	if ((p = getpath(file, &d)) && d == 0) {
X	    if (!(fp = fopen(p, "r"))) {
X		print("Cannot open help file \"%s\".\n", p);
X		return -1;
X	    }
X	} else {
X	    if (d < 0)
X		print("Cannot open help file \"%s\": %s\n", file, p);
X	    else
X		print("Help file \"%s\" is a directory?!?\n", p);
X	    return -1;
X	}
X    }
X
X    /* look for %str% in helpfile */
X    (void) sprintf(help_str, "%%%s%%\n", str);
X
X    while (p = fgets(buf, sizeof buf, fp))
X	if (*p == '%' && !strcmp(p, help_str))
X	    break;
X    if (!p)
X	print("There is no help found for \"%s\".\n", (char *)str);
X    else {
#ifdef SUNTOOL
#ifdef SUN_4_0 /* SunOS 4.0+ */
X	/* SunOS 3.5 doesn't have enough file descriptors */
X	turnon(glob_flags, NEW_FRAME);
#endif /* SUN_4_0 */
X	strdup(more_prompt, sprintf(buf, "%s help", (char *)str));
#endif /* SUNTOOL */
X	(void) do_pager(NULL, TRUE);
X	while ((p = fgets(buf, sizeof buf, fp)) && strcmp(p, "%%\n"))
X	    if (do_pager(buf, FALSE) == EOF)
X		break;
X	(void) do_pager(NULL, FALSE);
X    }
X    (void) fclose(fp);
X
X    return 0;
}
X
/* return -1 on error or number of arguments in argv that were parsed */
get_msg_list(argv, list)
register char **argv;
char list[];
{
X    register char *p2, *p, *end, ch;
X    char buf[BUFSIZ];
X    register int n;
X
X    if (!msg_cnt) {
X	print("No messages.\n");
X	return -1;
X    }
X    if (!argv || !*argv) {
X	if (isoff(glob_flags, IS_PIPE))
X	    set_msg_bit(list, current_msg);
X	return 0;
X    }
X    /* first, stuff argv's args into a single char array buffer */
X    (void) argv_to_string(buf, argv);
X    p = buf;
X
X    Debug("get_msg_list: parsing: (%s): ", p);
X    /* find the end of the message list */
X    skipmsglist(0);
X    end = p;
X    while (*end && end != buf && !isspace(*end))
X	--end;
X    ch = *end, *end = '\0'; /* temporarily plug with nul */
X    p = buf; /* reset to the beginning */
X    /*
X     * if do_range returns NULL, an invalid message was specified
X     */
X    if (!(p2 = do_range(p, list))) {
X	*end = ch; /* just in case */
X	return -1;
X    }
X    /*
X     * if p2 == p (and p isn't $ or ^ or .), then no message list was
X     * specified.  set the current message in such cases if we're not piping
X     */
X    if (p2 == p) {
X	if (*p == '$')
X	    set_msg_bit(list, msg_cnt-1);
X	else if (*p == '^')
X	    set_msg_bit(list, 0);
X	else if (*p == '.' || isoff(glob_flags, IS_PIPE))
X	    set_msg_bit(list, current_msg);
X    }
X    for (n = 0; p2 > p && *argv; n++)
X	p2 -= (strlen(*argv++)+1);
X    Debug("parsed %d args\n", n);
X    *end = ch;
X    return n;
}
X
/*
X * execute a command from a string.  f'rinstance: "pick -f foobar"
X * The string is made into an argv and then run.  Errors are printed
X * if the command failed to make.
X * NOTES:
X *   NEVER pass straight text: e.g. "pick -f foobar", ALWAYS strcpy(buf, "...")
X *   no history is expanded (ignore_bang).
X */
cmd_line(buf, list)
char buf[], list[];
{
X    register char **argv;
X    int argc, ret_val = -1;
X    u_long save_do_pipe = ison(glob_flags, DO_PIPE);
X    u_long save_is_pipe = ison(glob_flags, IS_PIPE);
X    char dummy_list[MAXMSGS_BITS];
X
X    turnoff(glob_flags, DO_PIPE);
X    turnoff(glob_flags, IS_PIPE);
X    if (argv = make_command(buf, TRPL_NULL, &argc))
X	ret_val = do_command(argc, argv, list? list : dummy_list);
X    if (save_do_pipe)
X	turnon(glob_flags, DO_PIPE);
X    else
X	turnoff(glob_flags, DO_PIPE);
X    if (save_is_pipe)
X	turnon(glob_flags, IS_PIPE);
X    else
X	turnoff(glob_flags, IS_PIPE);
X    return ret_val;
}
X
glob_test(s)
char *s;
{
X    print("%s: glob_flags =", s);
X    if (ison(glob_flags, DO_UPDATE))
X	print_more(" DO_UPDATE");
X    if (ison(glob_flags, REV_VIDEO))
X	print_more(" REV_VIDEO");
X    if (ison(glob_flags, CONT_PRNT))
X	print_more(" CONT_PRNT");
X    if (ison(glob_flags, DO_SHELL))
X	print_more(" DO_SHELL");
X    if (ison(glob_flags, DO_PIPE))
X	print_more(" DO_PIPE");
X    if (ison(glob_flags, IS_PIPE))
X	print_more(" IS_PIPE");
X    if (ison(glob_flags, IGN_SIGS))
X	print_more(" IGN_SIGS");
X    if (ison(glob_flags, IGN_BANG))
X	print_more(" IGN_BANG");
X    if (ison(glob_flags, ECHO_FLAG))
X	print_more(" ECHO_FLAG");
X    if (ison(glob_flags, IS_GETTING))
X	print_more(" IS_GETTING");
X    if (ison(glob_flags, PRE_CURSES))
X	print_more(" PRE_CURSES");
X    if (ison(glob_flags, READ_ONLY))
X	print_more(" READ_ONLY");
X    if (ison(glob_flags, REDIRECT))
X	print_more(" REDIRECT");
X    if (ison(glob_flags, WAS_INTR))
X	print_more(" WAS_INTR");
X    if (ison(glob_flags, WARNING))
X	print_more(" WARNING");
X    if (ison(glob_flags, NEW_MAIL))
X	print_more(" NEW_MAIL");
X    if (ison(glob_flags, CNTD_CMD))
X	print_more(" CNTD_CMD");
X    if (ison(glob_flags, IS_SENDING))
X	print_more(" IS_SENDING");
X    if (ison(glob_flags, MIL_TIME))
X	print_more(" MIL_TIME");
X    if (ison(glob_flags, DATE_RECV))
X	print_more(" DATE_RECV");
X    if (ison(glob_flags, IN_MACRO))
X	print_more(" IN_MACRO");
X    if (ison(glob_flags, LINE_MACRO))
X	print_more(" LINE_MACRO");
X    if (ison(glob_flags, QUOTE_MACRO))
X	print_more(" QUOTE_MACRO");
X    print_more("\n");
}
X
/*
X * Change the status flags for messages.
X *    flags +r		add the replied-to flag to the current message.
X *    flags -S 4-7	remove the "saved" status on msgs 4-7
X *    flags P *		preserves all messages.
X * The + implies: add this flag to the current message's flag bits
X * The - implies: delete this flag to the current message's flag bits
X * No + or - implies that the msg's flag bits are set explicitly.
X * Marks and priorities are preserved in the m_flags field despite
X * what we're doing here.  Thus, other actions taken by this function
X * do not affect marks and priorities.
X */
msg_flags(c, v, list)
register char **v, *list;
{
X    register int	i = 0, modify = 0, had_list = 0;
X    register u_long	newflag = 0;
X    char		sent[32], recv[32];
X
X    while (v && *v && *++v)
X	for (c = 0; v && v[0] && v[0][c]; c++)
X	    switch (lower(v[0][c])) {
X		case '?' : return help(0, "msg_flags", cmd_help);
X		case 'n' : turnon(newflag, UNREAD), turnoff(newflag, OLD);
X		when 'd' : turnon(newflag, DELETE);
X		when 'p' :
X		    if (v[0][c] == 'P')
X			turnon(newflag, PRESERVE);
X		    else
X			turnon(newflag, PRINTED);
X		when 's' : turnon(newflag, SAVED);
X		when 'u' : turnon(newflag, UNREAD); /* fall thru! */
X		case 'o' : turnon(newflag, OLD);
X		when 'r' :
X		    if (v[0][c] == 'R')
X			turnoff(newflag, UNREAD), turnon(newflag, OLD);
X		    else
X			turnon(newflag, REPLIED);
X		when 'f' : turnon(newflag, FORWARD);
X		when '+' : modify = 1;
X		when '-' : modify = 2;
X		when '\\' : ; /* skip to the next flag */
X		otherwise:
X		    if ((i = get_msg_list(v, list)) <= 0) {
X			print("Unknown flag: %c.  Use flags -? for help\n",
X			    v[0][c]);
X			return -1;
X		    } else {
X			/* advance argv passed the msg-list */
X			v += i;
X			/* c will get ++'ed, so it should be 0 */
X			c = -1;
X			/* record that we have seen a message list */
X			had_list = 1;
X		    }
X	    }
X
X    /* If we haven't got a msglist, use current_msg */
X    if (had_list == 0 && isoff(glob_flags, IS_PIPE))
X	set_msg_bit(list, current_msg);
X
X    for (i = 0; i < msg_cnt; i++) {
X	if (!msg_bit(list, i))
X	    continue;
X	else if (!newflag) {
X	    wprint("msg %d: offset: %d, lines: %d, bytes: %d, flags:", i+1,
X		msg[i].m_offset, msg[i].m_lines, msg[i].m_size);
X	    if (ison(msg[i].m_flags, UNREAD))
X		wprint(" UNREAD");
X	    if (ison(msg[i].m_flags, OLD))
X		wprint(" OLD");
X	    if (ison(msg[i].m_flags, DELETE))
X		wprint(" DELETE");
X	    if (ison(msg[i].m_flags, PRESERVE))
X		wprint(" PRESERVE");
X	    if (ison(msg[i].m_flags, REPLIED))
X		wprint(" REPLIED");
X	    if (ison(msg[i].m_flags, SAVED))
X		wprint(" SAVED");
X	    if (ison(msg[i].m_flags, PRINTED))
X		wprint(" PRINTED");
X	    if (ison(msg[i].m_flags, FORWARD))
X		wprint(" FORWARD");
X	    if (ison(msg[i].m_flags, UPDATE_STATUS))
X		wprint(" UPDATE_STATUS");
X	    for (modify = MAX_PRIORITY; modify > 0; modify--)
X		if (ison(msg[i].m_flags, M_PRIORITY(modify)))
X		    wprint(" %c", 'A' + modify - 1);
X	    (void) strcpy(sent, date_to_ctime(msg[i].m_date_sent));
X	    (void) strcpy(recv, date_to_ctime(msg[i].m_date_recv));
X	    wprint("\n\tsent: %s\trecv: %s", sent, recv);
X	} else {
X	    u_long save_priority = 0L;
X	    if (modify == 0) {
X		int j;
X		for (j = 0; j < MAX_PRIORITY; j++)
X		    if (ison(msg[i].m_flags, M_PRIORITY(j)))
X			turnon(save_priority, M_PRIORITY(j));
X	    }
X	    switch (modify) {
X		case 0: msg[i].m_flags = newflag;
X		when 1: msg[i].m_flags |= newflag;
X		when 2: msg[i].m_flags &= ~newflag;
X	    }
X	    if (save_priority)
X		msg[i].m_flags |= save_priority;
X	    if (isoff(glob_flags, READ_ONLY)) {
X		turnon(glob_flags, DO_UPDATE);
X		turnon(msg[i].m_flags, DO_UPDATE);
X	    }
X	}
X    }
X    return 0;
}
X
/*
X * Internal pager.  Start the internal pager by passing the name of
X * the pager in buf and passing TRUE as start_pager. If the internal
X * pager is desired, pass NULL as buf.  Continue paging by passing
X * FALSE as start_pager and the buf is the stuff to pass thru to the
X * pager.  End paging by passing NULL as buf and FALSE as start_pager.
X * start_pager actually has a ternary value -- for use by pipe_msg.
X * If the pager can't be used, or is null, we're paging ourselves.
X * Windows does nothing but echo buf to the msg window (this will change).
X * The "buf" passed to the pager should be a line at a time so as to
X * count \n's.  If there is more than one newline, the first one is nulled
X * and the next line done by calling do_pager recursively.  WARNING: because
X * "buf" is changed, it is *illegal* for anyone calling this routine to pass
X * _constant_ strings --they should be strcpy'ed or sprintf'ed into a temp
X * buff before passing to this routine!  Otherwise, ANSI-C compilers will
X * core dump.  This is because constant strings are read-only.
X * Return EOF if pager died, user exited pager, or if user types 'q'
X * at the --more-- prompt for the internal pager.
X *
X * For windows, copy all the info into a tmpfile and set the pager_textsw
X * to that file.  When the pager ends, delete the file -- textsw will
X * continue to read it since it does its own buffering.
X */
do_pager(buf, start_pager)
char *buf;
{
X    static FILE *pp;
X    static int cnt, len;
X    static u_long save_echo_flag;
#ifdef SUNTOOL
X    static char file[MAXPATHLEN];
X    static Textsw sw;
X
X    /* pipe_msg will pass -1 for start_pager to avoid this block */
X    if (start_pager > -1 && istool) {
X	if (buf && !start_pager) {
X	    if (istool < 2) /* can't use windows yet -- send to stdout */
X		(void) fputs(buf, stdout);
X	    else {
X		if (pp)
X		    fputs(buf, pp);
X		else
X		    textsw_insert(isoff(glob_flags, NEW_FRAME)?
X			pager_textsw : sw, buf, strlen(buf));
X	    }
X	} else if (istool >= 2 && start_pager) {
X	    Frame text_frame;
X	    extern char *more_prompt;
X	    char *p;
X
X	    timeout_cursors(TRUE);
X	    if (ison(glob_flags, NEW_FRAME)) {
X		char *crt_win = do_set(set_options, "crt_win");
X		text_frame = window_create(tool, FRAME,
X		    FRAME_SHOW_LABEL,	TRUE,
X		    FRAME_LABEL,	more_prompt,
X		    WIN_HEIGHT,		l_height()*(crt_win? atoi(crt_win):12),
X		    NULL);
X		sw = window_create(text_frame, TEXTSW,
X		    TEXTSW_LINE_BREAK_ACTION,	TEXTSW_WRAP_AT_CHAR,
X		    TEXTSW_CLIENT_DATA,		text_frame,
X		    NULL);
X		notify_interpose_event_func(sw, scroll_textwin, NOTIFY_SAFE);
X	    } else
X		textsw_reset(pager_textsw, 0, 0);
X
X	    /* find a free tmpfile */
X	    if (!(p = getdir(do_set(set_options, "tmpdir"))))
alted:
X		p = ALTERNATE_HOME;
X	    {
X		int pid = getpid();
X		do
X		    sprintf(file, "%s/..X%d", p, pid++);
X		while (!Access(file, F_OK));
X	    }
X	    if (!(pp = mask_fopen(file, "w"))) {
X		if (strcmp(p, ALTERNATE_HOME))
X		    goto alted;
X		error("Can't create '%s'", tempfile);
X	    }
X	    return 0;
X	} else if (!buf && !start_pager) { /* pager is done */
X	    if (pp)
X		(void) fclose(pp);
X	    window_set(isoff(glob_flags, NEW_FRAME)? pager_textsw : sw,
X		TEXTSW_FILE,		file,
X		TEXTSW_READ_ONLY,	TRUE,
X		TEXTSW_UPDATE_SCROLLBAR,
X		NULL);
X	    if (ison(glob_flags, NEW_FRAME)) {
X		turnoff(glob_flags, NEW_FRAME);
X		window_set(window_get(sw, TEXTSW_CLIENT_DATA),
X		    WIN_SHOW,		TRUE,
X		    FRAME_NO_CONFIRM,	TRUE,
X		    FRAME_DONE_PROC,	window_destroy,
X		    NULL);
X	    }
X	    if (unlink(file) == -1)
X		error("Cannot unlink %s", file);
X	    timeout_cursors(FALSE);
X	}
X	return 0;
X    }
#endif /* SUNTOOL */
X
X    if (start_pager) {
X	turnon(glob_flags, IGN_SIGS);
X	if (!buf) {
X	    /* internal pager */
X	    save_echo_flag = ison(glob_flags, ECHO_FLAG);
X	    pp = stdout;
X	    if (save_echo_flag) {
X		turnoff(glob_flags, ECHO_FLAG);
X		echo_off();
X	    }
X	} else {
X	    echo_on();
X	    if (!(pp = popen(buf, "w")))
X		error(buf);
X	}
X	cnt = len = 0;
X    } else if (!buf) {
X	if (pp && pp != stdout)
X	    (void) pclose(pp);
X	pp = NULL_FILE;
X	if (save_echo_flag) {
X	    echo_on();
X	    turnon(glob_flags, ECHO_FLAG);
X	} else
X	    echo_off();
X	turnoff(glob_flags, IGN_SIGS);
X    } else if (pp != stdout)
X	return fputs(buf, pp); /* returns EOF if user exited pager */
X    else {
X	register char c = 0, *cr = index(buf, '\n');
X	len += strlen(buf);
X	if (cr) {
X	    int maxlen =
#ifdef CURSES
X		iscurses ? COLS :
#endif /* CURSES */
X		80;
X	    if (len > maxlen)
X		cnt += len / maxlen;
X	    len = 0;
X	}
X	if (cr && (c = *++cr) != '\0')
X	    *cr = 0; /* send one line to stdout and prompt for more */
X	(void) fputs(buf, pp);
X	if (cr && (++cnt / (crt-1))) {
X	    int n = c_more(NULL);
X	    if (n == '\n' || n == '\r')
X		cnt--; /* go line by line */
X	    else if (n == CTRL('D') || lower(n) == 'd' || n < 0) {
X		clearerr(stdin);
X		cnt = ((crt-1)/2);
X	    } else if (lower(n) == 'q')
X		/* could check if "c" is set, but... see warning above */
X		return EOF;
X	    else
X		cnt = 1;
X	}
X	if (c) {
X	    *cr = c;
X	    return do_pager(cr, FALSE);
X	}
X    }
X    return 0;
}
X
/* curses based "more" like option */
c_more(p)
register char *p;
{
X    register int c;
X
X    if (!p)
X	p = "--more--";
X    print_more(p);
X
X    while ((c = getchar()) >= 0 && c != CTRL('D') && !isspace(c) &&
X	    c != '\n' && c != '\r' && lower(c) != 'q' && lower(c) != 'd')
X	bell();
X    if (ison(glob_flags, ECHO_FLAG) && c != '\n' && c != '\r')
X	while (getchar() != '\n');
X    (void) printf("\r%*c\r", strlen(p), ' '); /* remove the prompt */
X    (void) fflush(stdout);
X    return c;
}
X
/*
X * Your "signature" is of the type:
X *    file_or_path
X *    $variable
X *    \ literal string preceded by a backslash.
X * The variable will be expanded into its string value.
X * To sign the letter, the list of addresses is passed to this routine
X * (separated by whitespace and/or commas).  No comment fields!
X *
X * If "autosign2" is set, then it must be of the form:
X *    autosign2 = "*user user !host !some!path @dom.ain: ~/.sign2"
X *
X * The colon terminates the user/host lists from the "signature" to the right.
X *
X * Whitespace or commas separate tokens.  If everyone on the list exists in
X * the autosign2 list, the alternate signature is used. In case of syntax
X * error, the alternate signature is used without checks (e.g. if the colon
X * is missing).  The alternate signature == null is the same as not signing
X * the letter. An empty list forces signature2.
X *
X * If autosign2 is not set at all, then autosign is checked and used.
X * autosign = <signature>
X */
void
sign_letter(list, flags, fp)
register char *list; /* list of addresses -- no comment fields */
u_long flags;
FILE *fp;
{
X    char buf[MAXPATHLEN], *signature;
X    register char *p = NULL;
X    FILE 	*pp2;
X    int 	lines = 0, noisy;
X
X    if (!list)
X	return;
X    while (isspace(*list))
X	list++;
X    if (!*list)
X	return;
X    if (ison(flags, SIGN)) {
X	noisy = !chk_option("quiet", "autosign");
X	if (!(p = do_set(set_options, "autosign2")))
X	    buf[0] = 0;
X	else {
X	    if (!(signature = index(p, ':')))
X		(void) strcpy(buf, p); /* No colon; use entire string as sig */
X	    else {
X		int ret_val = 0;
X		*signature = 0;
X		/* p now points to a list of addresses and p2 points to the
X		 * signature format to use. Check that each address in the list
X		 * provided (parameter) matches the "addrs" in autosign2.
X		 */
X		skipspaces(0);
X		if (!*p)
X		    /* autosign2 = " : <signature>"  send to all recipients */
X		    ret_val = 1;
X		else if (p = alias_to_address(p)) {
X		    rm_cmts_in_addr(p);
X		    ret_val = compare_addrs(list, p, NULL);
X		}
X		*signature++ = ':'; /* must reset first! */
X		buf[0] = 0;
X		if (ret_val) {
X		    while (isspace(*signature))
X			signature++;
X		    /* Null signatures don't sign anything. */
X		    if (!*strcpy(buf, signature))
X			return;
X		}
X	    }
X	}
X	if (!buf[0]) {
X	    if (!(p = do_set(set_options, "autosign")) || !*p) {
X		char *home;
X		if (!(home = do_set(set_options, "home")) || !*home)
X		    home = ALTERNATE_HOME;
X		(void) sprintf(buf, "%s/%s", home, SIGNATURE);
X	    } else
X		(void) strcpy(buf, p);
X	    if (noisy)
X		wprint("Signing letter... ");
X	} else if (noisy)
X	    wprint("Using alternate signature... ");
X	(void) fseek(fp, 0L, 2); /* guarantee position at end of file */
X	(void) fputc('\n', fp);
X	(void) fflush(fp);
X	if (*buf == '$')
X	    if (!(p = do_set(set_options, buf)))
X		wprint("(%s isn't set -- letter not signed)\n", buf);
X	    else {
X		putstring(p+1, fp);
X		if (noisy)
X		    wprint("\n");
X	    }
X	else if (*buf == '\\') {
X	    putstring(buf, fp);
X	    if (noisy)
X		wprint("\n");
X	} else if (*buf == '[') {
X	    char *rbr = index(buf, ']');
X	    if (rbr)
X		*rbr = 0;
X	    putstring(buf + 1, fp);
X	    if (noisy)
X		wprint("\n");
X	} else if (*buf == '|' || *buf == '!') {
X	    (void) strcat(buf, " ");
X	    (void) strcat(buf, list);
X	    if (!(pp2 = popen(buf+1, "r")))
X		error(buf+1);
X	    else {
X		turnon(glob_flags, IGN_SIGS);
X		while (fgets(buf, sizeof(buf), pp2)) {
X		    int len = strlen(buf);
X		    (void) fputs(buf, fp), lines++;
X		    if (len < sizeof buf - 1 && buf[len - 1] != '\n')
X			(void) fputc('\n', fp);
X		}
X		(void) pclose(pp2);
X		(void) fflush(fp);
X		turnoff(glob_flags, IGN_SIGS);
X		if (noisy)
X		    wprint("added %d line%s\n", lines, lines == 1? "" : "s");
X	    }
X	} else {
X	    /* precede _file_ signatures ONLY with "-- \n" */
X	    (void) fputs("-- \n", fp);
X	    (void) fflush(fp);
X	    (void) file_to_fp(buf, fp, "r");
X	}
X    }
X
X    (void) fflush(stdout); /* for sys-v and older xenix */
X
X    /* if fortune is set, check to see if fortunates is set. If so,
X     * check to see if all the recipient are on the fortunates list.
X     */
X    if (ison(flags, DO_FORTUNE)) {
X	noisy = !chk_option("quiet", "fortune");
X	if (p = do_set(set_options, "fortunates")) {
X	    if (!(p = alias_to_address(p)))
X		return; /* no reason to hang around */
X	    rm_cmts_in_addr(p);
X	    if (!compare_addrs(list, p, buf)) {
X		if (noisy) {
X		    wprint("\"fortunates\" does not contain \"%s\".\n", buf);
X		    wprint("No fortune added.\n");
X		}
X		return;
X	    }
X	}
X	if (noisy)
X	    wprint("You may be fortunate... ");
X	if ((p = do_set(set_options, "fortune")) && *p == '/')
X	    (void) strcpy(buf, p);
X	else
X	    (void) sprintf(buf, "%s %s", FORTUNE, (p && *p == '-')? p: "-s");
X	if (!(pp2 = popen(buf, "r")))
X	    error(buf);
X	else {
X	    turnon(glob_flags, IGN_SIGS);
X	    (void) fseek(fp, 0L, 2); /* go to end of file */
X	    while (fgets(buf, sizeof(buf), pp2))
X		(void) fputs(buf, fp), lines++;
X	    (void) pclose(pp2);
X	    turnoff(glob_flags, IGN_SIGS);
X	    (void) fflush(fp);
X	    if (noisy)
X		wprint("added %d line%s\n", lines, lines == 1? "" : "s");
X	}
X    }
X    (void) fflush(stdout); /* for sys-v and older xenix */
}
X
X
/* return -1 since function doesn't affect messages */
check_flags(flags)
u_long flags;
{
X    print_more(" ");
X    if (ison(flags, VERBOSE))
X	print_more("VERBOSE ");
X    if (ison(flags, INCLUDE))
X	print_more("INCLUDE ");
X    if (ison(flags, INCLUDE_H))
X	print_more("INCLUDE_H ");
X    if (ison(flags, EDIT))
X	print_more("EDIT ");
X    if (ison(flags, SIGN))
X	print_more("SIGN ");
X    if (ison(flags, DO_FORTUNE))
X	print_more("DO_FORTUNE ");
X    if (ison(flags, NO_HEADER))
X	print_more("NO_HEADER ");
X    if (ison(flags, DELETE))
X	print_more("DELETE ");
X    if (ison(flags, OLD))
X	print_more("OLD ");
X    if (ison(flags, UNREAD))
X	print_more("UNREAD ");
X    if (ison(flags, UPDATE_STATUS))
X	print_more("UPDATE_STATUS ");
X    if (ison(flags, NO_PAGE))
X	print_more("NO_PAGE ");
X    if (ison(flags, INDENT))
X	print_more("INDENT ");
X    if (ison(flags, NO_IGNORE))
X	print_more("NO_IGNORE ");
X    if (ison(flags, PRESERVE))
X	print_more("PRESERVE ");
X    print_more("\n");
X    return -1;
}
SHAR_EOF
chmod 0644 misc.c ||
echo 'restore of misc.c failed'
Wc_c="`wc -c < 'misc.c'`"
test 22738 -eq "$Wc_c" ||
	echo 'misc.c: original size 22738, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= misc_frame.c ==============
if test -f 'misc_frame.c' -a X"$1" != X"-c"; then
	echo 'x - skipping misc_frame.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting misc_frame.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'misc_frame.c' &&
/* @(#) misc_frame.c	(c) copyright	9/29/89 (Dan Heller) */
X
/*
X * This file contains several functions which create dialog box frames
X * for (currently) mail aliases and ignored headers.  Each dialog box
X * has a list of some kind and a way to add or delete items from the
X * list.  The list is a textsw which is updated (currently) by do_set().
X * Public routines:
X *    update_list_textsw(struct options **) updates the textsw list.
X *    do_alias()	creates the alias dialog frame box
X *    do_ignore()	creates the ignored headers dialog frame box
X */
X
#include "mush.h"
X
extern Notify_value fkey_interposer();
X
/****************** Mail Aliases ********************/
X
Frame	alias_frame;
Panel_item alias_msg, alias_name, alias_value, alias_list_textsw;
static void set_alias();
X
Frame	ignore_frame;
Panel_item ignore_msg, ignore_name, ignore_list_textsw;
static Panel_setting set_ignore();
X
#define MY_FRAME_WIDTH	600
X
static void
frame_help(item)
Panel_item item;
{
X    (void) help(0, panel_get(item, PANEL_CLIENT_DATA), tool_help);
}
X
void
update_list_textsw(list)
struct options **list;
{
X    Textsw save = pager_textsw;
X
X    if (list == &aliases)
X	pager_textsw = alias_list_textsw;
X    else if (list == &ignore_hdr)
X	pager_textsw = ignore_list_textsw;
X    else
X	/* no textsw for this guy yet */
X	return;
X
X    if (pager_textsw && !!window_get(pager_textsw, WIN_SHOW))
X	(void) do_set(*list, NULL);
X    pager_textsw = save;
}
X
static void
alias_done()
{
X    window_destroy(alias_frame);
X    alias_frame = (Frame) 0;
}
X
void
do_aliases()
{
X    Panel	panel;
X
X    if (alias_frame) {
X	window_set(alias_frame, WIN_SHOW, TRUE, NULL);
X	return;
X    }
#ifdef SUN_3_5
X    if (nopenfiles(0) < 5) {
X	print("Too many frames; close one first!\n");
X	return;
X    }
#endif /* SUN_3_5 */
X
X    alias_frame = window_create(tool, FRAME,
X	FRAME_SHOW_LABEL,	TRUE,
X	FRAME_LABEL,		"Mail Aliases",
X	FRAME_NO_CONFIRM,	TRUE,
X	FRAME_DONE_PROC,	alias_done,
X	WIN_SHOW,		TRUE,
X	WIN_WIDTH,		MY_FRAME_WIDTH,
X	NULL);
X
X    panel = window_create(alias_frame, PANEL,
X	PANEL_WIDTH,		MY_FRAME_WIDTH,
X	NULL);
X    notify_interpose_event_func(panel, fkey_interposer, NOTIFY_SAFE);
X
X    panel_create_item(panel, PANEL_BUTTON,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(panel, "Help", 4, mush_font),
X	PANEL_CLIENT_DATA,	"aliases",
X	PANEL_NOTIFY_PROC,	frame_help,
X	NULL);
X    panel_create_item(panel, PANEL_BUTTON,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(panel, "Set", 3, mush_font),
X	PANEL_NOTIFY_PROC,	set_alias,
X	PANEL_CLIENT_DATA,	TRUE,
X	NULL);
X    panel_create_item(panel, PANEL_BUTTON,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(panel, "Unset", 5, mush_font),
X	PANEL_NOTIFY_PROC,	set_alias,
X	PANEL_CLIENT_DATA,	FALSE,
X	NULL);
X
X    alias_msg = panel_create_item(panel, PANEL_MESSAGE,
X	PANEL_LABEL_STRING,
X	    "Type name of alias and address list and select <set> or <unset>",
X	NULL);
X
X    alias_name = panel_create_item(panel, PANEL_TEXT,
X	PANEL_LABEL_STRING,	"Alias Name:",
X	PANEL_VALUE_DISPLAY_LENGTH, 60,
X	NULL);
X    alias_value = panel_create_item(panel, PANEL_TEXT,
X	PANEL_LABEL_STRING,	"Alias Address(es):",
X	PANEL_VALUE_DISPLAY_LENGTH, 60,
X	NULL);
X    window_fit_height(panel);
X
X    alias_list_textsw = window_create(alias_frame, TEXTSW,
X	WIN_BELOW,			panel,
X	WIN_WIDTH,			MY_FRAME_WIDTH,
X	WIN_HEIGHT,			15 * l_height(),
#ifdef SUN_4_0 /* SunOS 4.0+ */
X	TEXTSW_LINE_BREAK_ACTION,	TEXTSW_WRAP_AT_WORD,
#else /* SUN_4_0 */
X	TEXTSW_LINE_BREAK_ACTION,	TEXTSW_WRAP_AT_CHAR,
#endif /* SUN_4_0 */
X	NULL);
X    (void) notify_interpose_event_func(alias_list_textsw,
X	fkey_interposer, NOTIFY_SAFE);
X
X    window_fit_height(alias_frame);
X    update_list_textsw(&aliases);
}
X
static void
set_alias(item)
Panel_item item;
{
X    int argc, set_it = (int)panel_get(item, PANEL_CLIENT_DATA);
X    char buf[BUFSIZ], **argv, *name, *value;
X
X    name = panel_get_value(alias_name);
X    if (!*name) {
X	panel_set(alias_msg, PANEL_LABEL_STRING, "Need an alias name.", NULL);
X	return;
X    }
X    if (any(name, " \t")) {
X	panel_set(alias_msg,
X	    PANEL_LABEL_STRING, "Alias name may not contain spaces.",
X	    NULL);
X	return;
X    }
X    if (set_it) {
X	value = panel_get_value(alias_value);
X	if (!*value) {
X	    panel_set(alias_msg,
X		PANEL_LABEL_STRING, "Specify alias address(es).",
X		NULL);
X	    return;
X	}
X	sprintf(buf, "alias %s %s", name, value);
X    } else
X	sprintf(buf, "unalias %s", name);
X    if (!(argv = mk_argv(buf, &argc, TRUE)) || do_alias(argc, argv) == -1)
X	panel_set(alias_msg,
X	    PANEL_LABEL_STRING, "Couldn't set alias.",
X	    NULL);
X    else
X	panel_set(alias_msg,
X	    PANEL_LABEL_STRING, "",
X	    NULL);
X    panel_set_value(alias_name, "");
X    panel_set_value(alias_value, "");
X    free_vec(argv);
}
X
/* int cuz it's also the callback for the text item */
static Panel_setting
set_ignore(item)
Panel_item item;
{
X    int argc, set_it = (int)panel_get(item, PANEL_CLIENT_DATA);
X    char buf[BUFSIZ], *name, **argv;
X
X    name = panel_get_value(ignore_name);
X    if (!*name) {
X	panel_set(ignore_msg, PANEL_LABEL_STRING, "Missing header name.", NULL);
X	return PANEL_NONE;
X    }
X    if (set_it)
X	sprintf(buf, "ignore %s", name);
X    else
X	sprintf(buf, "unignore %s", name);
X    /* set() will call update_list_textsw() */
X    if (!(argv = mk_argv(buf, &argc, TRUE)) || set(argc, argv, NULL) == -1)
X	panel_set(ignore_msg,
X	    PANEL_LABEL_STRING, "Internal Error!?",
X	    NULL);
X    else
X	panel_set(ignore_msg,
SHAR_EOF
true || echo 'restore of misc_frame.c failed'
fi
echo 'End of  part 13'
echo 'File misc_frame.c is continued in part 14'
echo 14 > _shar_seq_.tmp
exit 0
exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.