home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume12
/
mush
/
part11
< prev
next >
Wrap
Text File
|
1990-05-05
|
56KB
|
1,889 lines
Newsgroups: comp.sources.misc
subject: v12i039: Mail User's Shell, Part11/19
from: argv@Eng.Sun.COM (Dan Heller)
Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
Posting-number: Volume 12, Issue 39
Submitted-by: argv@Eng.Sun.COM (Dan Heller)
Archive-name: mush/part11
#! /bin/sh
# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# If this archive is complete, you will see the following message at the end:
# "End of archive 11 (of 19)."
# Contents: mush/makefile.bsd mush/misc.c mush/msgs.c
# Wrapped by argv@turnpike on Wed May 2 13:59:35 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'mush/makefile.bsd' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'mush/makefile.bsd'\"
else
echo shar: Extracting \"'mush/makefile.bsd'\" \(2051 characters\)
sed "s/^X//" >'mush/makefile.bsd' <<'END_OF_FILE'
X# makefile.bsd (c) copyright 1986 (Dan Heller)
X# SunOS users should add -DSUN_3_5 or -DSUN_4_0 to the CFLAGS line below.
X#
XHDRS= mush.h config.h-dist strings.h bindings.h options.h version.h glob.h
X
XSRCS= main.c init.c misc.c mail.c hdrs.c execute.c commands.c print.c dates.c \
X signals.c setopts.c msgs.c pick.c sort.c expr.c folders.c \
X loop.c viewopts.c curses.c curs_io.c bind.c file.c strings.c \
X lock.c macros.c options.c addrs.c malloc.c glob.c
XOBJS= 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 curses.o curs_io.o bind.o \
X lock.o macros.o options.o addrs.o malloc.o glob.o
X
XHELP_FILES= README README-7.0 README-7.1 mush.1 cmd_help \
X Mushrc Mailrc Gnurc sample.mushrc advanced.mushrc digestify
X
XMAKES= makefile.bsd makefile.xenix makefile.sys.v makefile.hpux makefile.sun
X
X# See the README for changes needed to compile under Ultrix.
X# In particular, you may need -DSIGRET=void and/or -ltermcap.
XCFLAGS= -O -DCURSES -DBSD
XLDFLAGS=
XLINTFLAGS= -bxah -Dlint -DCURSES -DBSD
XLIBES= -lcurses -ltermlib
XOTHERLIBS=
X# Use some variant of this one if you #define MMDF in config.h
X#OTHERLIBS=/usr/src/mmdf/lib/libmmdf.a
X
Xmush: $(OBJS)
X @echo loading...
X @cc $(LDFLAGS) $(OBJS) $(LIBES) $(OTHERLIBS) -o mush
X
X$(OBJS): config.h mush.h
Xloop.o: version.h
X
Xtape:
X @tar cv $(MAKES) $(HDRS) $(SRCS) $(HELP_FILES)
X
Xtar:
X @tar fcv MUSH $(MAKES) $(HDRS) $(SRCS) $(HELP_FILES)
X
Xtarmail:
X tar fcv - $(MAKES) $(HDRS) $(SRCS) $(HELP_FILES) | \
X compress | btoa > mush.tarmail
X
Xlint:
X lint $(LINTFLAGS) $(SRCS)
X
Xclean:
X rm -f *.o core mush
X
XBINDIR= /usr/local/bin
XLIBDIR= /usr/local/lib
XMRCDIR= /usr/lib
XMANDIR= /usr/local/man/man1
XMANEXT= 1
X
Xinstall: mush
X mv 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
END_OF_FILE
if test 2051 -ne `wc -c <'mush/makefile.bsd'`; then
echo shar: \"'mush/makefile.bsd'\" unpacked with wrong size!
fi
# end of 'mush/makefile.bsd'
fi
if test -f 'mush/misc.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'mush/misc.c'\"
else
echo shar: Extracting \"'mush/misc.c'\" \(22011 characters\)
sed "s/^X//" >'mush/misc.c' <<'END_OF_FILE'
X/* @(#)misc.c (c) copyright 10/18/86 (Dan Heller) */
X
X#include "mush.h"
X
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 */
Xchk_msg(s)
Xregister char *s;
X{
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
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 */
Xnext_msg()
X{
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}
X
X/* since print_help just prints help, always return help() */
Xprint_help(argc, argv)
Xregister char **argv;
X{
X#ifdef SUNTOOL
X if (istool)
X return help(0, "general", tool_help);
X#endif /* SUNTOOL */
X
X if (!argc || !*++argv)
X return help(0, "general", cmd_help);
X if (argv[0][0] == '-')
X return help(0, "help", cmd_help);
X return help(0, *argv, cmd_help);
X}
X
X/* since this function does not affect messages, return -1 */
X/*ARGSUSED*/
Xhelp(unused, str, file)
Xchar *str, *file;
X{
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) {
X#ifdef SUNTOOL
X#ifdef SUN_4_0 /* SunOS 4.0+ */
X /* SunOS 3.5 doesn't have enough file descriptors */
X turnon(glob_flags, NEW_FRAME);
X#endif /* SUN_4_0 */
X strdup(more_prompt, "help");
X#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 {
X#ifdef SUNTOOL
X#ifdef SUN_4_0 /* SunOS 4.0+ */
X /* SunOS 3.5 doesn't have enough file descriptors */
X turnon(glob_flags, NEW_FRAME);
X#endif /* SUN_4_0 */
X strdup(more_prompt, sprintf(buf, "%s help", (char *)str));
X#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}
X
X/* return -1 on error or number of arguments in argv that were parsed */
Xget_msg_list(argv, list)
Xregister char **argv;
Xchar list[];
X{
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
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 */
Xcmd_line(buf, list)
Xchar buf[], list[];
X{
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}
X
Xglob_test(s)
Xchar *s;
X{
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
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 */
Xmsg_flags(c, v, list)
Xregister char **v, *list;
X{
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 /* 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 (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 if (isoff(glob_flags, READ_ONLY))
X turnon(glob_flags, DO_UPDATE);
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 }
X }
X return 0;
X}
X
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 */
Xdo_pager(buf, start_pager)
Xchar *buf;
X{
X static FILE *pp;
X static char file[MAXPATHLEN];
X static int cnt, len;
X static u_long save_echo_flag;
X#ifdef SUNTOOL
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"))))
Xalted:
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 }
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 =
X#ifdef CURSES
X iscurses ? COLS :
X#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}
X
X/* curses based "more" like option */
Xc_more(p)
Xregister char *p;
X{
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
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 */
Xvoid
Xsign_letter(list, flags, fp)
Xregister char *list; /* list of addresses -- no comment fields */
Xu_long flags;
XFILE *fp;
X{
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 (void) fputs(buf, fp), lines++;
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
X
X/* return -1 since function doesn't affect messages */
Xcheck_flags(flags)
Xu_long flags;
X{
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;
X}
END_OF_FILE
if test 22011 -ne `wc -c <'mush/misc.c'`; then
echo shar: \"'mush/misc.c'\" unpacked with wrong size!
fi
# end of 'mush/misc.c'
fi
if test -f 'mush/msgs.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'mush/msgs.c'\"
else
echo shar: Extracting \"'mush/msgs.c'\" \(27478 characters\)
sed "s/^X//" >'mush/msgs.c' <<'END_OF_FILE'
X/* @(#)msgs.c (c) copyright 10/18/86 (Dan Heller) */
X
X#include "mush.h"
X
Xvoid
Xdisplay_msg(n, flg)
Xregister int n;
Xu_long flg;
X{
X char buf[32], *pager = NULL;
X
X if (ison(msg[n].m_flags, DELETE) && !do_set(set_options, "show_deleted")) {
X print("Message %d deleted; ", n+1);
X#ifdef SUNTOOL
X if (istool)
X wprint("Select UNDELETE to read.\n");
X else
X#endif /* SUNTOOL */
X if (iscurses)
X print_more("Type 'u' to undelete.");
X else
X wprint("Type 'undelete %d' to undelete\n", n+1);
X return;
X }
X set_isread(n);
X if (ison(flg, M_TOP)) {
X turnon(flg, NO_HEADER);
X print("Top of "), turnon(glob_flags, CONT_PRNT);
X }
X
X#ifdef MSG_SEPARATOR
X turnon(flg, NO_SEPARATOR);
X#endif /* MMDF */
X if (!istool && isoff(flg, NO_PAGE) &&
X crt < msg[n].m_lines && isoff(flg, M_TOP)) {
X if (!(pager = do_set(set_options, "pager")))
X pager = DEF_PAGER;
X if (!*pager || !strcmp(pager, "internal"))
X pager = NULL; /* default to internal pager if pager set to "" */
X }
X (void) do_pager(pager, TRUE); /* start pager */
X (void) do_pager(sprintf(buf, "Message #%d (%d lines)\n",
X n+1, msg[n].m_lines), FALSE);
X (void) copy_msg(n, NULL_FILE, flg, NULL);
X (void) do_pager(NULL, FALSE); /* end pager */
X}
X
X/*
X * copy message 'n' to file "fp" according to various flag arguments
X * return number of lines copied or -1 if system error on fputs.
X * If "fp" is null, send to internal pager. This can only happen from
X * display_msg above.
X */
Xcopy_msg(n, fp, flags, pattern)
Xregister int n;
Xregister FILE *fp;
Xu_long flags;
Xchar *pattern;
X{
X register int ignoring = 0, lines = 0;
X register char *indent_str, *p, *end_pat = NULL;
X int on_hdr = 1, top, squeeze = 0;
X long still_more = 0;
X int pat_len, pat_seek;
X char line[BUFSIZ], *show_hdrs = NULL;
X
X if (ison(flags, M_TOP)) {
X p = do_set(set_options, "toplines");
X top = (p)? atoi(p) : crt;
X }
X /* When updating to a folder, always write all headers! */
X if (ison(flags, UPDATE_STATUS))
X turnon(flags, NO_IGNORE);
X else if (ison(flags, NO_IGNORE) &&
X (p = do_set(set_options, "alwaysignore")) && !*p)
X turnoff(flags, NO_IGNORE); /* preserve historic behavior */
X if (isoff(flags, NO_IGNORE)) {
X if (do_set(set_options, "squeeze"))
X squeeze = 1;
X show_hdrs = do_set(set_options, "show_hdrs");
X }
X if (pattern && *pattern == '/' && (end_pat = index(pattern+1, '/'))) {
X if (end_pat[1] == ',') {
X pattern++;
X *end_pat++ = 0;
X } else
X end_pat = NULL;
X }
X pat_len = pattern? strlen(pattern) : 0;
X pat_seek = !!pat_len;
X
X#ifdef SUNTOOL
X xfree(more_prompt), more_prompt = NULL;
X#endif /* SUNTOOL */
X
X if (ison(flags, INDENT)) {
X if ((indent_str = do_set(set_options, "pre_indent_str"))) {
X fputs(format_hdr(n, indent_str, FALSE) + 9, fp); /* magic 9 !! */
X fputc('\n', fp);
X }
X if (!(indent_str = do_set(set_options, "indent_str")))
X indent_str = DEF_INDENT_STR;
X }
X /* "line" used as dummy here, since 0 bytes read */
X if (!msg_get(n, line, 0)) {
X error("Unable to find msg %d", n+1);
X return -1;
X }
X while (still_more < msg[n].m_size && fgets(line, sizeof (line), tmpf)) {
X still_more += strlen(line);
X#ifdef MSG_SEPARATOR
X if (ison(flags, NO_SEPARATOR)) {
X#ifdef MMDF
X if (!strncmp(line, MSG_SEPARATOR, 4))
X#else /* !MMDF */
X if (!strncmp(line, MSG_SEPARATOR, strlen(MSG_SEPARATOR)))
X#endif /* MMDF */
X continue;
X }
X#endif /* MMDF */
X /*
X * If squeeze is one, all blanks lines squeeze down to one blank line.
X * If squeeze is two, squeezing is in progress so wait for the next \n.
X */
X if (*line == '\n') {
X if (on_hdr) { /* blank line -- end of header */
X on_hdr = 0;
X if (ison(flags, NO_HEADER))
X continue;
X }
X if (squeeze > 1 || pat_len && pat_seek)
X continue;
X else if (squeeze)
X squeeze = 2;
X } else {
X if (squeeze > 1)
X squeeze = 1;
X if (pat_len && (!on_hdr || isoff(flags, NO_HEADER))) {
X /* If we're looking for a pattern for mush-pipe, then
X * continue if this line doesn't match the pattern.
X */
X if (pat_len == 0)
X continue;
X Debug("Seeking (%s) in (%s)", pattern, line);
X if (strncmp(line, pattern, pat_len)) {
X if (pat_seek)
X continue;
X } else if (end_pat && *end_pat++ == ',') {
X pattern = end_pat;
X if (*pattern == '/') {
X pattern++;
X if (end_pat = index(pattern, '/'))
X *end_pat++ = 0;
X }
X pat_len = pattern? strlen(pattern) : 0;
X pat_seek = !pat_seek;
X } else {
X pat_len = 0;
X pat_seek = !pat_seek;
X }
X }
X }
X
X if (ison(flags, UPDATE_STATUS))
X if (!strncmp(line, "Status:", 7))
X continue; /* ignore this and other "Status" lines */
X else if (!on_hdr) {
X /* preserve NEW/UNREAD status on preserved messages */
X p = line;
X p += Strcpy(p, "Status: O");
X if (isoff(msg[n].m_flags, UNREAD) &&
X isoff(msg[n].m_flags, PRESERVE))
X *p++ = 'R';
X if (ison(msg[n].m_flags, SAVED))
X *p++ = 'S';
X if (ison(msg[n].m_flags, REPLIED))
X *p++ = 'r';
X if (ison(msg[n].m_flags, PRINTED))
X *p++ = 'p';
X if (ison(msg[n].m_flags, FORWARD))
X *p++ = 'f';
X *p++ = '\n', *p = 0;
X (void) fputs(line, fp);
X line[0] = '\n', line[1] = '\0';
X turnoff(flags, UPDATE_STATUS);
X }
X if (on_hdr && (isoff(flags, NO_IGNORE) || ison(flags, FORWARD))) {
X p = any(line, " \t:");
X if (!p)
X ignoring = 0, on_hdr = 0;
X else if (ignoring)
X if (*p != ':') {
X Debug("Ignoring: %s", line);
X continue;
X } else
X ignoring = 0;
X if (p && *p == ':') {
X *p = 0;
X ignoring = 0;
X if (ison(flags, FORWARD)) {
X if (chk_two_lists(line, IGNORE_ON_FWD, ":, \t"))
X ignoring = 1;
X } else if (show_hdrs) {
X if (!chk_two_lists(line, show_hdrs, ":, \t"))
X ignoring = 1;
X } else {
X register struct options *opts;
X for (opts = ignore_hdr; opts; opts = opts->next)
X if (!lcase_strncmp(opts->option, line, -1)) {
X ignoring = 1;
X break;
X }
X }
X *p = ':';
X if (ignoring) {
X Debug("Ignoring: %s", line);
X continue;
X }
X }
X }
X if (!on_hdr && ison(flags, M_TOP) && !--top)
X break;
X if (!on_hdr && (still_more < msg[n].m_size || line[0] != '\n') ||
X isoff(flags, NO_HEADER)) {
X /* note that function returns the number of lines */
X lines++;
X if (ison(flags, INDENT))
X (void) fputs(indent_str, fp);
X if (!fp) {
X if (do_pager(line, FALSE) == EOF)
X return -1;
X } else if (fputs(line, fp) == EOF)
X /* Pipe broken, out of file space, etc */
X return -1;
X }
X if (pat_seek && !pat_len)
X break; /* Skip the rest */
X }
X if (ison(flags, INDENT) &&
X (indent_str = do_set(set_options, "post_indent_str")) && *indent_str) {
X (void) fprintf(fp, "%s\n", format_hdr(n, indent_str, FALSE)+9);
X }
X if (fp && fflush(fp) == EOF)
X return -1; /* Write failure? */
X return lines;
X}
X
X/*
X * copy tempfile back to folder.
X * Return 1 on success, 0 on failure.
X */
Xcopyback(prompt)
Xchar *prompt;
X{
X register int i = 0, held = 0, saved = 0;
X register u_long flg = 0;
X register FILE *mbox = NULL_FILE, *mail_fp = NULL_FILE;
X#ifdef SYSV
X FILE *save_mail_fp = NULL_FILE;
X#endif /* SYSV */
X char *mbox_file, action = 0;
X int hold = 0, delete_it = 0, dont_unlink = FALSE;
X int isspool, keepsave, write_err = FALSE;
X static int first = 1;
X
X /*
X * if there is new mail in this folder, the user is notified and
X * prompted if he really wants to update the folder. He's either
X * quitting or changing folders, so let him read the new mail first.
X */
X if (!first && mail_size()) {
Xlost_lock:
X if (get_new_mail(TRUE) && prompt && isoff(glob_flags, REDIRECT)
X && show_new_mail()) {
X char buf[80];
X if (iscurses)
X putchar('\n'), turnon(glob_flags, CNTD_CMD);
X if (!istool)
X print("%s [n] ", prompt);
X buf[0] = 0;
X#ifdef SUNTOOL
X if (istool) {
X (void) sprintf(buf, "New mail -- %s", prompt);
X if (ask(buf) != TRUE)
X return 0;
X } else
X#endif /* SUNTOOL */
X if (!Getstr(buf, sizeof (buf), 0) || lower(*buf) != 'y')
X return 0;
X }
X }
X first = 0;
X
X /* If the user hasn't changed anything, just return true */
X if (isoff(glob_flags, DO_UPDATE))
X return 1;
X if (ison(glob_flags, READ_ONLY)) {
X print("Unable to update %s: read only\n", mailfile);
X return 0; /* user should use "exit" instead of "quit". */
X }
X if (!msg_cnt) /* prevent unnecessary overwrite */
X return 1;
X
X#ifdef SUNTOOL
X if (istool) {
X (void) notify_set_itimer_func(tool, do_check,
X ITIMER_REAL, (struct itimerval *) 0, (struct itimerval *) 0);
X }
X#endif /* SUNTOOL */
X
X /* We can't lock a file unless we have an fd, but "w+" will zero
X * the file. If the lock later failed for any reason (possible
X * race condition with an MTA), we would lose all current mail.
X * So, open read/write (if possible) and truncate later.
X */
X if (!(mail_fp = lock_fopen(mailfile, "r+"))) {
X error("WARNING: unable to lock %s -- update aborted", mailfile);
X#ifdef SUNTOOL
X write_err = 1; /* forces return 0; below */
X goto resume_timer; /* blecch */
X#else /* !SUNTOOL */
X return 0;
X#endif /* SUNTOOL */
X }
X /* Make sure no mail arrived between the last check and when we
X * got the lock. If it did, release the lock and try again.
X */
X if (mail_size()) {
X (void) close_lock(mailfile, mail_fp);
X goto lost_lock;
X }
X
X /* open mbox if: "autodelete" AND "hold" are NOT set. */
X if (!strcmp(mailfile, spoolfile)
X && !(delete_it = !!do_set(set_options, "autodelete"))
X && !(hold = !!do_set(set_options, "hold"))) {
X register char *p;
X int x = 1; /* tell getpath to ignore "ENOENT" if file not found */
X
X if (!(p = do_set(set_options, "mbox")))
X p = DEF_MBOX;
X mbox_file = getpath(p, &x); /* static data -- copy? */
X if (x) {
X if (x > 0)
X print("%s is a directory.\n", mbox_file);
X else
X print("Unable to open %s: %s\n", p, mbox_file);
X mbox = NULL_FILE;
X } else {
X if (Access(mbox_file, F_OK) == -1) /* does it exist? */
X mbox = lock_fopen(mbox_file, "w");
X else
X mbox = lock_fopen(mbox_file, "a");
X if (!mbox)
X error("Unable to write to %s", mbox_file);
X }
X }
X
X /* ignore signals before truncating */
X turnon(glob_flags, IGN_SIGS);
X#ifdef SYSV
X /* SysV can't truncate a file in the middle, so we can't just
X * write to mail_fp and close. Instead, we save the mail_fp
X * and reopen for writing, ignoring our own lock. After updating,
X * we can safely fclose both file pointers.
X */
X save_mail_fp = mail_fp;
X /* This could fail if we run out of file descriptors */
X if (!(mail_fp = fopen(mailfile, "w"))) {
X error("WARNING: unable to reopen %s for update", mailfile);
X if (save_mail_fp)
X (void) close_lock(mailfile, save_mail_fp);
X if (mbox)
X (void) close_lock(mbox_file, mbox);
X turnoff(glob_flags, IGN_SIGS);
X return 0;
X }
X#endif /* SYSV */
X
X print("Updating \"%s\"", mailfile);
X
X turnon(flg, UPDATE_STATUS);
X
X keepsave = !!do_set(set_options, "keepsave");
X isspool = !strcmp(mailfile, spoolfile);
X
X for (i = 0; i < msg_cnt; i++) {
X /* Maintain the current message across update; if this turns out
X * to be unnecessary (changing folders), folder() will reset it.
X */
X if (current_msg == i)
X current_msg = held;
X /* Check to see if message is marked for deletion or, if read and not
X * preserved, delete it if autodelete is set. Otherwise, if hold is
X * set save the message in the spool file. If all fails, save in mbox.
X */
X if (ison(msg[i].m_flags, DELETE)
X || ison(msg[i].m_flags, SAVED) && !keepsave &&
X isoff(msg[i].m_flags, PRESERVE) && isspool
X || isoff(msg[i].m_flags, UNREAD) && isoff(msg[i].m_flags, PRESERVE)
X && delete_it) {
X Debug("%s %d",
X (action!='d')? "\ndeleting message:" : "", i+1), action = 'd';
X continue;
X } else if (ison(msg[i].m_flags, UNREAD) ||
X ison(msg[i].m_flags, PRESERVE) || hold || !mbox) {
X Debug("%s %d",
X (action!='s')? "\nsaving in spool:" : "", i+1), action = 's';
X if (copy_msg(i, mail_fp, flg, NULL) == -1) {
X error("WARNING: unable to write back to spool");
X print_more("ALL mail left in %s\n", tempfile);
X print_more("Spool mailbox may be corrupted.\n");
X dont_unlink = TRUE;
X write_err = TRUE;
X break;
X }
X held++;
X } else if (isspool) { /* copy back to mbox */
X if (copy_msg(i, mbox, flg, NULL) == -1) {
X error("WARNING: unable to write to mbox");
X print_more("Unresolved mail left in %s\n", tempfile);
X dont_unlink = TRUE;
X write_err = TRUE;
X break;
X }
X saved++;
X Debug("%s %d",
X (action!='m')? "\nsaving in mbox:" : "", i+1), action = 'm';
X }
X }
X if (write_err)
X current_msg = 0;
X else if (current_msg == held)
X current_msg--; /* Don't point to a message that got deleted */
X Debug("\n%s", mailfile);
X
X#ifdef SYSV
X /* Close the write file pointer first */
X (void) fclose(mail_fp);
X mail_fp = save_mail_fp;
X#else /* !SYSV */
X /* Truncate the file at the end of what we just wrote.
X * If you aren't SYSV and you still can't ftruncate(),
X * you're out of luck?
X */
X (void) ftruncate(fileno(mail_fp), ftell(mail_fp));
X#endif /* SYSV */
X
X /* some users like to have zero length folders for frequent usage */
X if (mbox && close_lock(mbox_file, mbox) == EOF) {
X error("WARNING: unable to close mbox");
X print_more("Unresolved mail left in %s\n", tempfile);
X dont_unlink = TRUE;
X write_err = TRUE;
X }
X if (held) {
X print_more(": saved %d message%s\n", held, (held==1)? NO_STRING: "s");
X } else
X#ifdef HOMEMAIL
X if (!dont_unlink && !do_set(set_options, "save_empty"))
X#else /* HOMEMAIL */
X if (strcmp(mailfile, spoolfile) && !dont_unlink &&
X !do_set(set_options, "save_empty"))
X#endif /* HOMEMAIL */
X if (unlink(mailfile))
X turnon(glob_flags, CONT_PRNT), error(": cannot remove");
X else {
X print_more(": removed\n");
X held = -1;
X }
X else
X print_more(": empty\n");
X if (saved)
X print("saved %d message%s in %s\n",
X saved,(saved==1)? NO_STRING:"s", mbox_file);
X
X if (held > 0) {
X /* Reset the access time of the spool file to prevent
X * bogus "new mail" messages from the shell.
X */
X long times[2];
X (void) fflush(mail_fp); /* just in case */
X times[1] = time(×[0]) - (long)2;
X if (!strcmp(mailfile, spoolfile) && utime(mailfile, times))
X error("utime");
X }
X
X if (close_lock(mailfile, mail_fp) == EOF) {
X error("WARNING: unable to close spool");
X print_more("ALL mail left in %s\n", tempfile);
X print_more("Spool mailbox may be corrupted.\n");
X write_err = TRUE;
X }
X
X#ifdef SUNTOOL
X if (istool) {
Xresume_timer:
X mail_timer.it_value.tv_sec = time_out;
X mail_timer.it_interval.tv_sec = time_out;
X (void) notify_set_itimer_func(tool, do_check,
X ITIMER_REAL, &mail_timer, (struct itimerval *) 0);
X }
X#endif /* SUNTOOL */
X
X turnoff(glob_flags, IGN_SIGS);
X
X /* Return nonzero for success, -1 if file removed */
X if (write_err)
X return 0;
X else if (held < 0)
X return -1;
X else
X return 1;
X}
X
X/*
X * check the sizes of the current folder (file) and the spool file.
X * spool_size is the size in bytes of the user's main mailbox.
X * last_size is the size of the _current_ folder the last time we checked.
X * return true if the current folder has new mail. check_new_mail() checks
X * for new mail in the system mailbox since it checks against last_spool_size.
X */
Xmail_size()
X{
X struct stat buf;
X
X if (!stat(spoolfile, &buf))
X spool_size = buf.st_size;
X else if (!strcmp(mailfile, spoolfile))
X return 0;
X if (!is_shell || ison(glob_flags, IS_SENDING))
X return 0;
X if (strcmp(mailfile, spoolfile) && stat(mailfile, &buf)) {
X if (errno != ENOENT)
X error("Unable to stat %s", mailfile);
X return 0;
X }
X if (buf.st_size != last_size) {
X last_size = buf.st_size;
X return 1;
X }
X return 0;
X}
X
Xstatic
Xstruct mailstat {
X int new, unread, deleted;
X} mail_stat;
X
Xvoid
Xmail_status(as_prompt)
X{
X char buf[MAXPATHLEN];
X register int cnt;
X
X mail_stat.new = mail_stat.unread = mail_stat.deleted = 0;
X
X for (cnt = 0; cnt < msg_cnt; cnt++) {
X if (ison(msg[cnt].m_flags, UNREAD))
X mail_stat.unread++;
X if (ison(msg[cnt].m_flags, DELETE))
X mail_stat.deleted++;
X if (isoff(msg[cnt].m_flags, OLD))
X mail_stat.new++;
X }
X if (as_prompt) {
X /* use %s in case prompt has any %'s in it */
X print("%s", format_prompt(current_msg, prompt));
X return;
X }
X (void) sprintf(buf,"\"%s\"%s: %d message%s, %d new, %d unread",
X trim_filename(mailfile),
X ison(glob_flags, READ_ONLY)? " [read only]" : "",
X msg_cnt, (msg_cnt != 1)? "s": NO_STRING,
X mail_stat.new, mail_stat.unread);
X if (istool || iscurses)
X (void) sprintf(buf+strlen(buf), ", %d deleted", mail_stat.deleted);
X#ifdef SUNTOOL
X if (istool) {
X static char ic_text[4];
X char *lbl;
X Icon icon;
X extern struct pixrect mail_icon_image1, mail_icon_image2;
X (void) sprintf(ic_text, "%3d", msg_cnt);
X if (!(lbl = (char *)window_get(tool, FRAME_LABEL)) || strcmp(lbl, buf))
X (void) window_set(tool, FRAME_LABEL, buf, NULL);
X icon = (Icon) window_get(tool, FRAME_ICON);
X (void) icon_set(icon,
X ICON_IMAGE, ison(glob_flags, NEW_MAIL)?
X &mail_icon_image2 : &mail_icon_image1,
X NULL);
X if (!chk_option("quiet", "iconlabel"))
X (void) icon_set(icon, ICON_LABEL, ic_text, NULL);
X else
X (void) icon_set(icon, ICON_LABEL, NO_STRING, NULL);
X (void) window_set(tool, FRAME_ICON, icon, NULL);
X } else
X#endif /* SUNTOOL */
X
X#ifdef CURSES
X if (iscurses) {
X move (0, 0);
X printw("%-3d %-.*s",
X ((msg_cnt)? current_msg+1 : 0), COLS-5, buf), clrtoeol();
X } else
X#endif /* CURSES */
X puts(buf);
X return;
X}
X
X/*
X * Construct a prompt for the given message number using the given format
X */
Xchar *
Xformat_prompt(num, fmt)
Xint num;
Xchar *fmt;
X{
X static char buf[MAXPATHLEN];
X register char *p, *b = buf, *mf;
X
X if (is_shell)
X mf = mailfile;
X else
X mf = "[no folder]";
X
X for (p = fmt; *p; p++)
X if (*p == '\\')
X switch (*++p) {
X case 'n': case 'r': *b++ = '\n';
X when 't': *b++ = '\t';
X otherwise: *b++ = *p;
X }
X else if (*p == '%')
X switch (*++p) {
X case 'm':
X b += strlen(sprintf(b,"%d",(msg_cnt)? num + 1 : 0));
X when 't':
X b += strlen(sprintf(b, "%d", msg_cnt));
X when 'd':
X b += strlen(sprintf(b, "%d", mail_stat.deleted));
X when 'u':
X b += strlen(sprintf(b, "%d", mail_stat.unread));
X when 'n':
X b += strlen(sprintf(b, "%d", mail_stat.new));
X when 'f':
X {
X char *tail = rindex(mf, '/');
X if (tail && tail[1])
X b += Strcpy(b, tail+1);
X else {
X /* Fall through */
X case 'F':
X b += Strcpy(b, mf);
X }
X if (ison(glob_flags, READ_ONLY))
X b += Strcpy(b, " [read-only]");
X }
X when 'T': case 'D': case 'Y': case 'y':
X case 'M': case 'N': case 'W':
X b += Strcpy(b, Time(p, (long)0));
X otherwise: *b++ = *p;
X }
X else if (*p == '!')
X b += strlen(sprintf(b, "%d", hist_no+1));
X else
X *b++ = *p;
X *b = 0;
X return buf;
X}
X
X/*
X * For uucp mailers that use >From lines with "remote from <path>":
X * (where "path" is a hostname or pathnames)
X *
X * a. Set the return_path to the empty string.
X * b. For each From_ or >From_ line:
X * c. Save the username (second token).
X * d. Save the date (3-7 tokens).
X * e. If it has a "remote from" then append the remote host
X * (last token) followed by a "!" to the return_path.
X * f. If the saved username has a '@' but no '!' then convert it
X * to UUCP path form.
X * g. Append the saved username to return_path.
X */
Xparse_from(fp, path)
XFILE *fp;
Xchar path[];
X{
X char user[256], buf[256]; /* max size for each line in a mail file */
X register char *p;
X long save_offset = ftell(fp);
X
X path[0] = '\0';
X while (fgets(buf, sizeof buf, fp)) {
X if (strncmp(buf, ">From ", 6))
X break;
X p = buf + 6;
X
X (void) sscanf(p, "%s", user);
X
X while (p = index(p+1, 'r')) {
X if (!strncmp(p, "remote from ", 12)) {
X char *p2 = path+strlen(path);
X skipspaces(12);
X (void) sscanf(p, "%s", p2); /* add the new machine to current path */
X (void) strcat(p2, "!");
X break;
X }
X }
X
X if (p)
X (void) bang_form(path + strlen(path), user);
X save_offset = ftell(fp);
X }
X (void) fseek(fp, save_offset, L_SET);
X}
X
X/*
X * Scan a file and select messages from it and append them to the current folder
X *
X * If "append" is 1, start where we left off (held in msg[cnt].m_offset)
X * and scan for messages. Append all messages found until EOF.
X *
X * If "append" is 2, we're merging in a new file, so start at the end of
X * the present folder and append all messages found until EOF.
X *
X * If "append" is 0, then the message separator must exist once and
X * only once. All extra occurrences of the separator is preceded by a '>'.
X * The list argument will be the message number to replace in the current
X * folder with the message read in from other filename.
X */
Xload_folder(file, append, list)
Xchar *file, *list;
Xint append;
X{
X char buf[BUFSIZ];
X int lines = 0, msg_found = 0, had_error = 1;
X int get_status = 1, cnt;
X long bytes, ftell();
X struct msg old;
X char *p, date[64];
X FILE *fp;
X#ifdef MMDF
X int begin_sep = 0; /* track beginning vs ending separators */
X#endif /* MMDF */
X
X if (!(fp = lock_fopen(file, "r"))) {
X error("Unable to open %s", file);
X return -1;
X }
X
X if (append) {
X cnt = msg_cnt;
X (void) fseek(fp, append == 1 ? msg[cnt].m_offset : 0L, L_SET);
X } else {
X cnt = (int)list;
X old = msg[cnt];
X }
X
X if (isoff(glob_flags, READ_ONLY)) {
X if (tmpf)
X (void) fclose(tmpf);
X if (!(tmpf = mask_fopen(tempfile, "a"))) {
X error("Unable to open %s for appending", tempfile);
X close_lock(file, fp);
X return -1;
X }
X (void) fseek(tmpf, 0L, 2); /* assure we're at the end of the file */
X } else if (append == 2) {
X /* you can't merge in a folder to a read-only folder */
X close_lock(file, fp);
X return -1;
X }
X
X#ifdef MMDF
X if (!append) {
X (void) strcpy(buf, MSG_SEPARATOR);
X goto do_headers;
X }
X#endif /* MMDF */
X buf[0] = 0;
X while (fgets(buf, sizeof (buf), fp)) {
X#ifndef MSG_SEPARATOR
X int warn = ison(glob_flags, WARNING);
X turnoff(glob_flags, WARNING);
X if (!strncmp(buf, "From ", 5)) {
X p = buf + 5; /* skip "From " */
X skipspaces(0);
X p = any(p, " \t"); /* skip the address */
X } else
X p = buf;
X if (p > buf && (p = parse_date(p + 1)) && strcpy(date, p))
X#else /* MSG_SEPARATOR */
X if (!strncmp(buf, MSG_SEPARATOR, strlen(MSG_SEPARATOR)))
X#endif /* MSG_SEPARATOR */
X {
X#ifdef MMDF
X if (!append)
X (void) fputc('>', tmpf);
X else if (begin_sep = !begin_sep)
Xdo_headers:
X#else /* MMDF */
X if (!append && msg_found)
X (void) fputc('>', tmpf);
X else
X#endif /* MMDF */
X {
X msg_found++;
X had_error = 0;
X if (append && cnt == MAXMSGS-append) {
X wprint("WARNING: exceeded %d messages.\n", MAXMSGS-append);
X wprint("Not all messages have been loaded.\n");
X msg_cnt--;
X had_error++;
X break;
X }
X if (ison(glob_flags, READ_ONLY))
X bytes = ftell(fp) - strlen(buf);
X else {
X char path[256];
X parse_from(fp, path);
X if (path[0])
X (void)sprintf(buf,"From %s %s", path,
X date_to_ctime(date));
X bytes = ftell(tmpf);
X }
X /* finish up message structure from previous message.
X * if this is incorporating new mail, check "lines" to
X * see if previous message has already been set!
X */
X if (cnt && lines) {
X msg[cnt-1].m_size = bytes - msg[cnt-1].m_offset;
X msg[cnt-1].m_lines = lines;
X }
X if (isoff(glob_flags, READ_ONLY) && fputs(buf, tmpf) == -1) {
X error(tempfile);
X had_error++;
X break;
X }
X msg[cnt].m_offset = bytes;
X msg[cnt].m_flags = 0L;
X#ifdef MSG_SEPARATOR
X lines = 0;
X#else /* MSG_SEPARATOR */
X lines = 1; /* count the From_ line */
X if (warn)
X turnon(glob_flags, WARNING);
X strdup(msg[cnt].m_date_recv, date);
X#endif /* MSG_SEPARATOR */
X turnon(msg[cnt].m_flags, UNREAD); /* initialize */
X /* we've read the "From " line(s), now read the rest of
X * the message headers till we get to a blank line.
X */
X while (fgets(buf, sizeof (buf), fp) && (*buf != '\n')) {
X p = buf;
X if (!strncmp(buf, "Date:", 5))
X strdup(msg[cnt].m_date_sent, parse_date(p+5));
X if (get_status &&
X !(get_status = strncmp(p, "Status:", 7))) {
X /* new mail should not have a Status: field! */
X turnon(msg[cnt].m_flags, OLD);
X for (p += 7 ; *p != '\n'; p++) {
X if (isspace(*p))
X continue;
X switch(*p) {
X case 'R': turnoff(msg[cnt].m_flags, UNREAD);
X when 'P': turnon(msg[cnt].m_flags, UNREAD);
X when 'N': turnon(msg[cnt].m_flags, UNREAD);
X turnoff(msg[cnt].m_flags, OLD);
X when 'S': turnon(msg[cnt].m_flags, SAVED);
X when 'r': turnon(msg[cnt].m_flags, REPLIED);
X when 'O': ; /* do nothing */
X when 'f': turnon(msg[cnt].m_flags, FORWARD);
X when 'p': turnon(msg[cnt].m_flags, PRINTED);
X otherwise :
X if (ison(glob_flags, WARNING))
X print("unknown msg status flag: %c\n",
X *p);
X }
X }
X }
X if (isoff(glob_flags,READ_ONLY) && fputs(buf, tmpf) == -1) {
X error(tempfile);
X had_error++;
X break;
X }
X lines++;
X }
X if (!msg[cnt].m_date_sent || !*msg[cnt].m_date_sent)
X if (!msg[cnt].m_date_recv || !*msg[cnt].m_date_recv) {
X wprint("Message %d has *no* date!?\n", cnt+1);
X msg[cnt].m_date_sent = msg[cnt].m_date_recv =
X "0000000000XXX";
X } else
X strdup(msg[cnt].m_date_sent, msg[cnt].m_date_recv);
X else if (!msg[cnt].m_date_recv || !*msg[cnt].m_date_recv)
X strdup(msg[cnt].m_date_recv, msg[cnt].m_date_sent);
X if (had_error)
X break;
X if (append && list)
X set_msg_bit(list, cnt);
X if (append)
X cnt = ++msg_cnt;
X get_status = 1;
X }
X } else if (!msg_found && buf[0] != '\n') {
X /* Allow leading blank lines, but anything else is wrong */
X lines++;
X had_error++;
X break;
X }
X if (msg_found) {
X lines++;
X if (isoff(glob_flags, READ_ONLY) && fputs(buf, tmpf) == -1) {
X error(tempfile);
X had_error++;
X break;
X }
X }
X }
X if (msg_found && append != 1)
X turnon(glob_flags, DO_UPDATE);
X#ifdef MMDF
X if (!append)
X (void) fputs(END_MSG_SEP, tmpf);
X#endif /* MMDF */
X if (had_error) {
X if (!append)
X msg[cnt] = old;
X else if (msg_found && append == 1 && cnt == MAXMSGS-append) {
X /* reset fp to the beginning of the not-loaded message */
X bytes = ftell(fp) - strlen(buf);
X (void) fseek(fp, bytes, L_SET);
X }
X if (!msg_found) {
X if (!append)
X print("File not left in correct message format.\n");
X else if (cnt == 0) {
X if (buf[0])
X print("\"%s\" does not seem to be a folder\n", file);
X else
X had_error = 0; /* empty files are OK */
X }
X }
X } else {
X if (append)
X cnt--;
X if (isoff(glob_flags, READ_ONLY))
X msg[cnt].m_size = ftell(tmpf) - msg[cnt].m_offset;
X else
X msg[cnt].m_size = ftell(fp) - msg[cnt].m_offset;
X msg[cnt].m_lines = lines;
X /* remember where we were to seek to for when we append new mail */
X if (append)
X cnt++;
X }
X if (append == 1) /* merge_folders takes care of this for append == 2 */
X msg[cnt].m_offset = ftell(fp);
X close_lock(file, fp);
X if (isoff(glob_flags, READ_ONLY)) {
X if (had_error && msg_found && append == 1 && cnt == MAXMSGS-append) {
X wprint("Using read-only mode.\n");
X turnon(glob_flags, READ_ONLY);
X had_error = 0; /* return successfully anyway */
X }
X (void) fclose(tmpf);
X if (!(tmpf = fopen(tempfile, "r"))) {
X error("Unable to open %s for reading", tempfile);
X return -1;
X }
X }
X return !had_error;
X}
END_OF_FILE
if test 27478 -ne `wc -c <'mush/msgs.c'`; then
echo shar: \"'mush/msgs.c'\" unpacked with wrong size!
fi
# end of 'mush/msgs.c'
fi
echo shar: End of archive 11 \(of 19\).
cp /dev/null ark11isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 19 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0