# To unbundle, run this file echo Makefile sed 's/.//' >Makefile <<'//GO.SYSIN DD Makefile' -# -# @(#)Makefile 1.49 -# -BINDIR = $(HOME)/bin/$(cputype) -SHBINDIR = $(HOME)/bin -CC = gcc -CFLAGS = -O -g -DYYDEBUG -STICKY = 0 -XMODE = $(STICKY)711 -SHXMODE = 755 -XSGID = $(STICKY)2711 -MAIL = mail -RANLIB = : ranlib -YFLAGS = #-v -SHELL = /bin/sh - -# -# Braindamage for broken socket installations -# -NETLIBS = -lsocket -lnsl - -NEW = - -INC = \ - addr.h \ - conf.h \ - flex.h \ - headers.h \ - line.h \ - mace.h \ - message.h \ - pop.h \ - regexp.h \ - regmagic.h \ - tty.h - -LIBSRC = \ - addr.y \ - aka.c \ - args.c \ - conf.c \ - dir.c \ - domain.c \ - id.c \ - flex.c \ - headers.c \ - host.c \ - line.c \ - lock.c \ - mail.c \ - macebox.c \ - macedir.c \ - memory.c \ - mesg.c \ - mess.c \ - misc.c \ - name.c \ - pipe.c \ - re.c \ - readdir.c \ - readfile.c \ - readpass.c \ - regexp.c \ - rfc.c \ - run.c \ - string.c \ - sysmess.c \ - tn.c \ - tty.c \ - vec.c \ - writefile.c - -SH = \ - bundle \ - mal - -SRC = \ - $(INC) \ - $(LIBSRC) \ - $(SH) \ - box.c \ - com.c \ - despool.c \ - mace.c \ - mad.c \ - mal \ - mam.c \ - mda.c \ - mox.c \ - msg.c \ - pop.c \ - reo.c \ - ret.c - -DOC = \ - box.1 \ - com.1 \ - mace.1 \ - mal.1 \ - mam.1 \ - mov.1 \ - mox.1 \ - msg.1 \ - pop.1 \ - reo.1 \ - mace-config.4 \ - mace-proto.4 - -TEXT = \ - Makefile \ - NEW \ - TODO \ - :yyfix \ - setup \ - $(DOC) \ - $(SRC) - -LIB = libmace.a - -LIBOBJ = \ - addr.o \ - aka.o \ - args.o \ - conf.o \ - dir.o \ - domain.o \ - id.o \ - flex.o \ - headers.o \ - host.o \ - line.o \ - lock.o \ - macebox.o \ - macedir.o \ - mail.o \ - memory.o \ - mesg.o \ - mess.o \ - misc.o \ - name.o \ - pipe.o \ - re.o \ - readdir.o \ - readfile.o \ - readpass.o \ - regexp.o \ - rfc.o \ - run.o \ - string.o \ - sysmess.o \ - tn.o \ - tty.o \ - vec.o \ - writefile.o - -BIN = \ - box \ - com \ - mace \ - despool \ - mad \ - mam \ - mda \ - mox \ - msg \ - pop \ - reo \ - ret - -MACE = \ - $(BIN) \ - $(SH) - -all : $(MACE) - -install : all - cp $(BIN) $(BINDIR) - cd $(BINDIR) ; chmod $(XMODE) $(BIN) - cp $(SH) $(SHBINDIR) - cd $(SHBINDIR) ; chmod $(SHXMODE) $(SH) - -cd $(BINDIR) ; rm -f rem ; ln msg rem - -cd $(BINDIR) ; rm -f med ; ln msg med - -cd $(BINDIR) ; rm -f mov ; ln msg mov - -cd $(BINDIR) ; rm -f del ; ln msg del - -cd $(BINDIR) ; rm -f cop ; ln msg cop - -cd $(BINDIR) ; rm -f lnk ; ln msg lnk - -cd $(BINDIR) ; rm -f mrk ; ln msg mrk - -cd $(BINDIR) ; rm -f ./- ; ln msg ./- - -cd $(BINDIR) ; rm -f + ; ln msg + - -cd $(BINDIR) ; rm -f rep ; ln com rep - -cd $(BINDIR) ; rm -f fwd ; ln com fwd - -cd $(BINDIR) ; rm -f mcp ; ln mad mcp - -cd $(BINDIR) ; rm -f mln ; ln mad mln -# cd $(BINDIR) ; chgrp $(MAIL) despool -# cd $(BINDIR) ; chmod $(XSGID) despool - -print : - pr -l66 -w132 $(TEXT) | lp - -dist : bundle - sh bundle $(TEXT) > mace.bundle - -shar : bundle - sh bundle $(TEXT) > mace.$@ - -$(LIB) : $(LIBOBJ) - @-rm -f $(LIB) - ar qv $(LIB) $(LIBOBJ) - $(RANLIB) $(LIB) - -test : test.o $(LIB) - $(CC) -o test test.o $(LIB) - -clean : - rm -f $(LIB) *.o y.output y.tab.c - -nuke : clean - rm -f $(BIN) - -tags :: - ctags $(SRC) - -admin : $(NEW) - @echo 'Comment? ' | tr -d '\012' ; read x ; set -x ; \ - for i in $(NEW) ; \ - do \ - admin -i"$$i" -y"$$x" SCCS/s."$$i" ; \ - done - -delta : - @echo 'Comment? ' | tr -d '\012' ; read x ; set -x ; \ - for i in $(TEXT) ; \ - do \ - delta -y"$$x" SCCS/s."$$i" || : ; \ - done - -box : $(LIB) box.o - $(CC) -o box box.o $(LIB) - -com : $(LIB) com.o - $(CC) -o com com.o $(LIB) - -mace : $(LIB) mace.o - $(CC) -o mace mace.o $(LIB) - -despool : $(LIB) despool.o - $(CC) -o despool despool.o $(LIB) - -mad : $(LIB) mad.o - $(CC) -o mad mad.o $(LIB) - -mam : $(LIB) mam.o - $(CC) -o mam mam.o $(LIB) - -mda : $(LIB) mda.o - $(CC) -o mda mda.o $(LIB) - -mox : $(LIB) mox.o - $(CC) -o mox mox.o $(LIB) - -msg : $(LIB) msg.o - $(CC) -o msg msg.o $(LIB) - -pop : $(LIB) pop.o - $(CC) -o pop pop.o $(LIB) || ( set -x ; $(CC) -o pop pop.o $(LIB) $(NETLIBS) ) - -reo : $(LIB) reo.o - $(CC) -o reo reo.o $(LIB) - -ret : $(LIB) ret.o - $(CC) -o ret ret.o $(LIB) - -.c.o : - $(CC) $(CFLAGS) -c $*.c - -addr.c : addr.y - yacc $(YFLAGS) addr.y - sh :yyfix - -box.o : box.c mace.h line.h message.h headers.h conf.h regexp.h -com.o : com.c mace.h message.h headers.h conf.h regexp.h addr.h -mace.o : mace.c mace.h conf.h headers.h line.h message.h regexp.h flex.h -despool.o : despool.c mace.h -mad.o : mad.c mace.h -mam.o : mam.c mace.h regexp.h message.h line.h -mda.o : mad.c conf.h line.h mace.h headers.h message.h regexp.h addr.h -mox.o : mox.c mace.h regexp.h conf.h line.h message.h -msg.o : msg.c mace.h line.h flex.h message.h -pop.o : pop.c mace.h line.h flex.h pop.h -reo.o : reo.c mace.h line.h message.h -ret.o : ret.c mace.h line.h message.h -test.o : test.c mace.h - -messid.o : messid.c mace.h - -addr.o : addr.c mace.h flex.h headers.h addr.h -aka.o : aka.c mace.h -args.o : args.c mace.h line.h -conf.o : conf.c conf.h flex.h headers.h line.h mace.h message.h regexp.h -dir.o : dir.c mace.h -domain.o : domain.c mace.h line.h -id.o : id.c mace.h -flex.o : flex.c flex.h mace.h -host.o : host.c mace.h line.h -headers.o : headers.c mace.h headers.h -line.o : line.c flex.h line.h mace.h -lock.o : lock.c mace.h -macebox.o : macebox.c mace.h -macedir.o : macedir.c mace.h -mail.o : mail.c mace.h line.h headers.h -memory.o : memory.c mace.h -mesg.o : mesg.c mace.h -mess.o : mess.c mace.h message.h headers.h line.h -misc.o : misc.c mace.h -name.o : name.c mace.h -pipe.o : pipe.c mace.h -re.o : re.c mace.h -readdir.o : readdir.c mace.h -readfile.o : readfile.c mace.h -readpass.o : readpass.c mace.h flex.h tty.h -regexp.o : regexp.c mace.h regmagic.h regexp.h -rfc.o : rfc.c mace.h conf.h headers.h line.h message.h regexp.h -run.o : run.c mace.h -string.o : string.c mace.h -sysmess.o : sysmess.c -tn.o : tn.c mace.h -tty.o : tty.c tty.h mace.h -vec.o : vec.c mace.h -writefile.o : writefile.c mace.h //GO.SYSIN DD Makefile echo NEW sed 's/.//' >NEW <<'//GO.SYSIN DD NEW' -What's New (1.1): - - bundle - - A /bin/sh version of Plan 9 bundle; a simple shell archiver. - - mal +box ... - - A simple alias facility that uses the To: line in a box's .proto. - - % mal +bonehead - Bonehead - - mam - - Used to add messages to boxes: - - mam [ -u ] [ -dps ] [ +[+]box ] [ files ] ... - - It's a more or less like 'mace' and handles multiple box/file arguments - in the same style as 'msg': - - mam +foo a b c ++bar d - - It can also be invoked as a filter. - - It's options are: - - d - don't audit - p - preserve a box's current message - s - silent (doesn't print the message summary) - u - unlock audit trail - - pop - - A POP 3 client which splits a POP mailbox into multiple files: - - pop [ -delete ] [ -n number ] [ -r [ seconds ] ] [ -s spooldir ] [ -t ] [ [user@]server ] - - It's options are: - - -delete - - Delete messages off the POP server after they've all been retrieved. - - -n number - - Message file names start at 'number', instead of 0. - - -r [ seconds ] - - Run in the background and interrogate the server periodically. - A timeout value can be specified in seconds. If none is given - a default of 120 seconds (2 minutes) is used. - - In this mode the password is asked for once and from then on it - lives in a pipe. This eliminates tedious password typing and minimises - the likelyhood of the password winding up in a core dump. - - -s spooldir - - Create messages in 'spooldir'. The current directory is the default. - - -t - - Trace the POP 3 protocol to standard error: - - system% pop -s /tmp -t pacific - pop: <-- +OK QUALCOMM Pop server derived from UCB (version 2.1.4-R3) at PACIFIC starting. - pop: --> USER boyd - pop: <-- +OK Password required for boyd. - pop: --> PASS ... - pop: <-- +OK boyd has 37 message(s) (106154 octets). - pop: --> STAT - pop: <-- +OK 37 106154 - pop: --> RETR 1 - pop: <-- +OK 1397 octets - ... - - [user@]server - - Optional user/mailbox name and POP 3 server to contact. - Otherwise the current user on 'localhost' is used. - - reo - - A filter to re-order headers in an RFC 822 message. It is not configurable - and uses the standard mace order of: - - From: - Date: - To: - Cc: - Bcc: - Subject: - - See headers.c for the ordering code. - - It was written to fix messages broken by a braindamaged delivery agent in - conjunction with this script: - - #!/bin/sh - - # Fix broken mail headers - - sed -e '1,5d' -e '/^>From:/s/>//' | reo - - setup [ directory ] - - A script to setup the directory for Mace and a sample configuration file. //GO.SYSIN DD NEW echo TODO sed 's/.//' >TODO <<'//GO.SYSIN DD TODO' -Things To Do (1.1): - -1. Integrate 'mam' and 'pop -r' in some way. Possibly a script 'mop' is invoked - by the user to pick up the messages retrieved by 'pop'. - -2. Limbo rewrite for Inferno? //GO.SYSIN DD TODO echo :yyfix sed 's/.//' >:yyfix <<'//GO.SYSIN DD :yyfix' -: -: "@(#):yyfix 1.17" -: -sed '/in:/{s/in:/in state %d:/ - s/yyn/&, yystate/ - }' y.tab.c > addr.c //GO.SYSIN DD :yyfix echo setup sed 's/.//' >setup <<'//GO.SYSIN DD setup' -#!/bin/sh - -# -# @(#)setup 1.1 -# -# mace setup -# - -macedir="$HOME/.macedir" -config=".config" - -umask 077 - -myname="`basename \"$0\"`" - -# use argument or prompt for directory -case $# in -0) - dir="$HOME/Mace" - echo "Directory where your mail will be kept [$dir]? " | tr -d '\012' - - if read x - then - case "$x" in - '') - ;; - - *) - dir="$x" - ;; - esac - else - exit 1 - fi - ;; - -1) - dir="$1" - ;; - -*) - echo "usage: $myname [ directory ]" 1>&2 - exit 1 - ;; -esac - -# full path name -case "$dir" in -/*) - ;; - -*) - dir="`pwd`/$dir" - ;; -esac - -# create if necessary -if [ ! -d "$dir" ] -then - mkdir "$dir" || exit 1 -fi - -# slice off $HOME and put in $macedir -if echo "$dir" | sed "s;^$HOME/;;" > "$macedir" 2> /dev/null -then - # determine login name - user=your.login.name - - case "$USER" in - '') - user="$LOGNAME" - ;; - - *) - user="$USER" - ;; - esac - - # create prototype configuration in $config - if cat < "$dir/$config" -incoming in -outgoing out -address your.address.here -remove "$user" -#deliver custom delivery agent command -#exec "regexp" "command" -! - then - echo "Tailor '$dir/$config' to suit your environment." - echo 'It currently contains:' - cat "$dir/$config" - else - echo "$myname: Could not write '$dir/$config'" 1>&2 - exit 1 - fi - -else - echo "$myname: Could not write '$macedir'" 1>&2 - exit 1 -fi //GO.SYSIN DD setup echo box.1 sed 's/.//' >box.1 <<'//GO.SYSIN DD box.1' -.\" -.\" @(#)box.1 1.1 -.\" -.TH BOX 1 -.SH NAME -box \- manage boxes -.SH SYNOPSIS -.B box -[ -.B -acdilmorst -] -[ -[\fB+\fP]\fB+\fP\fIbox\fP -\&... -] -.SH DESCRIPTION -.B Box -allows boxes to be created and deleted as well as providing information on -their status and contents. A particular -.I box -can be specified by prefixing its name by the -.I "box character" -.BR + . -.PP -With no arguments -.B box -displays the name of the current -.I box -prepended with the -.I "box character" -.BR + . -If one -.I box -is specified with no options it is made the -.IR "current box" . -A -.I box -can also be made the current box by specifying the -.I "box character" -.B + -twice. -.PP -Several options, some mutually exclusive, are available: -.TP -.B -a -Apply action to all boxes. -.TP -.B -c -Create the named box(es). -.TP -.B -d -Delete the named box(es). -.TP -.B -i -Show the name of the -.I incoming -box. -.TP -.B -l -Gives a one line summary for the -.IR box . -The output consists of the -.I "box character" -.BR + , -prepended to the name of the box, the name of the current message and -number of messages in the box followed by -.BR messages ( s ). -If the -.I box -contains no messages the message count is replaced by -.BR empty . -.TP -.B -m -Gives a one line summary for the current message in the -.IR box . -.TP -.B -o -Show the name of the -.I outgoing -box. -.TP -.B -r -Gives a one line summary for each message in the -.I box -in reverse message order. -.TP -.B -s -Gives a one line summary for each message in the -.IR box . -The output consists of a -.B - -(indicating that the message was received) or a -.B + -(indicating that the message is pending delivery), the -.I "box character" -.B + -prepended to the name of the box, an optional -.B ? -(indicating links to the message), -an optional -.B | -(indicating delivery by -.BR del ( 1 )) -and the text of the message's -.BR From: , -.B Date: -and -.B Subject: -lines. -.TP -.B -t -Gives a one line summary for each message in the -.I box -showing the message's -.B To: -line instead of the -.B From: -line. -.PP -Before a -.I box -can be deleted all its messages must be removed with -.BR rem ( 1 ). -.SH FILES -$MACEDIR/.config -.br -$MACEDIR/.box -.br -.RI $MACEDIR/ box /.messid -.br -.RI $MACEDIR/ box / id -.SH "SEE ALSO" -.BR del ( 1 ), -.BR msg ( 1 ), -.BR rem ( 1 ), -.BR mace-config ( 4 ). //GO.SYSIN DD box.1 echo com.1 sed 's/.//' >com.1 <<'//GO.SYSIN DD com.1' -.\" -.\" %W% -.\" -.TH COM 1 -.SH NAME -com, fwd, rep \- compose, forward or reply to messages -.SH SYNOPSIS -.B com -[ -.B --eis -] -[ -[\fB+\fP]\fB+\fP\fIbox\fP -] -.sp -.B fwd -[ -.B --eis -] -[ -[\fB+\fP]\fB+\fP\fIbox\fP -] -[ -.I id -] -.sp -.B rep -[ -.B --eis -] -[ -[\fB+\fP]\fB+\fP\fIbox\fP -] -[ -.I id -] -.SH DESCRIPTION -All create a new message template and then invoke -.B $EDITOR -on it. The new message is located in the one of the following boxes: -.TP -.I multiple -.B Rep -applies the -.I refile -regular expressions to the headers of message being replied to. The -first match determines the box used. -.I Copies -are made for boxes in subsequent matches with -.BR mln ( 1 ). -.TP -.I outgoing -If the current box is -.IR incoming . -.TP -.I current -If the current box is not -.IR incoming . -.TP -.I box -The named -.I box -specified by the argument. -.PP -The -.I id -of the message in the chosen -.I box -is the next in the series after the last message in the -.IR box . -.PP -Once the message has been edited it is set to be the -.I "current message" -and it is ready to be delivered with -.BR del ( 1 ). -The separation of composition and delivery is a deliberate choice. -.PP -All support the following options: -.TP -.B -e -An external agent requests only the creation of the template; -.B $EDITOR -is not invoked. -.TP -.B -i -Include the current message, after the headers, in the template. -.TP -.B -s -Insert -.B Sender: -and -.B Reply-To: -headers in the template. The text in the -.B Sender: -header is that which would normally appear in the -.B From: -header. -.PP -The headers are constructed based on a standard template as modified -by the global and local -.I "message prototype" -files. The standard headers are: -.TP -From: -This is followed by your email address. If -.B $NAME -is set it consists of -.B "$NAME <\fIuser\fP@\fIdomain\fP>" otherwise -it is -.BR \fIuser\fP@\fIdomain\fP . -.I User -is your login name. -.I Domain -is the parameter specified with the -.B address -configuration option. -.TP -Date: -The current date and time. -.TP -To: -Not initialised. -.TP -Cc: -Not initialised. -.TP -Bcc: -Not initialised. -.TP -Subject: -Not initialised. -.TP -Message-ID: -An RFC 822 message id of the form -.BR "<\fIyyyymmddhhmm\fP.\fIpid\fP.\fIbox\fP.\fIid\fP@\fIdomain\fP>" . -.PP -The global and local prototype files are read in turn and matching headers -are replaced by those specified in the prototypes. Non-matching headers found -in the prototypes are concatenated to the existing headers. This provides a -mechanism for header customisation. -.PP -.B Fwd -forwards a message by constructing a template which has the current -message or -.I id -in the current box appended to it. -.PP -.B Rep -replies to a message with the headers constructed as before -but with some further initialisation (based on the message being -replied to): -.TP -To: -Contains the address(es) found in the -.B From: -header. -.TP -Cc: -Contains the address(es) found in the -.B Cc: -header. -.TP -Subject: -If the message has a -.B Subject: -header it contains -.B Re: -followed by the subject. -.TP -.B In-Reply-To: -This header is added with the contents of the -.B Message-ID: -header, if present. -.SH FILES -$MACEDIR/.config -.br -$MACEDIR/.proto -.br -$MACEDIR/.box -.br -.RI $MACEDIR/ box /.proto -.br -.RI $MACEDIR/ box /.messid -.br -.RI $MACEDIR/ box / id -.SH "SEE ALSO" -.BR del ( 1 ), -.BR mln ( 1 ), -.BR environ ( 5 ), -.BR mace-config ( 4 ), -.BR mace-proto ( 4 ). //GO.SYSIN DD com.1 echo mace.1 sed 's/.//' >mace.1 <<'//GO.SYSIN DD mace.1' -.\" -.\" @(#)mace.1 1.1 -.\" -.TH MACE 1 -.SH NAME -mace \- add messages to incoming box -.SH SYNOPSIS -.B mace -[ -.B -adsu -] -[ -.B -f -.I mailfile -] -.SH DESCRIPTION -.B Mace -reads a user's -.I mailfile -and copies the messages into the -.I incoming -box. After the messages have been added sucessfully the -.I mailfile -is deleted. -.PP -As messages are read they are added to the -.I "audit trail" -which contains a verbatim copy of the message, as it existed in the -file. To prevent audit trail corruption a simple locking protocol is -used. -.PP -A one line summary for each message processed is output using -the same format used by -.BR box ( 1 ). -The first message added is set to be the -.IR "current message" . -.PP -The headers of each message are re-ordered, before the message is -added to the -.IR box , -so that all messages -have their headers in a standard order. The order is documented in -.BR reo ( 1 ). -.PP -.B Mace -supports several options: -.TP -.B -a -Use the audit trail. -.TP -.B -d -Don't use the audit trail. -.TP -.B -s -Silently add messages without printing a summary. -.TP -.B -u -Unlock the audit trail and exit. -.TP -.BI -f " mailfile" -Use -.I mailfile -as the user's mail file instead of -.BR $MAIL . -The -.I mailfile -is not deleted in this case. -.PP -.BR Pop ( 1 ) -and -.BR mam ( 1 ) -should be used in preference to -.B mace -where mail is managed by a Post Office Protocol (POP) version 3 server. -.SH FILES -$MACEDIR/.audit -.br -$MACEDIR/.audit.lck -.br -$MACEDIR/.box -.br -.RI $MACEDIR/ box /.messid -.br -.RI $MACEDIR/ box / id -.SH "SEE ALSO" -.BR box ( 1 ), -.BR msg ( 1 ), -.BR pop ( 1 ), -.BR mam ( 1 ), -.BR reo ( 1 ), -.BR mace-config ( 4 ). //GO.SYSIN DD mace.1 echo mal.1 sed 's/.//' >mal.1 <<'//GO.SYSIN DD mal.1' -.\" -.\" @(#)mal.1 1.1 -.\" -.TH MAL 1 -.SH NAME -mal \- per box aliases -.SH SYNOPSIS -.B mam -\fB+\fP\fIbox\fP -\&... -.SH DESCRIPTION -.B Mal -uses a -.IR box 's -.I "message prototype" -file to provide a simple alias facility. A -.I box -is specified by prepending the -.I "box character" -.B + -to its name. For each -.I box -specified its -.I "message prototype" -file is read and if a -.B To: -header is found the corresponding address contained in this header is output. -.PP -It is assumed that addresses to not span multiple lines. A comma is -inserted between pairs of lines to construct a valid RFC 822 address -list. The output of -.B mal -is designed to be used with -.BR com ( 1 ). -.SH FILES -.RI $MACEDIR/ box /.proto -.SH "SEE ALSO" -.BR box ( 1 ), -.BR com ( 1 ), -.BR mace-proto ( 4 ). //GO.SYSIN DD mal.1 echo mam.1 sed 's/.//' >mam.1 <<'//GO.SYSIN DD mam.1' -.\" -.\" @(#)mam.1 1.1 -.\" -.TH MAM 1 -.SH NAME -mam \- add messages to boxes -.SH SYNOPSIS -.B mam -[ -.B -u -] -[ -.B -dps -] -[ -[\fB+\fP]\fB+\fP\fIbox\fP -] -[ -.I files -] -\&... -.SH DESCRIPTION -.B Mam -reads standard input or files for RFC 822 messages and adds them -to boxes. Boxes are specified by the name of the -.I box -prefixed by the -.I "box character" -.BR + . -The -.I "current box" -can be changed by inserting an extra -.B + -character. -.PP -Multiple -.I box -options can be specified with one or more -.IR files . -If no -.I files -are specified the standard input is read. -If no -.I box -is specified the current box is used. -.PP -As messages are read they are added to the -.I "audit trail" -which contains a verbatim copy of the message, as it existed in the -file. To prevent audit trail corruption a simple locking protocol is -used. -.PP -A one line summary for each message processed is output using -the same format used by -.BR box ( 1 ). -The first message added to a -.I box -it is set to be the -.I "current message" -for that -.IR box . -.PP -The headers of each message are re-ordered, before the message is -added to the -.IR box , -so that all messages -have their headers in a standard order. The order is documented in -.BR reo ( 1 ). -.PP -.B Mam -supports several options: -.TP -.B -d -Don't use the audit trail. -.TP -.B -p -Preserve a -.IR box 's -current message as current. -.TP -.B -s -Silently add messages without printing a summary. -.TP -.B -u -Unlock the audit trail and exit. -.SH FILES -$MACEDIR/.audit -.br -$MACEDIR/.audit.lck -.br -$MACEDIR/.box -.br -.RI $MACEDIR/ box /.messid -.br -.RI $MACEDIR/ box / id -.SH "SEE ALSO" -.BR msg ( 1 ), -.BR rem ( 1 ). //GO.SYSIN DD mam.1 echo mov.1 sed 's/.//' >mov.1 <<'//GO.SYSIN DD mov.1' -.\" -.\" @(#)mov.1 1.1 -.\" -.TH MOV 1 -.SH NAME -mov, lnk, cop \- move, link or copy messages -.SH SYNOPSIS -.B mov -[ -[\fB+\fP]\fB+\fP\fIbox\fP -] -[ -.I id -] -[ -first|previous|current|next|last -] -[ -.RI [ from ]\-[ to ] -] -[ -.I regex -] -[ -all -] -\&... -.BI + target -.sp -.B mln -[ -[\fB+\fP]\fB+\fP\fIbox\fP -] -[ -.I id -] -[ -first|previous|current|next|last -] -[ -.RI [ from ]\-[ to ] -] -[ -.I regex -] -[ -all -] -\&... -.BI + target -.sp -.B cop -[ -[\fB+\fP]\fB+\fP\fIbox\fP -] -[ -.I id -] -[ -first|previous|current|next|last -] -[ -.RI [ from ]\-[ to ] -] -[ -.I regex -] -[ -all -] -\&... -.BI + target -.SH DESCRIPTION -.B Mov -moves messages from one or more boxes into a single -.I target -box. Messages are named either by their -.I id -or by their -.I box -and -.IR id . -A full explanation of message naming can be found in -.BR msg ( 1 ). -If no message is specified the current message is moved. -.PP -Messages created in the -.I target -box are relative to that box, starting with the -.I next -.I id -after the -.I last -message in that box. The last message created in the -.I target -box is set to be the current message for that box. -.PP -.B Lnk -links messages. It is not available on Plan 9. -.PP -.B Cop -copies messages. -.SH FILES -$MACEDIR/.config -.br -$MACEDIR/.box -.br -.RI $MACEDIR/ box /.messid -.br -.RI $MACEDIR/ box / id -.SH "SEE ALSO" -.BR msg ( 1 ). //GO.SYSIN DD mov.1 echo mox.1 sed 's/.//' >mox.1 <<'//GO.SYSIN DD mox.1' -.\" -.\" @(#)mox.1 1.1 -.\" -.TH MOX 1 -.SH NAME -mox \- add messages from a directory to incoming box -.SH SYNOPSIS -.B mox -[ -.B -ds -] -[ -.B -delete -] -.SH DESCRIPTION -.B Mox -acts like -.BR mace ( 1 ) -but takes messages from a spool directory, one per file, and adds them -to the -.I incoming -box with -.BR mam ( 1 ). -The location of the spool directory is determined -by the -.I spooldir -keyword (see -.BR mace-config ( 1 )). -.B -Mox -was designed to work with mail despoolers such as -.BR pop ( 1 ). -.PP -After a message has been added, -.B mox -applies any -.I refile -directives, prints a summary of the message and then -applies any -.I exec -directives. -This order is to ensure that the summary reflects an accurate view of -reality. An explanation of these directives can be found in -.BR mace-config ( 4 ). -.PP -The default behaviour can be modified by the following options: -.TP -.B -d -Don't use the audit trail. -.TP -.B -delete -Delete messages from -.I spooldir -after they have been processed -successfully. -.TP -.B -s -Silently add messages without printing a summary. -.SH "SEE ALSO" -.BR mace ( 1 ), -.BR mam ( 1 ), -.BR pop ( 1 ), -.BR mace-config ( 4 ). //GO.SYSIN DD mox.1 echo msg.1 sed 's/.//' >msg.1 <<'//GO.SYSIN DD msg.1' -.\" -.\" @(#)msg.1 1.1 -.\" -.TH MSG 1 -.SH NAME -msg, med, del, rem \- display, edit, deliver or remove messages -.SH SYNOPSIS -.B msg -[ -[\fB+\fP]\fB+\fP\fIbox\fP -] -[ -.I id -] -[ -first|previous|current|next|last -] -[ -.RI [ from ]\-[ to ] -] -[ -.I regex -] -[ -all -] -\&... -.sp -.B med -[ -[\fB+\fP]\fB+\fP\fIbox\fP -] -[ -.I id -] -[ -first|previous|current|next|last -] -[ -.RI [ from ]\-[ to ] -] -[ -.I regex -] -[ -all -] -\&... -.sp -.B del -[ -[\fB+\fP]\fB+\fP\fIbox\fP -] -[ -.I id -] -[ -first|previous|current|next|last -] -[ -.RI [ from ]\-[ to ] -] -[ -.I regex -] -[ -all -] -\&... -.sp -.B rem -[ -[\fB+\fP]\fB+\fP\fIbox\fP -] -[ -.I id -] -[ -first|previous|current|next|last -] -[ -.RI [ from ]\-[ to ] -] -[ -.I regex -] -[ -all -] -\&... -.SH DESCRIPTION -.B Msg -displays messages based on its arguments or the current message if none are -specified. Messages are named either by their -.I id -or by their -.I box -and -.IR id . -An -.I id -consists of 5 characters constructed from alternating consonant -and vowel -characters to make a -.I pronounceable -identifier. Consonants are taken from the set [bdfgjklmnprstvyz]. -.PP -Messages can also be referred to by these aliases: -.TP -first -The first message in a box. -.TP -previous -The message before the current message. -.TP -current -The current message. This not normally used but is included for completeness. -.TP -next -The message after the current message. -.TP -last -The last message in a box. -.PP -Aliases may be abbreviated to their first four characters. -.PP -Ranges of messages can be specified by two -.IR id 's -separated by a -.BR \- . -These can be either a pronounceable message -.I id -or an alias and one or both need not be specified. If one is missing -then the current message is used to start or terminate the range. If -both are missing the current message is used. -.PP -Groups of messages may be referred to with a -.I regex -in the form of -.BR sh ( 1 ) -style metacharacters -.B ? -and -.BR * , -as well as character ranges of the form -.B [a-z] -and -.BR [abc] . -Care should be taken to quote such arguments to prevent interpretation -by the shell. -.PP -All messages in a box may be specified by -.BR all . -.PP -A message (or messages) in a particular -.I box -can be specified by prefixing the name of the -.I box -by the -.B + -character. Subsequent messages identifiers are then interpreted relative -to the messages in that -.IR box . -Two -.B + -characters can be used to make the named -.I box -to be the current -.IR box . -More than one -.IR box -argument with zero or more message identifiers can be specified. If no -message identifier is specified the current message in that box is used. -.PP -.B Msg -converts the arguments to filenames and uses -.B $PAGER -to display them all. It is run once and the current message for each -box is set to the last message selected from that box if the exit status -is zero. Regardless of the exit status the current box is set as -directed by the arguments. -.PP -.B Med -uses -.B $EDITOR -instead of -.BR $PAGER . -.PP -.B Del -delivers messages that have been created with -.BR com ( 1 ). -.PP -.B Rem -removes the selected messages. -.SH FILES -$MACEDIR/.config -.br -$MACEDIR/.box -.br -.RI $MACEDIR/ box /.messid -.br -.RI $MACEDIR/ box / id -.SH "SEE ALSO" -.BR mov ( 1 ), -.BR environ ( 5 ). //GO.SYSIN DD msg.1 echo pop.1 sed 's/.//' >pop.1 <<'//GO.SYSIN DD pop.1' -.\" -.\" @(#)pop.1 1.1 -.\" -.TH POP 1 -.SH NAME -pop \- POP 3 client -.SH SYNOPSIS -.B pop -[ -.B -delete -] -[ -.B -n -.I number -] -[ -.B -r -[ -.I seconds -] -] -[ -.B -s -.I spooldir -] -[ -.B -t -] -[ -[\fIuser\fP\fB@\fP]\fIserver\fP -] -.SH DESCRIPTION -.B Pop -is a client that uses version 3 of the Post Office Protocol (POP). It -is designed to be used in conjunction with -.BR mam ( 1 ) -to add messages from a maildrop to one or more boxes. -.PP -By default it connects to -.B localhost -as the current user and prompts for the user's password on the maildrop. -If the supplied password is correct, it then copies each message into -files in the current directory. Files are named numerically, starting at 0, -increasing monotonically. -An alternative -.I user -name and POP -.I server -can be specified as an argument. -.PP -The default behaviour can be modified by the following options: -.TP -.B -delete -Delete messages on the maildrop after they have been transferred -successfully. Should an error occur, -.B pop -does not request that the messages be deleted. -.TP -.BI -n " number" -Files are named starting with -.IR number . -.TP -\fB-r\fP [ \fIseconds\fP ] -Re-check the maildrop every -.IR seconds . -If no time is given a default of 2 minutes (120 seconds) is used. -It is not necessary to re-enter the password for the mail-drop each -time. The password is maintained by -.B pop -in a pipe to minimise the risk of is appearing in a -.BR core ( 4 ) -file. -.TP -.BI -s " spooldir -Files are created in the directory -.I spooldir -rather than the current directory. -.TP -.B -t -Communication with the POP server is traced to standard error. Commands -sent to the server are prefixed with -.BR --> . -Responses from the server are prefixed with -.BR <-- . -The password is not traced. -.PP -Files are created -.I write-only -(owner) -to prevent other processes from reading them while they are being written. -Once a file has been completely written it is changed to be -.I read/write -(owner). This simple mechanism negates the need for a locking protocol. -.PP -.B Pop -was designed to use as few POP commands as necessary. The following -are used: -.TP -USER -User name. -.TP -PASS -User password. -.TP -STAT -Query maildrop status. -.TP -RETR -Retrieve message. -.TP -DELE -Delete message. -.TP -RSET -Reset protocol. -.TP -QUIT -Quit session. -.SH "SEE ALSO" -RFC 1225, -.BR mam ( 1 ), -.BR core ( 4 ). //GO.SYSIN DD pop.1 echo reo.1 sed 's/.//' >reo.1 <<'//GO.SYSIN DD reo.1' -.\" -.\" @(#)reo.1 1.1 -.\" -.TH REO 1 -.SH NAME -reo \- re-order message headers -.SH SYNOPSIS -.B reo -.SH DESCRIPTION -.B Reo -is a filter that reorders the headers of an RFC 822 message. After it has -output the re-ordered headers it copies the body of the message unchanged. -The order chosen is: -.BR From: , -.BR Date: , -.BR To: , -.BR Cc: , -.B Bcc -and -.BR Subject: . -The remaining headers are then appended as they appeared in the message. -.SH "SEE ALSO" -.BR mam ( 1 ). //GO.SYSIN DD reo.1 echo mace-config.4 sed 's/.//' >mace-config.4 <<'//GO.SYSIN DD mace-config.4' -.\" -.\" @(#)mace-config.4 1.2 -.\" -.TH MACE-CONFIG 4 -.SH NAME -mace\-config \- mace configuration -.SH SYNOPSIS -$MACEDIR -.SH DESCRIPTION -Mail managed by mace is located in the directory -.B $MACEDIR -(if set) or by the directory specified in -.BR $HOME/.macedir . -If the directory in -.B $HOME/.macedir -does not begin with a -.B / -the directory is interpreted to be -relative to -.BR $HOME . -.PP -The directory contains the following: -.TP -.B .config -The configuration file. -.TP -.B .audit -The -.I "audit trail" -maintained by -.BR mace ( 1 ) -and -.BR mam ( 1 ). -.TP -.B .audit.lck -The -.I "audit trail" -lock file. -.TP -.B .box -A file containing the name of the current -.IR box . -.TP -.B .proto -The global -.I "message prototype" -file. -.TP -.I box -A directory for each -.IR box . -.PP -A -.I box -is a directory in -.B $MACEDIR -which contains: -.TP -.B .messid -The file containing the name of the -.IR box 's -.IR "current message" . -.TP -.B .proto -The -.IR box 's -.I "message prototype" -file. -.TP -.I id -Message files are named by their -.IR id . -An -.I id -consists of 5 characters constructed from alternating consonant -and vowel -characters to make a -.I pronounceable -identifier. Consonants are taken from the set [bdfgjklmnprstvyz]. -The first message -.I id -is -.BR babab . -The last is -.BR zuzuz . -.PP -The configuration file consists of a list of keywords and values, -separated by spaces and tabs. Lines commencing with -.B # -are comments and are ignored. An entry can be continued on the next line -by a -.B \e -at the end of the line. -.PP -The following keywords are understood: -.TP -.BI "address* " domain -The -.I domain -used in creating the user's -.B From: -address. -.TP -.BI "deliver* " command -A -.I command -to deliver messages. -.TP -.BI "despool " command -The -.I command -run by -.BR mace ( 1 ) -to lock, output, unlock and remove the user's mail -.IR file . -.TP -\fBexec\fP "\fIregex\fP" "\fIcommand\fP" -A regular expression matched against the headers of a message by -.BR mace ( 1 ) -and -.BR mox ( 1 ). -If a header matches -.I regex -then then -.I command -is executed. A two character sequence beginning with a -.B % -allows substitution of the following parameters: -.BR b , -.I "incoming box" -preceded by the -.I "box character" -.BR + ; -.BR d , -.BR $MACEDIR ; -.BR m , -message -.IR id ; -.BR p , -message pathname; -.BR % , -%. -.TP -.BI "incoming " box -The name of the -.I box -where incoming mail is held. -.TP -.BI "outgoing " box -The name of the -.I box -where outgoing mail templates are created by default. -.TP -.BI "peruse " command -The -.I command -run by -.BR mace ( 1 ) -to lock, output and unlock the user's mail file. -.TP -\fBrefile\fP "\fIregex\fP" \fIbox\fP -A regular expression matched against the headers of a message by -.BR mace ( 1 ) -and -.BR mox ( 1 ). -If a header matches -.I regex -then the message is linked into -.IR box . -.TP -\fBremove\fP "\fIregex\fP" -A regular expression that is matched against the recipient list -when replying to a message. Addresses matching -.I regex -are removed from the -.B To: -and -.B Cc: -headers when the template is created. -It is used to delete the replier's address. -.TP -.BI "spool " file -The name of the user's mail file. -.TP -.BI "spooldir " file -The name of a directory containing mail messages, one per file. -This directory can be used by mail despoolers that operate like -.BR pop ( 1 ). -Files -in this directory can be added to -.I incoming -by -.BR mox ( 1 ). -.PP -Regular expressions are of the form used by -.BR egrep ( 1 ). -Keywords marked with an -.B * -are mandatory. -.SH EXAMPLES -.IP -.nf -address civil.su.oz.au -incoming in -outgoing out -remove "(john@(.+\.)?(civil|vetsci|physiol)\.su\.[Oo][Zz]\.[Aa][Uu])|(mackin@(.+\.)?geology\.su\.oz\.au)|(^john$)" -exec "^Sender: Viet Nam War Discussion List" "mov %b %m +vwar" -.fi -.SH FILES -$HOME/.macedir -.br -$MACEDIR/.audit -.br -$MACEDIR/.audit.lck -.br -$MACEDIR/.config -.br -$MACEDIR/.box -.br -$MACEDIR/.proto -.br -.RI $MACEDIR/ box /.messid -.br -.RI $MACEDIR/ box /.proto -.br -.RI $MACEDIR/ box / id -.SH "SEE ALSO" -.BR mace-proto ( 4 ), -.BR environ ( 5 ). //GO.SYSIN DD mace-config.4 echo mace-proto.4 sed 's/.//' >mace-proto.4 <<'//GO.SYSIN DD mace-proto.4' -.\" -.\" @(#)mace-proto.4 1.1 -.\" -.TH MACE-PROTO 4 -.SH NAME -mace\-proto \- message prototype files -.SH SYNOPSIS -$MACEDIR/.proto -.sp -.RI $MACEDIR/ box /.proto -.SH DESCRIPTION -.I "Message prototype" -files are used to customise message prototypes generated by -.BR com ( 1 ). -The global prototype is $MACEDIR/.proto and -boxes also may have a local prototype in -.RI $MACEDIR/ box /.proto. -.PP -These files consist of a series of RFC 822 headers and text following -the header. They follow the usual conventions of RFC 822 headers. -.SH EXAMPLES -To customise your -.B From: -address: -.IP -From: donald.duck@duckpond.arpa -.PP -To add an -.B X-Face: -header (used by -.BR faces ( 1 )): -.IP -.nf -X-Face: #"03$i1:"_[Hbg~GCPw}`+d4_R`}RaDfYixB`n-mCB0E8m#tNd>uyd[d)`nEix7Bys(:o#o2y7$(=,&BTXdH7)Hm5jP}H5:y]}0GT4?uTT(Y0(Cu7tWBXj\|q\@jZ8 - Y_qn8)NV0*$uO][i7p"K2>Kg( -.fi -.SH FILES -$MACEDIR/.proto -.br -.RI $MACEDIR/ box /.proto -.SH "SEE ALSO" -.BR com ( 1 ). //GO.SYSIN DD mace-proto.4 echo addr.h sed 's/.//' >addr.h <<'//GO.SYSIN DD addr.h' -/* -** Mail address data structures -** -** %W% -*/ - -#define NEED_BZERO -#define NSUBDOM 20 /* # of subdomain names in domain */ - -typedef unsigned int MALLOCT; /* Parameter to malloc */ - -/* -** An address. -*/ -typedef struct _addr { - struct _addr *next; /* next address in list */ - struct _dom *route; /* route icl. destination domain */ - struct _dom *destdom; /* destination domain */ - char *localp; /* RFC local part */ - char *name; /* Comment name */ - char *group; /* Group (List) phrase */ - char *comment; /* () comment phrase */ - char *text; /* literal text */ - char *error; /* error text if not NULL */ -} Addr; - - -/* -** A domain. -*/ -typedef struct _dom { - struct _dom *next; /* next domain (f.i. in route) */ - char *sub[NSUBDOM]; /* subdomain strins */ - char **top; /* toplevel domain */ -} Dom; - - -extern Addr *newAddr(); /* Create a new address */ -extern Dom *newDom(); /* Create a new domain */ -extern Addr *adrlist; -extern Addr *errlist; -extern char *strcpy(); -extern char *strncpy(); -extern char *strcat(); - -/* SHUT UP! */ -#define Strcpy (void)strcpy -#define Strncpy (void)strncpy -#define Strcat (void)strcat -#define Sprintf (void)sprintf //GO.SYSIN DD addr.h echo conf.h sed 's/.//' >conf.h <<'//GO.SYSIN DD conf.h' -/* - * Configuration stuff. - * - * @(#)conf.h 1.36 - */ - -/* - * Tokens to be found in the CONFIG file. - */ -#define CT_ADDRESS "address" -#define CT_DELIVER "deliver" -#define CT_DESPOOL "despool" -#define CT_EXEC "exec" -#define CT_INBOX "incoming" -#define CT_OUTBOX "outgoing" -#define CT_PERUSE "peruse" -#define CT_REFILE "refile" -#define CT_REMOVE "remove" -#define CT_SAVE "save" -#define CT_SPOOL "spool" -#define CT_SPOOLDIR "spooldir" - -typedef struct match match; - -struct match -{ - char *m_re; - regexp *m_cre; - char *m_action; - match *m_next; -}; - -typedef struct -{ - char *c_address; - char *c_deliver; - char *c_despool; - char *c_inbox; - char *c_outbox; - char *c_peruse; - match *c_exec; - match *c_refile; - match *c_remove; - match *c_save; - char *c_spool; - char *c_spooldir; -} - conf; - -extern conf *read_config(); - -/* - * Substitution characters for CT_EXEC. - */ -#define CE_SPECIAL '%' -#define CE_BOX 'b' -#define CE_MACEDIR 'd' -#define CE_MESSID 'm' -#define CE_PATH 'p' - -extern char *special_expand(char *, char *, char *); -extern void regex_apply(char *, message *, match *, void (*)(char *, message *, match *)); //GO.SYSIN DD conf.h echo flex.h sed 's/.//' >flex.h <<'//GO.SYSIN DD flex.h' -/* - * Flexible string definitions. - * - * @(#)flex.h 1.31 - */ - -#define FLEXZ 128 - -typedef struct -{ - char *f_str; - char *f_end; - char *f_ptr; -} - flex; - -#define flex_char(f, c) (*((f)->f_ptr == (f)->f_end ? flex_fill(f) : (f)->f_ptr++) = (c)) - -extern void flex_end(); -extern char *flex_fill(); -extern void flex_init(); -extern void flex_str(); -extern void flex_nstr(); //GO.SYSIN DD flex.h echo headers.h sed 's/.//' >headers.h <<'//GO.SYSIN DD headers.h' -/* - * Unix mail / RFC 822 headers. - * - * %W% - */ - -#define UNIX_FROM "From " -#define UNIX_FWD_CHAR '>' - -#define UNIX_DATE_LEN 25 - -#define UNIX_REGARDING "Re:" - -#define RFC_BCC "Bcc:" -#define RFC_CC "Cc:" -#define RFC_DATE "Date:" -#define RFC_FROM "From:" -#define RFC_IN_REPLY_TO "In-Reply-To:" -#define RFC_MESSAGE_ID "Message-ID:" -#define RFC_REPLY_TO "Reply-To:" -#define RFC_SENDER "Sender:" -#define RFC_SUBJECT "Subject:" -#define RFC_TO "To:" - -#define RFC_LWSP_1 ' ' -#define RFC_LWSP_2 '\t' - -#define RFC_SPEC_AT '@' -#define RFC_SPEC_DOT '.' -#define RFC_SPEC_LANGLE '<' -#define RFC_SPEC_RANGLE '>' -#define RFC_SPEC_COMMA ',' -#define RFC_SPEC_COLON ':' -#define RFC_SPEC_PLUS '+' -#define RFC_SPEC_MINUS '-' -#define RFC_SPEC_PERCENT '%' - -#define RFC_STR_GMT "GMT" - -#define RFC_ZONE_HOUR(h) ((h) * 60) - -extern char **find_header(); -extern char *header_text(); -extern char *make_address(); -extern char *parse_address(); -extern char *rfc_cvt_date(); -extern char *rfc_date(); -extern char *rfc_message_id(); - -extern int rfc_header(char *); -extern int rfc_hdr_cmp(char *, char *); -extern int rfc_month(char *); -extern int rfc_weekday(char *); -extern int rfc_zone(char *); -extern int strcasecmp(char *, char *); - -extern void reorder_headers(vec *); //GO.SYSIN DD headers.h echo line.h sed 's/.//' >line.h <<'//GO.SYSIN DD line.h' -/* - * Line i/o definitions. - * - * @(#)line.h 1.31 - */ - -#define LBUFZ 1024 - -typedef struct -{ - int l_fd; - char l_buf[LBUFZ]; - char *l_ptr; - char *l_end; - int l_flag; -} - lineio; - -#define LREAD 0x01 /* open for read */ -#define LWRITE 0x02 /* open for write */ -#define LEOF 0x04 /* eof seen on read */ -#define LCRLF 0x08 /* CR/LF terminated lines */ -#define LLBUF 0x10 /* line buffered output */ -#define LERROR 0x80 /* error on an i/o */ - -extern lineio *lopen(); -extern int lclose(); -extern char *lread(); -extern char *lwrite(); //GO.SYSIN DD line.h echo mace.h sed 's/.//' >mace.h <<'//GO.SYSIN DD mace.h' -/* - * Mace global & system dependent definitions. - * - * Tune these to suit your system. - * - * Boyd Roberts 1989/1990 - * - * Thanks to: - * - * John Mackin (alpha testing and suggestions) - * Andrew Gollan (BSD mail-file locking code) - * - * @(#)mace.h 1.46 - */ - -/* - * Compiler options. - */ -#define CC_VOID 1 /* 1 iff cc groks void */ -#define CC_UCHAR 1 /* 1 iff cc groks unsigned chars */ -#define CC_STATIC 1 /* 1 iff cc groks forward static declarations */ - - /* - * Environment variable names. - */ -#define ENV_EDITOR "EDITOR" -#define ENV_HOME "HOME" -#define ENV_NAME "NAME" -#define ENV_PAGER "PAGER" -#define ENV_SHELL "SHELL" -#define ENV_USER "LOGNAME" - -#define SPEC_CHAR '.' -#define BOX_CHAR '+' -#define SPEC_NAME(s) "."#s -#define AUDIT SPEC_NAME(audit) -#define BOX SPEC_NAME(box) -#define MESSID SPEC_NAME(messid) -#define CONFIG SPEC_NAME(config) -#define PROTO SPEC_NAME(proto) -#define MARK SPEC_NAME(mark) -#define MACEDIR ".macedir" - -/* - * String to insert before each line of a forwarded message - */ -#define FWD_LEADER " " - -/* - * Regular expression to match the name of the delivery agent. - * - * Used to discard the bogus From line added by "rmail". - * - * If your mail delivery doesn't exhibit this behaivour - * define it to be NULLSTR. - */ -#define DELIVERY_AGENT "Unknown" - -/* - * The default system mail despooler. NULLSTR if there isn't one. - */ -#define DESPOOLER "despool -delete" - -/* - * The default system mail printer. Allows mail to be viewed - * without deletion. NULLSTR if there isn't one. - */ -#define PERUSER "despool" - -/* - * The default system mail deliverer. NULLSTR if there isn't one. - * - * This must be set if RFC_DELIVERER is 1. -#define DELIVERER "/usr/lib/sendmail -t -oi -odb" - */ -#define DELIVERER "/bin/echo" - -#define RFC_DELIVERER 1 /* 1 iff the delivery agent can read the - recipients from the message body */ - -/* - * If RFC_DELIVERER == 1 and you want the headers verified before - * they are passed to the delivery agent. This is useful is you're - * using sendmail and don't want anoying messages from `mailer-daemon' - * about syntactically incorrect addresses. - */ -#define RFC_VALIDATE 1 - -#define ID_LEN 5 - -#define NPIPES 64 /* == NOFILE */ - -#define FS_BLKZ 8192 /* size of a filesystem block */ - -#define CREAT_MODE 0666 /* file creation mode */ -#define MKDIR_MODE 0777 /* directory creation mode */ - -#define LOCK_STR ".lck" /* file lock extension */ - -#define BSD_STR 0 /* 1 iff str[r]chr == [r]index */ -#define BSD_DIR 0 /* 1 iff 4.2BSD directories */ -#define BSD_MKDIR 1 /* 1 iff 4.2BSD mkdir() call */ - -#define STR_CSPN 1 /* 1 iff you have strcspn() */ - -#define DIRECTORY_3 1 /* 1 iff you have the directory(3) routines */ -#define V9_DIRECTORY_3 0 /* 1 iff you have the V9 directory(3) routines */ -#define DEC_DIRECTORY_3 1 /* 1 iff you have old (ULTRIX) directory(3) */ - -#define USG_MAIL 1 /* 1 iff mail file is locked by USG .lock */ -#define BSD_MAIL 0 /* 1 iff mail file is locked by flock(2) */ - -#define USG_UNAME 1 /* 1 iff you have uname(2) */ -#define BSD_GETHOSTNAME 0 /* 1 iff you have gethostname(2) */ - -#define SIG_RET void /* signal(2) returns int/void? */ - -/* - * If the previous two are both 0 then specify a command - * that writes the system's nodename to standard output. - * - * Set to NULLSTR otherwise. - */ -#define HOST_CMD NULLSTR - -/* - * Specify the command that writes the system's domain - * name to standard output. - * - * Set to NULLSTR if you intend to specify it in "config". - */ -#define DOMAIN_CMD NULLSTR - -/* - * The negation character used by your shell to negate a character - * class in a metacharacter expansion (ie [!a-z]*). Usually '!', - * but some shells use '^'. - */ -#define SH_META_NOT '!' - -#define SYSERROR (-1) /* system call error return */ - -/* - * Default commands; tailor them to suit. - */ -#define DEF_PAGER "cat" -#define DEF_EDITOR "ed" -#define DEF_SHELL "/bin/sh" /* full pathname required */ - -#define COM_STR "com" /* compose message */ -#define COP_STR "cop" /* front end to MCP_STR */ -#define DEL_STR "del" /* front end to MDA_STR */ -#define FWD_STR "fwd" /* forward message */ -#define LNK_STR "lnk" /* front end to MLN_STR */ -#define MAM_STR "mam" /* mace add message (from a file) */ -#define MED_STR "med" /* message edit */ -#define MOV_STR "mov" /* front end to MAD_STR */ -#define MSG_STR "msg" /* show message */ -#define REM_STR "rem" /* remove message */ -#define REP_STR "rep" /* reply to a message */ - -#define MAD_STR "mad" /* Message add (to a box) */ -#define MCP_STR "mcp" /* Message copy (to a box) */ -#define MLN_STR "mln" /* Message link (to a box) */ -#define MDA_STR "mda" /* Message delivery agent */ -#define MKDIR_STR "mkdir" /* Make directory */ -#define RMDIR_STR "rmdir" /* Remove directory */ - -#define O_RD 0 /* open mode for read */ -#define O_WR 1 /* open mode for write */ -#define O_RW 2 /* open mode for read/write */ - -#define A_RD 4 /* access mode for read */ - -#if BSD_STR -#define strchr index -#define strrchr rindex -#endif - -#if CC_VOID == 0 -#define void int -#endif - -#if CC_STATIC == 0 -#define STATIC extern -#endif - -#if CC_UCHAR == 0 -#define CHARBITS 0377 -#endif - -#if STR_CSPN == 0 -#define STRCSPN 1 -#endif - -#if V9_DIRECTORY_3 -#define DIRECTORY_3 1 -#endif - -#define NULLBOX (mbox *)0 -#define NULLSTR (char *)0 -#define NULLMSG ((msg_idx)-1) - -typedef long msg_idx; - -typedef struct -{ - char *m_name; - char *m_path; - msg_idx m_count; - msg_idx m_current; - char *m_messid; - char **m_list; -} - mbox; - -typedef struct -{ - msg_idx v_count; - msg_idx v_size; - msg_idx v_incr; - char **v_list; -} - vec; - -extern char *my_name; -extern char *re_error; - -extern char *basename(); -extern char *check_box(); -extern char *concat(); -extern char *concat3(); -extern char *create_box(); -extern char *curr_box(); -extern char *curr_in_box(); -extern char *defenv(); -extern char *domain(); -extern char *host(); -extern char *mace_dir(); -extern char *mess_to_path(); -extern char *newstr(); -extern char *nextid(); -extern char *read_file(); -extern char *readpass(char *); -extern char *salloc(); -extern char *splice(); -extern char *srealloc(); -extern char *strstr(); -extern char *sysmess(); -extern char *user_id(); -extern char *user_name(); -extern char *vec_str(); -extern char *vec_cat(); - -extern char **mess_range(); -extern char **read_dir(); - -extern int args_to_messages(); -extern int delete_box(); -extern int lock(); -extern int mail_check(); -extern int mail_locked(); -extern int mail_lock(); -extern int mail_unlock(); -extern int pipe_exec(); -extern int pipe_open(); -extern int pipe_close(); -extern int run(); -extern int set_box(); -extern int set_current(); -extern int unlock(); -extern int valid_id(); - -extern mbox *read_box(); - -extern msg_idx mess_alias(); -extern msg_idx mess_index(); - -extern void bcopy(); -extern void could_not(); -extern void fatal(); -extern void free_dir(); -extern void free_box(); -extern void free_mess(); -extern void name(); -extern void path_to_mess(); -extern void print_summary(); -extern void vec_free(); -extern void vec_init(); -extern void would_not(); //GO.SYSIN DD mace.h echo message.h sed 's/.//' >message.h <<'//GO.SYSIN DD message.h' -/* - * Internal message format. - * - * @(#)message.h 1.33 - */ - -typedef struct -{ - char *ms_path; - char *ms_messid; - vec ms_headers; - long ms_size; - int ms_copies; - int ms_state; -} - message; - -#define NULLMESS (message *)0 - -extern int set_state(char *, int); -extern int clear_state(char *, int); - -extern message *read_mess(mbox *, char *); -extern message *parse_fd(int, lineio *); -extern message *parse_file(char *, lineio *); - -#define MESG_SENT S_IEXEC -#define MESG_COMP (S_IEXEC >> 3) -#define MESG_MARK (S_IEXEC >> 6) //GO.SYSIN DD message.h echo pop.h sed 's/.//' >pop.h <<'//GO.SYSIN DD pop.h' -/* - * @(#)pop.h 1.2 - * - * POP 3 (RFC 1225) definitions. - */ - -/* - * Maximum length of a POP password. Must be less that PIPSIZ. - */ -#define POP_PASS_LEN 1024 - -/* - * POP server - */ -#define POP_SERVICE "pop3" -#define POP_PROTOCOL "tcp" -#define POP_PORT 110 - -/* - * Commands - */ -#define POP_CMD_DELE "DELE" -#define POP_CMD_LAST "LAST" -#define POP_CMD_LIST "LIST" -#define POP_CMD_NOOP "NOOP" -#define POP_CMD_PASS "PASS" -#define POP_CMD_QUIT "QUIT" -#define POP_CMD_RETR "RETR" -#define POP_CMD_RSET "RSET" -#define POP_CMD_STAT "STAT" -#define POP_CMD_USER "USER" - -#define POP_REP_OK "+OK" -#define POP_REP_ERR "-ERR" -#define POP_REP_TCHAR '.' //GO.SYSIN DD pop.h echo regexp.h sed 's/.//' >regexp.h <<'//GO.SYSIN DD regexp.h' -/* - * Definitions etc. for regexp(3) routines. - * - * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], - * not the System V one. - * - * Snarfed to be part of "mace" but not modified save - * for the odd include & sccsid. - * -- Boyd Roberts - * May '89 - * - * @(#)regexp.h 1.6 - */ -#define NSUBEXP 10 -typedef struct regexp { - char *startp[NSUBEXP]; - char *endp[NSUBEXP]; - char regstart; /* Internal use only. */ - char reganch; /* Internal use only. */ - char *regmust; /* Internal use only. */ - int regmlen; /* Internal use only. */ - char program[1]; /* Unwarranted chumminess with compiler. */ -} regexp; - -extern regexp *regcomp(); -extern int regexec(); -extern void regsub(); -extern void regerror(); //GO.SYSIN DD regexp.h echo regmagic.h sed 's/.//' >regmagic.h <<'//GO.SYSIN DD regmagic.h' -/* - * The first byte of the regexp internal "program" is actually this magic - * number; the start node begins in the second byte. - * - * Snarfed to be part of "mace" but not modified save - * for the odd include & sccsid. - * -- Boyd Roberts - * May '89 - * - * @(#)regmagic.h 1.6 - */ -#define MAGIC 0234 //GO.SYSIN DD regmagic.h echo tty.h sed 's/.//' >tty.h <<'//GO.SYSIN DD tty.h' -/* - * @(#)tty.h 1.1 - * - * Definitions for horrible system dependent tty routines. - */ - -extern int ttyecho(int, int); -extern int ttyechoing(int); //GO.SYSIN DD tty.h echo addr.y sed 's/.//' >addr.y <<'//GO.SYSIN DD addr.y' -%{ -/* - * RFC 822 address parsing routines. - */ - -#ifndef lint -static char sccsid[] = "%W%"; -#endif lint - -#include "mace.h" -#include "headers.h" -#include "flex.h" -#include "addr.h" -#include -#include - -#define panic(s) fatal(s) -#define nomem() fatal("nomem") - -static flex f = { NULLSTR, NULLSTR, NULLSTR, }; - -/* $Log: addr.y,v $ - * Revision 1.1 2004/02/15 15:14:13 boyd - * Initial revision - * - * Revision 1.5 88/12/29 00:44:14 john - * Moved to MIPS - * - * Revision 1.5 88/12/29 00:44:14 john - * Move eatcomment() into address.y where it belongs, and fix it to - * handle \-quoting of parens inside comments. - * - * Revision 1.4 88/12/28 22:13:40 john - * Fix \ quoting within quoted-strings and domain-literals (it was - * missing). Also fix missing cases for ']' as an atom. - * - * Revision 1.3 88/12/28 00:14:03 john - * Fix lexical analysis bug, parentheses were not being correctly - * recognized as atoms. - * - * Revision 1.2 88/10/30 07:46:22 john - * Improve compliance of grammar to RFC822: - * - insist on a domain at the end of a source-route - * Change makeaddress() to do the right thing with a - * source-routed address (i.e., make it an actual textual - * representation of the source-routed address). - * Fix bug in putdom. - * - * Revision 1.1 88/10/26 09:54:04 john - * Initial revision - * - */ - -static char RCSid[] = - "$Header: /home/boyd/src/mace/RCS/addr.y,v 1.1 2004/02/15 15:14:13 boyd Exp boyd $"; - -typedef struct token token; - -struct token -{ - char *name; - int token; -}; - -static char *errstr; -static char *comstr; -static char *cp; -static char *savecp; -static char *saveline; -static flex errbuf = { NULLSTR, NULLSTR, NULLSTR }; -static flex combuf = { NULLSTR, NULLSTR, NULLSTR }; -static int iseol; - -static char *text; -Addr *adrlist; -Addr *errlist; -%} - -%union { - char yChar; - char *yString; - Dom *yDom; - Addr *yAddr; - time_t yTime; - int yInt; -} - -%token EOL ATOM LIT_DOMAIN QUOTED_STRING - -%type word domain_ref sub_domain local_part phrase -%type domain route_list route -%type addr_spec non_local_addr_spec route_addr mailbox mbox_list group address - -%start addr - -%% -addr: addr_lel - | addr addr_lel - ; - -addr_lel: address EOL { - $1->comment = comstr; - $1->error = errstr; - comstr = NULL; - errstr = NULL; - appAddr(&adrlist, $1); - } - | address ',' { - $1->comment = comstr; - $1->error = errstr; - comstr = NULL; - errstr = NULL; - appAddr(&adrlist, $1); - } - | error { - register Addr *ap; - - ap = newAddr(); - if (savecp > saveline) { - flex_str(&errbuf, " after \""); - flex_nstr(&errbuf, saveline, savecp - saveline); - flex_char(&errbuf, '"'); - if (cp && *cp) { - flex_str(&errbuf, ", before \""); - flex_str(&errbuf, cp); - flex_char(&errbuf, '"'); - } - } - else if (cp && *cp) { - flex_str(&errbuf, " before \""); - flex_str(&errbuf, cp); - flex_char(&errbuf, '"'); - } - - if (errbuf.f_ptr != errbuf.f_str) { - flex_char(&errbuf, '\0'); - errstr = newstring2(errstr, errbuf.f_str); - flex_end(&errbuf); - } - - ap->error = errstr; - errstr = NULL; - comstr = NULL; - appAddr(&errlist, ap); - } - ; - -address: mailbox { - $$ = $1; - } - | group { - $$ = $1; - } - ; - -group : phrase ':' mbox_list ';' { - register Addr *a; - - for (a = $3; a; a = a->next) - a->group = $1; - $$ = $3; - } - ; - -mbox_list: mailbox { - $$ = $1; - } - | mbox_list ',' mailbox { - $3->comment = comstr; - $3->error = errstr; - comstr = NULL; - errstr = NULL; - appAddr(&($1), $3); - $$ = $1; - } - ; - -mailbox: addr_spec { - $$ = $1; - } - | route_addr { - $$ = $1; - } - | phrase route_addr { - $2->name = $1; - $$ = $2; - } - ; - -phrase : word { - $$ = $1; - } - | phrase word { - $$ = newstring3($1, " ", $2); - free($1); - free($2); - } - ; - -route_addr: '<' addr_spec '>' { - $$ = $2; - } - | '<' route non_local_addr_spec '>' { - prepDom(&($3->route), $2); - $$ = $3; - } - ; - -route : route_list ':' { - $$ = $1; - } - ; - -route_list: '@' domain { - $$ = $2; - } - | route_list ',' '@' domain { - appDom(&($1), $4); - $$ = $1; - } - ; - -addr_spec: non_local_addr_spec - | local_part { - register Addr *ap; - - $$ = ap = newAddr(); - ap->localp = $1; - ap->destdom = NULL; - } - ; - -non_local_addr_spec: local_part '@' domain { - register Addr *ap; - - $$ = ap = newAddr(); - ap->localp = $1; - ap->destdom = $3; - ap->route = $3; - } - ; - -local_part: word { - $$ = $1; - } - | local_part '.' word { - $$ = newstring3($1, ".", $3); - free($1); - free($3); - } - | local_part '%' word { - $$ = newstring3($1, "%", $3); - free($1); - free($3); - } - ; - -domain : sub_domain { - register Dom *dp; - - dp = newDom(); - dp->sub[0] = $1; - dp->top = dp->sub; - $$ = dp; - } - | domain '.' sub_domain { - ($1->top)++; - *($1->top) = $3; - $$ = $1; - } - ; - -sub_domain: domain_ref { - $$ = $1; - } - | LIT_DOMAIN { - $$ = yylval.yString; - } - ; - -domain_ref: ATOM { - $$ = yyval.yString; - } - ; - -word : ATOM { - $$ = yylval.yString; - } - | QUOTED_STRING { - $$ = yylval.yString; - } - ; -%% - -#include -#include - -#define ERROR -2 - -enum -{ - Header, - Colon, - Body, -}; - -static char * -newstring3(a, b, c) - char *a; - char *b; - char *c; -{ - char *p; - char *q; - int i; - - i = strlen(a) + strlen(b) + strlen(c) + 1; - if ((p = salloc((MALLOCT)i)) == NULL) - nomem(); - q = p + strlen(strcpy(p, a)); - q += strlen(strcpy(q, b)); - Strcpy(q, c); - return(p); -} - - -static char * -newstring2(a, b) - char *a; - char *b; -{ - char *p; - int i; - - if (a == (char *)0) - a = ""; - i = strlen(a) + strlen(b) + 1; - if ((p = salloc((MALLOCT)i)) == NULL) - nomem(); - Strcpy(p, a); - Strcat(p, b); - return(p); -} - -/* - * : [ "" ] unexpected [ ] - */ -static void -unexpected(mess, what, tail) -char *mess; -char *what; -char *tail; -{ - flex_str(&errbuf, mess); - flex_str(&errbuf, ": "); - - if (what != NULLSTR) - { - flex_char(&errbuf, '"'); - flex_str(&errbuf, what); - flex_str(&errbuf, "\" "); - } - - flex_str(&errbuf, "unexpected"); - - if (tail != NULLSTR) - { - flex_char(&errbuf, ' '); - flex_str(&errbuf, tail); - } - - flex_char(&errbuf, '\0'); -} - -static void -yyerror(s) - char *s; -{ - static char c[2] = { '\0', '\0' }; - - switch(yychar) { - default: - c[0] = yylval.yChar; - unexpected(s, c, NULLSTR); - errstr = newstring2(errstr, errbuf.f_str); - break; - case LIT_DOMAIN: - case QUOTED_STRING: - case ATOM: - unexpected(s, yylval.yString, NULLSTR); - errstr = newstring2(errstr, errbuf.f_str); - break; - case EOL: - case 0: /* EOF */ - unexpected(s, NULLSTR, "end-of-header"); - errstr = newstring2(errstr, errbuf.f_str); - break; - } - flex_end(&errbuf); -} - - -parseit(char *line) -{ -extern int yydebug; - saveline = cp = text = line; - adrlist = NULL; - errlist = NULL; - if (combuf.f_str == NULLSTR) - flex_init(&combuf); - flex_end(&combuf); - if (errbuf.f_str == NULLSTR) - flex_init(&errbuf); - flex_end(&errbuf); - - if (!rfc_header(line)) - { - Addr *ap; - - ap = newAddr(); - errstr = newstring2("not a header field", errbuf.f_str); - ap->error = errstr; - comstr = NULL; - errstr = NULL; - appAddr(&adrlist, ap); - return; - } - - (void)yyparse(); -} - -char * -eatcomment(s) -register char *s; -{ - register int parencount; - - parencount = 0; - for (;;) { - if (*s == '\\') { /* quoted-pair */ - s++; - if (*s == '\0') - return ((char *)0); - s++; - if (*s == '\0') - return ((char *)0); - continue; - } - if (*s == '(') - parencount++; - else if (*s == ')') - parencount--; - - if (parencount == 0) - return (++s); - else if (parencount < 0) - panic("eatcomment botch"); - - if (*++s == '\0') - return ((char *)0); - } -} - - -/* - * Case independent strcmp(). - */ -static int -strcasecmp(char *s1, char *s2) -{ - while (*s1 != '\0') - { - int c1; - int c2; - - if (*s1 != *s2 && (c1 = tolower(*s1)) != (c2 = tolower(*s2))) - return c1 < c2 ? -1 : 1; - - s1++; - s2++; - } - - return 0; -} - -yylex() -{ - char *p; - - savecp = cp; - while (isascii(*cp) && (isspace(*cp) || (*cp == '('))) { - if (*cp == '(') { - p = eatcomment(cp); - if (p == (char *)0) - return (EOF); - flex_nstr(&combuf, cp + 1, (p - 2) - cp); - flex_char(&combuf, '\0'); - if (comstr == NULL) { - if ((comstr = salloc((MALLOCT)(strlen(combuf.f_str) + 1))) == NULL) - nomem(); - Strcpy(comstr, combuf.f_str); - } - else - comstr = newstring3(comstr, ", ", combuf.f_str); - flex_end(&combuf); - cp = p; - } - else - cp++; - } - - if (!isascii(*cp)) - return(ERROR); - - switch (*cp) { - case '\0': - if (iseol) { - iseol = 0; - return(EOF); - } - iseol = 1; - return(EOL); - case ':': - case ',': - case ';': - case '.': - case '@': - case '%': - case '<': - case '>': - case '(': - case ')': - case ']': - yylval.yChar = *cp; - return(*cp++); - case '[': /* LIT_DOMAIN */ - for (p = cp + 1; *p && *p != ']'; ) { - if (*p == '\\') { - p++; - if (*p == '\0') - return(EOF); - } - p++; - } - if (*p == '\0') - return(EOF); - if ((yylval.yString = salloc((MALLOCT)(p - cp + 2))) == NULL) - nomem(); - Strncpy(yylval.yString, cp, p - cp + 1); - yylval.yString[p - cp + 1] = '\0'; - cp = ++p; - return(LIT_DOMAIN); - case '"': /* QUOTED_STRING */ - for (p = cp + 1; *p && *p != '"'; ) { - if (*p == '\\') { - p++; - if (*p == '\0') - return(EOF); - } - p++; - } - if (*p == '\0') - return(EOF); - if ((yylval.yString = salloc((MALLOCT)(p - cp))) == NULL) - nomem(); - Strncpy(yylval.yString, cp + 1, p - cp); - yylval.yString[p - cp - 1] = '\0'; - cp = ++p; - return(QUOTED_STRING); - } - - for (p = cp; ; p++) - switch (*p) { - case ',': - case ':': - case ';': - case '.': - case '@': - case '%': - case '<': - case '>': - case '(': - case ')': - case '[': - case ']': - case '"': - case '\0': - goto out; - default: - if (isspace(*p)) - goto out; - } -out: - if ((yylval.yString = salloc((MALLOCT)(p - cp + 1))) == NULL) - nomem(); - Strncpy(yylval.yString, cp, p - cp); - yylval.yString[p - cp] = '\0'; - cp = p; - return ATOM; -} - -/* -** Create and initialize a new address. -*/ -Addr * -newAddr() -{ - register Addr *ap; - - if ((ap = (Addr *)salloc((MALLOCT)sizeof *ap)) == NULL) - nomem(); - memset((char *)ap, '\0', sizeof *ap); - return(ap); -} - - -/* -** Append addresslist "addr" to addresslist "head". -*/ -appAddr(head, addr) - Addr **head; - Addr *addr; -{ - register Addr *ap; - register char *p; - register int i; - - if (*head) { - for (ap = *head; ap->next; ap = ap->next) - ; - ap->next = addr; - } - else - *head = addr; - - if (head == &adrlist) - { - while (isspace(*text)) - text++; - - if (*(p = cp) != '\0') - { - p--; - - if (isspace(p[-1])) - { - p--; - - while (isspace(*p)) - p--; - - p++; - } - } - - if ((addr->text = salloc((MALLOCT)(p - text + 1))) == NULLSTR) - nomem(); - - strncpy(addr->text, text, i = p - text); - addr->text[i] = '\0'; - - text = cp; - } - else - addr->text = NULLSTR; -} - - - -/* -** Create and initialize a new domain. -*/ -Dom * -newDom() -{ - register Dom *dp; - - if ((dp = (Dom *)salloc((MALLOCT)sizeof *dp)) == NULL) - nomem(); - memset((char *)dp, '\0', sizeof *dp); - dp->top = dp->sub; - return(dp); -} - - -/* -** Append domainlist "dom" to domainlist "head". -*/ -appDom(head, dom) - Dom **head; - Dom *dom; -{ - register Dom *dp; - - if (*head) { - for (dp = *head; dp->next; dp = dp->next) - ; - dp->next = dom; - } - else - *head = dom; -} - - -/* -** Prepend domainlist "dom" before domainlist "head". -*/ -prepDom(head, dom) - Dom **head; - Dom *dom; -{ - register Dom *dp; - - for (dp = dom; dp->next; dp = dp->next) - ; - dp->next = *head; - *head = dom; -} - -static void -putdom(d) -register Dom *d; -{ - register char **p; - - for (p = d->sub; p != d->top; p++) - { - flex_str(&f, *p); - flex_char(&f, RFC_SPEC_DOT); - } - - flex_str(&f, *p); -} - -/* - * Take an Addr struct and return a textual representation that - * a delivery agent can use to deliver the message. - */ -char * -make_address(a) -register Addr *a; -{ - register Dom *d; - register char *p; - - if (f.f_str == NULLSTR) - flex_init(&f); - - d = a->route; - - while (d != (Dom *)0 && d->next != (Dom *)0) - { - /* source route */ - - flex_char(&f, RFC_SPEC_AT); - putdom(d); - flex_char(&f, d->next->next ? RFC_SPEC_COMMA : RFC_SPEC_COLON); - d = d->next; - } - - flex_str(&f, a->localp); - - if (d != (Dom *)0) - { - flex_char(&f, RFC_SPEC_AT); - putdom(d); - } - - flex_char(&f, '\0'); - p = newstr(f.f_str); - flex_end(&f); - - return p; -} - -static char * -cleanup(Addr **ap) -{ - Addr *a; - - if (errlist != (Addr *)0) - { - for (a = errlist; a != (Addr *)0; a = a->next) - { - if (a->error != NULLSTR) - return a->error; - } - - fatal("make_address"); - /* NOTREACHED */ - } - - for (a = adrlist; a != (Addr *)0; a = a->next) - { - if (a->localp == (char *)0 || a->localp[0] == '\0') - return "null local-part in address"; - } - - *ap = adrlist; - - return NULLSTR; -} - -/* - * Parse a textual address list and return it as a list of Addr structs. - * - * Returns NULLSTR for ok; otherwise an error string. - */ -char * -parse_address(ap, s) -Addr **ap; -char *s; -{ - parseit(s); - - return cleanup(ap); -} - -/* - * Parse a Received: header and return it as a list of Addr structs. - * - * Returns NULLSTR for ok; otherwise an error string. - */ -char * -parse_received(Addr **ap, char *s) -{ - parseit(s); - - return cleanup(ap); -} //GO.SYSIN DD addr.y echo aka.c sed 's/.//' >aka.c <<'//GO.SYSIN DD aka.c' -/* - * Message aliases & aka's. - */ - -#ifndef lint -static char sccsid[] = "@(#)aka.c 1.30"; -#endif - -#include "mace.h" - -#define ABBREV_CHAR '|' - -typedef struct -{ - char *a_str; - msg_idx (*a_func)(); -} - abbrev; - -static msg_idx first_mess(); -static msg_idx last_mess(); -static msg_idx current_mess(); -static msg_idx next_mess(); -static msg_idx previous_mess(); - -static abbrev mess_abbrev[] = -{ - { "firs|t", first_mess }, - { "last", last_mess }, - { "curr|ent", current_mess }, - { "next", next_mess }, - { "prev|ious", previous_mess }, - { NULLSTR, }, -}; - -static msg_idx -first_mess(m) -register mbox *m; -{ - return m->m_count > 0 ? 0 : NULLMSG; -} - -static msg_idx -last_mess(m) -register mbox *m; -{ - return m->m_count > 0 ? m->m_count - 1 : NULLMSG; -} - -static msg_idx -current_mess(m) -register mbox *m; -{ - return m->m_current; -} - -static msg_idx -next_mess(m) -register mbox *m; -{ - register msg_idx i; - register char *s; - - if ((i = m->m_current) != NULLMSG) - return ++i == m->m_count ? NULLMSG : i; - - if ((s = m->m_messid) == NULLSTR || m->m_count == 0) - return NULLMSG; - - if (strcmp(s, m->m_list[0]) < 0) - return 0; - - if (strcmp(s, m->m_list[m->m_count - 1]) > 0) - return NULLMSG; - - for (i = 0; i < m->m_count; i++) - { - if (strcmp(s, m->m_list[i]) > 0) - continue; - - return i; - } - - return NULLMSG; -} - -static msg_idx -previous_mess(m) -register mbox *m; -{ - register msg_idx i; - register char *s; - - if ((i = m->m_current) != NULLMSG) - return --i < 0 ? NULLMSG : i; - - if ((s = m->m_messid) == NULLSTR || m->m_count == 0) - return NULLMSG; - - if (strcmp(s, m->m_list[0]) < 0) - return NULLMSG; - - if (strcmp(s, m->m_list[m->m_count - 1]) > 0) - return m->m_count - 1; - - for (i = m->m_count - 1; i >= 0; i--) - { - if (strcmp(s, m->m_list[i]) < 0) - continue; - - return i; - } - - return NULLMSG; -} - -msg_idx -mess_alias(m, s) -mbox *m; -char *s; -{ - register char *p; - register abbrev *ap; - - for (p = s; *p != '\0'; p++) - { - if (*p == ABBREV_CHAR) - return NULLMSG; - } - - for (ap = mess_abbrev; ap->a_str != NULLSTR; ap++) - { - register char *q; - int seen_bar; - - p = s; - q = ap->a_str; - seen_bar = 0; - - for (;;) - { - if (!seen_bar) - seen_bar = *q == '|'; - - if (*p == '\0') - { - if (seen_bar || *q == '\0') - return (*ap->a_func)(m); - - break; - } - - if (*p == *q) - { - p++; - q++; - continue; - } - - if (*q++ != '|') - break; - } - } - - return NULLMSG; -} - -char ** -mess_range(m, from, to) -mbox *m; -msg_idx from; -msg_idx to; -{ - register char **n; - register msg_idx i; - register char **v; - - if ((i = to - from) < 0) - i = -i; - - i++; - - v = n = (char **)salloc((int)((i + 1) * sizeof(char *))); - - while (i-- > 0) - { - /* I could use a ?: here, but the MIPS doesn't like it */ - - if (from > to) - *n++ = newstr(m->m_list[from--]); - else - *n++ = newstr(m->m_list[from++]); - } - - *n = NULLSTR; - - return v; -} //GO.SYSIN DD aka.c echo args.c sed 's/.//' >args.c <<'//GO.SYSIN DD args.c' -/* - * Message argument list processing. - */ - -#ifndef lint -static char sccsid[] = "@(#)args.c 1.4"; -#endif - -#include "mace.h" -#include "line.h" -#include - -#define ALL_NAME "all" -#define ALL_RANGE "first-last" - -static char *metas = "?*[]"; /* sh(1) metacharacters */ - -/* - * Shell metacharacter matcher. - */ -static int -match(str, pat) -register char *str; -register char *pat; -{ - register char c; - - switch (c = *pat++) - { - case '?': - return match(++str, pat); - - case '*': - while (*pat == '*') - pat++; - - if (*pat == '\0') - return 1; - - while (*++str != '\0') - { - if (match(str, pat)) - return 1; - } - - return 0; - - case '[': - { - int not; - int hit; - int range; - char pc; - - hit = 0; - not = 0; - pc = 0; - - if (*pat == SH_META_NOT) - { - not = 1; - hit = 1; - pat++; - } - - while ((c = *pat++) != '\0') - { - if (c == ']') - return hit ? match(++str, pat) : 0; - - if (c == '-') - { - if ((range = *pat++) == '\0' || range == ']') - return 0; - - if (*str >= pc && *str <= range) - { - if (not) - return 0; - - hit = 1; - } - } - else - { - pc = c; - - if (*str == c) - { - if (not) - return 0; - - hit = 1; - } - } - } - - return 0; - } - - default: - if (c == *str) - { - if (c == '\0') - return 1; - - return match(++str, pat); - } - - return 0; - } -} - -/* - * Turn a shell metacharacter specification into messages id's. - */ -static void -metas_to_messages(mb, pattern, vp) -register mbox *mb; -char *pattern; -register vec *vp; -{ - register msg_idx i; - - for (i = 0; i < mb->m_count; i++) - { - if (match(mb->m_list[i], pattern)) - vec_str(vp, mess_to_path(mb, mb->m_list[i])); - } -} - -/* - * Find a messages' index into a mailbox. - */ -static msg_idx -find_msg(m, s) -register mbox *m; -register char *s; -{ - register msg_idx i; - - if (*s == '\0') - { - if (m->m_current == NULLMSG) - fprintf(stderr, "%s: No current message in \"%s\".\n", my_name, m->m_name); - - return m->m_current; - } - - if ((i = valid_id(s) ? mess_index(m, s) : mess_alias(m, s)) == NULLMSG) - fprintf(stderr, "%s: No such message qualifier as \"%s\".\n", my_name, s); - - return i; -} - -/* - * Take a command line and interpret it into messages. - * - * [ [+]box ] [ messages ] ... - */ -int -args_to_messages(argc, argv, vp, bp) -register int argc; -register char *argv[]; -register vec *vp; -char **bp; -{ - register int i; - register mbox *mb; - char *box; - - mb = NULLBOX; - box = NULLSTR; - - if (argc == 1) - { - /* - * Current message in the current box. - */ - if ((box = curr_box()) == NULLSTR) - { - fprintf(stderr, "%s: No current box.\n", my_name); - return 0; - } - - if ((mb = read_box(box)) == NULLBOX) - { - fprintf(stderr, "%s: No such box as \"%s\".\n", my_name, box); - return 0; - } - - if (mb->m_current == NULLMSG) - { - fprintf(stderr, "%s: No current message in \"%s\".\n", my_name, box); - return 0; - } - - vec_str(vp, mess_to_path(mb, mb->m_list[mb->m_current])); - } - - for (i = 1; i < argc; i++) - { - register char *id; - char *p; - msg_idx x; - extern char *strchr(); - - /* - * New box to pick messages from? - */ - if (argv[i][0] == BOX_CHAR) - { - /* - * Change current box? - */ - if (argv[i][1] == BOX_CHAR) - { - if (*bp != NULLSTR) - { - usage(); - /* NOTREACHED */ - } - - *bp = box = newstr(&argv[i][2]); - } - else - box = newstr(&argv[i][1]); - - if (*box == '\0') - { - usage(); - /* NOTREACHED */ - } - - if (mb != NULLBOX) - free_box(mb); - - if ((mb = read_box(box)) == NULLBOX) - { - fprintf(stderr, "%s: No such box as \"%s\".\n", my_name, box); - - if (*bp != NULLSTR && strcmp(*bp, box) == 0) - *bp = NULLSTR; - - continue; - } - - /* - * If this is the end of the line or the next - * argument is a box then get the current message - * in the specified box. Otherwise continue. - */ - if (i + 1 < argc && argv[i + 1][0] != BOX_CHAR) - continue; - - if (mb->m_current == NULLMSG) - { - fprintf(stderr, "%s: No current message in \"%s\".\n", my_name, box); - continue; - } - - vec_str(vp, mess_to_path(mb, mb->m_list[mb->m_current])); - continue; - } - - /* - * Kludge the qualifier "all" into a "range". - */ - if (strcmp(argv[i], ALL_NAME) == 0) - id = ALL_RANGE; - else - id = argv[i]; - - /* - * No specified box, so use current one. - */ - if (mb == NULLBOX) - { - if (box != NULLSTR) - continue; - - if ((box = curr_box()) == NULLSTR) - { - fprintf(stderr, "%s: No current box.\n", my_name); - - while (++i < argc && argv[i][0] != BOX_CHAR) - ; - - i--; - continue; - } - - if ((mb = read_box(box)) == NULLBOX) - { - fprintf(stderr, "%s: No such box as \"%s\".\n", my_name, box); - continue; - } - } - - /* - * Literal message id. - */ - if (valid_id(id)) - { - if (mess_index(mb, id) != NULLMSG) - vec_str(vp, mess_to_path(mb, id)); - else - fprintf(stderr, "%s: No message \"%s\" in \"%s\".\n", my_name, id, box); - - continue; - } - - /* - * Shell metacharacter message specifier. - */ - if (strstr(id, metas) != NULLSTR) - { - metas_to_messages(mb, id, vp); - continue; - } - - /* - * Range of messages. - */ - if ((p = strchr(id, '-')) != NULLSTR) - { - char **v; - char **n; - msg_idx start; - msg_idx finish; - - *p++ = '\0'; - - if - ( - (start = find_msg(mb, id)) == NULLMSG - || - (finish = find_msg(mb, p)) == NULLMSG - ) - continue; - - if ((v = n = mess_range(mb, start, finish)) == (char **)0) - continue; - - while (*n != NULLSTR) - vec_str(vp, mess_to_path(mb, *n++)); - - *--p = '-'; - (void)free((char *)v); - - continue; - } - - /* - * An alias (first, current, last, etc ...) - */ - if ((x = mess_alias(mb, id)) != NULLMSG) - { - vec_str(vp, mess_to_path(mb, mb->m_list[x])); - continue; - } - - fprintf(stderr, "%s: Message \"%s\" not in \"%s\".\n", my_name, id, box); - } - - if (mb != NULLBOX) - free_box(mb); - - return vp->v_count; -} //GO.SYSIN DD args.c echo conf.c sed 's/.//' >conf.c <<'//GO.SYSIN DD conf.c' -/* - * Configuration stuff. - */ - -#ifndef lint -static char sccsid[] = "@(#)conf.c 1.39"; -#endif - -#include -#include "mace.h" -#include "regexp.h" -#include "line.h" -#include "message.h" -#include "conf.h" -#include "flex.h" -#include "headers.h" - -typedef struct -{ - char *p_token; - char **p_strp; - match **p_matp; - int (*p_func)(); - int p_required; -} - parse; - -static conf cf = -{ - NULLSTR, - NULLSTR, - NULLSTR, - NULLSTR, - NULLSTR, - NULLSTR, - (match *)0, - (match *)0, - (match *)0, -}; - -static int lineno; -static char *file; - -static void -white(pp) -register char **pp; -{ - register char *s; - register char c; - - s = *pp; - - for (;;) - { - switch (c = *s++) - { - case ' ': - case '\t': - continue; - - case '\\': - if (*s == '\n') - { - s++; - lineno++; - continue; - } - /* fall through */ - - default: - s--; - break; - } - - break; - } - - *pp = s; -} - -static char * -copy(p, q) -register char *p; -register char *q; -{ - register char c; - - - if (q[-1] == '\n') - q--; - - c = *q; - *q = '\0'; - p = newstr(p); - *q = c; - - return p; -} - -static char * -string(pp) -register char **pp; -{ - register char *s; - register char c; - char *p; - - white(pp); - - s = p = *pp; - - while ((c = *s) != '\0' && c != '\n') - s++; - - *pp = s; - - if (s == p) - return NULLSTR; - - return copy(p, s); -} - -static char * -quoted_string(pp) -register char **pp; -{ - register char *p; - register char c; - static flex f = { NULLSTR, NULLSTR, NULLSTR, }; - - white(pp); - - if (*(p = *pp) != '"') - return NULLSTR; - - if (f.f_str == NULLSTR) - flex_init(&f); - - for (;;) - { - switch (c = *++p) - { - case '\0': - case '\n': - *pp = p; - flex_end(&f); - return NULLSTR; - - case '\\': - if (p[1] == '"') - flex_char(&f, *++p); - else if (p[1] == '\n') - { - p++; - lineno++; - } - else - flex_char(&f, c); - - continue; - - case '"': - flex_char(&f, '\0'); - p++; - break; - - default: - flex_char(&f, c); - continue; - } - - break; - } - - *pp = p; - p = newstr(f.f_str); - flex_end(&f); - - return p; -} - -static char * -token(pp) -register char **pp; -{ - register char *s; - register char c; - register char *p; - - white(pp); - - p = s = *pp; - - for (;;) - { - if - ( - ((c = *s) >= 'a' && c <= 'z') - || - ((c = *s) >= 'A' && c <= 'Z') - || - *s == '-' - ) - { - s++; - continue; - } - - break; - } - - *pp = s; - - if (s == p) - return NULLSTR; - - return copy(p, s); -} - -static int -newline(pp) -register char **pp; -{ - register char *s; - register char c; - - s = *pp; - - while ((c = *s++) != '\n') - { - if (c == '\0') - { - *pp = --s; - return 1; - } - - if (c == '\\' && *s == '\n') - { - s++; - lineno++; - } - } - - lineno++; - - *pp = s; - - return 0; -} - -static int -string_value(pi, pp) -register parse *pi; -register char **pp; -{ - if (*pi->p_strp != NULLSTR) - { - fprintf(stderr, "%s: \"%s\": \"%s\" multiply declared on line %d.\n", my_name, file, pi->p_token, lineno); - return 1; - } - - if ((*pi->p_strp = string(pp)) == NULLSTR) - { - fprintf(stderr, "%s: \"%s\": String expected after \"%s\" on line %d.\n", my_name, file, pi->p_token, lineno); - return 1; - } - - pi->p_required = 0; - - return 0; -} - -static int -re_value(pi, pp) -register parse *pi; -register char **pp; -{ - register match *mp; - regexp *cre; - char *re; - - if (*pi->p_matp != (match *)0) - { - fprintf(stderr, "%s: \"%s\": Multiple definition of \"%s\" on line %d.\n", my_name, file, pi->p_token, lineno); - return 1; - } - - if ((re = quoted_string(pp)) == NULLSTR) - { - fprintf(stderr, "%s: \"%s\": Quoted string expected after \"%s\" on line %d.\n", my_name, file, pi->p_token, lineno); - return 1; - } - - if ((cre = regcomp(re)) == (regexp *)0) - { - fprintf(stderr, "%s: \"%s\": Regular expression \"%s\" on line %d %s\n", my_name, file, re, lineno, re_error); - return 1; - } - - mp = (match *)salloc(sizeof *mp); - mp->m_re = re; - mp->m_cre = cre; - mp->m_action = NULLSTR; - mp->m_next = (match *)0; - - *pi->p_matp = mp; - pi->p_required = 0; - - return 0; -} - -static int -regex_string(pi, pp, quoted) -register parse *pi; -register char **pp; -{ - register match **n; - register match *mp; - regexp *cre; - char *re; - char *action; - - if ((re = quoted_string(pp)) == NULLSTR) - { - fprintf(stderr, "%s: \"%s\": Quoted string expected after \"%s\" on line %d.\n", my_name, file, pi->p_token, lineno); - return 1; - } - - if (quoted) - { - if ((action = quoted_string(pp)) == NULLSTR) - { - fprintf(stderr, "%s: \"%s\": Quoted string expected after regular expression \"%s\" on line %d.\n", my_name, file, re, lineno); - return 1; - } - } - else - { - if ((action = string(pp)) == NULLSTR) - { - fprintf(stderr, "%s: \"%s\": String expected after regular expression \"%s\" on line %d.\n", my_name, file, re, lineno); - return 1; - } - } - - if ((cre = regcomp(re)) == (regexp *)0) - { - fprintf(stderr, "%s: \"%s\": Regular expression \"%s\" on line %d %s\n", my_name, file, re, lineno, re_error); - return 1; - } - - mp = (match *)salloc(sizeof *mp); - mp->m_re = re; - mp->m_cre = cre; - mp->m_action = action; - mp->m_next = (match *)0; - - for (n = pi->p_matp; *n != (match *)0; n = &(*n)->m_next) - ; - - *n = mp; - pi->p_required = 0; - - return 0; -} - -static int -re_string(pi, pp) -register parse *pi; -register char **pp; -{ - return regex_string(pi, pp, 0); -} - -static int -re_qstring(pi, pp) -register parse *pi; -register char **pp; -{ - return regex_string(pi, pp, 1); -} - -conf * -read_config() -{ - register char *p; - register parse *pi; - static char *despool = DESPOOLER; - static char *deliver = DELIVERER; - static char *peruse = PERUSER; - char *s; - int ok; - static int done = 0; - static parse look_for[] = - { - { CT_ADDRESS, &cf.c_address, (match **)0, string_value, 0, }, - { CT_DELIVER, &cf.c_deliver, (match **)0, string_value, 0, }, - { CT_DESPOOL, &cf.c_despool, (match **)0, string_value, 0, }, - { CT_EXEC, (char **)0, &cf.c_exec, re_qstring, 0, }, - { CT_INBOX, &cf.c_inbox, (match **)0, string_value, 1, }, - { CT_OUTBOX, &cf.c_outbox, (match **)0, string_value, 1, }, - { CT_PERUSE, &cf.c_peruse, (match **)0, string_value, 0, }, - { CT_REFILE, (char **)0, &cf.c_refile, re_string, 0, }, - { CT_REMOVE, (char **)0, &cf.c_remove, re_value, 0, }, - { CT_SAVE, (char **)0, &cf.c_save, re_string, 0, }, - { CT_SPOOL, &cf.c_spool, (match **)0, string_value, 0, }, - { CT_SPOOLDIR, &cf.c_spooldir, (match **)0, string_value, 0, }, - { NULLSTR, (char **)0, (match **)0, (int (*)())0, 0, }, - }; - - if (done) - return &cf; - - file = concat3(mace_dir(), "/", CONFIG); - - if ((s = p = read_file(file)) == NULLSTR) - { - could_not("read", file); - /* NOTREACHED*/ - } - - ok = 0; - lineno = 1; - - do - { - register char *t; - - if (*s == '#') - { - newline(&s); - continue; - } - - if ((t = token(&s)) != NULLSTR) - { - for (pi = look_for; pi->p_token != NULLSTR; pi++) - { - if (strcmp(pi->p_token, t) == 0) - { - ok |= (*pi->p_func)(pi, &s); - break; - } - } - - if (pi->p_token == NULLSTR) - fprintf(stderr, "%s: \"%s\": Unrecognised token \"%s\" on line %d.\n", my_name, file, t, lineno); - - (void)free(t); - } - else - fprintf(stderr, "%s: \"%s\": Token expected on line %d.\n", my_name, file, lineno); - - newline(&s); - } - while (*s != '\0'); - - for (pi = look_for; pi->p_token != NULLSTR; pi++) - { - if (pi->p_required) - { - fprintf(stderr, "%s: \"%s\": Specification of \"%s\" required.\n", my_name, file, pi->p_token); - ok = 1; - } - } - - if (ok) - { - exit(1); - /* NOTREACHED */ - } - - if (cf.c_despool == NULLSTR) - { - if (despool == NULLSTR) - { - fprintf(stderr, "%s: \"%s\": Specification of \"%s\" required.\n", my_name, file, CT_DESPOOL); - exit(1); - /* NOTREACHED */ - } - - cf.c_despool = newstr(despool); - } - - if (cf.c_deliver == NULLSTR) - { - if (deliver == NULLSTR) - { - fprintf(stderr, "%s: \"%s\": Specification of \"%s\" required.\n", my_name, file, CT_DELIVER); - exit(1); - /* NOTREACHED */ - } - - cf.c_deliver = newstr(deliver); - } - - if (cf.c_address == NULLSTR) - { - static char dot[2] = { RFC_SPEC_DOT, '\0' }; - - if (DOMAIN_CMD == NULLSTR) - { - fprintf(stderr, "%s: Don't know your domain. Specify it with \"%s\" in \"%s\".\n", my_name, CT_ADDRESS, file); - exit(1); - } - - cf.c_address = concat3(host(), dot, domain()); - } - - if (cf.c_peruse == NULLSTR) - { - if (peruse == NULLSTR) - { - fprintf(stderr, "%s: \"%s\": Specification of \"%s\" required.\n", my_name, file, CT_PERUSE); - exit(1); - /* NOTREACHED */ - } - - cf.c_peruse = newstr(peruse); - } - - (void)free(file); - (void)free(p); - done = 1; - - return &cf; -} - -/* - * Expand a string containing `exec' CE_SPECIAL substitutions. - */ -char * -special_expand(char *s, char *box, char *id) -{ - char c; - static flex f = { NULLSTR, NULLSTR, NULLSTR }; - - if (f.f_str == NULLSTR) - flex_init(&f); - - while ((c = *s++) != '\0') - { - if (c == CE_SPECIAL) - { - switch (*s++) - { - case CE_BOX: - flex_char(&f, BOX_CHAR); - flex_str(&f, box); - break; - - case CE_MESSID: - flex_str(&f, id); - break; - - case CE_MACEDIR: - flex_str(&f, mace_dir()); - break; - - case CE_PATH: - /* this is wrong and should be changed */ - flex_str(&f, mace_dir()); - flex_char(&f, '/'); - flex_str(&f, box); - flex_char(&f, '/'); - flex_str(&f, id); - break; - - case CE_SPECIAL: - flex_char(&f, CE_SPECIAL); - break; - - default: - flex_char(&f, CE_SPECIAL); - s--; - break; - } - - continue; - } - - flex_char(&f, c); - } - - flex_char(&f, '\0'); - flex_end(&f); - - return f.f_str; -} - -/* - * Call f() for each time a regex matches a message's headers. - */ -void -regex_apply(char *inbox, message *m, match *re, void (*f)(char *, message *, match *)) -{ - char **n; - - while (re != (match *)0) - { - for (n = m->ms_headers.v_list; *n != NULLSTR && **n != '\0'; n++) - { - re_error = NULLSTR; - - if (regexec(re->m_cre, *n) == 0) - { - if (re_error != NULLSTR) - { - fprintf(stderr, "%s: Regular expression \"%s\" %s\n", my_name, re->m_re, re_error); - break; - } - - continue; - } - - (*f)(inbox, m, re); - } - - re = re->m_next; - } -} //GO.SYSIN DD conf.c echo dir.c sed 's/.//' >dir.c <<'//GO.SYSIN DD dir.c' -/* - * mkdir/rmdir [in]compatibility. - */ - -#include "mace.h" - -#if !BSD_MKDIR - -#ifndef lint -static char sccsid[] = "@(#)dir.c 1.30"; -#endif - -static int -dir_op(op, s) -register char *op; -register char *s; -{ - char *v[3]; - - v[0] = op; - v[1] = s; - v[2] = NULLSTR; - - return run(v) != 0 ? SYSERROR : 0; -} - -int -mkdir(s, mode) -register char *s; -register int mode; -{ - return dir_op(MKDIR_STR, s); -} - -int -rmdir(s) -register char *s; -{ - return dir_op(RMDIR_STR, s); -} - -#endif //GO.SYSIN DD dir.c echo domain.c sed 's/.//' >domain.c <<'//GO.SYSIN DD domain.c' -/* - * Discover this host's domain. - * - * Returns static data. - */ - -#ifndef lint -static char sccsid[] = "@(#)domain.c 1.25"; -#endif - -#include "mace.h" -#include "line.h" - -static char *domainname = NULLSTR; - -char * -domain() -{ - register int fd; - register char *p; - lineio l; - char *cmd = DOMAIN_CMD; - - if (domainname != NULLSTR) - return domainname; - - if (cmd == NULLSTR) - { - fatal("domain"); - /* NOTREACHED */ - } - - if ((fd = pipe_open(cmd, 'r')) == -1) - { - could_not("pipe to", cmd); - /* NOTREACHED */ - } - - (void)lopen(&l, fd, LREAD); - - if ((p = lread(&l)) == NULLSTR) - { - could_not("read", cmd); - /* NOTREACHED */ - } - - if (lclose(&l)) - { - (void)pipe_close(fd); - could_not("close", cmd); - /* NOTREACHED */ - } - - if (pipe_close(fd)) - { - could_not("close", cmd); - /* NOTREACHED */ - } - - return domainname = p; -} //GO.SYSIN DD domain.c echo id.c sed 's/.//' >id.c <<'//GO.SYSIN DD id.c' -/* - * Generate message id's - */ - -#ifndef lint -static char sccsid[] = "@(#)id.c 1.31"; -#endif - -#include "mace.h" - -static char *vowels = "aeiou"; -static char *cons = "bdfgjklmnprstvyz"; - -char * -nextid(s) -char *s; -{ - register char *p; - register char *q; - char *set; - char *id; - int carry; - extern char *strchr(); - - if (s == NULLSTR) - { - for (p = id = salloc(ID_LEN + 1); p < &id[ID_LEN]; p++) - *p = ((p - id) & 1 ? vowels : cons)[0]; - - *p = '\0'; - - return id; - } - - id = newstr(s); - - if (!valid_id(id)) - { - fatal("nextid"); - /* NOTREACHED */ - } - - carry = 1; - - p = &id[ID_LEN]; - - while (--p >= id) - { - set = (p - id) & 1 ? vowels : cons; - - q = strchr(set, *p); - - if (carry) - { - if (*++q == '\0') - q = set; - else - carry = 0; - - *p = *q; - } - } - - return id; -} - -int -valid_id(id) -register char *id; -{ - register char *p; - - for (p = id; *p != '\0'; p++) - ; - - if (p - id != ID_LEN) - return 0; - - for (p = id; *p != '\0'; p++) - { - if (strchr((p - id) & 1 ? vowels : cons, *p) == NULLSTR) - return 0; - } - - return 1; -} //GO.SYSIN DD id.c echo flex.c sed 's/.//' >flex.c <<'//GO.SYSIN DD flex.c' -/* - * Flexible string handling. - */ - -#ifndef lint -static char sccsid[] = "@(#)flex.c 1.31"; -#endif - -#include "mace.h" -#include "flex.h" - -void -flex_init(f) -register flex *f; -{ - f->f_str = f->f_ptr = salloc(FLEXZ); - f->f_end = f->f_ptr + FLEXZ; -} - -char * -flex_fill(f) -register flex *f; -{ - register int s; - - s = f->f_end - f->f_str + FLEXZ; - - f->f_str = srealloc(f->f_str, s); - f->f_end = f->f_str + s; - f->f_ptr = f->f_end - FLEXZ; - - return f->f_ptr++; -} - -void -flex_end(f) -register flex *f; -{ - f->f_ptr = f->f_str; -} - -void -flex_str(f, s) -register flex *f; -register char *s; -{ - while (*s != '\0') - flex_char(f, *s++); -} - -void -flex_nstr(f, s, n) -register flex *f; -register char *s; -register int n; -{ - while (n-- > 0 && *s != '\0') - flex_char(f, *s++); -} //GO.SYSIN DD flex.c echo headers.c sed 's/.//' >headers.c <<'//GO.SYSIN DD headers.c' -/* - * RFC 822 header routines. - */ - -#ifndef lint -static char sccsid[] = "@(#)headers.c 1.33"; -#endif - -#include "mace.h" -#include "headers.h" - -char ** -find_header(v, h) -register char **v; -register char *h; -{ - register char *p; - - while ((p = *v) != NULLSTR) - { - if (rfc_hdr_cmp(p, h)) - return v; - - v++; - } - - return (char **)NULLSTR; -} - -char * -header_text(h) -register char *h; -{ - while (*h++ != RFC_SPEC_COLON) - ; - - while ((*h == RFC_LWSP_1 || *h == RFC_LWSP_2) && *h != '\0') - h++; - - return *h == '\0' ? NULLSTR : h; -} - -/* - * Re-order the headers in a message so they are in this order: - * - * From: - * Date: - * To: - * Cc: - * Bcc: - * Subject: - */ -static char *header_order[] = -{ - RFC_FROM, - RFC_DATE, - RFC_TO, - RFC_CC, - RFC_BCC, - RFC_SUBJECT, - NULLSTR, -}; - -void -reorder_headers(vec *h) -{ - register char **hp; - register int i; - static vec new; - static char stolen[] = ""; - - if (new.v_size == 0) - vec_init(&new, 64); - - /* - * Steal the headers that we want. - */ - for (hp = header_order; *hp != NULLSTR; hp++) - { - register char **n; - - /* - * Search all the headers because multiple To:/Cc:/Bcc: - * headers can occur. - */ - for (n = h->v_list; *n != NULLSTR; n++) - { - if (rfc_hdr_cmp(*n, *hp)) - { - vec_str(&new, *n); - *n = stolen; - } - } - } - - /* - * Append the others. - */ - for (hp = h->v_list; *hp != NULLSTR; hp++) - { - if (*hp != stolen) - vec_str(&new, *hp); - } - - vec_str(&new, NULLSTR); - - /* - * Return the re-ordered headers. - */ - if (new.v_count != h->v_count) - { - fatal("reorder_headers"); - /* NOTREACHED */ - } - - for (i = 0; i < new.v_count; i++) - h->v_list[i] = new.v_list[i]; - - new.v_count = 0; -} //GO.SYSIN DD headers.c echo host.c sed 's/.//' >host.c <<'//GO.SYSIN DD host.c' -/* - * Discover this host's name. - * - * Returns static data. - */ - -#ifndef lint -static char sccsid[] = "@(#)host.c 1.25"; -#endif - -#include "mace.h" - -static char *hostname = NULLSTR; - -#if USG_UNAME && BSD_GETHOSTNAME - -$$ "You're either on a USG or BSD system" $$ - -#endif - -#if USG_UNAME - -#include - -char * -host() -{ - static struct utsname n; - - if (hostname != NULLSTR) - return hostname; - - if (uname(&n) == -1) - { - could_not("uname", "host"); - /* NOTREACHED */ - } - - return hostname = n.nodename; -} - -#endif - -#if BSD_GETHOSTNAME - -char * -host() -{ - static char n[64]; - - if (hostname != NULLSTR) - return hostname; - - if (gethostname(n, sizeof n) == -1) - { - could_not("gethostname", "host"); - /* NOTREACHED */ - } - - return hostname = n; -} - -#endif - -#if !USG_UNAME && !BSD_GETHOSTNAME - -#include "line.h" - -char * -host() -{ - register int fd; - register char *p; - lineio l; - char *cmd = HOST_CMD; - - if (hostname != NULLSTR) - return hostname; - - if (cmd == NULLSTR) - { - fatal("host"); - /* NOTREACHED */ - } - - if ((fd = pipe_open(cmd, 'r')) == -1) - { - could_not("pipe to", cmd); - /* NOTREACHED */ - } - - (void)lopen(&l, fd, LREAD); - - if ((p = lread(&l)) == NULLSTR) - { - could_not("read", cmd); - /* NOTREACHED */ - } - - if (lclose(&l)) - { - (void)pipe_close(fd); - could_not("close", cmd); - /* NOTREACHED */ - } - - if (pipe_close(fd)) - { - could_not("close", cmd); - /* NOTREACHED */ - } - - return hostname = p; -} - -#endif //GO.SYSIN DD host.c echo line.c sed 's/.//' >line.c <<'//GO.SYSIN DD line.c' -/* - * Line i/o routines. - */ - -#ifndef lint -static char sccsid[] = "@(#)line.c 1.31"; -#endif - -#include "mace.h" -#include "line.h" -#include "flex.h" - -lineio * -lopen(lp, fd, flag) -register lineio *lp; -register int fd; -register int flag; -{ - lp->l_fd = fd; - lp->l_ptr = lp->l_end = lp->l_buf; - lp->l_flag = flag; - - return lp; -} - -int -lclose(lp) -register lineio *lp; -{ - register int n; - - if ((lp->l_flag & (LWRITE|LERROR)) == LWRITE && (n = lp->l_ptr - lp->l_buf) > 0) - { - if (write(lp->l_fd, lp->l_buf, n) != n) - lp->l_flag |= LERROR; - } - - n = (lp->l_flag & LERROR) != 0; - - lp->l_flag = 0; - - return n; -} - -char * -lread(lp) -register lineio *lp; -{ - register char *p; - static flex f = { NULLSTR, NULLSTR, NULLSTR, }; - - switch (lp->l_flag & ~LCRLF) - { - case LREAD: - break; - - case LREAD|LEOF: - return NULLSTR; - - default: - fatal("lread"); - /* NOTREACHED */ - } - - if (f.f_str == NULLSTR) - flex_init(&f); - - for (;;) - { - register char c; - - if (lp->l_ptr == lp->l_end) - { - register int n; - - switch (n = read(lp->l_fd, lp->l_buf, LBUFZ)) - { - case SYSERROR: - lp->l_flag |= LERROR; - flex_end(&f); - return NULLSTR; - - case 0: - lp->l_flag |= LEOF; - break; - - default: - lp->l_ptr = lp->l_buf; - lp->l_end = lp->l_ptr + n; - } - } - - if ((lp->l_flag & LEOF) != 0) - { - if (f.f_ptr == f.f_str) - return NULLSTR; - - break; - } - - if ((c = *lp->l_ptr++) == '\n') - { - if ((lp->l_flag & LCRLF) == 0) - break; - - if (f.f_ptr != f.f_str && f.f_ptr[-1] == '\r') - { - f.f_ptr--; - break; - } - } - - flex_char(&f, c); - } - - flex_char(&f, '\0'); - p = newstr(f.f_str); - flex_end(&f); - return p; -} - -static void -lflush(lp) -register lineio *lp; -{ - register int n; - - switch (lp->l_flag & ~(LCRLF|LLBUF)) - { - case LWRITE: - break; - - default: - fatal("lflush"); - /* NOTREACHED */ - } - - n = lp->l_ptr - lp->l_buf; - - if (write(lp->l_fd, lp->l_buf, n) != n) - { - lp->l_flag |= LERROR; - return; - } - - lp->l_ptr = lp->l_buf; -} - -#define lputchar(lp, c) do \ - { \ - if (((lp)->l_flag & LERROR) != 0) \ - break; \ - if ((lp)->l_ptr == &(lp)->l_buf[LBUFZ]) \ - lflush(lp); \ - if ((*(lp)->l_ptr++ = (c)) == '\n' && ((lp)->l_flag & LLBUF) != 0) \ - lflush(lp); \ - } while(0) - - -char * -lwrite(lp, s) -register lineio *lp; -register char *s; -{ - register char *p; - - switch (lp->l_flag & ~(LCRLF|LLBUF)) - { - case LWRITE: - break; - - default: - fatal("lwrite"); - /* NOTREACHED */ - } - - p = s; - - for (;;) - { - register char c; - - if ((c = *p++) == '\0') - { - if ((lp->l_flag & LCRLF) != 0) - lputchar(lp, '\r'); - - lputchar(lp, '\n'); - - return (lp->l_flag & LERROR) == 0 ? s : NULLSTR; - } - - lputchar(lp, c); - } -} //GO.SYSIN DD line.c echo lock.c sed 's/.//' >lock.c <<'//GO.SYSIN DD lock.c' -/* - * File locking. - */ - -#ifndef lint -static char sccsid[] = "@(#)lock.c 1.30"; -#endif - -#include "mace.h" -#include - -int -lock(f) -register char *f; -{ - register char *p; - register int tries; - extern int errno; - - tries = 0; - - p = concat(f, LOCK_STR); - - while (tries++ < 5) - { - errno = 0; - - link(f, p); - - if (errno != EEXIST) - break; - - sleep(2); - } - - (void)free(p); - - return errno; -} - -int -unlock(f) -register char *f; -{ - register char *p; - extern int errno; - - errno = 0; - - (void)unlink(p = concat(f, LOCK_STR)); - - (void)free(p); - - return errno; -} //GO.SYSIN DD lock.c echo mail.c sed 's/.//' >mail.c <<'//GO.SYSIN DD mail.c' -/* - * System independent mail box locking. - */ - -#ifndef lint -static char sccsid[] = "@(#)mail.c 1.33"; -#endif - -#include "mace.h" -#include "line.h" -#include "headers.h" -#include -#include - -#define MAIL_FORWARD "Forward to " -#define MAIL_PIPE "Pipe to " - -static char *mail_file = NULLSTR; -static int locked = 0; - -/* - * Returns a pointer to static data, unlike the rest. - */ -static char * -mail_name() -{ - register char *p; - extern char *getenv(); - - if (mail_file == NULLSTR) - { - if ((p = getenv("MAIL")) == NULLSTR) - { - would_not("getenv", "MAIL"); - return NULLSTR; - } - - mail_file = p; - } - - return mail_file; -} - -int -mail_check(mf) -char *mf; -{ - register char *p; - register char *l; - int fd; - lineio mld; - extern int errno; - - if ((p = mf) == NULLSTR && (p = mail_name()) == NULLSTR) - return 0; - - if (access(p, 4) == SYSERROR && errno == EACCES) - { - fprintf(stderr, "%s: Mail in \"%s\" is not accessable by you.\n", my_name, p); - return 0; - } - - if ((fd = open(p, O_RD)) == SYSERROR) - { - fprintf(stderr, "%s: No mail in \"%s\".\n", my_name, p); - return 0; - } - - lopen(&mld, fd, LREAD); - - if ((l = lread(&mld)) == NULLSTR) - { - fprintf(stderr, "%s: No mail in \"%s\".\n", my_name, p); - (void)lclose(&mld); - (void)close(fd); - - return 0; - } - - (void)lclose(&mld); - (void)close(fd); - - if (strncmp(l, UNIX_FROM, (sizeof UNIX_FROM) - 1) == 0) - { - free(l); - return 1; - } - - if (strncmp(l, MAIL_FORWARD, (sizeof MAIL_FORWARD) - 1) == 0) - { - fprintf(stderr, "%s: Mail in \"%s\" is being forwarded to \"%s\".\n", my_name, p, l + (sizeof MAIL_FORWARD) - 1); - - free(l); - return 0; - } - - if (strncmp(l, MAIL_PIPE, (sizeof MAIL_PIPE) - 1) == 0) - { - fprintf(stderr, "%s: Mail in \"%s\" is being piped to \"%s\".\n", my_name, p, l + (sizeof MAIL_PIPE) - 1); - - free(l); - return 0; - } - - free(l); - - fprintf(stderr, "%s: Mail in \"%s\" is not in a UNIX format.\n", my_name, p); - return 0; -} - -#if USG_MAIL && BSD_MAIL -#include "You cannot have both USG_MAIL and BSD_MAIL defined!" -#endif - -#if USG_MAIL - -#define USG_LOCK ".lock" - -static char *lock_file = NULLSTR; - -#endif - -#if BSD_MAIL - -#include -#include - -static int lock_fd; - -#endif - -int -mail_lock(m) -register char **m; -{ - register char *p; - register int fd; - register int tries; - - if (locked) - { - fprintf(stderr, "%s: \"%s\" locked.\n", my_name, mail_file); - return SYSERROR; - } - - if ((p = *m) != NULLSTR) - mail_file = newstr(*m); - else if ((p = mail_name()) == NULLSTR) - return SYSERROR; - - if (!mail_check(p)) - return SYSERROR; - -#if USG_MAIL - - if (lock_file == NULLSTR) - lock_file = concat(p, USG_LOCK); - - tries = 0; - - while ((fd = creat(lock_file, 0)) == SYSERROR) - { - if (errno != EPERM || tries++ > 5) - { - would_not("creat", lock_file); - return SYSERROR; - } - - sleep(2); - } - - if (close(fd) == SYSERROR) - { - would_not("close", lock_file); - return SYSERROR; - } - -#endif - - if ((fd = open(mail_file, O_RD)) == SYSERROR) - { - would_not("open", mail_file); - return SYSERROR; - } - -#if BSD_MAIL - - while (flock(lock_fd = fd, LOCK_EX) == SYSERROR) - { - if (tries++ > 5) - { - would_not("lock", mail_file); - close(fd); - return SYSERROR; - } - - sleep(2); - } - -#endif - - if (*m == NULLSTR) - *m = mail_file; - locked = 1; - - return fd; -} - -int -mail_unlock(delete) -register int delete; -{ - register int ret; - - if - ( - mail_file == NULLSTR -#if USG_MAIL - || - lock_file == NULLSTR -#endif - ) - { - fatal("mail_unlock"); - /* NOTREACHED */ - } - - if (delete && (ret = unlink(mail_file)) == SYSERROR) - would_not("unlink", mail_file); - else - ret = 0; - -#if USG_MAIL - - if (unlink(lock_file) == SYSERROR) - { - ret = SYSERROR; - would_not("unlink", mail_file); - } - -#endif - -#if BSD_MAIL - - (void)flock(lock_fd, LOCK_UN); - (void)close(lock_fd); - -#endif - - locked = 0; - - return ret; -} - -int -mail_locked() -{ - return locked; -} //GO.SYSIN DD mail.c echo macebox.c sed 's/.//' >macebox.c <<'//GO.SYSIN DD macebox.c' -/* - * Box handling stuff. - */ - -#ifndef lint -static char sccsid[] = "@(#)macebox.c 1.32"; -#endif - -#include -#include -#include -#include -#include "mace.h" - -/* - * Return the name of the current box. - */ -char * -curr_box() -{ - register char *box; - register char *p; - - if ((box = read_file(p = concat3(mace_dir(), "/", BOX))) == NULLSTR) - { - (void)free(p); - return NULLSTR; - } - - (void)free(p); - - if ((p = check_box(box)) == NULLSTR) - { - (void)free(box); - return NULLSTR; - } - - (void)free(p); - - return box; -} - -char * -check_box(s) -char *s; -{ - register char *box; - struct stat statb; - - if (*s == SPEC_CHAR) - return NULLSTR; - - box = concat3(mace_dir(), "/", s); - - if (stat(box, &statb) == SYSERROR || (statb.st_mode & S_IFMT) != S_IFDIR) - { - (void)free(box); - return NULLSTR; - } - - return box; -} - -char * -create_box(s) -char *s; -{ - register char *dir; - register char *messid; - register char *id; - - if (*s == SPEC_CHAR) - return NULLSTR; - - dir = concat3(mace_dir(), "/", s); - - if (mkdir(dir, MKDIR_MODE) == SYSERROR) - { - (void)free(dir); - return NULLSTR; - } - - messid = concat3(dir, "/", MESSID); - - if (write_file(messid, id = nextid(NULLSTR))) - { - (void)free(id); - (void)free(dir); - (void)free(messid); - return NULLSTR; - } - - (void)free(id); - (void)free(messid); - - return dir; -} - -int -delete_box(s) -char *s; -{ - register char *b; - register char *m; - register int ok; - - if ((b = check_box(s)) == NULLSTR) - { - fprintf(stderr, "%s: No such box as \"%s\".\n", my_name, s); - return 1; - } - - m = concat3(b, "/", MESSID); - (void)unlink(m); - (void)free(m); - - m = concat3(b, "/", PROTO); - (void)unlink(m); - - if ((ok = rmdir(b)) != 0) - would_not("rmdir", b); - - (void)free(b); - (void)free(m); - - return ok != 0; -} - -static int -mess_cmp(m1, m2) -register char **m1; -register char **m2; -{ - return strcmp(*m1, *m2); -} - -mbox * -read_box(s) -char *s; -{ - register char *box; - register char **list; - register int i; - register mbox *info; - register char **n; - register char *current; - - if ((box = check_box(s)) == NULLSTR) - return NULLBOX; - - list = read_dir(box); - - /* - * Ensure there are no invalid message id's in the box. - */ - for (i = 0; list[i] != NULLSTR; i++) - { - register int j; - - if (valid_id(list[i])) - continue; - - fprintf(stderr, "%s: warning - Invalid message id \"%s\" in \"%c%s\".\n", my_name, list[i], BOX_CHAR, s); - - /* shuffle down by one */ - (void)free(list[i]); - - for (j = i; list[j] != NULLSTR; j++) - list[j] = list[j + 1]; - - i--; - } - - qsort((char *)list, i, sizeof(*list), mess_cmp); - - if ((current = curr_in_box(s)) != NULLSTR) - { - for (n = list; *n != NULLSTR; n++) - { - if (strcmp(*n, current) == 0) - break; - } - } - else - n = &list[i]; - - info = (mbox *)salloc(sizeof(mbox)); - info->m_name = newstr(s); - info->m_path = box; - info->m_count = i; - info->m_messid = current; - info->m_list = list; - info->m_current = *n == NULLSTR ? NULLMSG : n - list; - - return info; -} - -void -free_box(mp) -register mbox *mp; -{ - free_dir(mp->m_list); - (void)free(mp->m_name); - (void)free(mp->m_path); - if (mp->m_messid != NULLSTR) - (void)free(mp->m_messid); - (void)free((char *)mp); -} - -int -set_box(s) -register char *s; -{ - register char *f; - - if ((f = check_box(s)) == NULLSTR) - { - fprintf(stderr, "%s: No such box as \"%s\".\n", my_name, s); - return 1; - } - - (void)free(f); - - f = concat3(mace_dir(), "/", BOX); - - if (write_file(f, s)) - { - would_not("write", f); - (void)free(f); - return 1; - } - - (void)free(f); - return 0; -} - //GO.SYSIN DD macebox.c echo macedir.c sed 's/.//' >macedir.c <<'//GO.SYSIN DD macedir.c' -/* - * Spool directory finder. - */ - -#ifndef lint -static char sccsid[] = "@(#)macedir.c 1.32"; -#endif - -#include -#include "mace.h" - -/* - * Unlike the others we return a pointer to static data. - * It doesn't need to be free()'d. - * - * If the first character of the pathname contained in MAIL_DIR - * is a '/' assume that it's a full pathname and return it. - */ -char * -mace_dir() -{ - char *s; - char *t; - static char *home = NULLSTR; - static char *dir = NULLSTR; - extern char *getenv(); - - if (dir != NULLSTR) - return dir; - - if (home == NULLSTR && (home = getenv(ENV_HOME)) == NULLSTR) - { - fprintf(stderr, "%s: You have no $%s in your environment.\n", my_name, ENV_HOME); - exit(1); - /* NOTREACHED */ - } - - s = concat3(home, "/", MACEDIR); - - if ((t = read_file(s)) == NULLSTR) - { - could_not("read", s); - /* NOTREACHED */ - } - - if (*t != '/') - { - dir = concat3(home, "/", t); - (void)free(t); - } - else - dir = t; - - (void)free(s); - - return dir; -} //GO.SYSIN DD macedir.c echo memory.c sed 's/.//' >memory.c <<'//GO.SYSIN DD memory.c' -/* - * Memory allocation. - */ - -#ifndef lint -static char sccsid[] = "@(#)memory.c 1.30"; -#endif - -#include -#include "mace.h" - -char * -salloc(n) -int n; -{ - register char *s; - extern char *malloc(); - - if ((s = malloc((unsigned)n)) == NULLSTR) - { - fprintf(stderr, "%s: Ran out of memory.\n", my_name); - exit(1); - /* NOTREACHED */ - } - - return s; -} - -char * -srealloc(p, n) -char *p; -int n; -{ - register char *s; - extern char *realloc(); - - if ((s = realloc(p, (unsigned)n)) == NULLSTR) - { - fprintf(stderr, "%s: Ran out of memory.\n", my_name); - exit(1); - /* NOTREACHED */ - } - - return s; -} - -void -bcopy(from, to, len) -register char *from; -register char *to; -register int len; -{ - while (len-- > 0) - *to++ = *from++; -} //GO.SYSIN DD memory.c echo mesg.c sed 's/.//' >mesg.c <<'//GO.SYSIN DD mesg.c' -/* - * Messages. - */ - -#ifndef lint -static char sccsid[] = "@(#)mesg.c 1.30"; -#endif - -#include -#include "mace.h" - -void -could_not(what, with) -char *what; -char *with; -{ - fprintf(stderr, "%s: Could not %s \"%s\". %s\n", my_name, what, with, sysmess()); - exit(1); - /* NOTREACHED */ -} - -void -would_not(what, with) -char *what; -char *with; -{ - fprintf(stderr, "%s: Could not %s \"%s\". %s\n", my_name, what, with, sysmess()); -} - -void -fatal(what) -char *what; -{ - fprintf(stderr, "%s: Internal error: \"%s\".\n", my_name, what); - exit(1); - /* NOTREACHED */ -} //GO.SYSIN DD mesg.c echo mess.c sed 's/.//' >mess.c <<'//GO.SYSIN DD mess.c' -/* - * Message naming & reading. - */ - -#ifndef lint -static char sccsid[] = "@(#)mess.c 1.40"; -#endif - -#include "mace.h" -#include "line.h" -#include "message.h" -#include "headers.h" - -#include -#include -#include -#include - -char * -curr_in_box(box) -register char *box; -{ - register char *messid; - register char *m; - - if ((m = check_box(box)) == NULLSTR) - return NULLSTR; - - messid = concat3(m, "/", MESSID); - (void)free(m); - - if ((m = read_file(messid)) == NULLSTR) - { - (void)free(messid); - return NULLSTR; - } - - (void)free(messid); - - if (!valid_id(m)) - { - (void)free(m); - m = NULLSTR; - } - - return m; -} - -void -free_mess(mp) -register message *mp; -{ - (void)free(mp->ms_path); - (void)free(mp->ms_messid); - vec_free(&mp->ms_headers); - (void)free((char *)mp); -} - -/* - * Allocate a new message. Returns NULLMESS on failure. - */ -static message * -new(char *f, char *id, int fd) -{ - message *mp; - struct stat statb; - extern int errno; - - mp = (message *)salloc(sizeof(*mp)); - mp->ms_path = newstr(f); - mp->ms_messid = newstr(id); - vec_init(&mp->ms_headers, 128); - - if (fstat(fd, &statb) == SYSERROR) - goto broken; - - switch (statb.st_mode & S_IFMT) - { - case S_IFDIR: - errno = EISDIR; - goto broken; - - case S_IFREG: - mp->ms_size = statb.st_size; - mp->ms_copies = statb.st_nlink; - mp->ms_state = statb.st_mode; - break; - - default: - /* - * Fake it for a pipe/socket/device. - */ - mp->ms_size = statb.st_size; - mp->ms_copies = 1; - mp->ms_state = 0; - break; - } - - return mp; - -broken: - free_mess(mp); - return NULLMESS; -} - -/* - * Parse a message using lread(), optionally closing the lineio. - * Returns 0 on success, 1 on failure. - */ -static int -parse(message *mp, lineio *l, int clunk) -{ - char *p; - int line; - - line = 0; - - while ((p = lread(l)) != NULLSTR) - { - line++; - - switch (*p) - { - case '\0': - (void)free(p); - break; - - case RFC_LWSP_1: - case RFC_LWSP_2: - if (line > 1) - { - vec_cat(&mp->ms_headers, concat("\n", p)); - (void)free(p); - continue; - } - /* fall through */ - - default: - if (!rfc_header(p)) - { - fprintf(stderr, "%s: \"%s\" line %d: warning: \"%s\" is not an RFC 822 header.\n", my_name, mp->ms_path, line, p); - (void)free(p); - break; - } - - vec_str(&mp->ms_headers, p); - continue; - } - - break; - } - - vec_str(&mp->ms_headers, NULLSTR); - - /* - * Fake size, based on what was read. - */ - if (mp->ms_size == 0) - { - char **h; - char *s; - - for (h = mp->ms_headers.v_list; (s = *h) != NULLSTR; h++) - mp->ms_size += strlen(s); - - if (p != NULLSTR) - mp->ms_size++; - } - - /* - * Finished with lineio? - */ - if (clunk == 0) - return 0; - - if (lclose(l) == 0) - { - if (close(l->l_fd) != SYSERROR) - return 0; - } - else - (void)close(l->l_fd); - - return 1; - -} - -/* - * Parse an RFC 822 message from a file descriptor, optionally returning - * a lineio positioned to read the message body. - */ -message * -parse_fd(int fd, lineio *l) -{ - message *mp; - lineio mld; - lineio *ml; - - ml = l ? l : &mld; - - if ((mp = new("", "", fd)) == NULLMESS) - return mp; - - (void)lopen(ml, fd, LREAD); - - if (parse(mp, ml, l == 0)) - { - free_mess(mp); - mp = NULLMESS; - } - - return mp; -} - -/* - * Parse an RFC 822 message from a file, optionally returning - * a lineio positioned to read the message body. - */ -message * -parse_file(char *s, lineio *l) -{ - message *mp; - int fd; - lineio mld; - lineio *ml; - - if ((fd = open(s, O_RD)) == SYSERROR) - return NULLMESS; - - ml = l ? l : &mld; - - if ((mp = new(s, "", fd)) == NULLMESS) - return mp; - - (void)lopen(ml, fd, LREAD); - - if (parse(mp, ml, l == 0)) - { - free_mess(mp); - mp = NULLMESS; - } - - return mp; -} - - -/* - * Parse an RFC 822 message from a box. - */ -message * -read_mess(mbox *mb, char *id) -{ - message *mp; - int fd; - lineio mld; - lineio *ml; - char *p; - - ml = &mld; - - p = concat3(mb->m_path, "/", id); - - if ((fd = open(p, O_RD)) == SYSERROR) - return NULLMESS; - - (void)lopen(ml, fd, LREAD); - - if ((mp = new(p, id, fd)) == NULLMESS) - return mp; - - if (parse(mp, ml, 1)) - { - free_mess(mp); - mp = NULLMESS; - } - - return mp; -} - -int -set_current(b, m) -register char *b; -register char *m; -{ - register char *f; - - if (!valid_id(m)) - { - fprintf(stderr, "%s: \"%s\" is not a valid message id.\n", my_name, m); - return 1; - } - - if ((b = check_box(b)) == NULLSTR) - { - fprintf(stderr, "%s: No such box as \"%s\".\n", my_name, b); - return 1; - } - - f = concat3(b, "/", MESSID); - - (void)free(b); - - if (write_file(f, m)) - { - would_not("write", f); - (void)free(f); - return 1; - } - - (void)free(f); - return 0; -} - -/* - * Print an `n' character field turning new-lines into `~' and - * mashing tabs into spaces (a necessary evil). - */ -static void -lprintn(p, n) -register char *p; -register int n; -{ - while (n-- > 0) - { - register char c; - - switch ((c = *p)) - { - case '\0': - putchar(' '); - continue; - - case '\n': - putchar('~'); - break; - - case '\t': - putchar(' '); - break; - - default: - putchar(c); - break; - } - - p++; - } -} - -/* - * Print a one line message summary. - */ -void -print_summary(box, id, h, current, copies, to, state) -char *box; -char *id; -register char **h; -int current; -int copies; -int to; -int state; -{ - register char *p; - register char **n; - char cc; - - if (current) - cc = (state & MESG_MARK) != 0 ? '=' : '-'; - else if ((state & MESG_MARK) != 0) - cc = '\''; - else - cc = ' '; - - printf - ( - "%c %c%s %s %c%c%c ", - (state & (MESG_SENT|MESG_COMP)) == MESG_COMP ? '+' : '-', - BOX_CHAR, - box, - id, - cc, - copies > 1 ? '?' : ' ', - (state & MESG_SENT) != 0 ? '|' : ' ' - ); - - if ((n = find_header(h, to ? RFC_TO : RFC_FROM)) == (char **)0 || (p = header_text(*n)) == NULLSTR) - p = ""; - - lprintn(p, 16); - putchar(' '); - - if ((n = find_header(h, RFC_DATE)) == (char **)0 || (p = header_text(*n)) == NULLSTR) - p = ""; - - lprintn(p, 16); - putchar(' '); - - if ((n = find_header(h, RFC_SUBJECT)) != (char **)0 && (p = header_text(*n)) != NULLSTR) - { - putchar('"'); - lprintn(p, strlen(p)); - putchar('"'); - } - - printf("\n"); -} - -int -set_state(m, s) -register char *m; -register int s; -{ - struct stat statb; - - if (stat(m, &statb) == SYSERROR) - { - would_not("stat", m); - return 1; - } - - if (chmod(m, statb.st_mode | s) == SYSERROR) - { - would_not("chmod", m); - return 1; - } - - return 0; -} - -int -clear_state(m, s) -register char *m; -register int s; -{ - struct stat statb; - - if (stat(m, &statb) == SYSERROR) - { - would_not("stat", m); - return 1; - } - - if (chmod(m, statb.st_mode & ~s) == SYSERROR) - { - would_not("chmod", m); - return 1; - } - - return 0; -} - -/* - * Convert a mailbox/message pair into a pathname. - */ -char * -mess_to_path(mb, m) -register mbox *mb; -register char *m; -{ - return concat3(mb->m_path, "/", m); -} - -/* - * Convert a pathname into a mailbox/message name pair. - */ -void -path_to_mess(p, b, m) -register char *p; -register char **b; -register char **m; -{ - static int l = 0; - - if (l == 0) - l = strlen(mace_dir()); - - *b = newstr(&p[l + 1]); - - for (p = *b; *p != '/'; p++) - ; - - *p++ = '\0'; - *m = p; -} //GO.SYSIN DD mess.c echo misc.c sed 's/.//' >misc.c <<'//GO.SYSIN DD misc.c' -/* - * Miscellaneous stuff. - */ - -#ifndef lint -static char sccsid[] = "@(#)misc.c 1.28"; -#endif - -#include "mace.h" -#include - -/* - * Returns the login name of the current user. - * - * This is nasty and can allow forgery, but who cares? - * - * Returns static data. - */ -char * -user_id() -{ - register char *p; - extern char *getenv(); - - if ((p = getenv(ENV_USER)) == NULLSTR) - { - fprintf(stderr, "%s: Who are you? \"$%s\" not set.\n", my_name, ENV_USER); - exit(1); - /* NOTREACHED */ - } - - return p; -} - -/* - * Returns the name of the current user. - * - * This is nasty and can allow forgery, but who cares? - * - * Returns static data. - */ -char * -user_name() -{ - extern char *getenv(); - - return getenv(ENV_NAME); -} - -/* - * Return an environment variable or its default. - */ -char * -defenv(s, d) -register char *s; -register char *d; -{ - register char *e; - extern char *getenv(); - - return (e = getenv(s)) != NULLSTR ? e : d; -} //GO.SYSIN DD misc.c echo name.c sed 's/.//' >name.c <<'//GO.SYSIN DD name.c' -/* - * Initialise my_name. - */ - -#ifndef lint -static char sccsid[] = "@(#)name.c 1.30"; -#endif - -#include -#include "mace.h" - -char *my_name; - -void -name(s) -register char *s; -{ - my_name = basename(s); -} //GO.SYSIN DD name.c echo pipe.c sed 's/.//' >pipe.c <<'//GO.SYSIN DD pipe.c' -/* - * Pipe to/from a process. - */ - -#ifndef lint -static char sccsid[] = "@(#)pipe.c 1.31"; -#endif - -#include "mace.h" -#include - -typedef struct -{ - int p_pid; - int p_stat; - int p_xstat; -} - pstat; - -#define SRUN 1 -#define SZOMB 2 - -static pstat pipes[NPIPES]; - -/* - * Set up a pipe. - */ -static int -pipe_action(s, v, rw) -register char *s; -register char *v[]; -register char rw; -{ - register pstat *p; - register int read; - register char *x; - int fds[2]; - - if (s != NULLSTR && v != (char **)0) - { - fatal("pipe_action"); - /* NOTREACHED */ - } - - if (pipe(fds) == SYSERROR) - return SYSERROR; - - if (fds[0] >= NPIPES || fds[1] >= NPIPES) - { - fatal("pipe_open"); - /* NOTREACHED */ - } - - read = rw == 'r'; - p = &pipes[fds[!read]]; - p->p_stat = SRUN; - - switch (p->p_pid = fork()) - { - case SYSERROR: - return SYSERROR; - - case 0: - if - ( - close(read) == SYSERROR - || - dup(fds[read]) != read - || - close(fds[0]) == SYSERROR - || - close(fds[1]) == SYSERROR - ) - { - could_not("pipe", s); - /* NOTREACHED */ - } - - if (s != NULLSTR) - { - x = defenv(ENV_SHELL, DEF_SHELL); - - execl(x, basename(x), "-c", s, NULLSTR); - could_not("exec", s); - } - else - { - execv(v[0], v); - could_not("exec", v[0]); - } - - /* NOTREACHED */ - - default: - if (close(fds[read]) == SYSERROR) - { - (void)close(fds[!read]); - p->p_stat = 0; - return SYSERROR; - } - - (void)signal(SIGPIPE, SIG_IGN); - - return fds[!read]; - } -} - -/* - * Pipe to a shell command. - */ -int -pipe_open(s, rw) -register char *s; -register char rw; -{ - return pipe_action(s, (char **)0, rw); -} - -/* - * Pipe to an argument vector. - */ -int -pipe_execv(v, rw) -register char *v[]; -register char rw; -{ - return pipe_action(NULLSTR, v, rw); -} - -int -pipe_close(fd) -register int fd; -{ - register pstat *p; - register int i; - int xstat; - - if (fd < 0 || fd >= NPIPES) - return SYSERROR; - - p = &pipes[fd]; - (void)close(fd); - - switch (p->p_stat) - { - case SRUN: - wait_some_more: - while ((i = wait(&xstat)) != p->p_pid) - { - register pstat *pp; - - if (i == SYSERROR) - { - fatal("pipe_wait"); - /* NOTREACHED */ - } - - for (pp = pipes; pp < &pipes[NPIPES]; pp++) - { - if (pp->p_stat == SRUN && pp->p_pid == i) - { - pp->p_stat = SZOMB; - pp->p_xstat = xstat; - goto wait_some_more; - } - } - - fatal("pipe_zombie"); - /* NOTREACHED */ - } - - p->p_stat = SZOMB; - p->p_xstat = xstat; - /* fall thru... */ - - case SZOMB: - p->p_stat = 0; - return p->p_xstat; - - default: - return SYSERROR; - } -} //GO.SYSIN DD pipe.c echo re.c sed 's/.//' >re.c <<'//GO.SYSIN DD re.c' -/* - * Regular expression hooks. - */ - -#ifndef lint -static char sccsid[] = "@(#)re.c 1.6"; -#endif - -#include "mace.h" - -char *re_error; /* regexp error string */ - -/* - * Save a regexp error message. - */ -void -regerror(msg) -char *msg; -{ - re_error = msg; -} //GO.SYSIN DD re.c echo readdir.c sed 's/.//' >readdir.c <<'//GO.SYSIN DD readdir.c' -/* - * Read a directory & return its files as a vector of strings. - */ - -#ifndef lint -static char sccsid[] = "@(#)readdir.c 1.33"; -#endif - -#include -#include -#include -#include -#include "mace.h" -#if DIRECTORY_3 -#if V9_DIRECTORY_3 -#include -#else -#if DEC_DIRECTORY_3 -#include -#else -#include -#endif -#endif -#else -#include -#endif - -#if DIRECTORY_3 - -/* - * Read the directory using directory(3). - */ -static char ** -directory_3(f) -register char *f; -{ - register DIR *dirp; -#if DEC_DIRECTORY_3 - register struct dirent *dp; -#else - register struct direct *dp; -#endif - register int i; - register char **v; - vec slots; - - if ((dirp = opendir(f)) == (DIR *)0) - { - could_not("open", f); - /* NOTREACHED */ - } - - vec_init(&slots, 64); - -#if DEC_DIRECTORY_3 - while ((dp = readdir(dirp)) != (struct dirent *)0) -#else - while ((dp = readdir(dirp)) != (struct direct *)0) -#endif - { - if (dp->d_name[0] == SPEC_CHAR || dp->d_name[0] == '.') - continue; - - vec_str(&slots, newstr(&dp->d_name[0])); - } - - closedir(dirp); - - v = (char **)salloc((slots.v_count + 1) * sizeof(char *)); - - for (i = 0; i < slots.v_count; i++) - v[i] = newstr(slots.v_list[i]); - - v[i++] = NULLSTR; - - vec_free(&slots); - - return v; -} - -#endif - -char ** -read_dir(f) -char *f; -{ -#if !DIRECTORY_3 - register int fd; - register int slot; - register struct direct *dp; - char *s; -#endif - register char **v; - struct stat statb; - -#if DIRECTORY_3 - - if (stat(f, &statb) == SYSERROR) - { - could_not("stat", f); - /* NOTREACHED */ - } - -#else - - if ((fd = open(f, O_RDONLY)) == SYSERROR) - { - could_not("open", f); - /* NOTREACHED */ - } - - if (fstat(fd, &statb) == SYSERROR) - { - could_not("stat", f); - /* NOTREACHED */ - } - -#endif - - if ((statb.st_mode & S_IFMT) != S_IFDIR) - { - fprintf(stderr, "%s: \"%s\" is not a directory.\n", my_name, f); - exit(1); - /* NOTREACHED */ - } - -#if DIRECTORY_3 - - v = directory_3(f); - -#else - - s = salloc((int)statb.st_size); - -#if BSD_DIR - v = (char **)salloc((int)((statb.st_size / (sizeof(struct direct) - (MAXNAMLEN + 1))) + 1) * sizeof(char *)); -#else - v = (char **)salloc((int)((statb.st_size / sizeof(struct direct)) + 1) * sizeof(char *)); -#endif - - if (read(fd, s, (int)statb.st_size) != (int)statb.st_size) - { - could_not("read", f); - /* NOTREACHED */ - } - - for - ( - slot = 0, dp = (struct direct *)s; - dp < (struct direct *)&s[statb.st_size]; -#if BSD_DIR - dp = (struct direct *)((char *)dp + dp->d_reclen) -#else - dp++ -#endif - ) - { - if (dp->d_ino == 0 || dp->d_name[0] == SPEC_CHAR || dp->d_name[0] == '.') - continue; - -#if BSD_DIR - v[slot++] = newstr(&dp->d_name[0]); -#else - v[slot] = salloc(DIRSIZ + 1); - bcopy(&dp->d_name[0], v[slot], DIRSIZ); - v[slot++][DIRSIZ] = '\0'; -#endif - } - - v[slot] = NULLSTR; - - if (close(fd) == SYSERROR) - { - could_not("close", f); - /* NOTREACHED */ - } - - (void)free(s); - -#endif - - return v; -} - -void -free_dir(v) -register char **v; -{ - register char **n; - - for (n = v; *n != NULLSTR; n++) - (void)free(*n); - - (void)free((char *)v); -} //GO.SYSIN DD readdir.c echo readfile.c sed 's/.//' >readfile.c <<'//GO.SYSIN DD readfile.c' -/* - * Read a named file & return it's contents. - */ - -#ifndef lint -static char sccsid[] = "@(#)readfile.c 1.31"; -#endif - -#include -#include -#include -#include -#include "mace.h" - -char * -read_file(f) -char *f; -{ - register int fd; - char *s; - struct stat statb; - - if ((fd = open(f, O_RDONLY)) == SYSERROR) - return NULLSTR; - - if (fstat(fd, &statb) == SYSERROR) - { - could_not("stat", f); - /* NOTREACHED */ - } - - if ((statb.st_mode & S_IFMT) != S_IFREG) - { - fprintf(stderr, "%s: \"%s\" is not a regular file.\n", my_name, f); - exit(1); - /* NOTREACHED */ - } - - s = salloc((int)statb.st_size + 1); - - if (statb.st_size != 0) - { - if (read(fd, s, (int)statb.st_size) != (int)statb.st_size) - { - could_not("read", f); - /* NOTREACHED */ - } - - if (s[statb.st_size - 1] == '\n') - s[statb.st_size - 1] = '\0'; - else - s[statb.st_size] = '\0'; - } - else - s[0] = '\0'; - - if (close(fd) == SYSERROR) - { - could_not("close", f); - /* NOTREACHED */ - } - - return s; -} //GO.SYSIN DD readfile.c echo readpass.c sed 's/.//' >readpass.c <<'//GO.SYSIN DD readpass.c' -/* - * @(#)readpass.c 1.1 - * - * Read a password from /dev/tty. Looks like getpass(3) but - * accepts an arbitarily long password. - */ - -#include "mace.h" -#include "flex.h" -#include "tty.h" -#include - -#define DEV_TTY "/dev/tty" - -/* - * Catch a signal and do nothing. - */ -static SIG_RET -catch(int s) -{ -} - -/* - * Prompt for an arbitary length password and read it. - */ -char * -readpass(char *prompt) -{ - int fd; - int l; - static flex f = { NULLSTR, NULLSTR, NULLSTR, }; - int echo; - char c; - SIG_RET (*int_sig)(); - SIG_RET (*quit_sig)(); - - echo = 0; - - if (f.f_str == NULLSTR) - flex_init(&f); - - if ((fd = open(DEV_TTY, O_RW)) == SYSERROR) - return NULLSTR; - - /* - * Catch signals so read will return with errno == EINTR. - */ - if ((int_sig = signal(SIGINT, catch)) != SIG_DFL) - signal(SIGINT, int_sig); - - if ((quit_sig = signal(SIGQUIT, catch)) != SIG_DFL) - quit_sig = signal(SIGQUIT, catch); - - /* - * Turn off echo. - */ - if - ( - (echo = ttyechoing(fd)) == SYSERROR - || - (echo && ttyecho(fd, 0) == SYSERROR) - ) - goto end; - - /* - * Write prompt. - */ - l = strlen(prompt); - - while (l > 0) - { - int n; - - if ((n = write(fd, prompt, l)) == SYSERROR) - goto end; - - prompt += n; - l -= n; - } - - /* - * Read password. - */ - for (;;) - { - int n; - - /* - * Do read(..., ..., 1) to avoid canon state. - */ - switch (n = read(fd, &c, 1)) - { - case 0: - flex_char(&f, '\0'); - break; - - case 1: - if (c == '\n') - { - flex_char(&f, '\0'); - - if (echo) - write(fd, &c, 1); - - break; - } - - flex_char(&f, c); - continue; - - case SYSERROR: - default: - f.f_ptr = f.f_str; - break; - } - - break; - } - -end: - /* - * Restore echo to previous state. - */ - if (echo) - ttyecho(fd, 1); - - close(fd); - - /* - * Restore signals. - */ - if (int_sig != SIG_DFL) - signal(SIGINT, int_sig); - - if (quit_sig != SIG_DFL) - signal(SIGQUIT, quit_sig); - - /* - * Errored? - */ - if (f.f_ptr == f.f_str) - return NULLSTR; - - flex_end(&f); - return f.f_str; -} //GO.SYSIN DD readpass.c echo regexp.c sed 's/.//' >regexp.c <<'//GO.SYSIN DD regexp.c' -/* - * regcomp and regexec -- regsub and regerror are elsewhere - * - * Copyright (c) 1986 by University of Toronto. - * Written by Henry Spencer. Not derived from licensed software. - * - * Permission is granted to anyone to use this software for any - * purpose on any computer system, and to redistribute it freely, - * subject to the following restrictions: - * - * 1. The author is not responsible for the consequences of use of - * this software, no matter how awful, even if they arise - * from defects in it. - * - * 2. The origin of this software must not be misrepresented, either - * by explicit claim or by omission. - * - * 3. Altered versions must be plainly marked as such, and must not - * be misrepresented as being the original software. - * - * Beware that some of this code is subtly aware of the way operator - * precedence is structured in regular expressions. Serious changes in - * regular-expression syntax might require a total rethink. - * - * Snarfed to be part of "mace" but not modified save - * for the odd include & sccsid. - * -- Boyd Roberts - * May '89 - */ -#ifndef lint -static char sccsid[] = "@(#)regexp.c 1.6"; -#endif - -#include "mace.h" -#include -#include "regexp.h" -#include "regmagic.h" - -/* - * The "internal use only" fields in regexp.h are present to pass info from - * compile to execute that permits the execute phase to run lots faster on - * simple cases. They are: - * - * regstart char that must begin a match; '\0' if none obvious - * reganch is the match anchored (at beginning-of-line only)? - * regmust string (pointer into program) that match must include, or NULL - * regmlen length of regmust string - * - * Regstart and reganch permit very fast decisions on suitable starting points - * for a match, cutting down the work a lot. Regmust permits fast rejection - * of lines that cannot possibly match. The regmust tests are costly enough - * that regcomp() supplies a regmust only if the r.e. contains something - * potentially expensive (at present, the only such thing detected is * or + - * at the start of the r.e., which can involve a lot of backup). Regmlen is - * supplied because the test in regexec() needs it and regcomp() is computing - * it anyway. - */ - -/* - * Structure for regexp "program". This is essentially a linear encoding - * of a nondeterministic finite-state machine (aka syntax charts or - * "railroad normal form" in parsing technology). Each node is an opcode - * plus a "next" pointer, possibly plus an operand. "Next" pointers of - * all nodes except BRANCH implement concatenation; a "next" pointer with - * a BRANCH on both ends of it is connecting two alternatives. (Here we - * have one of the subtle syntax dependencies: an individual BRANCH (as - * opposed to a collection of them) is never concatenated with anything - * because of operator precedence.) The operand of some types of node is - * a literal string; for others, it is a node leading into a sub-FSM. In - * particular, the operand of a BRANCH node is the first node of the branch. - * (NB this is *not* a tree structure: the tail of the branch connects - * to the thing following the set of BRANCHes.) The opcodes are: - */ - -/* definition number opnd? meaning */ -#define END 0 /* no End of program. */ -#define BOL 1 /* no Match "" at beginning of line. */ -#define EOL 2 /* no Match "" at end of line. */ -#define ANY 3 /* no Match any one character. */ -#define ANYOF 4 /* str Match any character in this string. */ -#define ANYBUT 5 /* str Match any character not in this string. */ -#define BRANCH 6 /* node Match this alternative, or the next... */ -#define BACK 7 /* no Match "", "next" ptr points backward. */ -#define EXACTLY 8 /* str Match this string. */ -#define NOTHING 9 /* no Match empty string. */ -#define STAR 10 /* node Match this (simple) thing 0 or more times. */ -#define PLUS 11 /* node Match this (simple) thing 1 or more times. */ -#define OPEN 20 /* no Mark this point in input as start of #n. */ - /* OPEN+1 is number 1, etc. */ -#define CLOSE 30 /* no Analogous to OPEN. */ - -/* - * Opcode notes: - * - * BRANCH The set of branches constituting a single choice are hooked - * together with their "next" pointers, since precedence prevents - * anything being concatenated to any individual branch. The - * "next" pointer of the last BRANCH in a choice points to the - * thing following the whole choice. This is also where the - * final "next" pointer of each individual branch points; each - * branch starts with the operand node of a BRANCH node. - * - * BACK Normal "next" pointers all implicitly point forward; BACK - * exists to make loop structures possible. - * - * STAR,PLUS '?', and complex '*' and '+', are implemented as circular - * BRANCH structures using BACK. Simple cases (one character - * per match) are implemented with STAR and PLUS for speed - * and to minimize recursive plunges. - * - * OPEN,CLOSE ...are numbered at compile time. - */ - -/* - * A node is one char of opcode followed by two chars of "next" pointer. - * "Next" pointers are stored as two 8-bit pieces, high order first. The - * value is a positive offset from the opcode of the node containing it. - * An operand, if any, simply follows the node. (Note that much of the - * code generation knows about this implicit relationship.) - * - * Using two bytes for the "next" pointer is vast overkill for most things, - * but allows patterns to get big without disasters. - */ -#define OP(p) (*(p)) -#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377)) -#define OPERAND(p) ((p) + 3) - -/* - * See regmagic.h for one further detail of program structure. - */ - - -/* - * Utility definitions. - */ -#ifndef CHARBITS -#define UCHARAT(p) ((int)*(unsigned char *)(p)) -#else -#define UCHARAT(p) ((int)*(p)&CHARBITS) -#endif - -#define FAIL(m) { regerror(m); return(NULL); } -#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?') -#define META "^$.[()|?+*\\" - -/* - * Flags to be passed up and down. - */ -#define HASWIDTH 01 /* Known never to match null string. */ -#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */ -#define SPSTART 04 /* Starts with * or +. */ -#define WORST 0 /* Worst case. */ - -/* - * Global work variables for regcomp(). - */ -static char *regparse; /* Input-scan pointer. */ -static int regnpar; /* () count. */ -static char regdummy; -static char *regcode; /* Code-emit pointer; ®dummy = don't. */ -static long regsize; /* Code size. */ - -/* - * Forward declarations for regcomp()'s friends. - */ -#ifndef STATIC -#define STATIC static -#endif -STATIC char *reg(); -STATIC char *regbranch(); -STATIC char *regpiece(); -STATIC char *regatom(); -STATIC char *regnode(); -STATIC char *regnext(); -STATIC void regc(); -STATIC void reginsert(); -STATIC void regtail(); -STATIC void regoptail(); -#ifdef STRCSPN -STATIC int strcspn(); -#endif - -/* - - regcomp - compile a regular expression into internal code - * - * We can't allocate space until we know how big the compiled form will be, - * but we can't compile it (and thus know how big it is) until we've got a - * place to put the code. So we cheat: we compile it twice, once with code - * generation turned off and size counting turned on, and once "for real". - * This also means that we don't allocate space until we are sure that the - * thing really will compile successfully, and we never have to move the - * code and thus invalidate pointers into it. (Note that it has to be in - * one piece because free() must be able to free it all.) - * - * Beware that the optimization-preparation code in here knows about some - * of the structure of the compiled regexp. - */ -regexp * -regcomp(exp) -char *exp; -{ - register regexp *r; - register char *scan; - register char *longest; - register int len; - int flags; - extern char *malloc(); - - if (exp == NULL) - FAIL("NULL argument"); - - /* First pass: determine size, legality. */ - regparse = exp; - regnpar = 1; - regsize = 0L; - regcode = ®dummy; - regc(MAGIC); - if (reg(0, &flags) == NULL) - return(NULL); - - /* Small enough for pointer-storage convention? */ - if (regsize >= 32767L) /* Probably could be 65535L. */ - FAIL("regexp too big"); - - /* Allocate space. */ - r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize); - if (r == NULL) - FAIL("out of space"); - - /* Second pass: emit code. */ - regparse = exp; - regnpar = 1; - regcode = r->program; - regc(MAGIC); - if (reg(0, &flags) == NULL) - return(NULL); - - /* Dig out information for optimizations. */ - r->regstart = '\0'; /* Worst-case defaults. */ - r->reganch = 0; - r->regmust = NULL; - r->regmlen = 0; - scan = r->program+1; /* First BRANCH. */ - if (OP(regnext(scan)) == END) { /* Only one top-level choice. */ - scan = OPERAND(scan); - - /* Starting-point info. */ - if (OP(scan) == EXACTLY) - r->regstart = *OPERAND(scan); - else if (OP(scan) == BOL) - r->reganch++; - - /* - * If there's something expensive in the r.e., find the - * longest literal string that must appear and make it the - * regmust. Resolve ties in favor of later strings, since - * the regstart check works with the beginning of the r.e. - * and avoiding duplication strengthens checking. Not a - * strong reason, but sufficient in the absence of others. - */ - if (flags&SPSTART) { - longest = NULL; - len = 0; - for (; scan != NULL; scan = regnext(scan)) - if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) { - longest = OPERAND(scan); - len = strlen(OPERAND(scan)); - } - r->regmust = longest; - r->regmlen = len; - } - } - - return(r); -} - -/* - - reg - regular expression, i.e. main body or parenthesized thing - * - * Caller must absorb opening parenthesis. - * - * Combining parenthesis handling with the base level of regular expression - * is a trifle forced, but the need to tie the tails of the branches to what - * follows makes it hard to avoid. - */ -static char * -reg(paren, flagp) -int paren; /* Parenthesized? */ -int *flagp; -{ - register char *ret; - register char *br; - register char *ender; - register int parno; - int flags; - - *flagp = HASWIDTH; /* Tentatively. */ - - /* Make an OPEN node, if parenthesized. */ - if (paren) { - if (regnpar >= NSUBEXP) - FAIL("too many ()"); - parno = regnpar; - regnpar++; - ret = regnode(OPEN+parno); - } else - ret = NULL; - - /* Pick up the branches, linking them together. */ - br = regbranch(&flags); - if (br == NULL) - return(NULL); - if (ret != NULL) - regtail(ret, br); /* OPEN -> first. */ - else - ret = br; - if (!(flags&HASWIDTH)) - *flagp &= ~HASWIDTH; - *flagp |= flags&SPSTART; - while (*regparse == '|') { - regparse++; - br = regbranch(&flags); - if (br == NULL) - return(NULL); - regtail(ret, br); /* BRANCH -> BRANCH. */ - if (!(flags&HASWIDTH)) - *flagp &= ~HASWIDTH; - *flagp |= flags&SPSTART; - } - - /* Make a closing node, and hook it on the end. */ - ender = regnode((paren) ? CLOSE+parno : END); - regtail(ret, ender); - - /* Hook the tails of the branches to the closing node. */ - for (br = ret; br != NULL; br = regnext(br)) - regoptail(br, ender); - - /* Check for proper termination. */ - if (paren && *regparse++ != ')') { - FAIL("unmatched ()"); - } else if (!paren && *regparse != '\0') { - if (*regparse == ')') { - FAIL("unmatched ()"); - } else - FAIL("junk on end"); /* "Can't happen". */ - /* NOTREACHED */ - } - - return(ret); -} - -/* - - regbranch - one alternative of an | operator - * - * Implements the concatenation operator. - */ -static char * -regbranch(flagp) -int *flagp; -{ - register char *ret; - register char *chain; - register char *latest; - int flags; - - *flagp = WORST; /* Tentatively. */ - - ret = regnode(BRANCH); - chain = NULL; - while (*regparse != '\0' && *regparse != '|' && *regparse != ')') { - latest = regpiece(&flags); - if (latest == NULL) - return(NULL); - *flagp |= flags&HASWIDTH; - if (chain == NULL) /* First piece. */ - *flagp |= flags&SPSTART; - else - regtail(chain, latest); - chain = latest; - } - if (chain == NULL) /* Loop ran zero times. */ - (void) regnode(NOTHING); - - return(ret); -} - -/* - - regpiece - something followed by possible [*+?] - * - * Note that the branching code sequences used for ? and the general cases - * of * and + are somewhat optimized: they use the same NOTHING node as - * both the endmarker for their branch list and the body of the last branch. - * It might seem that this node could be dispensed with entirely, but the - * endmarker role is not redundant. - */ -static char * -regpiece(flagp) -int *flagp; -{ - register char *ret; - register char op; - register char *next; - int flags; - - ret = regatom(&flags); - if (ret == NULL) - return(NULL); - - op = *regparse; - if (!ISMULT(op)) { - *flagp = flags; - return(ret); - } - - if (!(flags&HASWIDTH) && op != '?') - FAIL("*+ operand could be empty"); - *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH); - - if (op == '*' && (flags&SIMPLE)) - reginsert(STAR, ret); - else if (op == '*') { - /* Emit x* as (x&|), where & means "self". */ - reginsert(BRANCH, ret); /* Either x */ - regoptail(ret, regnode(BACK)); /* and loop */ - regoptail(ret, ret); /* back */ - regtail(ret, regnode(BRANCH)); /* or */ - regtail(ret, regnode(NOTHING)); /* null. */ - } else if (op == '+' && (flags&SIMPLE)) - reginsert(PLUS, ret); - else if (op == '+') { - /* Emit x+ as x(&|), where & means "self". */ - next = regnode(BRANCH); /* Either */ - regtail(ret, next); - regtail(regnode(BACK), ret); /* loop back */ - regtail(next, regnode(BRANCH)); /* or */ - regtail(ret, regnode(NOTHING)); /* null. */ - } else if (op == '?') { - /* Emit x? as (x|) */ - reginsert(BRANCH, ret); /* Either x */ - regtail(ret, regnode(BRANCH)); /* or */ - next = regnode(NOTHING); /* null. */ - regtail(ret, next); - regoptail(ret, next); - } - regparse++; - if (ISMULT(*regparse)) - FAIL("nested *?+"); - - return(ret); -} - -/* - - regatom - the lowest level - * - * Optimization: gobbles an entire sequence of ordinary characters so that - * it can turn them into a single node, which is smaller to store and - * faster to run. Backslashed characters are exceptions, each becoming a - * separate node; the code is simpler that way and it's not worth fixing. - */ -static char * -regatom(flagp) -int *flagp; -{ - register char *ret; - int flags; - - *flagp = WORST; /* Tentatively. */ - - switch (*regparse++) { - case '^': - ret = regnode(BOL); - break; - case '$': - ret = regnode(EOL); - break; - case '.': - ret = regnode(ANY); - *flagp |= HASWIDTH|SIMPLE; - break; - case '[': { - register int class; - register int classend; - - if (*regparse == '^') { /* Complement of range. */ - ret = regnode(ANYBUT); - regparse++; - } else - ret = regnode(ANYOF); - if (*regparse == ']' || *regparse == '-') - regc(*regparse++); - while (*regparse != '\0' && *regparse != ']') { - if (*regparse == '-') { - regparse++; - if (*regparse == ']' || *regparse == '\0') - regc('-'); - else { - class = UCHARAT(regparse-2)+1; - classend = UCHARAT(regparse); - if (class > classend+1) - FAIL("invalid [] range"); - for (; class <= classend; class++) - regc(class); - regparse++; - } - } else - regc(*regparse++); - } - regc('\0'); - if (*regparse != ']') - FAIL("unmatched []"); - regparse++; - *flagp |= HASWIDTH|SIMPLE; - } - break; - case '(': - ret = reg(1, &flags); - if (ret == NULL) - return(NULL); - *flagp |= flags&(HASWIDTH|SPSTART); - break; - case '\0': - case '|': - case ')': - FAIL("internal urp"); /* Supposed to be caught earlier. */ - break; - case '?': - case '+': - case '*': - FAIL("?+* follows nothing"); - break; - case '\\': - if (*regparse == '\0') - FAIL("trailing \\"); - ret = regnode(EXACTLY); - regc(*regparse++); - regc('\0'); - *flagp |= HASWIDTH|SIMPLE; - break; - default: { - register int len; - register char ender; - - regparse--; - len = strcspn(regparse, META); - if (len <= 0) - FAIL("internal disaster"); - ender = *(regparse+len); - if (len > 1 && ISMULT(ender)) - len--; /* Back off clear of ?+* operand. */ - *flagp |= HASWIDTH; - if (len == 1) - *flagp |= SIMPLE; - ret = regnode(EXACTLY); - while (len > 0) { - regc(*regparse++); - len--; - } - regc('\0'); - } - break; - } - - return(ret); -} - -/* - - regnode - emit a node - */ -static char * /* Location. */ -regnode(op) -char op; -{ - register char *ret; - register char *ptr; - - ret = regcode; - if (ret == ®dummy) { - regsize += 3; - return(ret); - } - - ptr = ret; - *ptr++ = op; - *ptr++ = '\0'; /* Null "next" pointer. */ - *ptr++ = '\0'; - regcode = ptr; - - return(ret); -} - -/* - - regc - emit (if appropriate) a byte of code - */ -static void -regc(b) -char b; -{ - if (regcode != ®dummy) - *regcode++ = b; - else - regsize++; -} - -/* - - reginsert - insert an operator in front of already-emitted operand - * - * Means relocating the operand. - */ -static void -reginsert(op, opnd) -char op; -char *opnd; -{ - register char *src; - register char *dst; - register char *place; - - if (regcode == ®dummy) { - regsize += 3; - return; - } - - src = regcode; - regcode += 3; - dst = regcode; - while (src > opnd) - *--dst = *--src; - - place = opnd; /* Op node, where operand used to be. */ - *place++ = op; - *place++ = '\0'; - *place++ = '\0'; -} - -/* - - regtail - set the next-pointer at the end of a node chain - */ -static void -regtail(p, val) -char *p; -char *val; -{ - register char *scan; - register char *temp; - register int offset; - - if (p == ®dummy) - return; - - /* Find last node. */ - scan = p; - for (;;) { - temp = regnext(scan); - if (temp == NULL) - break; - scan = temp; - } - - if (OP(scan) == BACK) - offset = scan - val; - else - offset = val - scan; - *(scan+1) = (offset>>8)&0377; - *(scan+2) = offset&0377; -} - -/* - - regoptail - regtail on operand of first argument; nop if operandless - */ -static void -regoptail(p, val) -char *p; -char *val; -{ - /* "Operandless" and "op != BRANCH" are synonymous in practice. */ - if (p == NULL || p == ®dummy || OP(p) != BRANCH) - return; - regtail(OPERAND(p), val); -} - -/* - * regexec and friends - */ - -/* - * Global work variables for regexec(). - */ -static char *reginput; /* String-input pointer. */ -static char *regbol; /* Beginning of input, for ^ check. */ -static char **regstartp; /* Pointer to startp array. */ -static char **regendp; /* Ditto for endp. */ - -/* - * Forwards. - */ -STATIC int regtry(); -STATIC int regmatch(); -STATIC int regrepeat(); - -#ifdef DEBUG -int regnarrate = 0; -void regdump(); -STATIC char *regprop(); -#endif - -/* - - regexec - match a regexp against a string - */ -int -regexec(prog, string) -register regexp *prog; -register char *string; -{ - register char *s; - extern char *strchr(); - - /* Be paranoid... */ - if (prog == NULL || string == NULL) { - regerror("NULL parameter"); - return(0); - } - - /* Check validity of program. */ - if (UCHARAT(prog->program) != MAGIC) { - regerror("corrupted program"); - return(0); - } - - /* If there is a "must appear" string, look for it. */ - if (prog->regmust != NULL) { - s = string; - while ((s = strchr(s, prog->regmust[0])) != NULL) { - if (strncmp(s, prog->regmust, prog->regmlen) == 0) - break; /* Found it. */ - s++; - } - if (s == NULL) /* Not present. */ - return(0); - } - - /* Mark beginning of line for ^ . */ - regbol = string; - - /* Simplest case: anchored match need be tried only once. */ - if (prog->reganch) - return(regtry(prog, string)); - - /* Messy cases: unanchored match. */ - s = string; - if (prog->regstart != '\0') - /* We know what char it must start with. */ - while ((s = strchr(s, prog->regstart)) != NULL) { - if (regtry(prog, s)) - return(1); - s++; - } - else - /* We don't -- general case. */ - do { - if (regtry(prog, s)) - return(1); - } while (*s++ != '\0'); - - /* Failure. */ - return(0); -} - -/* - - regtry - try match at specific point - */ -static int /* 0 failure, 1 success */ -regtry(prog, string) -regexp *prog; -char *string; -{ - register int i; - register char **sp; - register char **ep; - - reginput = string; - regstartp = prog->startp; - regendp = prog->endp; - - sp = prog->startp; - ep = prog->endp; - for (i = NSUBEXP; i > 0; i--) { - *sp++ = NULL; - *ep++ = NULL; - } - if (regmatch(prog->program + 1)) { - prog->startp[0] = string; - prog->endp[0] = reginput; - return(1); - } else - return(0); -} - -/* - - regmatch - main matching routine - * - * Conceptually the strategy is simple: check to see whether the current - * node matches, call self recursively to see whether the rest matches, - * and then act accordingly. In practice we make some effort to avoid - * recursion, in particular by going through "ordinary" nodes (that don't - * need to know whether the rest of the match failed) by a loop instead of - * by recursion. - */ -static int /* 0 failure, 1 success */ -regmatch(prog) -char *prog; -{ - register char *scan; /* Current node. */ - char *next; /* Next node. */ - extern char *strchr(); - - scan = prog; -#ifdef DEBUG - if (scan != NULL && regnarrate) - fprintf(stderr, "%s(\n", regprop(scan)); -#endif - while (scan != NULL) { -#ifdef DEBUG - if (regnarrate) - fprintf(stderr, "%s...\n", regprop(scan)); -#endif - next = regnext(scan); - - switch (OP(scan)) { - case BOL: - if (reginput != regbol) - return(0); - break; - case EOL: - if (*reginput != '\0') - return(0); - break; - case ANY: - if (*reginput == '\0') - return(0); - reginput++; - break; - case EXACTLY: { - register int len; - register char *opnd; - - opnd = OPERAND(scan); - /* Inline the first character, for speed. */ - if (*opnd != *reginput) - return(0); - len = strlen(opnd); - if (len > 1 && strncmp(opnd, reginput, len) != 0) - return(0); - reginput += len; - } - break; - case ANYOF: - if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL) - return(0); - reginput++; - break; - case ANYBUT: - if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL) - return(0); - reginput++; - break; - case NOTHING: - break; - case BACK: - break; - case OPEN+1: - case OPEN+2: - case OPEN+3: - case OPEN+4: - case OPEN+5: - case OPEN+6: - case OPEN+7: - case OPEN+8: - case OPEN+9: { - register int no; - register char *save; - - no = OP(scan) - OPEN; - save = reginput; - - if (regmatch(next)) { - /* - * Don't set startp if some later - * invocation of the same parentheses - * already has. - */ - if (regstartp[no] == NULL) - regstartp[no] = save; - return(1); - } else - return(0); - } - break; - case CLOSE+1: - case CLOSE+2: - case CLOSE+3: - case CLOSE+4: - case CLOSE+5: - case CLOSE+6: - case CLOSE+7: - case CLOSE+8: - case CLOSE+9: { - register int no; - register char *save; - - no = OP(scan) - CLOSE; - save = reginput; - - if (regmatch(next)) { - /* - * Don't set endp if some later - * invocation of the same parentheses - * already has. - */ - if (regendp[no] == NULL) - regendp[no] = save; - return(1); - } else - return(0); - } - break; - case BRANCH: { - register char *save; - - if (OP(next) != BRANCH) /* No choice. */ - next = OPERAND(scan); /* Avoid recursion. */ - else { - do { - save = reginput; - if (regmatch(OPERAND(scan))) - return(1); - reginput = save; - scan = regnext(scan); - } while (scan != NULL && OP(scan) == BRANCH); - return(0); - /* NOTREACHED */ - } - } - break; - case STAR: - case PLUS: { - register char nextch; - register int no; - register char *save; - register int min; - - /* - * Lookahead to avoid useless match attempts - * when we know what character comes next. - */ - nextch = '\0'; - if (OP(next) == EXACTLY) - nextch = *OPERAND(next); - min = (OP(scan) == STAR) ? 0 : 1; - save = reginput; - no = regrepeat(OPERAND(scan)); - while (no >= min) { - /* If it could work, try it. */ - if (nextch == '\0' || *reginput == nextch) - if (regmatch(next)) - return(1); - /* Couldn't or didn't -- back up. */ - no--; - reginput = save + no; - } - return(0); - } - break; - case END: - return(1); /* Success! */ - break; - default: - regerror("memory corruption"); - return(0); - break; - } - - scan = next; - } - - /* - * We get here only if there's trouble -- normally "case END" is - * the terminating point. - */ - regerror("corrupted pointers"); - return(0); -} - -/* - - regrepeat - repeatedly match something simple, report how many - */ -static int -regrepeat(p) -char *p; -{ - register int count = 0; - register char *scan; - register char *opnd; - - scan = reginput; - opnd = OPERAND(p); - switch (OP(p)) { - case ANY: - count = strlen(scan); - scan += count; - break; - case EXACTLY: - while (*opnd == *scan) { - count++; - scan++; - } - break; - case ANYOF: - while (*scan != '\0' && strchr(opnd, *scan) != NULL) { - count++; - scan++; - } - break; - case ANYBUT: - while (*scan != '\0' && strchr(opnd, *scan) == NULL) { - count++; - scan++; - } - break; - default: /* Oh dear. Called inappropriately. */ - regerror("internal foulup"); - count = 0; /* Best compromise. */ - break; - } - reginput = scan; - - return(count); -} - -/* - - regnext - dig the "next" pointer out of a node - */ -static char * -regnext(p) -register char *p; -{ - register int offset; - - if (p == ®dummy) - return(NULL); - - offset = NEXT(p); - if (offset == 0) - return(NULL); - - if (OP(p) == BACK) - return(p-offset); - else - return(p+offset); -} - -#ifdef DEBUG - -STATIC char *regprop(); - -/* - - regdump - dump a regexp onto stdout in vaguely comprehensible form - */ -void -regdump(r) -regexp *r; -{ - register char *s; - register char op = EXACTLY; /* Arbitrary non-END op. */ - register char *next; - extern char *strchr(); - - - s = r->program + 1; - while (op != END) { /* While that wasn't END last time... */ - op = OP(s); - printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */ - next = regnext(s); - if (next == NULL) /* Next ptr. */ - printf("(0)"); - else - printf("(%d)", (s-r->program)+(next-s)); - s += 3; - if (op == ANYOF || op == ANYBUT || op == EXACTLY) { - /* Literal string, where present. */ - while (*s != '\0') { - putchar(*s); - s++; - } - s++; - } - putchar('\n'); - } - - /* Header fields of interest. */ - if (r->regstart != '\0') - printf("start `%c' ", r->regstart); - if (r->reganch) - printf("anchored "); - if (r->regmust != NULL) - printf("must have \"%s\"", r->regmust); - printf("\n"); -} - -/* - - regprop - printable representation of opcode - */ -static char * -regprop(op) -char *op; -{ - register char *p; - static char buf[50]; - - (void) strcpy(buf, ":"); - - switch (OP(op)) { - case BOL: - p = "BOL"; - break; - case EOL: - p = "EOL"; - break; - case ANY: - p = "ANY"; - break; - case ANYOF: - p = "ANYOF"; - break; - case ANYBUT: - p = "ANYBUT"; - break; - case BRANCH: - p = "BRANCH"; - break; - case EXACTLY: - p = "EXACTLY"; - break; - case NOTHING: - p = "NOTHING"; - break; - case BACK: - p = "BACK"; - break; - case END: - p = "END"; - break; - case OPEN+1: - case OPEN+2: - case OPEN+3: - case OPEN+4: - case OPEN+5: - case OPEN+6: - case OPEN+7: - case OPEN+8: - case OPEN+9: - sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN); - p = NULL; - break; - case CLOSE+1: - case CLOSE+2: - case CLOSE+3: - case CLOSE+4: - case CLOSE+5: - case CLOSE+6: - case CLOSE+7: - case CLOSE+8: - case CLOSE+9: - sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE); - p = NULL; - break; - case STAR: - p = "STAR"; - break; - case PLUS: - p = "PLUS"; - break; - default: - regerror("corrupted opcode"); - break; - } - if (p != NULL) - (void) strcat(buf, p); - return(buf); -} -#endif - -/* - * The following is provided for those people who do not have strcspn() in - * their C libraries. They should get off their butts and do something - * about it; at least one public-domain implementation of those (highly - * useful) string routines has been published on Usenet. - */ -#ifdef STRCSPN -/* - * strcspn - find length of initial segment of s1 consisting entirely - * of characters not from s2 - */ - -static int -strcspn(s1, s2) -char *s1; -char *s2; -{ - register char *scan1; - register char *scan2; - register int count; - - count = 0; - for (scan1 = s1; *scan1 != '\0'; scan1++) { - for (scan2 = s2; *scan2 != '\0';) /* ++ moved down. */ - if (*scan1 == *scan2++) - return(count); - count++; - } - return(count); -} -#endif //GO.SYSIN DD regexp.c echo rfc.c sed 's/.//' >rfc.c <<'//GO.SYSIN DD rfc.c' -/* - * Various RFC 822 compatibility routines. - */ - -#ifndef lint -static char sccsid[] = "%W%"; -#endif - -#include "mace.h" -#include "headers.h" -#include "regexp.h" -#include "line.h" -#include "message.h" -#include "conf.h" -#include - -#define ZONE_HOUR(h) ((h) * 60) -#define YEAR_OFFSET 1900 - -static char *days[] = -{ - "Sun", - "Mon", - "Tue", - "Wed", - "Thu", - "Fri", - "Sat", - NULLSTR, -}; - -static char *months[] = -{ - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec", - NULLSTR, -}; - -typedef struct zone zone; - -struct zone -{ - char *name; - int offset; -}; - -static zone zones[] = -{ - { "UT", ZONE_HOUR(0) }, /* UTC */ - { "GMT", ZONE_HOUR(0) }, /* GMT */ - /* North American */ - { "EST", ZONE_HOUR(-5) }, - { "EDT", ZONE_HOUR(-4) }, - { "CST", ZONE_HOUR(-6) }, - { "CDT", ZONE_HOUR(-5) }, - { "MST", ZONE_HOUR(-7) }, - { "MDT", ZONE_HOUR(-6) }, - { "PST", ZONE_HOUR(-8) }, - { "PDT", ZONE_HOUR(-7) }, - /* Military */ - { "A", ZONE_HOUR(-1) }, - { "B", ZONE_HOUR(-2) }, - { "C", ZONE_HOUR(-3) }, - { "D", ZONE_HOUR(-4) }, - { "E", ZONE_HOUR(-5) }, - { "F", ZONE_HOUR(-6) }, - { "G", ZONE_HOUR(-7) }, - { "H", ZONE_HOUR(-8) }, - { "I", ZONE_HOUR(-9) }, - { "K", ZONE_HOUR(-10) }, - { "L", ZONE_HOUR(-11) }, - { "M", ZONE_HOUR(-12) }, - { "N", ZONE_HOUR(1) }, - { "O", ZONE_HOUR(2) }, - { "P", ZONE_HOUR(3) }, - { "Q", ZONE_HOUR(4) }, - { "R", ZONE_HOUR(5) }, - { "S", ZONE_HOUR(6) }, - { "T", ZONE_HOUR(7) }, - { "U", ZONE_HOUR(8) }, - { "V", ZONE_HOUR(9) }, - { "X", ZONE_HOUR(10) }, - { "Y", ZONE_HOUR(11) }, - { "Z", ZONE_HOUR(0) }, - { NULLSTR, ZONE_HOUR(24) }, -}; - -/* - * Case independent strcmp(). - */ -int -strcasecmp(char *s1, char *s2) -{ - while (*s1 != '\0') - { - int c1; - int c2; - - if (*s1 != *s2 && (c1 = tolower(*s1)) != (c2 = tolower(*s2))) - return c1 < c2 ? -1 : 1; - - s1++; - s2++; - } - - return 0; -} - -/* - * Return the offset in minutes from GMT. - */ -static int -gmt_offset(t) -long t; -{ - register int minutes; - register struct tm *gmtp; - register struct tm *localp; - register int day; - struct tm gmt; - - bcopy((char *)gmtime(&t), (char *)&gmt, sizeof gmt); - localp = localtime(&t); - - gmtp = &gmt; - - if (gmtp->tm_year == localp->tm_year) - { - if (gmtp->tm_yday == localp->tm_yday) - day = 0; - else if (gmtp->tm_yday < localp->tm_yday) - day = 1; - else - day = -1; - } - else if (gmtp->tm_year < localp->tm_year) - day = 1; - else - day = -1; - - return (localp->tm_hour + day * 24) * 60 + localp->tm_min - gmtp->tm_hour * 60 - gmtp->tm_min; -} - -/* - * Returns the date in the correct format. - */ -static char * -date_str(t, tp) -long t; -register struct tm *tp; -{ - register int hours; - register int minutes; - int east; - static char date[64]; - static char zone_name[9]; - extern char *strcpy(); - - if ((minutes = gmt_offset(t)) < 0) - { - minutes = -minutes; - east = 0; - } - else - east = 1; - - hours = minutes / 60; - minutes %= 60; - - if (hours != 0 || minutes != 0) - sprintf(zone_name, "%c%02d%02d", east ? RFC_SPEC_PLUS : RFC_SPEC_MINUS, hours, minutes); - else - (void)strcpy(zone_name, RFC_STR_GMT); - - if (tp == (struct tm *)0) - tp = localtime(&t); - - sprintf - ( - date, - "%s%c%c%2d%c%s%c%d%c%02d%c%02d%c%02d%c%s", - days[tp->tm_wday], - RFC_SPEC_COMMA, - RFC_LWSP_1, - tp->tm_mday, - RFC_LWSP_1, - months[tp->tm_mon], - RFC_LWSP_1, - tp->tm_year + YEAR_OFFSET, - RFC_LWSP_1, - tp->tm_hour, - RFC_SPEC_COLON, - tp->tm_min, - RFC_SPEC_COLON, - tp->tm_sec, - RFC_LWSP_1, - zone_name - ); - - return newstr(date); -} - -/* - * Returns the date in the correct format. - */ -char * -rfc_date(t) -long t; -{ - return date_str(t, (struct tm *)0); -} - -/* - * Is this char a digit? - */ -int -digit(c) -register char c; -{ - return c >= '0' && c <= '9'; -} - -/* - * Return the numeric value of a two digit ASCII sequence. - */ -static char * -two_digits(c, s, ip) -char c; -register char *s; -register int *ip; -{ - register int i; - - if (*s++ != c || !digit(*s)) - return NULLSTR; - - i = *s++ - '0'; - i *= 10; - - if (!digit(*s)) - return NULLSTR; - - i += *s++ - '0'; - - *ip = i; - return s; -} - -/* - * Take a UNIX date and return it's RFC 822 representation. - */ -char * -rfc_cvt_date(s) -register char *s; -{ - register struct tm *tp; - register char **n; - struct tm now; - extern long time(); - int year; - - tp = &now; - - n = days; - - for (;;) - { - if (*n == NULLSTR) - goto disaster; - - if (strncmp(s, *n, 3) == 0) - { - tp->tm_wday = n - days; - break; - } - - n++; - } - - s += 3; - - if (*s++ != ' ') - goto disaster; - - n = months; - - for (;;) - { - if (*n == NULLSTR) - goto disaster; - - if (strncmp(s, *n, 3) == 0) - { - tp->tm_mon = n - months; - break; - } - - n++; - } - - s += 3; - - if (*s != ' ') - goto disaster; - - if (digit(*++s)) - { - if ((s = two_digits(' ', --s, &tp->tm_mday)) == NULLSTR) - goto disaster; - } - else if (*s++ == ' ') - tp->tm_mday = *s++ - '0'; - else - goto disaster; - - if ((s = two_digits(' ', s, &tp->tm_hour)) == NULLSTR) - goto disaster; - - if ((s = two_digits(':', s, &tp->tm_min)) == NULLSTR) - goto disaster; - - if (*s == ':') - { - if ((s = two_digits(':', s, &tp->tm_sec)) == NULLSTR) - goto disaster; - } - else if (*s == ' ') - tp->tm_sec = 0; - else - goto disaster; - - while (*s != '\0') - s++; - - if (!digit(*--s) || !digit(*--s) || !digit(*--s) || !digit(*--s)) - goto disaster; - - year = 0; - - while (*s != '\0') - year = year * 10 + *s++ - '0'; - - tp->tm_year = year - YEAR_OFFSET; - - return date_str(time((long *)0), tp); - -disaster: - return rfc_date(time((long *)0)); -} - -/* - * Make up a message id from the: - * - * date - * pid - * box - * id - * host - * domain - */ -char * -rfc_message_id(t, cf, box, id) -long t; -register conf *cf; -char *box; -char *id; -{ - register struct tm *tp; - char *mid; - - tp = localtime(&t); - - mid = salloc - ( - 1 + /* Left angle bracket */ - 10 + 1 + /* Date */ - 10 + 1 + /* Worst case 32 bit pids */ - strlen(box) + 1 + /* box */ - strlen(id) + 1 + /* message id */ - strlen(cf->c_address) + 1 + /* address */ - 1 + /* Right angle bracket */ - 1 /* nul */ - ); - - sprintf - ( - mid, - "%c%d%02d%02d%02d%02d%c%d%c%s%c%s%c%s%c", - RFC_SPEC_LANGLE, - tp->tm_year + YEAR_OFFSET, - tp->tm_mon + 1, - tp->tm_mday, - tp->tm_hour, - tp->tm_min, - RFC_SPEC_DOT, - getpid(), - RFC_SPEC_DOT, - box, - RFC_SPEC_DOT, - id, - RFC_SPEC_AT, - cf->c_address, - RFC_SPEC_RANGLE - ); - - return mid; -} - -/* - * Case independant header comparison allowing LWSP - * between header and ':'. - */ -int -rfc_hdr_cmp(s, h) -register char *s; -register char *h; -{ - register char c; - register char d; - - for (;;) - { - if (*s == '\0') - return 0; - - if (*h == RFC_SPEC_COLON) - { - while (*s == RFC_LWSP_1 || *s == RFC_LWSP_2) - s++; - - return *s == RFC_SPEC_COLON; - } - - if (*s != *h) - { - if ((c = *s) >= 'A' && c <= 'Z') - c = c - 'A' + 'a'; - - if ((d = *h) >= 'A' && d <= 'Z') - d = d - 'A' + 'a'; - - if (c != d) - return 0; - } - - s++; - h++; - } -} - -/* - * Determine whether a string starts with an RFC 822 header. - */ -int -rfc_header(s) -char *s; -{ - register char *p; - - /* - * 1* - */ - p = s; - - do - { - if (*p <= RFC_LWSP_1 || *p == '\177') - { - if - ( - (*p != RFC_LWSP_1 && *p != RFC_LWSP_2) - || - p == s - ) - return 0; - - break; - } - - if (*p == RFC_SPEC_COLON) - { - if (p == s) - return 0; - - break; - } - } - while (*p++ != '\0'); - - /* - * 1* ":" - */ - do - { - if (*p == RFC_SPEC_COLON) - return 1; - } - while ((*p == RFC_LWSP_1 || *p == RFC_LWSP_2) && *p++ != '\0'); - - - return 0; -} - -/* - * Determine whether a string is an RFC 822 weekday. - */ -int -rfc_weekday(char *s) -{ - char **d; - - for (d = days; *d != NULLSTR; d++) - { - if (strcasecmp(*d, s) == 0) - return d - days; - } - - return -1; -} - -/* - * Determine whether a string is an RFC 822 month. - */ -int -rfc_month(char *s) -{ - char **m; - - for (m = months; *m != NULLSTR; m++) - { - if (strcasecmp(*m, s) == 0) - return m - months; - } - - return -1; -} - -/* - * Return a 4DIGIT local differential in minutes for an RFC 822 zone. - */ -static int -diff(char *s, int west) -{ - int m; - int n; - - m = 0; - n = 0; - - for (;;) - { - if (*s == '\0') - { - if (n != 4) - break; - - return west ? m : -m; - } - - if (!isdigit(*s) || n >= 4) - break; - - m = m * 10 + *s - '0'; - n++; - } - - return ZONE_HOUR(24); -} - -/* - * Return an offset in minutes for an RFC 822 zone. - */ -int -rfc_zone(char *s) -{ - zone *z; - int west; - - west = 1; - - /* optional +/- ? */ - switch (*s) - { - case RFC_SPEC_MINUS: - west = 0; - case RFC_SPEC_PLUS: - return diff(&s[1], west); - } - - for (z = zones; z->name != NULLSTR; z++) - { - if (strcasecmp(z->name, s) == 0) - break; - } - - return z->offset; -} //GO.SYSIN DD rfc.c echo run.c sed 's/.//' >run.c <<'//GO.SYSIN DD run.c' -/* - * Fork/exec an argument vector using sh(1). - */ - -#ifndef lint -static char sccsid[] = "@(#)run.c 1.30"; -#endif - -#include -#include "mace.h" - -int -run(argv) -register char *argv[]; -{ - register int i; - register int pid; - register char *x; - int status; - SIG_RET (*int_sig)(); - SIG_RET (*quit_sig)(); - - switch (pid = fork()) - { - case SYSERROR: - could_not("fork", argv[0]); - /* NOTREACHED */ - - case 0: - x = defenv(ENV_SHELL, DEF_SHELL); - - execl(x, basename(x), "-c", splice(argv, " "), NULLSTR); - could_not("exec", argv[0]); - /* NOTREACHED */ - - default: - break; - } - - int_sig = signal(SIGINT, SIG_IGN); - quit_sig = signal(SIGQUIT, SIG_IGN); - - while ((i = wait(&status)) != pid) - { - if (i == SYSERROR) - { - status = SYSERROR; - break; - } - } - - signal(SIGINT, int_sig); - signal(SIGQUIT, quit_sig); - - return status; -} //GO.SYSIN DD run.c echo string.c sed 's/.//' >string.c <<'//GO.SYSIN DD string.c' -/* - * String routines. - */ - -#ifndef lint -static char sccsid[] = "@(#)string.c 1.32"; -#endif - -#include "mace.h" - -char * -concat(s1, s2) -char *s1; -char *s2; -{ - register int l; - register char *s; - extern char *strcpy(); - extern char *strcat(); - - l = strlen(s1) + strlen(s2) + 1; - - s = salloc(l); - - (void)strcat(strcpy(s, s1), s2); - - return s; -} - -char * -concat3(s1, s2, s3) -char *s1; -char *s2; -char *s3; -{ - register int l; - register char *s; - extern char *strcpy(); - extern char *strcat(); - - l = strlen(s1) + strlen(s2) + strlen(s3) + 1; - - s = salloc(l); - - (void)strcat(strcat(strcpy(s, s1), s2), s3); - - return s; -} - -char * -newstr(s) -register char *s; -{ - extern char *strcpy(); - - return strcpy(salloc(strlen(s) + 1), s); -} - -char * -basename(s) -register char *s; -{ - register char *p; - extern char *strrchr(); - - if ((p = strrchr(s, '/')) == NULLSTR || *++p == '\0') - p = s; - - return p; -} - -char * -splice(v, s) -register char *v[]; -register char *s; -{ - register char *p; - register char *q; - register int i; - register int len; - char *r; - - len = 0; - - for (i = 0; v[i] != NULLSTR; i++) - len += strlen(v[i]); - - len += strlen(s) * (i - 1) + 1; - - p = r = salloc(len + 1); - - for (i = 0; (q = v[i]) != NULLSTR; i++) - { - while ((*p++ = *q++) != '\0') - ; - - p--; - - if (v[i + 1] != NULLSTR) - { - for (q = s; (*p++ = *q) != '\0'; q++) - ; - - p--; - } - } - - *p = '\0'; - - return r; -} - -char * -strstr(s, t) -register char *s; -register char *t; -{ - register char *p; - extern char *strchr(); - - while (*t != '\0') - { - if ((p = strchr(s, *t++)) != NULLSTR) - return p; - } - - return NULLSTR; -} //GO.SYSIN DD string.c echo sysmess.c sed 's/.//' >sysmess.c <<'//GO.SYSIN DD sysmess.c' -/* - * System error messages. - */ - -#ifndef lint -static char sccsid[] = "@(#)sysmess.c 1.30"; -#endif - -#include -#include - -char * -sysmess() -{ - extern int errno; - - return strerror(errno); -} //GO.SYSIN DD sysmess.c echo tn.c sed 's/.//' >tn.c <<'//GO.SYSIN DD tn.c' -/* - * Message true names (ie. indexes). - */ - -#ifndef lint -static char sccsid[] = "@(#)tn.c 1.30"; -#endif - -#include "mace.h" - -msg_idx -mess_index(m, s) -register mbox *m; -register char *s; -{ - register msg_idx i; - register msg_idx j; - register msg_idx k; - - i = 0; - k = m->m_count - 1; - - while (k >= i) - { - register int c; - - j = i + (k - i) / 2; - - if ((c = strcmp(s, m->m_list[j])) == 0) - return j; - - if (c > 0) - i = j + 1; - else - k = j - 1; - } - - return NULLMSG; -} //GO.SYSIN DD tn.c echo tty.c sed 's/.//' >tty.c <<'//GO.SYSIN DD tty.c' -/* - * @(#)tty.c 1.1 - * - * Horrible system dependent tty routines. - */ - -#include "mace.h" -#include - -/* - * Is echo on? - */ -int -ttyechoing(int fd) -{ - struct termios t; - - if (tcgetattr(fd, &t) == SYSERROR) - return SYSERROR; - - return (t.c_lflag & ECHO) != 0; -} - -/* - * Turn echo off/on? - */ -int -ttyecho(int fd, int on) -{ - struct termios t; - - if (tcgetattr(fd, &t) == SYSERROR) - return SYSERROR; - - if (on) - t.c_lflag |= ECHO; - else - t.c_lflag &= ~ECHO; - - return tcsetattr(fd, TCSADRAIN, &t); -} //GO.SYSIN DD tty.c echo vec.c sed 's/.//' >vec.c <<'//GO.SYSIN DD vec.c' -/* - * Dynamic vector of strings. - */ - -#ifndef lint -static char sccsid[] = "@(#)vec.c 1.31"; -#endif - -#include "mace.h" - -void -vec_init(v, n) -register vec *v; -register int n; -{ - v->v_count = 0; - v->v_size = v->v_incr = n; - v->v_list = (char **)salloc(n * sizeof(char *)); -} - -char * -vec_str(v, s) -register vec *v; -register char *s; -{ - if (v->v_count == v->v_size) - v->v_list = (char **)srealloc((char *)v->v_list, (int)(v->v_size += v->v_incr) * sizeof(char *)); - - v->v_list[v->v_count++] = s; - - return s; -} - -char * -vec_cat(v, s) -register vec *v; -register char *s; -{ - if (v->v_count != 0) - { - register char *p; - - if (v->v_list[v->v_count - 1] != NULLSTR) - { - p = concat(v->v_list[v->v_count - 1], s); - - (void)free(v->v_list[v->v_count - 1]); - (void)free(s); - } - else - p = s; - - return v->v_list[v->v_count - 1] = p; - } - else - return vec_str(v, s); -} - -void -vec_free(v) -register vec *v; -{ - register int i; - - for (i = 0; i < v->v_count; i++) - { - if (v->v_list[i] != NULLSTR) - (void)free(v->v_list[i]); - } - - v->v_count = 0; - v->v_size = 0; - v->v_incr = 0; - (void)free((char *)v->v_list); -} //GO.SYSIN DD vec.c echo writefile.c sed 's/.//' >writefile.c <<'//GO.SYSIN DD writefile.c' -/* - * Write a string to a file (adding a newline). - */ - -#ifndef lint -static char sccsid[] = "@(#)writefile.c 1.30"; -#endif - -#include "mace.h" - -int -write_file(f, s) -register char *f; -register char *s; -{ - register int fd; - register int l; - int ok; - - if ((fd = creat(f, CREAT_MODE)) == SYSERROR) - return 1; - - l = strlen(s); - s[l] = '\n'; - - ok = 0; - - if (write(fd, s, l + 1) != l + 1) - ok = 1; - - if (close(fd) == SYSERROR) - ok = 1; - - s[l] = '\0'; - - return ok; -} //GO.SYSIN DD writefile.c echo bundle sed 's/.//' >bundle <<'//GO.SYSIN DD bundle' -#!/bin/sh -# -# @(#)bundle 1.1 -# -# bundle file ... -# -# Plan 9 bundle; a simple shell archiver. -# - -echo '# To unbundle, run this file' - -for i -do - echo echo "$i" - echo "sed 's/.//' >$i <<'//GO.SYSIN DD $i'" - sed 's/^/-/' "$i" - echo "//GO.SYSIN DD $i" -done //GO.SYSIN DD bundle echo mal sed 's/.//' >mal <<'//GO.SYSIN DD mal' -#!/bin/sh -# -# @(#)mal 1.2 -# -# mal +box ... -# -# Mail aliasing based on a box's .proto -# - -dir="$HOME/.macedir" -bchar=+ -proto=.proto - -myname="`basename \"$0\"`" - -case $# in -0) - echo "usage: $myname ${bchar}box ..." 1>&2 - exit 1 - ;; -esac - -# find mail directory -if [ ! -r "$dir" ] -then - echo "$myname: Could not read '$dir'." 1>&2 - exit 1 -fi - -mdir="`cat \"$dir\"`" - -case "$mdir" in -"") - echo "$myname: '$dir' empty." 1>&2 - exit 1 - ;; - -/*) - # absolute pathname, ok - ;; - -*) - # relative pathname, so prepend $HOME - mdir="$HOME/$mdir" - ;; -esac - -for b -do - # use box to verify box name, but the usage message is a bit weird - if box -l "$b" > /dev/null - then - case "$b" in - ${bchar}*) - # slice off leading ${bchar} - b="`expr \"$b\" : \"^${bchar}\(.*\)$\"`" - ;; - esac - - # snarf To:/Cc:/Bcc: - sed -n \ - -e '/^[Tt][Oo][ ]*:[ ]*/s///p' \ - -e '/^[Cc][Cc][ ]*:[ ]*/s///p' \ - -e '/^[Bb][Cc][Cc][ ]*:[ ]*/s///p' \ - "$mdir/$b/$proto" 2> /dev/null - fi -done | sed -e '$n' -e 's/$/,/' # insert , between addresses //GO.SYSIN DD mal echo box.c sed 's/.//' >box.c <<'//GO.SYSIN DD box.c' -/* - * box [ -acdilmorst ] [ +box... ] - * - * Box specific stuff - */ - -#ifndef lint -static char sccsid[] = "@(#)box.c 1.37"; -#endif - -#include -#include -#include -#include "mace.h" -#include "line.h" -#include "message.h" -#include "headers.h" -#include "regexp.h" -#include "conf.h" - -int rev = 0; /* reverse scan */ -int show_to = 0; /* show the "To:" field */ -int current = 0; /* just show the current message */ -int inbox = 0; /* show the `incoming' box */ -int outbox = 0; /* show the `outgoing' box */ - -int -box_cmp(m1, m2) -register char **m1; -register char **m2; -{ - return strcmp(*m1, *m2); -} - -int -show(v) -register char **v; -{ - while (*v != NULLSTR) - printf("%c%s\n", BOX_CHAR, *v++); - - return 0; -} - -int -create(v) -register char **v; -{ - int ok; - - ok = 0; - - while (*v != NULLSTR) - { - register char *p; - - if ((p = create_box(*v)) == NULLSTR) - { - would_not("create", *v); - ok = 1; - } - else - (void)free(p); - - v++; - } - - return ok; -} - -int -delete(v) -register char **v; -{ - int ok; - - ok = 0; - - while (*v != NULLSTR) - { - if (delete_box(*v)) - ok = 1; - - v++; - } - - return ok; -} - -int -list(v) -register char **v; -{ - int ok; - - ok = 0; - - while (*v != NULLSTR) - { - register mbox *m; - register int i; - - if ((m = read_box(*v)) == NULLBOX) - { - would_not("read", *v); - ok = 1; - v++; - continue; - } - - printf("%c%-20s", BOX_CHAR, m->m_name); - - if (m->m_messid == NULLSTR) - { - for (i = 0; i < ID_LEN; i++) - putchar('?'); - } - else - printf("%s", m->m_messid); - - if (m->m_count != 0) - printf(" %4d %s", m->m_count, m->m_count == 1 ? "message" : "messages"); - else - printf(" empty"); - - putchar('\n'); - v++; - - (void)free_box(m); - } - - return ok; -} - -int -set(v) -register char **v; -{ - return set_box(v[0]); -} - -int -analyse(mb) -register mbox *mb; -{ - register message *mp; - register int i; - register int j; - register int id; - int errs; - - errs = 0; - - if (current) - { - if (mb->m_current == NULLMSG) - { - fprintf(stderr, "%s: No current message in \"%s\".\n", my_name, mb->m_name); - return 1; - } - - i = mb->m_current; - j = i + 1; - rev = 0; - } - else - { - i = 0; - j = mb->m_count; - } - - while (i < j) - { - if ((mp = read_mess(mb, mb->m_list[id = rev ? mb->m_count - (i + 1): i])) != NULLMESS) - { - print_summary(mb->m_name, mp->ms_messid, &mp->ms_headers.v_list[0], id == mb->m_current, mp->ms_copies, show_to || (mp->ms_state & MESG_SENT) != 0, mp->ms_state); - - free_mess(mp); - } - else - { - would_not("read message", mb->m_list[id]); - errs = 1; - } - - i++; - } - - return errs; -} - -int -scan(v) -register char **v; -{ - register char **n; - register mbox *mb; - register int errs; - - errs = 0; - - for (n = v; *n != NULLSTR; n++) - { - register char *p; - - if ((mb = read_box(p = *n)) == NULLBOX) - { - would_not("read", p); - errs = 1; - } - else if (analyse(mb)) - errs = 1; - - free_box(mb); - } - - return errs; -} - -void -validate(v, tp) -register char **v; -register char **tp; -{ - register char **n; - - for (n = v; *n != NULLSTR; n++) - { - register char *p; - - if ((p = check_box(*n)) != NULLSTR) - { - *v++ = *n; - (void)free(p); - } - else - { - fprintf(stderr, "%s: \"%s\" is not a box.\n", my_name, *n); - - if (*tp != NULLSTR && strcmp(*tp, *n) == 0) - *tp = NULLSTR; - } - } - - *v = NULLSTR; -} - -void -usage() -{ - fprintf(stderr, "usage: %s [ -acdilmorst ] [ [%c]%cbox... ]\n", my_name, BOX_CHAR, BOX_CHAR); - exit(1); -} - -/* - * Choose the current box, `incoming', or `outgoing'. - */ -char * -select_box() -{ - register char *p; - - if (inbox && outbox) - { - usage(); - /* NOTREACHED */ - } - - if (inbox || outbox) - { - register conf *cp; - - cp = read_config(); - - return newstr(inbox ? cp->c_inbox : cp->c_outbox); - } - - if ((p = curr_box()) == NULLSTR) - { - fprintf(stderr, "%s: No current box.\n", my_name); - exit(1); - /* NOTREACHED */ - } - - return newstr(p); -} - -int -main(argc, argv) -register char argc; -register char *argv[]; -{ - register int i; - register int j; - int all; - vec bvec; - char *target; - int (*action)(); - - name(argv[0]); - - action = show; - all = 0; - target = NULLSTR; - vec_init(&bvec, argc); - - for (i = 1; i < argc; i++) - { - j = 0; - - if (argv[i][j] == BOX_CHAR) - { - register char *p; - - p = &argv[i][1]; - - if (*p == BOX_CHAR) - { - if (target != NULLSTR) - { - usage(); - /* NOTREACHED */ - } - - target = ++p; - } - - if (*p == '\0') - { - usage(); - /* NOTREACHED */ - } - - vec_str(&bvec, newstr(p)); - continue; - } - - if (argv[i][j++] != '-') - { - usage(); - /* NOTREACHED */ - } - - while (argv[i][j] != '\0') - { - switch (argv[i][j++]) - { - case 'a': - all = 1; - continue; - - case 'c': - if (action != show) - { - usage(); - /* NOTREACHED */ - } - - action = create; - continue; - - case 'd': - if (action != show) - { - usage(); - /* NOTREACHED */ - } - - action = delete; - continue; - - case 'i': - inbox = 1; - continue; - - case 'l': - if (action != show) - { - usage(); - /* NOTREACHED */ - } - - action = list; - continue; - - case 'm': - current = 1; - goto set_scan; - - case 'o': - outbox = 1; - continue; - - case 'r': - rev = 1; - goto set_scan; - - case 't': - show_to = 1; - goto set_scan; - - case 's': - set_scan: - if (action != show && action != scan) - { - usage(); - /* NOTREACHED */ - } - - action = scan; - continue; - - default: - usage(); - /* NOTREACHED */ - } - - break; - } - } - - if (all && action == create) - { - usage(); - /* NOTREACHED */ - } - - if (rev && action != scan) - { - usage(); - /* NOTREACHED */ - } - - if (action == show) - { - if (bvec.v_count > 1) - { - usage(); - /* NOTREACHED */ - } - - if (bvec.v_count == 1) - action = set; - } - - if (all) - { - register char **v; - - if (bvec.v_count != 0) - { - usage(); - /* NOTREACHED */ - } - - v = read_dir(mace_dir()); - - if (*v == NULLSTR) - { - fprintf(stderr, "%s: You have no boxes.\n", my_name); - exit(1); - /* NOTREACHED */ - } - - for (i = 0; v[i] != NULLSTR; i++) - ; - - qsort((char *)v, i, sizeof(*v), box_cmp); - - while (*v != NULLSTR) - vec_str(&bvec, *v++); - } - else if (bvec.v_count == 0) - vec_str(&bvec, select_box()); - - vec_str(&bvec, NULLSTR); - - if (action != create) - { - validate(bvec.v_list, &target); - - if (bvec.v_list[0] == NULLSTR) - exit(1); - } - else - (*action)(bvec.v_list); - - if - ( - (target != NULLSTR && set_box(target)) - || - (action != create && (*action)(bvec.v_list)) - ) - { - exit(1); - /* NOTREACHED */ - } - - exit(0); - /* NOTREACHED */ -} //GO.SYSIN DD box.c echo com.c sed 's/.//' >com.c <<'//GO.SYSIN DD com.c' -/* - * com | rep | fwd [ -si ] [ +box ] [ message ] - * - * Message composition, reply and forwarding. - */ - -#ifndef lint -static char sccsid[] = "%W%"; -#endif - -#include "mace.h" -#include "line.h" -#include "message.h" -#include "headers.h" -#include "regexp.h" -#include "conf.h" -#include "addr.h" -#include -#include -#include - -vec to; -vec cc; -char *subject = NULLSTR; -char *message_id = NULLSTR; -char *my_address = NULLSTR; -match *removeit = (match *)0; - -int external = 0; -int sender = 0; -int include_current = 0; -int replying = 0; - -char *current; -vec refiled; - -msg_idx -find_msg(m, s) -mbox *m; -char *s; -{ - msg_idx i; - - if (*s == '\0') - { - if (m->m_current == NULLMSG) - fprintf(stderr, "%s: No current message in \"%s\".\n", my_name, m->m_name); - - return m->m_current; - } - - if ((i = valid_id(s) ? mess_index(m, s) : mess_alias(m, s)) == NULLMSG) - fprintf(stderr, "%s: No such message qualifier as \"%s\".\n", my_name, s); - - return i; -} - -mbox * -current_box(id) -char *id; -{ - static mbox *mb = NULLBOX; - msg_idx idx; - char *box; - - if (mb != NULLBOX) - return mb; - - if ((box = curr_box()) == NULLSTR) - { - fprintf(stderr, "%s: No current box.\n", my_name); - exit(1); - /* NOTREACHED */ - } - - if ((mb = read_box(box)) == NULLBOX) - { - fprintf(stderr, "%s: Box \"%s\" does not exist.\n", my_name, box); - exit(1); - /* NOTREACHED */ - } - - (void)free(box); - - if (id != NULLSTR) - { - if ((idx = find_msg(mb, id)) == NULLMSG) - { - exit(1); - /* NOTREACHED */ - } - - mb->m_current = idx; - mb->m_messid = mb->m_list[idx]; - - (void)set_current(mb->m_name, mb->m_messid); - } - - if (mb->m_current == NULLMSG) - { - fprintf(stderr, "%s: No current message in \"%s\".\n", my_name, mb->m_name); - exit(1); - /* NOTREACHED */ - } - - return mb; -} - -int -open_msg(id) -char *id; -{ - mbox *mb; - char *msg; - int fd; - - mb = current_box(id); - - msg = concat3(mb->m_path, "/", mb->m_messid); - - if ((fd = open(msg, O_RD)) == SYSERROR) - { - could_not("open", msg); - /* NOTREACHED */ - } - - current = msg; - - return fd; -} - -/* - * Compare two addresses. - */ -int -same_address(a, b) -char *a; -char *b; -{ - for (;;) - { - char c; - char d; - - if (*a != *b) - { - if (*a == '\0') - return (c = *b) == RFC_SPEC_PERCENT || c == RFC_SPEC_AT || c == RFC_SPEC_DOT; - - if (*b == '\0') - return (c = *a) == RFC_SPEC_PERCENT || c == RFC_SPEC_AT || c == RFC_SPEC_DOT; - - if ((c = *a) >= 'A' && c <= 'Z') - c = c - 'A' + 'a'; - - if ((d = *b) >= 'A' && d <= 'Z') - d = d - 'A' + 'a'; - - if (c != d) - return 0; - } - else if (*a == '\0') - return 1; - - a++; - b++; - } -} - -/* - * Add to a list of recipients after removing self. - */ -void -add_recipient(vp, s) -vec *vp; -char *s; -{ - char *p; - Addr *ap; - Addr *addrs; - - if ((p = parse_address(&addrs, s)) != NULLSTR) - { - /* - * If the address has a syntax error add the raw text. - */ - vec_str(vp, newstr(s)); - fprintf(stderr, "%s: warning: \"%s\" %s.\n", my_name, s, p); - return; - } - - for (ap = addrs; ap != (Addr *)0; ap = ap->next) - { - /* - * This is hideous, but necessary until I fix the `group bug'. - */ - if (ap->group != NULLSTR) - { - if (ap->text != NULLSTR) - vec_str(vp, newstr(ap->text)); - - continue; - } - - if (removeit != (match *)0) - { - if (regexec(removeit->m_cre, ap->text) == 0) - { - if (re_error != NULLSTR) - fprintf(stderr, "%s: Regular expression \"%s\" %s\n", my_name, removeit->m_re, re_error); - else - vec_str(vp, newstr(ap->text)); - } - } - else - { - if (!same_address(my_address, p = make_address(ap))) - vec_str(vp, newstr(ap->text)); - - (void)free(p); - } - } -} - -/* - * Add multiple To: and Cc: lines to a list of recipients (removing self). - */ -void -add_multiple(mbox *mb, vec *list, char **h, char *type) -{ - while (*h != NULLSTR) - { - if (rfc_hdr_cmp(*h, type)) - { - char *ht; - - if ((ht = header_text(*h)) == NULLSTR) - { - fprintf(stderr, "%s: Malformed \"%s\" line in \"%s\".\n", my_name, type, mb->m_messid); - exit(1); - /* NOTREACHED */ - } - - add_recipient(list, ht); - } - - h++; - } -} - -/* - * Add links to the message based on the boxes it it refiled in. - */ -static void -addlinks(char *box, char *id) -{ - int i; - - for (i = 1; i < refiled.v_count; i++) - { - char *a[6]; - int n; - int s; - int t; - - /* - * Use 'lnk' to avoid code duplication. - */ - n = 0; - a[n++] = LNK_STR; - a[s = n++] = concat(" ", box); - a[s][0] = BOX_CHAR; - a[n++] = id; - a[t = n++] = concat(" ", refiled.v_list[i]); - a[t][0] = BOX_CHAR; - a[n++] = NULLSTR; - run(a); - - free(a[s]); - free(a[t]); - } -} - -/* - * Create a list of boxes in which the message is refiled. - */ -void -refile(char *inbox, message *m, match *re) -{ - vec_str(&refiled, newstr(re->m_action)); -} - -void -set_recipients(conf *cf, char * id) -{ - message *mp; - mbox *mb; - char **h; - char *p; - char *ht; - static char lwsp_1[2] = { RFC_LWSP_1, '\0' }; - - mb = current_box(id); - - vec_init(&to, 64); - vec_init(&cc, 64); - - if (mb->m_current == NULLMSG) - { - fprintf(stderr, "%s: No current message in \"%s\".\n", my_name, mb->m_name); - exit(1); - /* NOTREACHED */ - } - - if ((mp = read_mess(mb, mb->m_messid)) == NULLMESS) - { - could_not("read", mb->m_name); - /* NOTREACHED */ - } - - if - ( - (h = find_header(&mp->ms_headers.v_list[0], p = RFC_REPLY_TO)) == (char **)NULLSTR - && - (h = find_header(&mp->ms_headers.v_list[0], p = RFC_FROM)) == (char **)NULLSTR - ) - { - fprintf(stderr, "%s: Missing \"%s\" or \"%s\" line in \"%s\".\n", my_name, RFC_REPLY_TO, RFC_FROM, mb->m_messid); - exit(1); - /* NOTREACHED */ - } - - if ((ht = header_text(*h)) == NULLSTR) - { - fprintf(stderr, "%s: Malformed \"%s\" line in \"%s\".\n", my_name, p, mb->m_messid); - exit(1); - /* NOTREACHED */ - } - - add_recipient(&to, ht); - - add_multiple(mb, &to, &mp->ms_headers.v_list[0], RFC_TO); - add_multiple(mb, &cc, &mp->ms_headers.v_list[0], RFC_CC); - - if - ( - (h = find_header(&mp->ms_headers.v_list[0], RFC_SUBJECT)) != (char **)NULLSTR - && - (subject = header_text(*h)) != NULLSTR - && - rfc_hdr_cmp(subject, UNIX_REGARDING) == 0 - ) - subject = concat3(UNIX_REGARDING, lwsp_1, subject); - - if ((h = find_header(&mp->ms_headers.v_list[0], RFC_MESSAGE_ID)) != (char **)NULLSTR) - message_id = header_text(*h); - - if (subject != NULLSTR) - subject = newstr(subject); - - if (message_id != NULLSTR) - message_id = newstr(message_id); - - /* - * Build a list of where there are refiled copies of the message. - */ - vec_init(&refiled, 64); - regex_apply(cf->c_inbox, mp, cf->c_refile, refile); - - (void)free_mess(mp); -} - -void -tack_address(vp, ap) -vec *vp; -vec *ap; -{ - int i; - static char sep[7] = - { - RFC_SPEC_COMMA, - '\n', - RFC_LWSP_1, - RFC_LWSP_1, - RFC_LWSP_1, - RFC_LWSP_1, - '\0' - }; - - for (i = 1; i < ap->v_count; i++) - vec_cat(vp, concat(sep, ap->v_list[i])); -} - -void -merge_headers(vp, h) -vec *vp; -char **h; -{ - while (*h != NULLSTR) - { - char **x; - - if ((x = find_header(vp->v_list, *h)) != (char **)NULLSTR) - { - if (header_text(*h) != NULLSTR) - { - (void)free(*x); - *x = newstr(*h); - } - else - { - char *p; - extern char *strchr(); - - p = *x; - *x = concat(*h, strchr(p, RFC_SPEC_COLON) + 1); - (void)free(p); - } - } - else - { - vec_cat(vp, newstr(*h)); - vec_str(vp, NULLSTR); - } - - h++; - } -} - -void -msg_proto(vp, cf, mb, id) -vec *vp; -conf *cf; -mbox *mb; -char *id; -{ - char *p; - message *pp; - static char lwsp_1[2] = { RFC_LWSP_1, '\0' }; - static char lwsp_2[2] = { RFC_LWSP_2, '\0' }; - static char at[2] = { RFC_SPEC_AT, '\0' }; - static char dot[2] = { RFC_SPEC_DOT, '\0' }; - static char langle[2] = { RFC_SPEC_LANGLE, '\0' }; - static char rangle[2] = { RFC_SPEC_RANGLE, '\0' }; - static char comma[2] = { RFC_SPEC_COMMA, '\0' }; - long t; - - vec_init(vp, 64); - time(&t); - - vec_str(vp, concat(RFC_FROM, lwsp_1)); - - if (sender) - vec_str(vp, concat(RFC_SENDER, lwsp_1)); - - if ((p = user_name()) != NULLSTR) - { - vec_cat(vp, concat(p, lwsp_1)); - vec_cat(vp, concat3(langle, my_address, rangle)); - } - else - vec_cat(vp, my_address); - - if (sender) - vec_str(vp, concat(RFC_REPLY_TO, lwsp_1)); - - vec_str(vp, concat(RFC_DATE, lwsp_1)); - vec_cat(vp, rfc_date(t)); - - if (to.v_count > 0) - { - vec_str(vp, concat3(RFC_TO, lwsp_1, to.v_list[0])); - tack_address(vp, &to); - } - else - vec_str(vp, concat(RFC_TO, lwsp_1)); - - if (cc.v_count > 0) - { - vec_str(vp, concat3(RFC_CC, lwsp_1, cc.v_list[0])); - tack_address(vp, &cc); - } - else - vec_str(vp, concat(RFC_CC, lwsp_1)); - - vec_str(vp, concat(RFC_BCC, lwsp_1)); - - if (subject == NULLSTR) - vec_str(vp, concat(RFC_SUBJECT, lwsp_1)); - else - vec_str(vp, concat3(RFC_SUBJECT, lwsp_1, subject)); - - if (message_id != NULLSTR) - vec_str(vp, concat3(RFC_IN_REPLY_TO, lwsp_1, message_id)); - - vec_str(vp, concat(RFC_MESSAGE_ID, lwsp_1)); - vec_cat(vp, rfc_message_id(t, cf, mb->m_name, id)); - - vec_str(vp, NULLSTR); - - /* global prototyping */ - - p = concat3(mace_dir(), "/", PROTO); - - if ((pp = parse_file(p, 0)) != NULLMESS) - { - merge_headers(vp, pp->ms_headers.v_list); - free_mess(pp); - } - - (void)free(p); - - /* per box prototyping for composition */ - - if (!replying && (pp = read_mess(mb, PROTO)) != NULLMESS) - { - merge_headers(vp, pp->ms_headers.v_list); - free_mess(pp); - } - - vec_cat(vp, newstr("")); - vec_str(vp, NULLSTR); -} - -void -interpolate(msg, fd, fp) -char *msg; -int fd; -FILE *fp; -{ - char *p; - lineio ld; - - (void)lopen(&ld, fd, LREAD); - - if (fseek(fp, 0, 2) == 0) - { - while ((p = lread(&ld)) != NULLSTR && !ferror(fp)) - { - fprintf(fp, "%s%s\n", *p == '\0' ? "" : FWD_LEADER, p); - (void)free(p); - } - - if (!ferror(fp)) - fprintf(fp, "\n"); - } - else - would_not("seek on", msg); - - if (lclose(&ld)) - { - (void)close(fd); - (void)fclose(fp); - (void)unlink(msg); - could_not("read", current); - /* NOTREACHED */ - } - - if (close(fd) == SYSERROR) - { - (void)fclose(fp); - (void)unlink(msg); - could_not("close", current); - /* NOTREACHED */ - } - - if (ferror(fp)) - { - (void)fclose(fp); - (void)unlink(msg); - could_not("write", msg); - /* NOTREACHED */ - } - - if (fclose(fp) != 0) - { - (void)unlink(msg); - could_not("close", msg); - /* NOTREACHED */ - } -} - -void -address(cf) -conf *cf; -{ - static char at[2] = { RFC_SPEC_AT, '\0' }; - static char dot[2] = { RFC_SPEC_DOT, '\0' }; - - my_address = concat3(user_id(), at, cf->c_address); -} - -void -usage() -{ - fprintf(stderr, "usage: %s [ -is ] [ %cbox ] [ message ]\n", my_name, BOX_CHAR); - exit(1); - /* NOTREACHED */ -} - -int -main(argc, argv) -int argc; -char *argv[]; -{ - char *s; - char *box; - conf *cf; - mbox *mb; - int i; - int mfd; - FILE *mfp; - char *id; - char *msg; - vec args; - vec proto; - int ok; - - name(argv[0]); - - box = NULLSTR; - id = NULLSTR; - - for (i = 1; i < argc; i++) - { - int j; - - if (argv[i][j = 0] == BOX_CHAR) - { - if (box != NULLSTR) - { - usage(); - /* NOTREACHED */ - } - - if (argv[i][1] == BOX_CHAR) - box = newstr(&argv[i][2]); - else - box = newstr(&argv[i][1]); - - if (*box == '\0') - { - usage(); - /* NOTREACHED */ - } - - continue; - } - - if (argv[i][j++] != '-') - { - if (id != NULLSTR) - { - usage(); - /* NOTREACHED */ - } - - id = newstr(argv[i]); - continue; - } - - while (argv[i][j] != '\0') - { - switch (argv[i][j++]) - { - case 'i': - include_current = 1; - continue; - - case 'e': - external = 1; - continue; - - case 's': - sender = 1; - continue; - - default: - usage(); - /* NOTREACHED */ - } - - break; - } - } - - mfd = SYSERROR; - - if (strcmp(my_name, "com") == 0 && id != NULLSTR) - fprintf(stderr, "%s: Message id \"%s\" ignored.\n", my_name, id); - - /* - * Construct the users' address. - */ - cf = read_config(); - - address(cf); - - removeit = cf->c_remove; - - if (strcmp(my_name, REP_STR) == 0) - { - replying = 1; - set_recipients(cf, id); - } - - if (strcmp(my_name, FWD_STR) == 0 || include_current) - mfd = open_msg(id); - - /* - * If the box isn't specified choose one. - */ - if (box == NULLSTR) - { - /* - * If this is a reply choose the box from the first - * of the boxes where the message is refiled. - */ - if (replying && refiled.v_count > 0) - box = refiled.v_list[0]; - else - { - /* - * If the current box is "inbox" choose "outbox", - * otherwise use the current box. - */ - if ((box = curr_box()) == NULLSTR) - { - fprintf(stderr, "%s: No current box.\n", my_name); - exit(1); - } - - if (strcmp(box, cf->c_inbox) == 0) - box = cf->c_outbox; - } - } - - if ((mb = read_box(box)) == NULLBOX) - { - fprintf(stderr, "%s: Box \"%s\" does not exist.\n", my_name, box); - exit(1); - /* NOTREACHED */ - } - - if (mb->m_count == 0) - s = nextid(NULLSTR); - else - s = nextid(mb->m_list[mb->m_count - 1]); - - msg_proto(&proto, cf, mb, s); - - msg = concat3(mb->m_path, "/", s); - - id = s; - - if (mfd != SYSERROR && (mfp = fopen(msg, "w")) == NULL) - { - could_not("open", msg); - /* NOTREACHED */ - } - - if (write_file(msg, s = splice(proto.v_list, "\n"))) - { - (void)unlink(msg); - could_not("write", msg); - /* NOTREACHED */ - } - - (void)free(s); - vec_free(&proto); - - if (mfd != SYSERROR) - interpolate(msg, mfd, mfp); - - /* - * Add refiled links to this message. - */ - if (replying && refiled.v_count > 0) - { - addlinks(mb->m_name, id); - vec_free(&refiled); - } - - /* - * Invoke $EDITOR - */ - if (!external) - { - vec_init(&args, 4); - vec_str(&args, newstr(defenv(ENV_EDITOR, DEF_EDITOR))); - vec_str(&args, msg); - vec_str(&args, NULLSTR); - - ok = run(args.v_list); - } - else - ok = 0; - - if (set_state(msg, MESG_COMP)) - ok = 1; - - if (set_box(mb->m_name) || set_current(mb->m_name, id)) - ok = 1; - - exit(ok != 0); - /* NOTREACHED */ - return ok != 0; /* shut up! */ -} //GO.SYSIN DD com.c echo despool.c sed 's/.//' >despool.c <<'//GO.SYSIN DD despool.c' -/* - * despool [ -delete ] [ -f mailfile ] - * - * Mail despooler. - * - * Prints mail on standard output and optionally removes it. - */ - -#ifndef lint -static char sccsid[] = "@(#)despool.c 1.31"; -#endif - -#include "mace.h" -#include -#include - -#define DELETE_STR "-delete" - -int -terminate(sig) -int sig; -{ - signal(sig, SIG_IGN); - - if (mail_locked()) - mail_unlock(0); - - exit(1); - - /* NOTREACHED */ -} - -void -usage() -{ - fprintf(stderr, "usage: %s [ %s ] [ -f mailfile ]\n", my_name, DELETE_STR); - exit(1); - /* NOTREACHED */ -} - -int -main(argc, argv) -int argc; -char *argv[]; -{ - register int i; - register int j; - register int fd; - int delete; - char *mail; - char buf[FS_BLKZ]; - - name(argv[0]); - - mail = NULLSTR; - delete = 0; - - for (i = 1; i < argc; i++) - { - if (argv[i][0] != '-') - { - usage(); - /* NOTREACHED */ - } - - j = 1; - - while (argv[i][j] != '\0') - { - switch (argv[i][j++]) - { - case 'd': - if (strcmp(argv[i], DELETE_STR) != 0) - { - usage(); - /* NOTREACHED */ - } - - delete = 1; - break; - - case 'f': - if (mail != NULLSTR) - { - usage(); - /* NOTREACHED */ - } - - if (argv[i][j] != '\0') - mail = &argv[i][j]; - else if (++i < argc) - mail = argv[i]; - else - { - usage(); - /* NOTREACHED */ - } - - break; - - default: - usage(); - /* NOTREACHED */ - } - - break; - } - } - - (void)signal(SIGHUP, terminate); - (void)signal(SIGINT, terminate); - (void)signal(SIGQUIT, terminate); - (void)signal(SIGPIPE, terminate); - (void)signal(SIGTERM, terminate); - - if ((fd = mail_lock(&mail)) == SYSERROR) - exit(1); - - for (;;) - { - register int n; - - switch (n = read(fd, buf, sizeof buf)) - { - case SYSERROR: - would_not("read", mail); - exit(mail_unlock(0) != 0); - /* NOTREACHED */ - - case 0: - if (close(fd) == SYSERROR) - { - would_not("close", mail); - exit(mail_unlock(0) != 0); - /* NOTREACHED */ - } - break; - - default: - if (write(fileno(stdout), buf, n) != n) - { - would_not("write", ""); - exit(mail_unlock(0) != 0); - /* NOTREACHED */ - } - - continue; - } - - break; - } - - exit(mail_unlock(delete) != 0); - - /* NOTREACHED */ -} //GO.SYSIN DD despool.c echo mace.c sed 's/.//' >mace.c <<'//GO.SYSIN DD mace.c' -/* - * mace [ -dsu ] [ -f mailfile ] - * - * Mace your mail-file & extract the mail. - */ - -#ifndef lint -static char sccsid[] = "@(#)mace.c 1.3"; -#endif - -#include -#include -#include -#include -#include "mace.h" -#include "regexp.h" -#include "line.h" -#include "message.h" -#include "conf.h" -#include "headers.h" -#include "flex.h" - -typedef struct boxes boxes; -typedef struct matches matches; - -struct boxes -{ - mbox *b_mbox; - char *b_messid; - boxes *b_next; -}; - -struct matches -{ - char *me_box; - char *me_messid; - char *me_private; - matches *me_next; -}; - -int just_unlock = 0; /* unlock the AUDIT trail */ -int do_audit = 1; /* create an AUDIT trail */ -int silent = 0; /* don't print the header lines */ -int fail = 0; - -matches *cmds = (matches *)0; - -void -mess_close(lp, id) -register lineio *lp; -register char *id; -{ - if (lp->l_fd != SYSERROR) - { - if (lclose(lp)) - { - fprintf(stderr, "%s: Warning - \"%s\" may be incomplete. %s\n", my_name, id, sysmess()); - fail = 1; - } - - if (close(lp->l_fd) == SYSERROR) - { - would_not("close", id); - fail = 1; - } - } -} - -char * -new_mess(lp, mb) -register lineio *lp; -register mbox *mb; -{ - register char *id; - register char *p; - register int fd; - static int first = 1; - - if (first) - { - if (mb->m_count == 0) - id = nextid(NULLSTR); - else - id = nextid(mb->m_list[mb->m_count - 1]); - - (void)set_current(mb->m_name, id); - first = 0; - } - else - { - id = nextid(mb->m_messid); - (void)free(mb->m_messid); - } - - p = concat3(mb->m_path, "/", id); - - if ((fd = creat(p, CREAT_MODE)) == SYSERROR) - { - lp->l_fd = SYSERROR; - lp->l_flag = LWRITE|LERROR; - fail = 1; - would_not("create", p); - } - else - (void)lopen(lp, fd, LWRITE); - - (void)free(p); - - return mb->m_messid = id; -} - -/* - * Maintain a cache (linked list) of boxes. - */ -boxes * -get_box(s) -register char *s; -{ - register boxes *bp; - register mbox *mb; - static boxes *all = (boxes *)0; - static boxes **n = &all; - - for (bp = all; bp != (boxes *)0; bp = bp->b_next) - { - if (strcmp(bp->b_mbox->m_name, s) == 0) - return bp; - } - - if ((mb = read_box(s)) == NULLBOX) - return (boxes *)0; - - bp = (boxes *)salloc(sizeof *bp); - bp->b_mbox = mb; - bp->b_messid = mb->m_count ? newstr(mb->m_list[mb->m_count - 1]) : NULLSTR; - bp->b_next = (boxes *)0; - - *n = bp; - n = &bp->b_next; - - return bp; -} - -/* - * Link two messages together. - */ -int -tag(box, id, target) -char *box; -char *id; -char *target; -{ - register char *curr; - register char *msg; - register boxes *bp; - register char *p; - int ok; - - ok = 0; - - if ((bp = get_box(target)) != (boxes *)0) - { - curr = concat3(mace_dir(), "/", p = concat3(box, "/", id)); - (void)free(p); - - msg = concat3(bp->b_mbox->m_path, "/", p = nextid(bp->b_messid)); - - if (bp->b_messid != NULLSTR) - (void)free(bp->b_messid); - - bp->b_messid = p; - - if (link(curr, msg) == -1) - would_not("link to", msg); - else - ok = 1; - - (void)free(msg); - (void)free(curr); - } - else - fprintf(stderr, "%s: Could not save \"%s\" in \"%s\". %s.\n", my_name, id, target, sysmess()); - - return ok; -} - -/* - * Match the regular expressions against the headers. - * - * This should be replaced by the more general regex_match(). - */ -int -save(cf, box, id, hdrs) -conf *cf; -char *box; -char *id; -char **hdrs; -{ - register char **n; - register match *mp; - int hit; - - hit = 0; - - for (mp = cf->c_save; mp != (match *)0; mp = mp->m_next) - { - for (n = hdrs; *n != NULLSTR && **n != '\0'; n++) - { - re_error = NULLSTR; - - if (regexec(mp->m_cre, *n) == 0) - { - if (re_error != NULLSTR) - { - fprintf(stderr, "%s: Regular expression \"%s\" %s\n", my_name, mp->m_re, re_error); - break; - } - - continue; - } - - if (tag(box, id, mp->m_action)) - hit = 1; - } - } - - return hit; -} - -/* - * Snarf away a regex match's private data. - */ -void -add_match(mp, box, id, private) -matches **mp; -char *box; -char *id; -char *private; -{ - matches *p; - - while (*mp != (matches *)0) - mp = &(*mp)->me_next; - - *mp = p = (matches *)salloc(sizeof (matches)); - p->me_box = newstr(box); - p->me_messid = newstr(id); - p->me_private = private; - p->me_next = (matches *)0; -} - -/* - * Match a list of regular expressions against a message's headers. - */ -void -regex_match(mp, box, id, hdrs, mlp) -match *mp; -char *box; -char *id; -char **hdrs; -matches **mlp; -{ - register char **n; - - while (mp != (match *)0) - { - for (n = hdrs; *n != NULLSTR && **n != '\0'; n++) - { - re_error = NULLSTR; - - if (regexec(mp->m_cre, *n) == 0) - { - if (re_error != NULLSTR) - { - fprintf(stderr, "%s: Regular expression \"%s\" %s\n", my_name, mp->m_re, re_error); - break; - } - - continue; - } - - add_match(mlp, box, id, mp->m_action); - } - - mp = mp->m_next; - } -} - -/* - * Take a list of matches and run the corresponding commands. - */ -void -run_matches(mp) -matches **mp; -{ - matches *p; - int fd; - lineio l; - char *av[2]; - - av[0] = defenv(ENV_SHELL, DEF_SHELL); - av[1] = NULLSTR; - - if ((fd = pipe_execv(av, 'w')) == SYSERROR) - { - would_not("pipe to", av[0]); - return; - } - - (void)lopen(&l, fd, LWRITE); - - while ((p = *mp) != (matches *)0 && (l.l_flag & LERROR) == 0) - { - (void)lwrite(&l, special_expand(p->me_private, p->me_box, p->me_messid)); - - (void)free(p->me_box); - (void)free(p->me_messid); - *mp = p->me_next; - (void)free((char *)p); - } - - if (lclose(&l)) - would_not("write pipe to", av[0]); - - if (pipe_close(fd) == SYSERROR) - would_not("close pipe to", av[0]); -} - -/* - * Simple RFC 822 canonical processing. - */ -int -rfc_peruse(cf, box, id, ps) -conf *cf; -char *box; -char *id; -char **ps; -{ - register char *p; - register char *q; - register char *s; - static char *agent = DELIVERY_AGENT; - static regexp *re = (regexp *)0; - static int bogus_from = 0; - static int prev_was_header = 0; - static char *from = NULLSTR; - static char *date = NULLSTR; - static vec hdr; - static char lwsp[2] = { RFC_LWSP_1, '\0'}; - extern char *strchr(); - - s = *ps; - - if (hdr.v_size == 0) - vec_init(&hdr, 64); - - if (agent != NULLSTR && re == (regexp *)0) - { - if ((re = regcomp(agent)) == (regexp *)0) - { - fprintf(stderr, "%s: Regular expression \"%s\" %s\n", my_name, agent, re_error); - agent = NULLSTR; - } - } - - if (*s == UNIX_FWD_CHAR) - { - /* - * Trash or keep misquoted headers gernerated by broken - * mailers in the middle of the message headers. - * - * Eg: - * From: foo - * >From foo ... # trash - * >From: foo # keep - * Date: ... - */ - if (prev_was_header) - { - if (!rfc_header(s + 1)) - free(s); - else - vec_str(&hdr, s); - - return 0; - } - - if (!bogus_from) - goto body; - - if (strncmp(s + 1, UNIX_FROM, (sizeof UNIX_FROM) - 1) != 0) - goto body; - - p = newstr(s + 1); - (void)free(s); - s = p; - } - - if (strncmp(s, UNIX_FROM, (sizeof UNIX_FROM) - 1) == 0) - { - if ((p = strchr(s, ' ')) == NULLSTR) - { - fprintf(stderr, "%s: Malformed \"%s\" line in mailbox.\n", my_name, UNIX_FROM); - (void)free(s); - return 0; - } - - q = ++p; - - while (*q != ' ' && *q != '\0') - q++; - - if (*q == ' ') - *q++ = '\0'; - - re_error = NULLSTR; - - if (re == (regexp *)0 || regexec(re, p) == 0) - { - if (re_error != NULLSTR) - { - fprintf(stderr, "%s: Regular expression \"%s\" %s\n", my_name, agent, re_error); - re = (regexp *)0; - } - - from = concat3(RFC_FROM, lwsp, p); - - /* - * Ensure removal of "remote from ...". - */ - for (p = q; *p != '\0'; p++) - { - if (p - q == UNIX_DATE_LEN) - { - *p = '\0'; - break; - } - } - - date = concat3(RFC_DATE, lwsp, p = rfc_cvt_date(q)); - (void)free(p); - bogus_from = 0; - } - else - bogus_from = 1; - - (void)free(s); - - return 0; - } - - /* - * This should be simpler but we can't guarantee - * RFC 822 compatibility in respect of the message - * body being preceeded by a blank line. After all, - * there are some V7 style mailers out there. - */ - - if (rfc_header(s)) - { - vec_str(&hdr, s); - prev_was_header = 1; - - return 0; - } - - /* - * Previous line was a header -- concatenate this header text. - */ - if (prev_was_header && (*s == RFC_LWSP_1 || *s == RFC_LWSP_2)) - { - vec_cat(&hdr, concat("\n", s)); - (void)free(s); - - return 0; - } - - /* - * End of headers and start of message body. - */ -body: - { - int hit; - extern long time(); - - vec_str(&hdr, NULLSTR); - - /* - * Fix the From: and Date: fields. - */ - if (find_header(hdr.v_list, RFC_FROM) == (char **)0) - { - if (from == NULLSTR) - from = concat3(RFC_FROM, lwsp, "Address Unknown "); - vec_cat(&hdr, from); - vec_str(&hdr, NULLSTR); - } - - if (find_header(hdr.v_list, RFC_DATE) == (char **)0) - { - if (date == NULLSTR) - { - date = concat3(RFC_DATE, lwsp, p = rfc_date(time((long *)0))); - (void)free(p); - } - - vec_cat(&hdr, date); - vec_str(&hdr, NULLSTR); - } - - if (*s != '\0') - { - vec_cat(&hdr, newstr("")); - vec_str(&hdr, s); - } - else - vec_cat(&hdr, s); - - vec_str(&hdr, NULLSTR); - - reorder_headers(&hdr); - - hit = save(cf, box, id, &hdr.v_list[0]); - - regex_match(cf->c_exec, box, id, &hdr.v_list[0], &cmds); - - if (!silent) - { - static int first = 1; - - print_summary(box, id, hdr.v_list, first, hit ? 2 : 1, 0, 0); - - first = 0; - } - - *ps = splice(&hdr.v_list[0], "\n"); - - (void)free(s); - - bogus_from = 0; - prev_was_header = 0; - from = NULLSTR; - date = NULLSTR; - vec_free(&hdr); - - return 1; - } -} - -/* - * This message has no body, so we fake it. - */ -int -botched_message(cf, mlp, box, id) -conf *cf; -register char *box; -register lineio *mlp; -register char *id; -{ - char *s; - - s = newstr(""); - - (void)rfc_peruse(cf, box, id, &s); - - if ((mlp->l_flag & LERROR) == 0 && lwrite(mlp, s) == NULLSTR) - fprintf(stderr, "%s: Warning - \"%s\" may be incomplete. %s\n", my_name, id, sysmess()); - - (void)free(s); - - return (mlp->l_flag & LERROR) != 0; -} - -int -mace(cf, mf, delete) -conf *cf; -char *mf; -int delete; -{ - register int fd; - register char *audit; - char *s; - register int text; - register mbox *mb; - lineio pld; - lineio ald; - lineio mld; - char *id; - char *despool; - extern long lseek(); - - if ((mb = read_box(cf->c_inbox)) == NULLBOX) - { - fprintf(stderr, "%s: Incoming box \"%s\" does not exist.\n", my_name, cf->c_inbox); - return 1; - } - - audit = concat3(mace_dir(), "/", AUDIT); - - if (just_unlock) - goto fix_locks; - - if (!mail_check(mf)) - return 1; - - if (set_box(cf->c_inbox)) - return 1; - - if (do_audit) - { - for (;;) - { - switch (lock(audit)) - { - case 0: - fd = open(audit, O_WRONLY); - - if (lseek(fd, 0L, 2) == SYSERROR) - { - (void)close(fd); - fd = SYSERROR; - unlock(audit); - } - break; - - case ENOENT: - if ((fd = creat(audit, 0666)) == SYSERROR) - break; - - continue; - - case EEXIST: - default: - fprintf(stderr, "%s: \"%s\" locked. %s\n", my_name, audit, sysmess()); - return 1; - } - - break; - } - - if (fd == SYSERROR) - { - would_not("create", audit); - return 1; - } - - (void)lopen(&ald, fd, LWRITE); - } - - despool = newstr(delete ? cf->c_despool : cf->c_peruse); - - if (mf != NULLSTR) - { - char *p; - - p = despool; - despool = concat3(p, " -f ", mf); - (void)free(p); - } - - if ((fd = pipe_open(despool, 'r')) == SYSERROR) - { - fail = 1; - would_not("pipe to", cf->c_despool); - goto fix_locks; - } - - (void)lopen(&pld, fd, LREAD); - - id = NULLSTR; - mld.l_fd = SYSERROR; - text = 0; - - while ((s = lread(&pld)) != NULLSTR) - { - if (strncmp(s, UNIX_FROM, (sizeof UNIX_FROM) - 1) == 0) - { - if (id != NULLSTR && text == 0 && botched_message(cf, &mld, mb->m_name, id)) - fail = 1; - - text = 0; - - mess_close(&mld, id); - - id = new_mess(&mld, mb); - } - - if - ( - do_audit - && - (ald.l_flag & LERROR) == 0 - && - lwrite(&ald, s) == NULLSTR - ) - { - would_not("write", audit); - fail = 1; - } - - if (!text && rfc_peruse(cf, mb->m_name, id, &s)) - text = 1; - - if (text) - { - if ((mld.l_flag & LERROR) == 0 && lwrite(&mld, s) == NULLSTR) - { - fprintf(stderr, "%s: Warning - \"%s\" may be incomplete. %s\n", my_name, id, sysmess()); - fail = 1; - } - - (void)free(s); - } - - if - ( - ( - (ald.l_flag & LERROR) != 0 - || - do_audit == 0 - ) - && - (mld.l_flag & LERROR) != 0 - ) - break; - } - - if (id != NULLSTR && text == 0 && botched_message(cf, &mld, mb->m_name, id)) - fail = 1; - - mess_close(&mld, id); - - if (do_audit) - { - if (lclose(&ald)) - { - fprintf(stderr, "%s: Warning - audit \"%s\" may be incomplete. %s\n", my_name, audit, sysmess()); - fail = 1; - } - - if (close(ald.l_fd) == SYSERROR) - { - would_not("close", audit); - fail = 1; - } - } - - if (lclose(&pld) != 0) - { - fprintf(stderr, "%s: \"%s\" line close error.\n", my_name, cf->c_despool, sysmess()); - fail = 1; - } - - if (pipe_close(fd) != 0) - { - fprintf(stderr, "%s: \"%s\" despooling error.\n", my_name, cf->c_despool, sysmess()); - fail = 1; - } - -fix_locks: - if (do_audit && unlock(audit) != 0) - would_not("unlock", audit); - - (void)free(audit); - - run_matches(&cmds); - - return fail; -} - -void -usage() -{ - fprintf(stderr, "usage: %s [ -dsu ] [ -f mailfile ]\n", my_name); - exit(1); - /* NOTREACHED */ -} - -int -main(argc, argv) -int argc; -char *argv[]; -{ - register int i; - register int j; - char *mail_file; - int delete; - - name(argv[0]); - mail_file = NULLSTR; - delete = 1; - - for (i = 1; i < argc; i++) - { - if (argv[i][0] != '-') - { - usage(); - /* NOTREACHED */ - } - - j = 1; - - while (argv[i][j] != '\0') - { - switch (argv[i][j++]) - { - case 'd': - do_audit = 0; - continue; - - case 's': - silent = 1; - continue; - - case 'u': - just_unlock = 1; - continue; - - case 'f': - if (mail_file != NULLSTR) - { - usage(); - /* NOTREACHED */ - } - - if (argv[i][j] != '\0') - mail_file = &argv[i][j]; - else if (++i < argc) - mail_file = argv[i]; - else - { - usage(); - /* NOTREACHED */ - } - - delete = 0; - break; - - default: - usage(); - /* NOTREACHED */ - } - - break; - } - } - - if (just_unlock && !do_audit) - { - usage(); - /* NOTREACHED */ - } - - /* - * Here's hoping... - */ - (void)signal(SIGHUP, SIG_IGN); - (void)signal(SIGINT, SIG_IGN); - (void)signal(SIGQUIT, SIG_IGN); - (void)signal(SIGTERM, SIG_IGN); - - exit(mace(read_config(), mail_file, delete)); - - /* NOTREACHED */ -} //GO.SYSIN DD mace.c echo mad.c sed 's/.//' >mad.c <<'//GO.SYSIN DD mad.c' -/* - * mad|mcp|mln +box messages... - * - * mad - add messages to a box - * - * mcp - copy messages to a box - */ - -#ifndef lint -static char sccsid[] = "@(#)mad.c 1.29"; -#endif - -#include "mace.h" -#include -#include - -int -mad(s, t) -register char *s; -register char *t; -{ - if - ( - link(s, t) == SYSERROR - || - unlink(s) == SYSERROR - ) - { - would_not("move", s); - (void)unlink(t); - return 1; - } - - return 0; -} - -int -mln(s, t) -register char *s; -register char *t; -{ - if (link(s, t) == SYSERROR) - { - would_not("link", s); - return 1; - } - - return 0; -} - -int -mcp(s, t) -register char *s; -register char *t; -{ - register int rfd; - register int wfd; - register int n; - char buf[FS_BLKZ]; - - if ((rfd = open(s, O_RD)) == SYSERROR) - { - would_not("open", s); - return 1; - } - - if ((wfd = creat(t, CREAT_MODE)) == SYSERROR) - { - (void)close(rfd); - would_not("create", t); - return 1; - } - - for (;;) - { - switch (n = read(rfd, buf, sizeof buf)) - { - case SYSERROR: - would_not("read", s); - goto disaster; - - case 0: - break; - - default: - if (write(wfd, buf, n) != n) - { - would_not("write", t); - goto disaster; - } - - continue; - } - - break; - } - - if (close(rfd) == SYSERROR) - { - (void)close(wfd); - (void)unlink(t); - return 1; - } - - if (close(wfd) == SYSERROR) - { - (void)unlink(t); - return 1; - } - - return 0; - -disaster: - (void)close(rfd); - (void)close(wfd); - (void)unlink(t); - - return 1; -} - -void -usage() -{ - fprintf(stderr, "usage: %s %cbox messages...\n", my_name, BOX_CHAR); - exit(1); - /* NOTREACHED */ -} - -int -main(argc, argv) -register int argc; -register char *argv[]; -{ - register mbox *mb; - register int i; - register char *id; - int (*action)(); - char *box; - int ok; - - name(argv[0]); - - if (strcmp(my_name, "mad") == 0) - action = mad; - else if (strcmp(my_name, "mcp") == 0) - action = mcp; - else if (strcmp(my_name, "mln") == 0) - action = mln; - else - { - fprintf(stderr, "%s: Invocation error.\n", my_name); - exit(1); - /* NOTREACHED */ - } - - if (argc < 3 || argv[1][0] != BOX_CHAR || argv[1][1] == '\0') - { - usage(); - /* NOTREACHED */ - } - - box = &argv[1][1]; - - if ((mb = read_box(box)) == NULLBOX) - { - fprintf(stderr, "%s: No such box as \"%s\".\n", my_name, box); - exit(1); - /* NOTREACHED */ - } - - if (mb->m_count == 0) - id = nextid(NULLSTR); - else - id = nextid(mb->m_list[mb->m_count - 1]); - - ok = 0; - - for (i = 2; i < argc; i++) - { - register char *p; - - p = concat3(mb->m_path, "/", id); - - signal(SIGHUP, SIG_IGN); - signal(SIGINT, SIG_IGN); - signal(SIGQUIT, SIG_IGN); - signal(SIGTERM, SIG_IGN); - - if ((*action)(argv[i], p)) - ok = 1; - else if (set_current(mb->m_name, id)) - ok = 1; - - signal(SIGHUP, SIG_DFL); - signal(SIGINT, SIG_DFL); - signal(SIGQUIT, SIG_DFL); - signal(SIGTERM, SIG_DFL); - - free(p); - p = id; - id = nextid(id); - free(p); - } - - return ok; -} //GO.SYSIN DD mad.c echo mal sed 's/.//' >mal <<'//GO.SYSIN DD mal' -#!/bin/sh -# -# @(#)mal 1.2 -# -# mal +box ... -# -# Mail aliasing based on a box's .proto -# - -dir="$HOME/.macedir" -bchar=+ -proto=.proto - -myname="`basename \"$0\"`" - -case $# in -0) - echo "usage: $myname ${bchar}box ..." 1>&2 - exit 1 - ;; -esac - -# find mail directory -if [ ! -r "$dir" ] -then - echo "$myname: Could not read '$dir'." 1>&2 - exit 1 -fi - -mdir="`cat \"$dir\"`" - -case "$mdir" in -"") - echo "$myname: '$dir' empty." 1>&2 - exit 1 - ;; - -/*) - # absolute pathname, ok - ;; - -*) - # relative pathname, so prepend $HOME - mdir="$HOME/$mdir" - ;; -esac - -for b -do - # use box to verify box name, but the usage message is a bit weird - if box -l "$b" > /dev/null - then - case "$b" in - ${bchar}*) - # slice off leading ${bchar} - b="`expr \"$b\" : \"^${bchar}\(.*\)$\"`" - ;; - esac - - # snarf To:/Cc:/Bcc: - sed -n \ - -e '/^[Tt][Oo][ ]*:[ ]*/s///p' \ - -e '/^[Cc][Cc][ ]*:[ ]*/s///p' \ - -e '/^[Bb][Cc][Cc][ ]*:[ ]*/s///p' \ - "$mdir/$b/$proto" 2> /dev/null - fi -done | sed -e '$n' -e 's/$/,/' # insert , between addresses //GO.SYSIN DD mal echo mam.c sed 's/.//' >mam.c <<'//GO.SYSIN DD mam.c' -/* - * mam [ -u ] [ -dps ] [ +[+]box ] [ files ] ... - * - * Read an RFC 822 message and add it to a box. - */ - -#ifndef lint -static char sccsid[] = "@(#)mam.c 1.5"; -#endif - -#include -#include -#include -#include -#include "mace.h" -#include "regexp.h" -#include "line.h" -#include "message.h" - -typedef struct boxes boxes; -typedef struct matches matches; - -struct boxes -{ - mbox *mbox; - char *messid; - int first; - boxes *next; -}; - -int just_unlock = 0; /* unlock the AUDIT trail */ -int do_audit = 1; /* create an AUDIT trail */ -int preserve = 0; /* preserve the current message */ -int silent = 0; /* don't print the header lines */ -int quit = 0; /* exit when ready */ -int errors = 0; /* error occured */ - -enum -{ - Lock = 0, /* lock audit file */ - Write, /* write to audit file */ - Unlock, /* unlock audit file */ -}; - -/* - * Maintain a cache (linked list) of boxes. - */ -boxes * -get_box(s) -register char *s; -{ - register boxes *bp; - register mbox *mb; - static boxes *all = (boxes *)0; - static boxes **n = &all; - - for (bp = all; bp != (boxes *)0; bp = bp->next) - { - if (strcmp(bp->mbox->m_name, s) == 0) - return bp; - } - - if ((mb = read_box(s)) == NULLBOX) - return (boxes *)0; - - bp = (boxes *)salloc(sizeof *bp); - bp->mbox = mb; - bp->messid = mb->m_count ? newstr(mb->m_list[mb->m_count - 1]) : NULLSTR; - bp->first = 1; - bp->next = (boxes *)0; - - *n = bp; - n = &bp->next; - - return bp; -} - -/* - * Manage the audit trail. - */ -void -audit(int type, char *s) -{ - static char *file = NULLSTR; - static lineio l = { SYSERROR, }; - - if (file == NULLSTR) - file = concat3(mace_dir(), "/", AUDIT); - - switch (type) - { - case Lock: - for (;;) - { - int fd; - - switch (lock(file)) - { - case 0: - fd = open(file, O_WRONLY); - - if (lseek(fd, 0L, 2) == SYSERROR) - { - (void)close(fd); - fd = SYSERROR; - unlock(file); - } - - lopen(&l, fd, LWRITE); - break; - - case ENOENT: - if ((fd = creat(file, CREAT_MODE)) == SYSERROR) - { - could_not("creat", file); - /* NOTREACHED */ - } - - continue; - - case EEXIST: - default: - fprintf(stderr, "%s: \"%s\" locked. %s\n", my_name, file, sysmess()); - exit(1); - /* NOTREACHED */ - } - - return; - } - - case Write: - if (l.l_fd == SYSERROR) - { - fatal("audit: not locked"); - /* NOTREACHED */ - } - - if ((l.l_flag & LERROR) != 0) - return; - - if (lwrite(&l, s) == NULLSTR) - { - would_not("write", file); - quit = 1; - } - break; - - case Unlock: - if (l.l_fd != SYSERROR && (l.l_flag & LERROR) == 0) - { - if (lclose(&l)) - { - fprintf(stderr, "%s: warning: '%s' incomplete. %s\n", my_name, file, sysmess()); - quit = 1; - } - - if (close(l.l_fd) == SYSERROR) - { - would_not("close", file); - quit = 1; - } - } - - if (unlock(file) != 0) - { - could_not("unlock", file); - /* NOTREACHED */ - } - - return; - - default: - fatal("audit: unknown type"); - /* NOTREACHED */ - } -} - -/* - * Catch a signal and force exit. - */ -void -signalled(int s) -{ - signal(s, SIG_IGN); - quit = 1; -} - -/* - * Arrange for signals to be caught. - */ -void -catch() -{ - int i; - static int sigs[] = - { - SIGHUP, - SIGINT, - SIGQUIT, - SIGTERM, - }; - static char *names[] = - { - "SIGHUP", - "SIGINT", - "SIGQUIT", - "SIGTERM", - }; - - for (i = 0; i < sizeof sigs / sizeof sigs[0]; i++) - { - SIG_RET (*f)(); - - if ((f = signal(sigs[i], signalled)) == (SIG_RET (*)())SYSERROR) - { - could_not("set signal", names[i]); - /* NOTREACHED */ - } - - if (f == SIG_DFL || f == SIG_IGN) - continue; - - if (signal(sigs[i], f) == (SIG_RET (*)())SYSERROR) - { - could_not("reset signal", names[i]); - /* NOTREACHED */ - } - } -} - -/* - * Close a line and it's file descriptor, handling errors. - */ -void -clunk(lineio *l, char *f, char *box, char *id) -{ - int fd; - int rw; - - if (l->l_flag == 0) - return; - - fd = l->l_fd; - rw = (l->l_flag & LWRITE) != 0; - - if (lclose(l)) - { - if (rw) - would_not("lclose", f); - else - fprintf(stderr, "%s: warning: %c%s %s may be incomplete. %s\n", my_name, BOX_CHAR, box, id, sysmess()); - - close(fd); - errors = 1; - return; - } - - if (close(fd) == SYSERROR) - { - would_not("close", f); - errors = 1; - } -} - -/* - * Write an audited line to a message file. - */ -void -awrite(lineio *l, char *s) -{ - if (do_audit) - audit(Write, s); - - if ((l->l_flag & LERROR) == 0) - lwrite(l, s); -} - -/* - * Read a file containing an RFC 822 message and add it to a box. - */ -void -mam(char *box, char *f) -{ - boxes *b; - char *id; - message *m; - int fd; - char *s; - char *new; - lineio in; - lineio out; - int first; - char **h; - - if ((b = get_box(box)) == 0) - { - fprintf(stderr, "%s: No such box as %c%s\n", my_name, BOX_CHAR, box); - errors = quit = 1; - return; - } - - first = 0; - id = b->messid = nextid(b->messid); - - /* - * Set first message to be current. - */ - if (preserve == 0 && b->first) - { - if (set_current(box, id) == 0) - { - first = 1; - b->first = 0; - } - else - errors = 1; - } - - /* - * Validate headers. - */ - if ((m = f != NULLSTR ? parse_file(f, &in) : parse_fd(fileno(stdin), &in)) == NULLMESS) - - { - would_not("parse", f != NULLSTR ? f : ""); - errors = 1; - return; - } - - if (!silent) - print_summary(box, id, m->ms_headers.v_list, first, 1, 0, 0); - - /* - * Copy the file into the new message with auditing. - */ - out.l_flag = 0; - - new = concat3(b->mbox->m_path, "/", id); - - if ((fd = creat(new, CREAT_MODE)) == SYSERROR) - { - would_not("create", new); - errors = 1; - goto finish; - } - - lopen(&out, fd, LWRITE); - - /* - * Write out headers. - */ - reorder_headers(&m->ms_headers); - - for (h = m->ms_headers.v_list; (s = *h) != NULLSTR; h++) - awrite(&out, s); - - free_mess(m); - - /* - * Write separator between headers and body. - */ - awrite(&out, ""); - - /* - * Write out message body. - */ - while ((s = lread(&in)) != NULLSTR && !quit) - { - awrite(&out, s); - free(s); - } - -finish: - clunk(&in, f, box, id); - clunk(&out, new, box, id); -} - -void -usage() -{ - fprintf(stderr, "usage: %s [ -u ] [ -dps ] [ +[+]box ] [ files ] ... \n", my_name); - exit(1); - /* NOTREACHED */ -} - -int -main(int argc, char *argv[]) -{ - int i; - int j; - char *box; - int filter; - - name(argv[0]); - - for (i = 1; i < argc; i++) - { - if (argv[i][0] != '-') - break; - - j = 1; - - while (argv[i][j] != '\0') - { - switch (argv[i][j++]) - { - case 'd': - do_audit = 0; - continue; - - case 'p': - preserve = 1; - continue; - - case 's': - silent = 1; - continue; - - case 'u': - just_unlock = 1; - continue; - - default: - usage(); - /* NOTREACHED */ - } - - break; - } - } - - if (just_unlock) - { - if (argc > 2) - { - usage(); - /* NOTREACHED */ - } - - audit(Unlock, NULLSTR); - exit(0); - /* NOTREACHED */ - } - - if ((box = curr_box()) == NULLSTR) - { - fprintf(stderr, "%s: No current box.\n", my_name); - exit(1); - /* NOTREACHED */ - } - - catch(); - - if (do_audit) - audit(Lock, NULLSTR); - - filter = 1; - - while (i < argc && !quit) - { - /* - * New box to pick messages from? - */ - if (argv[i][0] == BOX_CHAR) - { - /* - * Change current box? - */ - if (argv[i][1] == BOX_CHAR) - { - box = newstr(&argv[i][2]); - - if (set_box(box)) - { - quit = errors = 1; - filter = 0; - break; - } - } - else - box = &argv[i][1]; - } - else - { - mam(box, argv[i]); - filter = 0; - } - - i++; - } - - if (filter) - mam(box, NULLSTR); - - if (do_audit) - audit(Unlock, NULLSTR); - - exit(errors); - return errors; -} //GO.SYSIN DD mam.c echo mda.c sed 's/.//' >mda.c <<'//GO.SYSIN DD mda.c' -/* - * mda messages... - * - * Message delivery agent. - */ - -#ifndef lint -static char sccsid[] = "@(#)mda.c 1.31"; -#endif - -#include -#include -#include -#include -#include -#include -#include "mace.h" -#include "regexp.h" -#include "line.h" -#include "message.h" -#include "conf.h" -#include "headers.h" -#include "addr.h" - -/* - * Turn an RFC 822 address into a network address argument. - */ -char * -net_address(vp, s) -register vec *vp; -register char *s; -{ - register char *p; - register Addr *ap; - Addr *addrs; - - if ((p = parse_address(&addrs, s)) != NULLSTR) - return p; - - for (ap = addrs; ap != (Addr *)0; ap = ap->next) - vec_str(vp, make_address(ap)); - - return NULLSTR; -} - -/* - * Add multiple To:/Cc:/Bcc lines to a list of recipients. - * - * Returns 0 on success, 1 on failure. - */ -int -add_multiple(char *m, vec *list, char **h, char *type) -{ - int n; - - n = 0; - - while (*h != NULLSTR) - { - if (rfc_hdr_cmp(*h, type)) - { - char *p; - - if ((p = header_text(*h)) == NULLSTR) - { - /* Empty Bcc: is ok */ - if (strcmp(type, RFC_BCC) != 0) - { - fprintf(stderr, "%s: \"%s\": Malformed \"%s\" field.\n", my_name, m, type); - return 1; - } - } - else if ((p = net_address(list, p)) != NULLSTR) - { - fprintf(stderr, "%s: \"%s\": \"%s\" address error; %s\n", my_name, m, type, p); - return 1; - } - - n++; - } - - h++; - } - - /* Only one From: allowed */ - if (strcmp(type, RFC_FROM) == 0 && n > 1) - { - fprintf(stderr, "%s: \"%s\": Multiple \"%s\" fields.\n", my_name, m, RFC_FROM); - return 1; - } - - return 0; -} - -/* - * Check From: field(s). - * - * Returns 0 on success, 1 on failure. - */ -int -from(char *m, char **h) -{ - vec v; - int n; - int fail; - - fail = 0; - - vec_init(&v, 32); - - if (add_multiple(m, &v, h, RFC_FROM)) - fail = 1; - - n = v.v_count; - vec_free(&v); - - if (fail) - return fail; - - /* - * Check there is a Sender: field if more than one address in - * the From: field has been specified. - */ - if (n <= 1) - return 0; - - if - ( - (h = find_header(h, RFC_SENDER)) != (char **)NULLSTR - && - header_text(*h) != NULLSTR - ) - return 0; - - fprintf(stderr, "%s: \"%s\": Multiple \"%s\" addresses require a \"%s\" field.\n", my_name, m, RFC_FROM, RFC_SENDER); - return 1; -} - -#if RFC_DELIVERER == 0 - -/* - * Pipe the message into the delivery agent after some validation. - */ -int -deliver(d, m) -char *d; -char *m; -{ - char *p; - message *mp; - char **h; - lineio mld; - lineio pld; - vec args; - int mfd; - int pfd; - int headers; - static char *dests[] = { RFC_TO, RFC_CC, RFC_BCC, NULLSTR }; - - /* - * Read its headers. - */ - if ((mp = parse_file(m, 0)) == NULLMESS) - { - would_not("open", m); - return 1; - } - - vec_init(&args, 32); - - /* - * Date: field? - */ - if - ( - (h = find_header(&mp->ms_headers.v_list[0], RFC_DATE)) == (char **)NULLSTR - || - header_text(*h) == NULLSTR - ) - { - fprintf(stderr, "%s: \"%s\": Missing \"%s\" field.\n", my_name, m, RFC_DATE); - goto disaster; - } - - /* - * From: field(s)? - */ - if (from(m, mp->ms_headers.v_list)) - goto disaster; - - vec_str(&args, d); - - /* - * Add destination(s). - */ - for (h = dests; *h != NULLSTR; h++) - { - if (add_multiple(m, &args, mp->ms_headers.v_list, *h)) - goto disaster; - } - - if (args.v_count == 1) - { - fprintf(stderr, "%s: \"%s\": No destination.\n", my_name, m); - goto disaster; - } - - vec_str(&args, NULLSTR); - - /* - * Pipe it into the delivery agent. - */ - if ((mfd = open(m, O_RD)) == SYSERROR) - { - would_not("open", m); - goto disaster; - } - - (void)lopen(&mld, mfd, LREAD); - - if ((pfd = pipe_execv(args.v_list, 'w')) == -1) - { - would_not("pipe to", args.v_list[0]); - (void)lclose(&mld); - (void)close(mfd); - goto disaster; - } - - (void)lopen(&pld, pfd, LWRITE); - - for (h = mp->ms_headers.v_list; *h != NULLSTR; h++) - { - if (header_text(*h) == NULLSTR || rfc_hdr_cmp(*h, RFC_BCC)) - continue; - - if (lwrite(&pld, *h) == NULLSTR) - goto failure; - } - - headers = 1; - - while ((p = lread(&mld)) != NULLSTR) - { - if (headers) - { - if (*p != '\0') - { - (void)free(p); - continue; - } - - headers = 0; - } - - if (lwrite(&pld, p) == NULLSTR) - { - (void)free(p); - break; - } - - (void)free(p); - } - -failure: - if (lclose(&mld)) - { - would_not("read", m); - - (void)close(mfd); - (void)lclose(&pld); - (void)pipe_close(pfd); - goto disaster; - } - - (void)close(mfd); - - if (lclose(&pld)) - { - would_not("deliver", m); - (void)pipe_close(pfd); - goto disaster; - } - - if (pipe_close(pfd)) - { - would_not("deliver", m); - goto disaster; - } - - free_mess(mp); - vec_free(&args); - return 0; - -disaster: - free_mess(mp); - vec_free(&args); - return 1; -} - -#else - -#if RFC_VALIDATE != 0 - -/* - * Check that the supplied headers in the message are ok. If evils - * like `sendmail' were half way sane this wouldn't be necessary, - * but I'm sick of getting mail from `mailer-daemon' about garbled - * headers, that should have been barfed on at invocation. - */ -int -headers_ok(m) -char *m; -{ - char **cp; - message *mp; - int fail; - vec v; - static char *check[] = { RFC_TO, RFC_CC, RFC_BCC, NULLSTR, }; - - fail = 0; - - /* - * Read its headers. - */ - if ((mp = parse_file(m, 0)) == NULLMESS) - { - would_not("open", m); - return 1; - } - - /* - * From: field(s)? - */ - if (from(m, mp->ms_headers.v_list)) - fail = 1; - - vec_init(&v, 32); - - /* - * Check the specified headers. - */ - for (cp = check; *cp != NULLSTR; cp++) - { - if (add_multiple(m, &v, mp->ms_headers.v_list, *cp)) - fail = 1; - } - - if (v.v_count == 0) - { - fprintf(stderr, "%s: \"%s\": No destination.\n", my_name, m); - fail = 1; - } - - (void)free_mess(mp); - vec_free(&v); - return fail; -} - -#endif - -/* - * The delivery agent understands about the recipients - * being embedded in the message itself. - */ -int -deliver(d, m) -char *d; -char *m; -{ - register int fd; - register int ok; - register char *agent = DELIVERER; - char *argv[2]; - - if (agent == NULLSTR) - { - fatal("deliver"); - /* NOTREACHED */ - } - - (void)close(0); - - if ((fd = open(m, O_RD)) != 0) - { - would_not("open", m); - (void)close(fd); - return 1; - } - -#if RFC_VALIDATE != 0 - - if (headers_ok(m)) - { - (void)close(fd); - return 1; - } - -#endif - - argv[0] = d; - argv[1] = NULLSTR; - - ok = run(argv); - - if (close(0) == SYSERROR) - { - would_not("close", m); - ok = 1; - } - - return ok; -} - -#endif - -void -usage() -{ - fprintf(stderr, "usage: %s messages...\n", my_name); - exit(1); - /* NOTREACHED */ -} - -int -main(argc, argv) -int argc; -char *argv[]; -{ - register int i; - register conf *cf; - register int ok; - - name(argv[0]); - - if (argc < 2) - { - usage(); - /* NOTREACHED */ - } - - cf = read_config(); - - ok = 0; - - for (i = 1; i < argc; i++) - { - if (deliver(cf->c_deliver, argv[i]) || set_state(argv[i], MESG_SENT)) - ok = 1; - } - - exit(ok); - /* NOTREACHED */ -} //GO.SYSIN DD mda.c echo mox.c sed 's/.//' >mox.c <<'//GO.SYSIN DD mox.c' -/* - * mox [ -ds ] [ -delete ] - * - * Add messages, one per file, from a directory with mam. - * Sort of like mace, but not quite. - */ - -#ifndef lint -static char sccsid[] = "@(#)mox.c 1.2"; -#endif - -#include -#include -#include -#include -#include "mace.h" -#include "regexp.h" -#include "line.h" -#include "message.h" -#include "conf.h" - -int delete = 0; /* delete files from spool directory */ -char *_delete = "-delete"; -int do_audit = 1; /* create an AUDIT trail */ -int silent = 0; /* don't print message summary */ - -/* - * Link a message into another box by calling 'lnk'. - */ -void -refile(char *inbox, message *m, match *re) -{ - char *args[6]; - int i; - int bi; - int bo; - - args[i = 0] = LNK_STR; - args[bi = ++i] = concat(" ", inbox); - args[bi][0] = BOX_CHAR; - args[++i] = m->ms_messid; - args[bo = ++i] = concat(" ", re->m_action); - args[bo][0] = BOX_CHAR; - args[++i] = NULLSTR; - - if (run(args) == 0) - m->ms_copies++; - - free(args[bi]); - free(args[bo]); -} - -/* - * Run a command with a message. - */ -void -command(char *inbox, message *m, match *re) -{ - char *args[2]; - int i; - - /* we know that run calls sh -c */ - args[i = 0] = special_expand(re->m_action, inbox, m->ms_messid); - args[++i] = NULLSTR; - - run(args); -} - -/* - * Invoke 'mam' to add a message to a box returning the newly created message. - * - * Returns NULLMESS on failure. - */ -message * -mam(char *inbox, char *file, int first) -{ - message *m; - char *args[7]; - mbox *b; - int i; - int bi; - - /* - * Invoke mam, silently, preserving the first message added to the box. - */ - args[i = 0] = MAM_STR; - args[++i] = "-s"; - if (!first) - args[++i] = "-p"; - if (!do_audit) - args[++i] = "-d"; - args[bi = ++i] = concat(" ", inbox); - args[bi][0] = BOX_CHAR; - args[++i] = file; - args[++i] = NULLSTR; - - if (run(args) || (b = read_box(inbox)) == NULLBOX) - { - free(args[bi]); - return NULLMESS; - } - - free(args[bi]); - - /* - * Newly added message will be the last in the box. - */ - if (b->m_count == 0 || (m = read_mess(b, b->m_list[b->m_count - 1])) == NULLMESS) - { - free_box(b); - return NULLMESS; - } - - free_box(b); - return m; -} - -/* - * Treat each file in a directory as a mail message passing - * it to 'mam' and matching it against regular expressions. - */ -int -mox() -{ - conf *cf; - char **dir; - char **d; - int first; - int fail; - - first = 1; - fail = 0; - - cf = read_config(); - - if (cf->c_spooldir == NULLSTR) - { - fprintf(stderr, "%s: Specification of \"%s\" missing from \"%s/%s\".\n", my_name, CT_SPOOLDIR, mace_dir(), CONFIG); - return 1; - } - - dir = read_dir(cf->c_spooldir); - - for (d = dir; *d != NULLSTR; d++) - { - char *f; - message *m; - - f = concat3(cf->c_spooldir, "/", *d); - - if ((m = mam(cf->c_inbox, f, first)) == NULLMESS) - { - free(f); - fail = 1; - continue; - } - - if (first && set_box(cf->c_inbox)) - fail = 1; - - /* - * Summarise after the refile's but before the exec's. - * This way the output is more meaningful. - */ - regex_apply(cf->c_inbox, m, cf->c_refile, refile); - - if (!silent) - print_summary(cf->c_inbox, m->ms_messid, m->ms_headers.v_list, first, m->ms_copies, 0, m->ms_state); - - regex_apply(cf->c_inbox, m, cf->c_exec, command); - - free_mess(m); - first = 0; - - if (delete && unlink(f) == SYSERROR) - { - would_not("unlink", f); - fail = 1; - } - - free(f); - } - - free_dir(dir); - return fail; -} - -void -usage() -{ - fprintf(stderr, "usage: %s [ -ds ] [ %s ]\n", my_name, _delete); - exit(1); - /* NOTREACHED */ -} - -int -main(int argc, char *argv[]) -{ - int i; - int j; - - name(argv[0]); - - for (i = 1; i < argc; i++) - { - if (argv[i][0] != '-') - { - usage(); - /* NOTREACHED */ - } - - j = 1; - - while (argv[i][j] != '\0') - { - switch (argv[i][j++]) - { - case 's': - silent = 1; - continue; - - case 'd': - /* this is not good */ - if (strcmp(argv[i], _delete) != 0) - { - do_audit = 0; - continue; - } - - delete = 1; - break; - - default: - usage(); - /* NOTREACHED */ - } - - break; - } - } - - exit(mox()); - return 0; /* shut up! */ - /* NOTREACHED */ -} //GO.SYSIN DD mox.c echo msg.c sed 's/.//' >msg.c <<'//GO.SYSIN DD msg.c' -/* - * msg - show messages - */ - -#ifndef lint -static char sccsid[] = "@(#)msg.c 1.39"; -#endif - -#include -#include -#include -#include "mace.h" -#include "flex.h" -#include "line.h" -#include "message.h" - -char *target = NULLSTR; /* target box for mov|cop|lnk */ -char *new_box = NULLSTR; /* new current box */ - -int -apply(it, v) -register char *it; -register vec *v; -{ - register int i; - register char **n; - register char **argv; - int s; - - argv = n = (char **)salloc((int)((v->v_count + 2) * sizeof(char *))); - - *n++ = it; - - for (i = 0; i < v->v_count; i++) - *n++ = v->v_list[i]; - - *n = NULLSTR; - - s = run(argv); - - (void)free((char *)argv); - - return s != 0; -} - -int -msg(v) -register vec *v; -{ - return apply(defenv(ENV_PAGER, DEF_PAGER), v); -} - -int -med(v) -register vec *v; -{ - return apply(defenv(ENV_EDITOR, DEF_EDITOR), v); -} - -int -rem(v) -register vec *v; -{ - register int i; - int ok; - - ok = 0; - - for (i = 0; i < v->v_count; i++) - { - if (unlink(v->v_list[i]) == SYSERROR) - { - would_not("unlink", v->v_list[i]); - ok = 1; - } - } - - return ok; -} - -int -invoke_alias(s, v) -register char *s; -register vec *v; -{ - register char *what; - register char *q; - int ok; - char p[2]; - - p[0] = BOX_CHAR; - p[1] = '\0'; - - q = concat(p, target); - what = concat3(s, " ", q); - free(q); - - ok = apply(what, v); - - free(what); - - return ok; -} - -int -mov(v) -register vec *v; -{ - return invoke_alias(MAD_STR, v); -} - -int -cop(v) -register vec *v; -{ - return invoke_alias(MCP_STR, v); -} - -int -lnk(v) -register vec *v; -{ - return invoke_alias(MLN_STR, v); -} - -int -del(v) -register vec *v; -{ - return apply(MDA_STR, v); -} - -int -mrk(v) -register vec *v; -{ - register char *p; - register int i; - char *ids; - flex f; - int ok; - - flex_init(&f); - ok = 0; - - for (i = 0; i < v->v_count; i++) - { - char *b; - char *m; - - path_to_mess(v->v_list[i], &b, &m); - - (void)set_state(v->v_list[i], MESG_MARK); - - flex_char(&f, BOX_CHAR); - flex_str(&f, b); - flex_char(&f, ' '); - flex_str(&f, m); - flex_char(&f, '\n'); - - (void)free(b); - } - - if ((ids = read_file(p = concat3(mace_dir(), "/", MARK))) != NULLSTR) - flex_str(&f, ids); - else - f.f_ptr--; /* yuk */ - - flex_char(&f, '\0'); - - if (write_file(p, f.f_str)) - { - would_not("write", p); - ok = 1; - } - - (void)free(p); - flex_end(&f); - - return ok; -} - -void -usage() -{ - fprintf(stderr, "usage: %s [ [%c]%cbox ] [ first|previous|current|next|last|id|all ] ...\n", my_name, BOX_CHAR, BOX_CHAR); - exit(1); - /* NOTREACHED */ -} - -void -busage() -{ - fprintf(stderr, "usage: %s [ [%c]%cbox ] [ first|previous|current|next|last|id|all ] ... [%c]%cbox\n", my_name, BOX_CHAR, BOX_CHAR, BOX_CHAR, BOX_CHAR); - exit(1); - /* NOTREACHED */ -} - -int -main(argc, argv) -int argc; -char *argv[]; -{ - register int i; - int (*action)(); - vec mvec; - - name(argv[0]); - - if (strcmp(my_name, MSG_STR) == 0 || strcmp(my_name, "-") == 0) - action = msg; - else if (strcmp(my_name, REM_STR) == 0) - action = rem; - else if (strcmp(my_name, MED_STR) == 0) - action = med; - else if (strcmp(my_name, MOV_STR) == 0) - action = mov; - else if (strcmp(my_name, DEL_STR) == 0 || strcmp(my_name, "+") == 0) - action = del; - else if (strcmp(my_name, COP_STR) == 0) - action = cop; - else if (strcmp(my_name, LNK_STR) == 0) - action = lnk; - else if (strcmp(my_name, "mrk") == 0) - action = mrk; - else - { - fprintf(stderr, "%s: Invocation error.\n", my_name); - exit(1); - /* NOTREACHED */ - } - - vec_init(&mvec, 64); - - if (action == mov || action == cop || action == lnk) - { - char *p; - - if (argv[--argc][0] != BOX_CHAR) - { - busage(); - /* NOTREACHED */ - } - - if (*(target = &argv[argc][1]) == BOX_CHAR) - new_box = ++target; - - if (*target == '\0') - { - busage(); - /* NOTREACHED */ - } - - if ((p = check_box(target)) == NULLSTR) - { - fprintf(stderr, "%s: No such box as \"%s\".\n", my_name, target); - exit(1); - } - - (void)free(p); - } - - args_to_messages(argc, argv, &mvec, &new_box); - - if - ( - (new_box != NULLSTR && set_box(new_box)) - || - mvec.v_count == 0 - || - (*action)(&mvec) - ) - { - exit(1); - /* NOTREACHED */ - } - - if (action == cop || action == mov || action == lnk) - { - exit(0); - /* NOTREACHED */ - } - - /* set current messages */ - { - char *b; - char *m; - char *pm; - char *pb; - int ok; - - ok = 0; - - path_to_mess(mvec.v_list[i = 0], &pb, &pm); - - while (++i < mvec.v_count) - { - path_to_mess(mvec.v_list[i], &b, &m); - - if (strcmp(b, pb) != 0 && set_current(pb, pm)) - ok = 1; - - (void)free(pb); - pb = b; - pm = m; - } - - if (set_current(pb, pm)) - ok = 1; - - exit(ok); - /* NOTREACHED */ - } -} //GO.SYSIN DD msg.c echo pop.c sed 's/.//' >pop.c <<'//GO.SYSIN DD pop.c' -/* - * @(#)pop.c 1.4 - * - * pop [ -delete ] [ -n number ] [ -r [ seconds ] ] [ -s spooldir ] [ -t ] [ [user@]server ] - * - * POP 3 (RFC 1225) client. - */ - -#include "mace.h" -#include "line.h" -#include "flex.h" -#include "pop.h" -#include -#include -#include -#include -#include -#include -#include - -/* - * POP3 states - */ -enum -{ - Idle, - Authorization, - Transaction, - Retrieving, - Delete, - Done, -}; - -/* - * POP3 responses - */ -enum -{ - Ok, - Error, - End, - Data, - IoError, - Broken, -}; - -/* - * POP3 session termination states. - */ -enum -{ - Complete = 0, - NoMail, - PopError, - AuthError, -}; - -enum -{ - Timeout = 120 -}; - -typedef struct sig sig; - -struct sig -{ - int s; - char *name; - SIG_RET (*f)(int); -}; - -char *_delete = "-delete"; -char *localhost = "localhost"; - -char *user = NULLSTR; -char *server = NULLSTR; -char *spooldir = NULLSTR; -ulong number = 0L; -ulong retry = 0L; - -int delete = 0; -int trace = 0; -int state = Idle; -int signaled = 0; - -lineio tx; -lineio rx; - -SIG_RET catch(int); - -/* - * Signal dispositions when run in the foreground. - */ -sig foreground[] = -{ - { SIGHUP, "SIGHUP", catch, }, - { SIGINT, "SIGINT", catch, }, - { SIGQUIT, "SIGQUIT", catch, }, - { SIGTERM, "SIGTERM", catch, }, - { 0, NULLSTR, 0, }, -}; - -/* - * Signal dispositions when run in the background. - */ -sig background[] = -{ - { SIGHUP, "SIGHUP", catch, }, - { SIGINT, "SIGINT", SIG_IGN, }, - { SIGQUIT, "SIGQUIT", SIG_IGN, }, - { SIGTERM, "SIGTERM", SIG_IGN, }, - { 0, NULLSTR, 0, }, -}; - -/* - * Finish communicating with the POP server, handling errors. - */ -void -finish() -{ - char *r; - - switch (state) - { - case Idle: - case Done: - break; - - case Delete: - state = Transaction; - request(POP_CMD_RSET, NULLSTR, &r); - if (state == Done) - break; - - /* fall though */ - - case Authorization: - case Transaction: - state = Done; - request(POP_CMD_QUIT, NULLSTR, &r); - break; - - case Retrieving: - state = Done; - break; - - default: - fatal("unknown POP3 state"); - /* NOTREACHED */ - } - - if (state == Done) - { - int s; - - s = rx.l_fd; - lclose(&rx); - lclose(&tx); - close(s); - - state = Idle; - } -} - -/* - * Read a reply from the server, returning the text and the reply type. - */ -int -reply(char **r) -{ - static char *rcvd = NULLSTR; - - if (rcvd != NULLSTR) - free(rcvd); - - if ((rcvd = lread(&rx)) == NULLSTR) - { - fprintf(stderr, "%s: Server '%s' closed connection.\n", my_name, server); - state = Done; - finish(); - return IoError; - } - - *r = rcvd; - - if (trace) - fprintf(stderr, "%s: <-- %s\n", my_name, *r); - - if (state != Retrieving) - { - if (*rcvd == '\0') - { - finish(); - return Broken; - } - - if (strncmp(rcvd, POP_REP_OK, sizeof POP_REP_OK - 1) == 0) - { - *r += sizeof POP_REP_OK - 1; - return Ok; - } - - if (strncmp(rcvd, POP_REP_ERR, sizeof POP_REP_ERR - 1) == 0) - { - *r += sizeof POP_REP_ERR - 1; - fprintf(stderr, "%s: [%s] %s\n", my_name, server, *r); - finish(); - return Error; - } - } - - if (rcvd[0] == POP_REP_TCHAR && rcvd[1] == '\0') - return End; - - return Data; -} - -/* - * Signal catcher - */ -SIG_RET -catch(int s) -{ - signal(s, SIG_IGN); - signaled = 1; -} - -/* - * Set up signal defaults. - */ -void -signals(sig *s) -{ - while (s->s != 0) - { - if (signal(s->s, s->f) == (SIG_RET (*)())SYSERROR) - could_not("signal", s->name); - - s++; - } -} - -/* - * Send a request to the server and return the reply. - */ -int -request(char *cmd, char *arg, char **r) -{ - static flex f = { NULLSTR, NULLSTR, NULLSTR, }; - - if (f.f_str == NULLSTR) - flex_init(&f); - - if (trace) - fprintf(stderr, arg == NULLSTR ? "%s: --> %s\n" : "%s: --> %s %s\n", my_name, cmd, strcmp(cmd, POP_CMD_PASS) == 0 ? "..." : arg); - - flex_str(&f, cmd); - - if (arg != NULLSTR) - { - flex_char(&f, ' '); - flex_str(&f, arg); - } - - flex_char(&f, '\0'); - flex_end(&f); - - if (lwrite(&tx, f.f_str) == NULLSTR) - { - state = Done; - finish(); - return IoError; - } - - return reply(r); -} - -/* - * Manage the user typed password in a pipe. - */ -char * -password() -{ - char *p; - static int fds[2] = { SYSERROR, SYSERROR }; - static char buf[POP_PASS_LEN + 1]; - static int l; - - /* - * Return user typed password. - */ - if (fds[0] != SYSERROR) - { - if (read(fds[0], buf, l) != l) - { - could_not("read password for", user); - /* NOTREACHED */ - } - - if (write(fds[1], buf, l) != l) - { - could_not("write password for", user); - /* NOTREACHED */ - } - - buf[l] = '\0'; - return buf; - } - - /* - * Read password and write it into the pipe. - */ - if (pipe(fds) == SYSERROR) - { - could_not("create pipe for", server); - /* NOTREACHED */ - } - - if ((p = readpass("password: ")) == NULLSTR) - p = ""; - - if ((l = strlen(p)) > POP_PASS_LEN) - fprintf(stderr, "%s: Password too long, truncated to %d charecters.\n", my_name, server, POP_PASS_LEN); - - strncpy(buf, p, POP_PASS_LEN); - memset(p, '\0', l); - buf[POP_PASS_LEN] = '\0'; - l = strlen(buf); - - if (write(fds[1], buf, l) != l) - { - could_not("write password for", user); - /* NOTREACHED */ - } - - return buf; -} - -/* - * Create a new file for a message. Returns 0 on success, 1 on failure. - */ -int -newfile(flex *file, lineio *out, char *n) -{ - int fd; - - if (file->f_str == NULLSTR) - return 1; - - if (spooldir != NULLSTR) - { - flex_str(file, spooldir); - flex_char(file, '/'); - } - - flex_str(file, n); - flex_char(file, '\0'); - flex_end(file); - - if ((fd = creat(file->f_str, 0200)) == SYSERROR) - { - would_not("creat", file->f_str); - return 1; - } - - lopen(out, fd, LWRITE); - return 0; -} - -/* - * Close a message's file for a message. Returns 0 on success, 1 on failure. - */ -int -closefile(flex *file, lineio *out) -{ - int fail; - - if (file->f_str == NULLSTR || (out->l_flag & LWRITE) == 0) - return 1; - - fail = 0; - - if ((out->l_flag & LERROR) == 0) - { - if (lclose(out)) - { - would_not("lclose", file->f_str); - fail = 1; - } - } - else - fail = 1; - - if (close(out->l_fd) == SYSERROR) - { - would_not("close", file->f_str); - fail = 1; - } - - if (!fail && chmod(file->f_str, 0600) == SYSERROR) - { - would_not("chmod", file->f_str); - fail = 1; - } - - if (fail && unlink(file->f_str) == SYSERROR) - would_not("unlink", file->f_str); - - return fail; -} - -/* - * Receive mail with POP3 on a socket. - */ -int -pop3(int s) -{ - char *r; - lineio out; - char *pass; - ulong messages; - ulong size; - ulong i; - int rs; - int spoolfull; - flex file; - - flex_init(&file); - lopen(&rx, s, LREAD|LCRLF); - lopen(&tx, s, LWRITE|LCRLF|LLBUF); - out.l_flag = 0; - - /* - * Server up? - */ - state = Idle; - - if (reply(&r) != Ok) - return PopError; - - /* - * Send user name and password. - */ - state = Authorization; - - switch (request(POP_CMD_USER, user, &r)) - { - case Ok: - break; - - case Error: - return AuthError; - - default: - return PopError; - } - - rs = request(POP_CMD_PASS, pass = password(), &r); - memset(pass, '\0', strlen(pass)); - - switch (rs) - { - case Ok: - break; - - case Error: - return AuthError; - - default: - return PopError; - } - - /* - * Inquire maildrop state. - */ - state = Transaction; - - if (request(POP_CMD_STAT, NULLSTR, &r) != Ok) - return PopError; - - switch (sscanf(r, "%lu %lu", &messages, &size)) - { - case 1: - fprintf(stderr, "%s: %d message%s for '%s@%s', maildrop size unknown.\n", my_name, messages, messages == 1 ? "" : "s", user, server); - size = 0; - break; - - case 2: - if (messages == 0 && retry == 0) - { - fprintf(stderr, "%s: No messages for '%s@%s'.\n", my_name, user, server); - return NoMail; - } - - break; - - default: - fprintf(stderr, "%s: Unknown number of messages for '%s@%s'.\n", my_name, user, server); - return PopError; - } - - /* - * Retrieve each message. - */ - i = 1; - - while (i <= messages && !signaled) - { - char n[16]; - - sprintf(n, "%lu", i); - - if (request(POP_CMD_RETR, n, &r) != Ok) - return PopError; - - state = Retrieving; - - sprintf(n, "%ld", number); - - if (newfile(&file, &out, n)) - out.l_flag |= LERROR; - - for (;;) - { - switch (reply(&r)) - { - case End: - /* - * Quit when we've received a message after - * an I/O error on the message spool. - */ - if (closefile(&file, &out)) - { - i--; - goto break2; - } - - i++; - number++; - break; - - case Data: - if ((out.l_flag & LERROR) == 0 && lwrite(&out, &r[*r == POP_REP_TCHAR]) == NULLSTR) - would_not("write", file.f_str); - - continue; - - case IoError: - case Broken: - closefile(&file, &out); - return PopError; - - case Ok: - fatal("bogus POP3 OK reply"); - /* NOTREACHED */ - - default: - fatal("unknown POP3 reply"); - /* NOTREACHED */ - } - - break; - } - - state = Transaction; - } - -break2: - if (!(spoolfull = i <= messages)) - i = messages; - - /* - * Delete retrieved messages. - */ - if (delete && !signaled) - { - state = Delete; - - /* - * Delete backwards to preserve unreceived messages. - */ - while (i >= 1) - { - char n[16]; - - sprintf(n, "%lu", i); - - if (request(POP_CMD_DELE, n, &r) != Ok) - return PopError; - - i--; - } - } - - /* - * Finished with server. - */ - state = Transaction; - - if (request(POP_CMD_QUIT, NULLSTR, &r) != Ok) - return PopError; - - state = Done; - finish(); - return spoolfull ? PopError : Complete; -} - -/* - * Convert an unsigned decimal integer to an unsigned long. - */ -ulong -num(char *s) -{ - char *p; - ulong n; - - n = 0; - - for (p = s; *p != '\0'; p++) - { - char c; - - if ((c = *p) < '0' || c > '9') - { - fprintf(stderr, "%s: '%s' is not numeric.\n", my_name, s); - exit(1); - /* NOTREACHED */ - } - - n = n * 10 + c - '0'; - } - - return n; -} - -void -usage() -{ - fprintf(stderr, "usage: %s [ %s ] [ -n number ] [ -s spooldir ] [ -r [ seconds ] ] [ -t ] [ [user@]server ]\n", my_name, _delete); - exit(1); - /* NOTREACHED */ -} - -int -main(int argc, char *argv[]) -{ - struct sockaddr_in sin; - struct hostent *hp; - struct servent *se; - int i; - int j; - char *p; - extern char *strchr(); - - name(argv[0]); - - for (i = 1; i < argc; i++) - { - if (argv[i][0] != '-') - break; - - j = 1; - - while (argv[i][j] != '\0') - { - switch (argv[i][j++]) - { - case 'd': - if (strcmp(argv[i], _delete) != 0) - { - usage(); - /* NOTREACHED */ - } - - delete = 1; - break; - - case 'n': - if (number > 0) - { - usage(); - /* NOTREACHED */ - } - - if (argv[i][j] != '\0') - number = num(&argv[i][j]); - else if (++i < argc) - number = num(argv[i]); - else - { - usage(); - /* NOTREACHED */ - } - break; - - case 'r': - if (retry > 0) - { - usage(); - /* NOTREACHED */ - } - - if (argv[i][j] != '\0') - retry = num(&argv[i][j]); - else if (i + 1 < argc && argv[i + 1][0] != '-') - retry = num(argv[++i]); - else - retry = Timeout; - - break; - - case 's': - if (spooldir != NULLSTR) - { - usage(); - /* NOTREACHED */ - } - - if (argv[i][j] != '\0') - spooldir = &argv[i][j]; - else if (++i < argc) - spooldir = argv[i]; - else - { - usage(); - /* NOTREACHED */ - } - break; - - case 't': - trace = 1; - break; - - default: - usage(); - /* NOTREACHED */ - } - - break; - } - } - - /* - * Set user name and POP server. - */ - switch (argc - i) - { - case 0: - user = user_id(); - server = localhost; - break; - - case 1: - server = newstr(argv[i]); - - if ((p = strchr(server, '@')) != NULL) - { - user = server; - *p++ = '\0'; - server = p; - } - else - user = user_id(); - - break; - - default: - usage(); - /* NOTREACHED */ - } - - if (number < 0) - number = 0; - - if ((hp = gethostbyname(server)) == NULL) - { - could_not("gethostbyname", server); - /* NOTREACHED */ - } - - sin.sin_family = AF_INET; - - if ((se = getservbyname(POP_SERVICE, POP_PROTOCOL)) != NULL) - sin.sin_port = se->s_port; - else - sin.sin_port = htons(POP_PORT); - - signals(foreground); - - while (!signaled) - { - int s; - static int forked = 0; - - if ((s = socket(PF_INET, SOCK_STREAM, 0)) == SYSERROR) - { - could_not("get socket for", server); - /* NOTREACHED */ - } - - for (i = 0; hp->h_addr_list[i] != NULL; i++) - { - int e; - - sin.sin_addr = *(struct in_addr *)hp->h_addr_list[i]; - - if (connect(s, (struct sockaddr *)&sin, sizeof sin) == SYSERROR) - continue; - - e = pop3(s); - - if (retry == 0 || e == AuthError) - { - exit(e != 0); - /* NOTREACHED */ - } - - errno = 0; - break; - } - - if (errno != 0) - { - would_not("connect to", server); - - if (retry == 0) - { - exit(1); - /* NOTREACHED */ - } - } - - if (!forked) - { - switch (fork()) - { - case SYSERROR: - could_not("fork", my_name); - /* NOTREACHED */ - - case 0: - forked = 1; - signals(background); - break; - - default: - exit(0); - /* NOTREACHED */ - } - } - - sleep(retry); - } - - finish(); - exit(0); - return 0; /* shut up! */ -} //GO.SYSIN DD pop.c echo reo.c sed 's/.//' >reo.c <<'//GO.SYSIN DD reo.c' -/* - * reo - * - * Read an RFC 822 message and reorder its headers. - * - * This could be a script, but it's trivial as a program. - */ - -#ifndef lint -static char sccsid[] = "@(#)reo.c 1.1"; -#endif - -#include -#include -#include -#include -#include "mace.h" -#include "line.h" -#include "message.h" - -/* - * Write a line checking for errors. - */ -void -ewrite(lineio *l, char *s) -{ - if (lwrite(l, s) == NULLSTR) - { - fprintf(stderr, "%s Could not write standard output.\n", my_name); - exit(1); - /* NOTREACHED */ - } -} - -void -usage() -{ - fprintf(stderr, "usage: %s\n", my_name); - exit(1); - /* NOTREACHED */ -} - -int -main(int argc, char *argv[]) -{ - lineio in; - lineio out; - message *m; - char *s; - char **h; - - name(argv[0]); - - if (argc != 1) - { - usage(); - /* NOTREACHED */ - } - - /* - * Validate headers. - */ - if ((m = parse_fd(0, &in)) == NULLMESS) - { - could_not("parse", ""); - /* NOTREACHED */ - } - - lopen(&out, fileno(stdout), LWRITE); - - /* - * Write out headers. - */ - reorder_headers(&m->ms_headers); - - for (h = m->ms_headers.v_list; (s = *h) != NULLSTR; h++) - ewrite(&out, s); - - free_mess(m); - - /* - * Write separator between headers and body. - */ - ewrite(&out, ""); - - /* - * Write out message body. - */ - while ((s = lread(&in)) != NULLSTR) - { - ewrite(&out, s); - free(s); - } - - if (lclose(&out)) - { - fprintf(stderr, "%s: Message truncated.\n", my_name); - exit(1); - /* NOTREACHED */ - } - - exit(0); - return 0; - /* NOTREACHED */ -} //GO.SYSIN DD reo.c echo ret.c sed 's/.//' >ret.c <<'//GO.SYSIN DD ret.c' -/* - * ret - return to a mark - */ - -#ifndef lint -static char sccsid[] = "@(#)ret.c 1.3"; -#endif - -#include -#include -#include -#include "mace.h" -#include "line.h" -#include "message.h" - -void -usage() -{ - fprintf(stderr, "usage: %s\n", my_name); - exit(1); - /* NOTREACHED */ -} - -int -set(box, mess) -char *box; -char *mess; -{ - register mbox *mb; - int ok; - - ok = 0; - - if ((mb = read_box(box)) != NULLBOX) - { - if (!set_box(box) && !set_current(box, mess)) - { - char *f; - - if (!clear_state(f = concat3(mb->m_path, "/", mess), MESG_MARK)) - printf("%c%s %s\n", BOX_CHAR, box, mess); - else - ok = 1; - - (void)free(f); - } - else - ok = 1; - - free_box(mb); - } - else - { - fprintf(stderr, "%s: Box \"%s\" does not exist.\n", my_name, box); - ok = 1; - } - - return ok; -} - -main(argc, argv) -int argc; -char *argv[]; -{ - register char *m; - char *p; - int ok; - - name(argv[0]); - - if (argc > 1) - { - usage(); - /* NOTREACHED */ - } - - ok = 0; - - if ((m = read_file(p = concat3(mace_dir(), "/", MARK))) == NULLSTR) - { - exit(1); - /* NOTREACHED */ - } - - if (*m++ == BOX_CHAR) - { - register char c; - char *bp; - char *mp; - - bp = m; - mp = NULLSTR; - - while ((c = *m) != '\0') - { - if (c == ' ') - { - *m++ = '\0'; - mp = m; - - while ((c = *m) != '\0') - { - if (c == '\n') - { - *m++ = '\0'; - break; - } - - m++; - } - - ok = set(bp, mp); - break; - } - - if (c == '\n') - { - fprintf(stderr, "%s: \"%s\": missing message-id.\n", my_name, p, BOX_CHAR); - ok = 1; - m++; - break; - } - - m++; - } - } - else - { - fprintf(stderr, "%s: \"%s\": Leading '%c' missing.\n", my_name, p, BOX_CHAR); - - while (*m != '\0' && *m++ != '\n') - ; - - ok = 1; - } - - if (*m != '\0') - { - if (write_file(p, m)) - { - would_not("write", p); - ok = 1; - } - } - else if (unlink(p) == SYSERROR) - { - would_not("unlink", p); - ok = 1; - } - - return ok; -} //GO.SYSIN DD ret.c