# To unbundle, run this file echo Makefile sed 's/.//' >Makefile <<'//GO.SYSIN DD Makefile' -# -# @(#)Makefile 1.39 -# -BINDIR = $(HOME)/bin -CC = cc -systype bsd43 -CFLAGS = -O -STICKY = 0 -XMODE = $(STICKY)711 -XSGID = $(STICKY)2711 -MAIL = mail -RANLIB = ranlib -YFLAGS = #-v -SHELL = /bin/sh - -NEW = - -INC = \ - addr.h \ - conf.h \ - flex.h \ - headers.h \ - line.h \ - mace.h \ - message.h \ - regexp.h \ - regmagic.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 \ - regexp.c \ - rfc.c \ - run.c \ - string.c \ - sysmess.c \ - tn.c \ - vec.c \ - writefile.c - -SRC = \ - $(INC) \ - $(LIBSRC) \ - box.c \ - com.c \ - despool.c \ - mace.c \ - mad.c \ - mda.c \ - msg.c \ - ret.c - -TEXT = \ - Makefile \ - :yyfix \ - $(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 \ - regexp.o \ - rfc.o \ - run.o \ - string.o \ - sysmess.o \ - tn.o \ - vec.o \ - writefile.o - -MACE = \ - box \ - com \ - mace \ - despool \ - mad \ - mda \ - msg \ - ret - -all : $(MACE) - -install : all - cp $(MACE) $(BINDIR) - cd $(BINDIR) ; chmod $(XMODE) $(MACE) - -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 $(TEXT) > mace.bundle - -shar : - shar $(TEXT) > mace.shar - -$(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 - -tags :: - ctags $(SRC) - -admin : $(NEW) - echo "Comment? \c" ; read x ; set -x ; \ - for i in $(NEW) ; \ - do \ - admin -i"$$i" -y"$$x" SCCS/s."$$i" ; \ - done - -delta : - @echo "Comment? \c" ; 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) - -mda : $(LIB) mda.o - $(CC) -o mda mda.o $(LIB) - -msg : $(LIB) msg.o - $(CC) -o msg msg.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 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 conf.h line.h mace.h headers.h regexp.h flex.h -despool.o : despool.c mace.h -mad.o : mad.c mace.h -mda.o : mad.c conf.h line.h mace.h headers.h message.h regexp.h addr.h -msg.o : msg.c mace.h flex.h message.h -ret.o : ret.c mace.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 mace.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 -regexp.o : regexp.c mace.h regmagic.h regexp.h -rfc.o : rfc.c mace.h headers.h conf.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 -vec.o : vec.c mace.h -writefile.o : writefile.c mace.h //GO.SYSIN DD Makefile echo mkfile sed 's/.//' >mkfile <<'//GO.SYSIN DD mkfile' -# -# @(#)Makefile 1.39 -# - mace.bundle - -# -# shar : -# shar $(TEXT) > mace.shar -# -# $(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 -# -# tags :: -# ctags $(SRC) -# -# admin : $(NEW) -# echo "Comment? \c" ; read x ; set -x ; \ -# for i in $(NEW) ; \ -# do \ -# admin -i"$$i" -y"$$x" SCCS/s."$$i" ; \ -# done -# -# delta : -# @echo "Comment? \c" ; read x ; set -x ; \ -# for i in $(TEXT) ; \ -# do \ -# delta -y"$$x" SCCS/s."$$i" || : ; \ -# done -# - -$O.box : $LIB box.$O - $LD $LDFLAGS -o $O.box box.$O $LIB - -$O.com : $LIB com.$O - $LD $LDFLAGS -o $O.com com.$O $LIB - -$O.mace : $LIB mace.$O - $LD $LDFLAGS -o $O.mace mace.$O $LIB - -$O.despool : $LIB despool.$O - $LD $LDFLAGS -o $O.despool despool.$O $LIB - -$O.mad : $LIB mad.$O - $LD $LDFLAGS -o $O.mad mad.$O $LIB - -$O.mda : $LIB mda.$O - $LD $LDFLAGS -o $O.mda mda.$O $LIB - -$O.msg : $LIB msg.$O - $LD $LDFLAGS -o $O.msg msg.$O $LIB - -# mad aliases -$O.mcp : $O.mad - cp $O.mad $O.mcp - -# msg aliases -$O.cop : $O.msg - cp $O.msg $O.cop - -$O.del : $O.msg - cp $O.msg $O.del - -$O.med : $O.msg - cp $O.msg $O.med - -$O.mov : $O.msg - cp $O.msg $O.mov - -$O.rem : $O.msg - cp $O.msg $O.rem - -# com aliases -$O.rep : $O.com - cp $O.com $O.rep - -$O.fwd : $O.com - cp $O.com $O.fwd - -addr.c : addr.y - yacc $(YFLAGS) addr.y - sed '/in:/{s/in:/in state %d:/ - s/yyn/&, yystate/ - }' y.tab.c > addr.c - -$O.box : box.c mace.h message.h headers.h conf.h regexp.h -$O.com : com.c mace.h message.h headers.h conf.h regexp.h addr.h -$O.mace : mace.c conf.h line.h mace.h headers.h regexp.h flex.h -$O.despool : despool.c mace.h -$O.mad : mad.c mace.h message.h -$O.mda : mda.c conf.h line.h mace.h headers.h message.h regexp.h addr.h -$O.msg : msg.c mace.h flex.h message.h -$O.ret : ret.c mace.h message.h - -$O.test : test.c mace.h - -$O.messid : 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 mace.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 -note.$O : note.c mace.h -pipe.$O : pipe.c mace.h -regerror.$O : regerror.c mace.h -readdir.$O : readdir.c mace.h -readfile.$O : readfile.c mace.h -rfc.$O : rfc.c mace.h headers.h conf.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 -vec.$O : vec.c mace.h -writefile.$O : writefile.c mace.h //GO.SYSIN DD mkfile echo addr.h sed 's/.//' >addr.h <<'//GO.SYSIN DD addr.h' -/* -** Mail address data structures -** -** @(#)addr.h 1.18 -*/ - -#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; - - -#define NULLADDR ((Addr *)0) -#define NULLDOM ((Dom *)0) -#ifndef unix -#define EOF (-1) -#endif - -extern Addr *newAddr(void); /* Create a new address */ -extern Dom *newDom(void); /* Create a new domain */ -extern Addr *adrlist; -extern Addr *errlist; -extern char *malloc(); -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)sprint - -extern char *make_address(Addr *); -extern char *parse_address(Addr **, char *); //GO.SYSIN DD addr.h echo conf.h sed 's/.//' >conf.h <<'//GO.SYSIN DD conf.h' -/* - * Configuration stuff. - * - * @(#)conf.h 1.34 - */ - -#include - -/* - * 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_REMOVE "remove" - -typedef struct match match; - -struct match -{ - char *m_re; - Reprog *m_cre; - char *m_action; - match *m_next; -}; - -typedef struct -{ - char *c_inbox; - char *c_outbox; - char *c_despool; - char *c_deliver; - char *c_address; - char *c_peruse; - match *c_remove; - match *c_exec; -} - conf; - -/* - * 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 *reg_error; - -extern conf *read_config(void); -extern void regerror(char *); -extern char *rfc_message_id(long, conf *, char *, char *); //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(flex *); -extern char *flex_fill(flex *); -extern void flex_init(flex *); -extern void flex_str(flex *, char *); -extern void flex_nstr(flex *, char *, int); //GO.SYSIN DD flex.h echo headers.h sed 's/.//' >headers.h <<'//GO.SYSIN DD headers.h' -/* - * Unix mail / RFC 822 headers. - * - * @(#)headers.h 1.33 - */ - -#define UNIX_FROM "From " -#define UNIX_FWD_CHAR '>' - -/* 25 on unix, 28 on plan 9 */ -#define UNIX_DATE_LEN 28 - -#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" - -extern char **find_header(char **, char *); -extern char *header_text(char *); -extern char *rfc_cvt_date(char *); -extern char *rfc_date(long); - -extern int rfc_header(char *); -extern int rfc_hdr_cmp(char *, char *); //GO.SYSIN DD headers.h echo line.h sed 's/.//' >line.h <<'//GO.SYSIN DD line.h' -/* - * Line i/o definitions. - * - * @(#)line.h 1.30 - */ - -#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 LERROR 0x08 /* error on an i/o */ - -extern lineio *lopen(lineio *, int, int); -extern int lclose(lineio *); -extern char *lread(lineio *); -extern char *lwrite(lineio *, char *); //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.43 - */ - -#include -#include - -/* - * 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_SYSNAME "sysname" - -#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 MAIL_DIR ".mail_dir" - -/* - * Command interpreter. - */ -#define RC "/bin/rc" - -/* - * 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 NULLSTR - -/* - * 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 "/bin/upas/sendmail" - -/* - * Define if the delivery agent can read the - * recipients from the message body. -#define RFC_DELIVERER 1 - */ - -/* - * Define if RFC_DELIVERER is defined 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 2048 /* size of a filesystem block */ - -#define CREAT_MODE ((ulong)0666) /* file creation mode */ -#define MKDIR_MODE ((ulong)0777) /* directory creation mode */ - -/* - * 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 '\0' - -#define SYSERROR (-1) /* system call error return */ - -/* - * Define this if messages are delimited in this style: - * - * From ... - * - * message... - * - * morF - */ -#define MORF "morF" - -/* - * Default commands; tailor them to suit. - */ -#define DEF_PAGER "cat" -#define DEF_EDITOR "B" - -#define DEL_STR "del" /* Message delivery */ -#define MAD_STR "mad" /* Message add (to a box) */ -#define MCP_STR "mcp" /* Message copy (to a box) */ -#define MDA_STR "mda" /* Message delivery agent */ -#define MSG_STR "msg" /* Message print */ - -#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 *basename(char *); -extern char *defenv(char *, char *); -extern char *mace_dir(void); -extern char *nextid(char *); -extern char *strstr(); -extern char *sysmess(void); - -extern char **mess_range(); - -extern int args_to_messages(int, char **, vec *, char **); - -extern msg_idx mess_alias(); -extern msg_idx mess_index(); - -extern void free_mess(); - -/* misc */ -extern void hint(char *); -extern void name(char *); -extern void usage(void); - -/* string vectors */ -extern char *vec_cat(vec *, char *); -extern void vec_free(vec *); -extern void vec_init(vec *, int); -extern char *vec_str(vec *, char *); - -/* error messages */ -extern void could_not(char *, char *); -extern void fatal(char *); -extern void would_not(char *, char *); - -/* memory allocation */ -extern char *salloc(long); -extern char *srealloc(char *, long); - -/* string functions */ -extern char *concat(char *, char *); -extern char *concat3(char *, char *, char *); -extern char *newstr(char *); -extern char *splice(char **, char *); - -/* directory operations */ -extern int mkdir(char *, int); -extern int rmdir(char *); - -/* mailbox stuff */ -extern char *check_box(char *); -extern char *create_box(char *); -extern char *curr_box(void); -extern int delete_box(char *); -extern void free_box(mbox *); -extern void no_box(char *); -extern mbox *read_box(char *); -extern int set_box(char *); - -/* message stuff */ -extern char *curr_in_box(char *); -extern char *mess_to_path(mbox *, char *); -extern void path_to_mess(char *, char **, char **); -extern void print_summary(char *, char *, char **, int, int, int, int); -extern int set_current(char *, char *); -extern int valid_id(char *); - -/* aka.h ? */ -extern msg_idx mess_alias(mbox *, char *); -extern msg_idx mess_index(mbox *, char *); -extern char **mess_range(mbox *, msg_idx, msg_idx); - -/* dumb file i/o */ -extern char *read_file(char *); -extern int write_file(char *, char *); - -/* user/network id stuff */ -extern char *domain(void); -extern char *host(void); -extern char *user(void); -extern char *user_name(void); - -/* process control */ -extern int pipe_exec(char **, char); -extern int pipe_open(char *, char); -extern char *pipe_close(int); -extern void procwait(int, Waitmsg *); -extern char *run(char **); - -/* directory stuff */ -extern void free_dir(char **); -extern char **read_dir(char *); - -/* mail file stuff */ -extern int mail_check(char *, int); -extern char *mail_name(void); - -/* note handlers */ -extern int noints(void *, char *); -extern int nonotes(void *, char *); -extern int nopipe(void *, char *); - -#ifdef unix -#define exits(m) exit((m) ? 1 : 0) -#define print printf -#define sprint sprintf -#endif //GO.SYSIN DD mace.h echo message.h sed 's/.//' >message.h <<'//GO.SYSIN DD message.h' -/* - * Internal message format. - * - * @(#)message.h 1.32 - */ - -typedef struct -{ - char *ms_path; - char *ms_messid; - vec ms_headers; - int ms_state; -} - message; - -#define NULLMESS (message *)0 - -extern int get_state(char *, int *); -extern int set_state(char *, int); -extern int clear_state(char *, int); - -extern void free_mess(message *); -extern message *read_mess(mbox *, char *); -extern message *parse_mess(char *); - -#define MESG_SENT CHEXEC -#define MESG_COMP (CHEXEC << 3) -#define MESG_MARK (CHEXEC << 6) //GO.SYSIN DD message.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 addr.y sed 's/.//' >addr.y <<'//GO.SYSIN DD addr.y' -%{ -/* - * RFC 822 address parsing routines. - */ - -#ifndef lint -static char sccsid[] = "@(#)addr.y 1.21"; -#endif lint - -#include "mace.h" -#include "headers.h" -#include "flex.h" -#include "addr.h" - -#define panic(s) fatal(s) -#define malloc(s) salloc(s) -#define nomem() fatal("nomem") - -static flex f = { NULLSTR, NULLSTR, NULLSTR, }; - -/* $Log: address.y,v $ - * 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: address.y,v 1.5 88/12/29 00:44:14 john Exp $"; - -static char *perrstr; -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 int token; - -static char *text; -Addr *adrlist; -Addr *errlist; -%} - -%union { - char yChar; - char *yString; - Dom *yDom; - Addr *yAddr; -} - -%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_list - -%% -addr_list: addr_lel - | addr_list addr_lel - ; - -addr_lel: address EOL { - $1->comment = comstr; - $1->error = perrstr; - comstr = NULLSTR; - perrstr = NULLSTR; - appAddr(&adrlist, $1); - } - | address ',' { - $1->comment = comstr; - $1->error = perrstr; - comstr = NULLSTR; - perrstr = NULLSTR; - 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'); - perrstr = newstring2(perrstr, errbuf.f_str); - flex_end(&errbuf); - } - - ap->error = perrstr; - perrstr = NULLSTR; - comstr = NULLSTR; - 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 = perrstr; - comstr = NULLSTR; - perrstr = NULLSTR; - 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 = NULLDOM; - } - ; - -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; - } - ; - -%% - -#ifdef unix -#include -#endif -#include - -#define ERROR -2 - - -static char * -newstring3(char *a, char *b, char *c) -{ - char *p; - char *q; - int i; - - i = strlen(a) + strlen(b) + strlen(c) + 1; - if ((p = malloc((MALLOCT)i)) == NULLSTR) - nomem(); - q = p + strlen(strcpy(p, a)); - q += strlen(strcpy(q, b)); - Strcpy(q, c); - return(p); -} - - -static char * -newstring2(char *a, char *b) -{ - char *p; - int i; - - if (a == (char *)0) - a = ""; - i = strlen(a) + strlen(b) + 1; - if ((p = malloc((MALLOCT)i)) == NULLSTR) - nomem(); - Strcpy(p, a); - Strcat(p, b); - return(p); -} - -/* - * : [ "" ] unexpected [ ] - */ -static void -unexpected(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(char *s) -{ - static char c[2] = { '\0', '\0' }; - - switch(token) { - default: - c[0] = yylval.yChar; - unexpected(s, c, NULLSTR); - perrstr = newstring2(perrstr, errbuf.f_str); - break; - case LIT_DOMAIN: - case QUOTED_STRING: - case ATOM: - unexpected(s, yylval.yString, NULLSTR); - perrstr = newstring2(perrstr, errbuf.f_str); - break; - case EOL: - case 0: /* EOF */ - unexpected(s, NULLSTR, "end-of-header"); - perrstr = newstring2(perrstr, errbuf.f_str); - break; - } - flex_end(&errbuf); -} - - -parseit(char *line) -{ - extern int yyparse(void); - - saveline = cp = text = line; - adrlist = NULLADDR; - errlist = NULLADDR; - if (combuf.f_str == NULLSTR) - flex_init(&combuf); - flex_end(&combuf); - if (errbuf.f_str == NULLSTR) - flex_init(&errbuf); - flex_end(&errbuf); - (void)yyparse(); -} - - -char * -eatcomment(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); - } -} - - -yylex(void) -{ - register char *p; - - savecp = cp; - while (isascii(*cp) && (isspace(*cp) || (*cp == '('))) { - if (*cp == '(') { - p = eatcomment(cp); - if (p == (char *)0) - return(token = EOF); - flex_nstr(&combuf, cp + 1, (p - 2) - cp); - flex_char(&combuf, '\0'); - if (comstr == NULLSTR) { - if ((comstr = malloc((MALLOCT)(strlen(combuf.f_str) + 1))) == NULLSTR) - nomem(); - Strcpy(comstr, combuf.f_str); - } - else - comstr = newstring3(comstr, ", ", combuf.f_str); - flex_end(&combuf); - cp = p; - } - else - cp++; - } - - if (!isascii(*cp)) - return(token = ERROR); - - switch (*cp) { - case '\0': - if (iseol) { - iseol = 0; - return(token = EOF); - } - iseol = 1; - return(token = EOL); - case ',': - case ':': - case ';': - case '.': - case '@': - case '%': - case '<': - case '>': - case '(': - case ')': - case ']': - yylval.yChar = *cp; - return(token = *cp++); - case '[': /* LIT_DOMAIN */ - for (p = cp + 1; *p && *p != ']'; ) { - if (*p == '\\') { - p++; - if (*p == '\0') - return(token = EOF); - } - p++; - } - if (*p == '\0') - return(token = EOF); - if ((yylval.yString = malloc((MALLOCT)(p - cp + 2))) == NULLSTR) - nomem(); - Strncpy(yylval.yString, cp, p - cp + 1); - yylval.yString[p - cp + 1] = '\0'; - cp = ++p; - return(token = LIT_DOMAIN); - case '"': /* QUOTED_STRING */ - for (p = cp + 1; *p && *p != '"'; ) { - if (*p == '\\') { - p++; - if (*p == '\0') - return(token = EOF); - } - p++; - } - if (*p == '\0') - return(token = EOF); - if ((yylval.yString = malloc((MALLOCT)(p - cp))) == NULLSTR) - nomem(); - Strncpy(yylval.yString, cp + 1, p - cp); - yylval.yString[p - cp - 1] = '\0'; - cp = ++p; - return(token = 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 = malloc((MALLOCT)(p - cp + 1))) == NULLSTR) - nomem(); - Strncpy(yylval.yString, cp, p - cp); - yylval.yString[p - cp] = '\0'; - cp = p; - return(token = ATOM); -} - -extern char *memset(); - -/* -** Create and initialize a new address. -*/ -Addr * -newAddr(void) -{ - register Addr *ap; - - if ((ap = (Addr *)malloc((MALLOCT)sizeof *ap)) == NULLADDR) - nomem(); - memset((char *)ap, '\0', sizeof *ap); - return(ap); -} - - -/* -** Append addresslist "addr" to addresslist "head". -*/ -appAddr(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 = malloc((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(void) -{ - register Dom *dp; - - if ((dp = (Dom *)malloc((MALLOCT)sizeof *dp)) == NULLDOM) - nomem(); - memset((char *)dp, '\0', sizeof *dp); - dp->top = dp->sub; - return(dp); -} - - -/* -** Append domainlist "dom" to domainlist "head". -*/ -appDom(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(Dom **head, Dom *dom) -{ - register Dom *dp; - - for (dp = dom; dp->next; dp = dp->next) - ; - dp->next = *head; - *head = dom; -} - -static void -putdom(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(Addr *a) -{ - register Dom *d; - register char *p; - - if (f.f_str == NULLSTR) - flex_init(&f); - - d = a->route; - - while (d != NULLDOM && d->next != NULLDOM) - { - /* 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 != NULLDOM) - { - flex_char(&f, RFC_SPEC_AT); - putdom(d); - } - - flex_char(&f, '\0'); - p = newstr(f.f_str); - flex_end(&f); - - return p; -} - -/* - * 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(Addr **ap, char *s) -{ - register Addr *a; - - parseit(s); - - if (errlist != NULLADDR) - { - for (a = errlist; a != NULLADDR; a = a->next) - { - if (a->error != NULLSTR) - return a->error; - } - - fatal("make_address"); - /* NOTREACHED */ - } - - for (a = adrlist; a != NULLADDR; a = a->next) - { - if (a->localp == (char *)0 || a->localp[0] == '\0') - return "null local-part in address"; - } - - *ap = adrlist; - - return NULLSTR; -} //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 lint - -#include "mace.h" - -#define ABBREV_CHAR '|' - -typedef struct -{ - char *a_str; - msg_idx (*a_func)(mbox *); -} - 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(mbox *m) -{ - return m->m_count > 0 ? 0 : NULLMSG; -} - -static msg_idx -last_mess(mbox *m) -{ - return m->m_count > 0 ? m->m_count - 1 : NULLMSG; -} - -static msg_idx -current_mess(mbox *m) -{ - return m->m_current; -} - -static msg_idx -next_mess(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(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(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(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 lint - -#include "mace.h" -#include "line.h" - -#define ALL_NAME "all" -#define ALL_RANGE "first-last" - -static char *metas = "?*[]"; /* sh(1) metacharacters */ - -/* - * Shell metacharacter matcher. - */ -static int -match(char *str, 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(mbox *mb, char *pattern, 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(mbox *m, char *s) -{ - register msg_idx i; - - if (*s == '\0') - { - if (m->m_current == NULLMSG) - fprint(2, "%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) - fprint(2, "%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(int argc, char *argv[], 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) - { - fprint(2, "%s: No current box.\n", my_name); - return 0; - } - - if ((mb = read_box(box)) == NULLBOX) - { - fprint(2, "%s: No such box as \"%s\".\n", my_name, box); - return 0; - } - - if (mb->m_current == NULLMSG) - { - fprint(2, "%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; - - /* - * 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) - { - fprint(2, "%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) - { - fprint(2, "%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) - { - fprint(2, "%s: No current box.\n", my_name); - - while (++i < argc && argv[i][0] != BOX_CHAR) - ; - - i--; - continue; - } - - if ((mb = read_box(box)) == NULLBOX) - { - fprint(2, "%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 - fprint(2, "%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; - } - - fprint(2, "%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.37"; -#endif lint - -#include "mace.h" -#include "conf.h" -#include "flex.h" -#include "headers.h" - -struct parse -{ - char *p_token; - char **p_strp; - match **p_matp; - int (*p_func)(struct parse *, char **); - int p_required; -}; - -typedef struct parse parse; - -static conf cf = -{ - NULLSTR, - NULLSTR, - NULLSTR, - NULLSTR, - NULLSTR, - NULLSTR, - (match *)0, - (match *)0, -}; - -static int lineno; -static char *file; - -static void -white(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(char *p, char *q) -{ - register char c; - - if (q[-1] == '\n') - q--; - - c = *q; - *q = '\0'; - p = newstr(p); - *q = c; - - return p; -} - -static char * -string(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(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(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(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(parse *pi, char **pp) -{ - if (*pi->p_strp != NULLSTR) - { - fprint(2, "%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) - { - fprint(2, "%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(parse *pi, char **pp) -{ - register match *mp; - Reprog *cre; - char *re; - - if (*pi->p_matp != (match *)0) - { - fprint(2, "%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) - { - fprint(2, "%s: \"%s\": Quoted string expected after \"%s\" on line %d.\n", my_name, file, pi->p_token, lineno); - return 1; - } - - if ((cre = regcomp(re)) == (Reprog *)0) - { - fprint(2, "%s: \"%s\": Regular expression \"%s\" on line %d %s\n", my_name, file, re, lineno, reg_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(parse *pi, char **pp, int quoted) -{ - register match **n; - register match *mp; - Reprog *cre; - char *re; - char *action; - - if ((re = quoted_string(pp)) == NULLSTR) - { - fprint(2, "%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) - { - fprint(2, "%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) - { - fprint(2, "%s: \"%s\": String expected after regular expression \"%s\" on line %d.\n", my_name, file, re, lineno); - return 1; - } - } - - if ((cre = regcomp(re)) == (Reprog *)0) - { - fprint(2, "%s: \"%s\": Regular expression \"%s\" on line %d %s\n", my_name, file, re, lineno, reg_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_qstring(parse *pi, char **pp) -{ - return regex_string(pi, pp, 1); -} - -conf * -read_config(void) -{ - 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_INBOX, &cf.c_inbox, (match **)0, string_value, 1, }, - { CT_OUTBOX, &cf.c_outbox, (match **)0, string_value, 1, }, - { CT_DESPOOL, &cf.c_despool, (match **)0, string_value, 0, }, - { CT_DELIVER, &cf.c_deliver, (match **)0, string_value, 0, }, - { CT_PERUSE, &cf.c_peruse, (match **)0, string_value, 0, }, - { CT_ADDRESS, &cf.c_address, (match **)0, string_value, 1, }, - { CT_REMOVE, (char **)0, &cf.c_remove, re_value, 0, }, - { CT_EXEC, (char **)0, &cf.c_exec, re_qstring, 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) - fprint(2, "%s: \"%s\": Unrecognised token \"%s\" on line %d.\n", my_name, file, t, lineno); - - (void)free(t); - } - else - fprint(2, "%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) - { - fprint(2, "%s: \"%s\": Specification of \"%s\" required.\n", my_name, file, pi->p_token); - ok = 1; - } - } - - if (ok) - { - exits("configuration file error"); - /* NOTREACHED */ - } - - if (cf.c_despool == NULLSTR) - { - if (despool == NULLSTR) - { - fprint(2, "%s: \"%s\": Specification of \"%s\" required.\n", my_name, file, CT_DESPOOL); - exits("despooler missing"); - /* NOTREACHED */ - } - - cf.c_despool = newstr(despool); - } - - if (cf.c_deliver == NULLSTR) - { - if (deliver == NULLSTR) - { - fprint(2, "%s: \"%s\": Specification of \"%s\" required.\n", my_name, file, CT_DELIVER); - exits("deliverer missing"); - /* NOTREACHED */ - } - - cf.c_deliver = newstr(deliver); - } - - if (cf.c_peruse == NULLSTR) - { - if (peruse == NULLSTR) - { - fprint(2, "%s: \"%s\": Specification of \"%s\" required.\n", my_name, file, CT_PERUSE); - exits("peruser missing"); - /* NOTREACHED */ - } - - cf.c_peruse = newstr(peruse); - } - - (void)free(file); - (void)free(p); - done = 1; - - return &cf; -} //GO.SYSIN DD conf.c echo dir.c sed 's/.//' >dir.c <<'//GO.SYSIN DD dir.c' -/* - * mkdir/rmdir [in]compatibility. - */ - -#include "mace.h" - -#ifndef lint -static char sccsid[] = "@(#)dir.c 1.30"; -#endif lint - -int -mkdir(char *s, int mode) -{ - int fd; - - if ((fd = create(s, OREAD, CHDIR | mode)) == SYSERROR || close(fd) == SYSERROR) - return SYSERROR; - - return 0; -} - -int -rmdir(char *s) -{ - return remove(s); -} //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 lint - -#include "mace.h" -#include "line.h" - -static char *domainname = NULLSTR; - -char * -domain(void) -{ - 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 lint - -#include "mace.h" - -static char *vowels = "aeiou"; -static char *cons = "bdfgjklmnprstvyz"; - -char * -nextid(char *s) -{ - register char *p; - register char *q; - char *set; - char *id; - int carry; - - 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(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 lint - -#include "mace.h" -#include "flex.h" - -void -flex_init(flex *f) -{ - f->f_str = f->f_ptr = salloc(FLEXZ); - f->f_end = f->f_ptr + FLEXZ; -} - -char * -flex_fill(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(flex *f) -{ - f->f_ptr = f->f_str; -} - -void -flex_str(flex *f, char *s) -{ - while (*s != '\0') - flex_char(f, *s++); -} - -void -flex_nstr(flex *f, char *s, 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.31"; -#endif lint - -#include "mace.h" -#include "headers.h" - -char ** -find_header(char **v, char *h) -{ - register char *p; - - while ((p = *v) != NULLSTR) - { - if (rfc_hdr_cmp(p, h)) - return v; - - v++; - } - - return (char **)NULLSTR; -} - -char * -header_text(char *h) -{ - while (*h++ != RFC_SPEC_COLON) - ; - - while ((*h == RFC_LWSP_1 || *h == RFC_LWSP_2) && *h != '\0') - h++; - - return *h == '\0' ? NULLSTR : h; -} //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 lint - -#include "mace.h" - -char * -host(void) -{ - static char *hostname = NULLSTR; - - if (hostname != NULLSTR) - return hostname; - - if ((hostname = getenv(ENV_SYSNAME)) == NULLSTR) - { - could_not("getenv", "ENV_SYSNAME"); - /* NOTREACHED */ - } - - return hostname; -} //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.30"; -#endif lint - -#include "mace.h" -#include "line.h" -#include "flex.h" - -lineio * -lopen(lineio *lp, int fd, int flag) -{ - lp->l_fd = fd; - lp->l_ptr = lp->l_end = lp->l_buf; - lp->l_flag = flag; - - return lp; -} - -int -lclose(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(lineio *lp) -{ - static flex f = { NULLSTR, NULLSTR, NULLSTR, }; - - switch (lp->l_flag) - { - 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 || (c = *lp->l_ptr++) == '\n') - { - register char *p; - - if (f.f_ptr == f.f_str && (lp->l_flag & LEOF) != 0) - return NULLSTR; - - flex_char(&f, '\0'); - p = newstr(f.f_str); - flex_end(&f); - return p; - } - - flex_char(&f, c); - } -} - -char * -lwrite(lineio *lp, char *s) -{ - register char *p; - - if (lp->l_flag != LWRITE) - { - fatal("lwrite"); - /* NOTREACHED */ - } - - p = s; - - for (;;) - { - register char c; - - if (lp->l_ptr == &lp->l_buf[LBUFZ]) - { - register int n; - - n = lp->l_ptr - lp->l_buf; - - if (write(lp->l_fd, lp->l_buf, n) != n) - { - lp->l_flag |= LERROR; - return NULLSTR; - } - - lp->l_ptr = lp->l_buf; - } - - if ((c = *p++) == '\0') - { - *lp->l_ptr++ = '\n'; - return s; - } - - *lp->l_ptr++ = 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 lint - -#include "mace.h" -#include - -int -lock(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(char *f) -{ - register char *p; - extern int errno; - - errno = 0; - - (void)remove(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 lint - -#include "mace.h" -#include "line.h" -#include "headers.h" - -#define MAIL_BOX "/mail/box/" -#define FORWARD "forward" -#define LMBOX "L.mbox" -#define MBOX "mbox" -#define PIPETO "pipeto" - -static char *mail_file = NULLSTR; -static char *mail_forward = NULLSTR; -static char *mail_lockf = NULLSTR; -static char *mail_pipeto = NULLSTR; - -/* - * Returns a pointer to static data, unlike the rest. - */ -char * -mail_name(void) -{ - if (mail_file == NULLSTR) - { - char *u; - int l; - - u = user(); - - mail_file = salloc(l = sizeof MAIL_BOX + strlen(u) + sizeof MBOX); - l = sprint(mail_file, "%s%s/", MAIL_BOX, u); - - mail_forward = salloc(l + sizeof FORWARD); - sprint(mail_forward, "%s%s", mail_file, FORWARD); - - mail_lockf = salloc(l + sizeof LMBOX); - sprint(mail_lockf, "%s%s", mail_file, LMBOX); - - mail_pipeto = salloc(l + sizeof PIPETO); - sprint(mail_pipeto, "%s%s", mail_file, PIPETO); - - strcat(mail_file, MBOX); - } - - return mail_file; -} - -/* - * Read the first line of a file. - */ -static char * -sed1q(char *f) -{ - int fd; - lineio mld; - char *l; - - if ((fd = open(f, OREAD)) == SYSERROR) - return NULLSTR; - - lopen(&mld, fd, LREAD); - - if ((l = lread(&mld)) == NULLSTR) - { - (void)lclose(&mld); - (void)close(fd); - - return NULLSTR; - } - - (void)lclose(&mld); - (void)close(fd); - - return l; -} - -/* - * Lock the mail file via the mail lock file. - */ -void -mail_lock(void) -{ - int fd; - - if ((fd = open(mail_lockf, ORDWR)) != SYSERROR) - return; - - if ((fd = create(mail_lockf, ORDWR, CHEXCL | CREAT_MODE)) != SYSERROR) - return; - - would_not("create", mail_lockf); - exits("mail lock file broken"); -} - -/* - * Check if there's any mail in a mail file. - */ -int -mail_check(char *mf, int lock) -{ - char *p; - char *l; - - if ((p = mf) == NULLSTR && (p = mail_name()) == NULLSTR) - return 0; - - /* - * Lock the mail file if it's the standard one. - */ - if (mf == NULLSTR && lock) - mail_lock(); - - /* - * Check in mail file. - */ - if (access(p, 4) == SYSERROR) - { - fprint(2, "%s: Mail in \"%s\" is not accessable by you. %s\n", my_name, p, sysmess()); - return 0; - } - - if ((l = sed1q(p)) != NULLSTR) - { - if (strncmp(l, UNIX_FROM, (sizeof UNIX_FROM) - 1) == 0) - { - free(l); - return 1; - } - - free(l); - fprint(2, "%s: Mail in \"%s\" does not commence with \"%s\".\n", my_name, p, UNIX_FROM); - return 0; - } - - if (mf != NULLSTR) - { - fprint(2, "%s: No mail in \"%s\".\n", my_name, mf); - return 0; - } - - /* - * Check forwarding. - */ - if ((l = sed1q(mail_forward)) != NULLSTR) - { - fprint(2, "%s: Mail forwarded to \"%s\".\n", my_name, l); - free(l); - return 0; - } - - /* - * Check for a command to be run on each message. - */ - if ((l = sed1q(mail_pipeto)) != NULLSTR) - { - fprint(2, "%s: Mail piped to \"%s\".\n", my_name, l); - free(l); - return 0; - } - - fprint(2, "%s: No mail in \"%s\".\n", my_name, p); - return 0; -} //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 lint - -#include "mace.h" - -/* - * Return the name of the current box. - */ -char * -curr_box(void) -{ - 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(char *s) -{ - char *box; - Dir dirb; - - if (*s == SPEC_CHAR) - return NULLSTR; - - box = concat3(mace_dir(), "/", s); - - if (dirstat(box, &dirb) == SYSERROR || (dirb.mode & CHDIR) == 0) - { - (void)free(box); - return NULLSTR; - } - - return box; -} - -char * -create_box(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(char *s) -{ - register char *b; - register char *m; - register int ok; - - if ((b = check_box(s)) == NULLSTR) - { - fprint(2, "%s: No such box as \"%s\".\n", my_name, s); - return 1; - } - - m = concat3(b, "/", MESSID); - (void)remove(m); - (void)free(m); - - m = concat3(b, "/", PROTO); - (void)remove(m); - - if ((ok = rmdir(b)) != 0) - would_not("rmdir", b); - - (void)free(b); - (void)free(m); - - return ok != 0; -} - -static int -mess_cmp(char **m1, char **m2) -{ - return strcmp(*m1, *m2); -} - -mbox * -read_box(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; - - fprint(2, "%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(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(char *s) -{ - register char *f; - - if ((f = check_box(s)) == NULLSTR) - { - fprint(2, "%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; -} - -/* - * Complain about a non-existant box. - */ -void -no_box(char *box) -{ - fprint(2, "%s: Box \"%c%s\" does not exist.\n", my_name, BOX_CHAR, box); -} //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.31"; -#endif lint - -#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(void) -{ - char *s; - char *t; - static char *home = NULLSTR; - static char *dir = NULLSTR; - - if (dir != NULLSTR) - return dir; - - if (home == NULLSTR && (home = getenv(ENV_HOME)) == NULLSTR) - { - fprint(2, "%s: You have no $%s in your environment.\n", my_name, ENV_HOME); - exits(ENV_HOME); - /* NOTREACHED */ - } - - s = concat3(home, "/", MAIL_DIR); - - 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 lint - -#include "mace.h" - -char * -salloc(long n) -{ - register char *s; - - if ((s = malloc(n)) == NULLSTR) - { - fprint(2, "%s: Ran out of memory.\n", my_name); - exits("no memory"); - /* NOTREACHED */ - } - - return s; -} - -char * -srealloc(char *p, long n) -{ - register char *s; - - if ((s = realloc(p, n)) == NULLSTR) - { - fprint(2, "%s: Ran out of memory.\n", my_name); - exits("no memory"); - /* NOTREACHED */ - } - - return s; -} //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 lint - -#ifdef unix -#include -#endif -#include "mace.h" - -void -could_not(char *what, char *with) -{ - char *s; - - fprint(2, "%s: Could not %s \"%s\". %s\n", my_name, what, with, s = sysmess()); - exits(s); - /* NOTREACHED */ -} - -void -would_not(char *what, char *with) -{ - fprint(2, "%s: Could not %s \"%s\". %s\n", my_name, what, with, sysmess()); -} - -void -fatal(char *what) -{ - fprint(2, "%s: Internal error: \"%s\".\n", my_name, what); - exits("internal error"); - /* 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.37"; -#endif lint - -#include "mace.h" -#include "message.h" -#include "headers.h" -#include "line.h" -#include "flex.h" - -char * -curr_in_box(char *box) -{ - char *messid; - 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; -} - -message * -read_mess(mbox *mb, char *s) -{ - register char *p; - register message *mp; - - p = concat3(mb->m_path, "/", s); - - mp = parse_mess(p); - - (void)free(p); - - return mp; -} - -message * -parse_mess(char *s) -{ - register char *p; - register message *mp; - register int line; - int fd; - lineio mld; - - mp = (message *)salloc(sizeof(*mp)); - mp->ms_path = newstr(s); - mp->ms_messid = newstr(basename(s)); - - if ((fd = open(mp->ms_path, OREAD)) == SYSERROR) - { - (void)free(mp->ms_path); - (void)free(mp->ms_messid); - (void)free((char *)mp); - - return NULLMESS; - } - - { - Dir dirb; - - if (dirfstat(fd, &dirb) == SYSERROR) - { - would_not("stat", mp->ms_path); - goto trashed; - } - - switch (dirb.mode & CHDIR) - { - case 0: - mp->ms_state = dirb.mode; - break; - - default: - fprint(2, "%s: \"%s\" is not a file.\n", my_name, s); - exits("message not a file"); - /* NOTREACHED */ - } - } - - vec_init(&mp->ms_headers, 128); - (void)lopen(&mld, fd, LREAD); - line = 0; - - while ((p = lread(&mld)) != 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)) - { - fprint(2, "%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); - - if (lclose(&mld) == 0) - { - (void)close(fd); - return mp; - } - -trashed: - (void)lclose(&mld); - (void)close(fd); - (void)free_mess(mp); - - return NULLMESS; -} - -void -free_mess(message *mp) -{ - (void)free(mp->ms_path); - (void)free(mp->ms_messid); - vec_free(&mp->ms_headers); - (void)free((char *)mp); -} - -int -set_current(char *b, char *m) -{ - register char *f; - - if (!valid_id(m)) - { - fprint(2, "%s: \"%s\" is not a valid message id.\n", my_name, m); - return 1; - } - - if ((b = check_box(b)) == NULLSTR) - { - fprint(2, "%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; -} - -/* - * Format an `n' character field turning new-lines into `~' and - * mashing tabs into spaces (a necessary evil). - */ -static void -lfmtn(flex *fp, char *p, int n) -{ - while (n-- > 0) - { - register char c; - - switch ((c = *p)) - { - case '\0': - flex_char(fp, ' '); - continue; - - case '\n': - flex_char(fp, '~'); - break; - - case '\t': - flex_char(fp, ' '); - break; - - default: - flex_char(fp, c); - break; - } - - p++; - } -} - -/* - * Print a one line message summary. - */ -void -print_summary(char *box, char *id, char **h, int current, int copies, int to, int state) -{ - char *p; - char **n; - static flex f = { NULLSTR, NULLSTR, NULLSTR }; - - /* - * We use a flex to buffer up the line and then print(2) it. - */ - if (f.f_str == NULLSTR) - flex_init(&f); - - flex_str(&f, (state & (MESG_SENT|MESG_COMP)) == MESG_COMP ? DEL_STR : MSG_STR); - flex_char(&f, ' '); - flex_char(&f, BOX_CHAR); - flex_str(&f, box); - flex_char(&f, ' '); - flex_str(&f, id); - flex_char(&f, ' '); - flex_char(&f, current ? '-' : ' '); - flex_char(&f, copies > 1 ? '?' : ' '); - flex_char(&f, (state & MESG_SENT) != 0 ? '|' : ' '); - flex_char(&f, ' '); - -/* - print - ( - "%s %c%s %s %c%c%c ", - (state & (MESG_SENT|MESG_COMP)) == MESG_COMP ? DEL_STR : MSG_STR, - BOX_CHAR, - box, - id, - cc = current ? '-' : ' ', - copies > 1 ? '?' : ' ', - (state & MESG_SENT) != 0 ? '|' : ' ' - ); -*/ - - if ((n = find_header(h, to ? RFC_TO : RFC_FROM)) == (char **)0 || (p = header_text(*n)) == NULLSTR) - p = ""; - - lfmtn(&f, p, 16); - flex_char(&f, ' '); - - if ((n = find_header(h, RFC_DATE)) == (char **)0 || (p = header_text(*n)) == NULLSTR) - p = ""; - - lfmtn(&f, p, 16); - flex_char(&f, ' '); - - if ((n = find_header(h, RFC_SUBJECT)) != (char **)0 && (p = header_text(*n)) != NULLSTR) - { - flex_char(&f, '"'); - lfmtn(&f, p, strlen(p)); - flex_char(&f, '"'); - } - - flex_char(&f, '\0'); - - print("%s\n", f.f_str); - flex_end(&f); -} - -int -get_state(char *m, int *s) -{ - Dir dirb; - - if (dirstat(m, &dirb) == SYSERROR) - { - would_not("stat", m); - return 1; - } - - *s = dirb.mode & (MESG_SENT|MESG_COMP|MESG_MARK); - return 0; -} - -int -set_state(char *m, int s) -{ - Dir dirb; - - if (dirstat(m, &dirb) == SYSERROR) - { - would_not("stat", m); - return 1; - } - - dirb.mode |= s; - - if (dirwstat(m, &dirb) == SYSERROR) - { - would_not("dirwstat", m); - return 1; - } - - return 0; -} - -int -clear_state(char *m, int s) -{ - Dir dirb; - - if (dirstat(m, &dirb) == SYSERROR) - { - would_not("stat", m); - return 1; - } - - dirb.mode &= ~s; - - if (dirwstat(m, &dirb) == SYSERROR) - { - would_not("dirwstat", m); - return 1; - } - - return 0; -} - -/* - * Convert a mailbox/message pair into a pathname. - */ -char * -mess_to_path(mbox *mb, char *m) -{ - return concat3(mb->m_path, "/", m); -} - -/* - * Convert a pathname into a mailbox/message name pair. - */ -void -path_to_mess(char *p, char **b, 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 lint - -#include "mace.h" - -#define DEV_USER "/dev/user" - -/* - * Returns the login name of the current user. - * - * Returns static data. - */ -char * -user(void) -{ - int fd; - long n; - static char u[NAMELEN + 1]; - - if (u[0] != '\0') - return u; - - if ((fd = open(DEV_USER, OREAD)) == SYSERROR) - { - would_not("open", DEV_USER); - exits("open"); - } - - if ((n = read(fd, u, NAMELEN)) == SYSERROR) - { - would_not("read", DEV_USER); - exits("read"); - } - - u[n] = '\0'; - - - if (close(fd) == SYSERROR) - { - would_not("close", DEV_USER); - exits("close"); - } - - return u; -} - -/* - * Returns the name of the current user. - * - * Returns static data. - */ -char * -user_name(void) -{ - - return getenv(ENV_NAME); -} - -/* - * Return an environment variable or its default. - */ -char * -defenv(char *s, char *d) -{ - register char *e; - - return (e = getenv(s)) != NULLSTR ? e : d; -} - -/* - * Set $hint. - */ -void -hint(char *s) -{ - if (putenv("hint", s) == SYSERROR) - would_not("putenv", "$hint"); -} //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 lint - -#ifdef unix -#include -#endif -#include "mace.h" - -char *my_name; - -void -name(char *s) -{ - my_name = basename(s); -} //GO.SYSIN DD name.c echo note.c sed 's/.//' >note.c <<'//GO.SYSIN DD note.c' -/* - * Note catching. - */ - -#include "mace.h" - -/* - * Ignore interrupt notes. - */ -int -noints(void *r, char *s) -{ - USED(r); - return strcmp(s, "interrupt") == 0; -} - -/* - * Ignore interrupts and hangups. - */ -int -nonotes(void *r, char *s) -{ - USED(r); - return noints(r, s) || strcmp(s, "hangup") == 0; -} - -/* - * Ignore notes generated by writes on closed pipes, interrupts and hangups. - */ -int -nopipe(void *r, char *s) -{ - USED(r); - return nonotes(r, s) || strcmp(s, "sys: write on closed pipe") == 0; -} //GO.SYSIN DD note.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 lint - -#include "mace.h" - -typedef struct -{ - int p_pid; - int p_stat; - Waitmsg p_wstat; -} - pstat; - -#define SRUN 1 -#define SZOMB 2 - -static pstat pipes[NPIPES]; - -/* - * Set up a pipe. - */ -static int -pipe_action(char *s, char *v[], 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) != read - || - close(fds[0]) == SYSERROR - || - close(fds[1]) == SYSERROR - ) - { - could_not("pipe", s); - /* NOTREACHED */ - } - - if (s != NULLSTR) - { - x = RC; - - execl(x, basename(x), "-c", s, NULLSTR); - could_not("exec", s); - } - else - { - exec(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; - } - - if (atnotify(nopipe, 1) == SYSERROR) - { - fatal("pipe notify"); - /* NOTREACHED */ - } - - return fds[!read]; - } -} - -/* - * Pipe to a shell command. - */ -int -pipe_open(char *s, char rw) -{ - return pipe_action(s, (char **)0, rw); -} - -/* - * Pipe to an argument vector. - */ -int -pipe_exec(char *v[], char rw) -{ - return pipe_action(NULLSTR, v, rw); -} - -void -procwait(int pid, Waitmsg *w) -{ - int wpid; - -again: - w->msg[0] = '\0'; - - while ((wpid = wait(w)) != SYSERROR) - { - pstat *p; - - if (pid == wpid) - break; - - for (p = pipes; p < &pipes[NPIPES]; p++) - { - if (p->p_stat == SRUN && p->p_pid == wpid) - { - p->p_stat = SZOMB; - p->p_wstat = *w; - goto again; - } - } - - fatal("procwait"); - } - - if (wpid == SYSERROR) - (void)errstr(w->msg); - - w->msg[(sizeof w->msg) - 1] = '\0'; -} - -char * -pipe_close(int fd) -{ - pstat *p; - - if (fd < 0 || fd >= NPIPES) - return NULLSTR; - - p = &pipes[fd]; - (void)close(fd); - - switch (p->p_stat) - { - case SRUN: - procwait(p->p_pid, &p->p_wstat); - - p->p_stat = SZOMB; - /* fall thru... */ - - case SZOMB: - if (atnotify(nopipe, 0) == SYSERROR) - { - fatal("pipe de-notify"); - /* NOTREACHED */ - } - - p->p_stat = 0; - return p->p_wstat.msg[0] == '\0' ? NULLSTR : p->p_wstat.msg; - - default: - fatal("pipe_close"); - /* NOTREACHED */ - } -} //GO.SYSIN DD pipe.c echo regerror.c sed 's/.//' >regerror.c <<'//GO.SYSIN DD regerror.c' -/* - * Regular expression hooks. - */ - -#ifndef lint -static char sccsid[] = "@(#)re.c 1.6"; -#endif lint - -#include "mace.h" - -char *reg_error; /* regexp error string */ - -/* - * Save a regexp error message. - */ -void -regerror(char *msg) -{ - reg_error = msg; -} //GO.SYSIN DD regerror.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 lint - -#include "mace.h" - -char ** -read_dir(char *f) -{ - int fd; - int n; - Dir *dp; - vec v; - Dir dirs[64]; - - if ((fd = open(f, OREAD)) == SYSERROR) - { - could_not("open", f); - /* NOTREACHED */ - } - - vec_init(&v, 64); - - while ((n = dirread(fd, dirs, (long)(sizeof dirs))) != 0) - { - if (n == -1) - { - could_not("read", f); - /* NOTREACHED */ - } - - n /= sizeof *dp; - - for (dp = dirs; dp < &dirs[n]; dp++) - { - char *s; - - if (dp->name[0] == SPEC_CHAR || dp->name[0] == '.') - continue; - - s = salloc(NAMELEN + 1); - memcpy((void *)s, (void *)&dp->name[0], NAMELEN); - s[NAMELEN] = '\0'; - vec_str(&v, s); - } - } - - vec_str(&v, NULLSTR); - - if (close(fd) == SYSERROR) - { - could_not("close", f); - /* NOTREACHED */ - } - - return v.v_list; -} - -void -free_dir(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 lint - -#include "mace.h" - -char * -read_file(char *f) -{ - register int fd; - char *s; - Dir dirb; - - if ((fd = open(f, OREAD)) == SYSERROR) - return NULLSTR; - - if (dirfstat(fd, &dirb) == SYSERROR) - { - could_not("fstat", f); - /* NOTREACHED */ - } - - if ((dirb.mode & CHDIR) != 0) - { - fprint(2, "%s: \"%s\" is a directory.\n", my_name, f); - exits("file is a directory"); - /* NOTREACHED */ - } - - s = salloc(dirb.length + 1); /* length may be wrong one day? */ - - if (dirb.length != 0) - { - if (read(fd, s, dirb.length) != dirb.length) - { - could_not("read", f); - /* NOTREACHED */ - } - - if (s[dirb.length - 1] == '\n') - s[dirb.length - 1] = '\0'; - else - s[dirb.length] = '\0'; - } - else - s[0] = '\0'; - - if (close(fd) == SYSERROR) - { - could_not("close", f); - /* NOTREACHED */ - } - - return s; -} //GO.SYSIN DD readfile.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 lint - -#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(char *exp) -{ - register regexp *r; - register char *scan; - register char *longest; - register int len; - int flags; - - 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(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(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(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(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(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(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(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(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(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(regexp *prog, char *string) -{ - register char *s; - - /* 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(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(char *prog) -{ - register char *scan; /* Current node. */ - char *next; /* Next node. */ - - scan = prog; -#ifdef DEBUG - if (scan != NULL && regnarrate) - fprint(2, "%s(\n", regprop(scan)); -#endif - while (scan != NULL) { -#ifdef DEBUG - if (regnarrate) - fprint(2, "%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(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(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(regexp *r) -{ - register char *s; - register char op = EXACTLY; /* Arbitrary non-END op. */ - register char *next; - - - 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(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: - sprint(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: - sprint(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(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[] = "@(#)rfc.c 1.33"; -#endif lint - -#include "mace.h" -#include "headers.h" -#include "conf.h" - -#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, -}; - -/* - * Return the offset in minutes from GMT. - */ -static int -gmt_offset(long t) -{ - Tm *gmtp; - Tm *localp; - int day; - Tm gmt; - - memcpy((void *)&gmt, (void *)gmtime(t), sizeof gmt); - localp = localtime(t); - - gmtp = &gmt; - - if (gmtp->year == localp->year) - { - if (gmtp->yday == localp->yday) - day = 0; - else if (gmtp->yday < localp->yday) - day = 1; - else - day = -1; - } - else if (gmtp->year < localp->year) - day = 1; - else - day = -1; - - return (localp->hour + day * 24) * 60 + localp->min - gmtp->hour * 60 - gmtp->min; -} - -/* - * Returns the date in the correct format. - */ -static char * -date_str(long t, Tm *tp) -{ - register int hours; - register int minutes; - int east; - static char date[64]; - static char zone_name[9]; - - if ((minutes = gmt_offset(t)) < 0) - { - minutes = -minutes; - east = 0; - } - else - east = 1; - - hours = minutes / 60; - minutes %= 60; - - if (hours != 0 || minutes != 0) -#ifdef unix - sprint(zone_name, "%c%02d%02d", east ? RFC_SPEC_PLUS : RFC_SPEC_MINUS, hours, minutes); -#else - sprint(zone_name, "%c%.2d%.2d", east ? RFC_SPEC_PLUS : RFC_SPEC_MINUS, hours, minutes); -#endif - else - (void)strcpy(zone_name, RFC_STR_GMT); - - if (tp == (Tm *)0) - tp = localtime(t); - - sprint - ( - date, -#ifdef unix - "%s%c%c%2d%c%s%c%d%c%02d%c%02d%c%02d%c%s", -#else - "%s%c%c%2d%c%s%c%d%c%.2d%c%.2d%c%.2d%c%s", -#endif - days[tp->wday], - RFC_SPEC_COMMA, - RFC_LWSP_1, - tp->mday, - RFC_LWSP_1, - months[tp->mon], - RFC_LWSP_1, - tp->year + YEAR_OFFSET, - RFC_LWSP_1, - tp->hour, - RFC_SPEC_COLON, - tp->min, - RFC_SPEC_COLON, - tp->sec, - RFC_LWSP_1, - zone_name - ); - - return newstr(date); -} - -/* - * Returns the date in the correct format. - */ -char * -rfc_date(long t) -{ - return date_str(t, (Tm *)0); -} - -/* - * Is this char a digit? - */ -static int -digit(char c) -{ - return c >= '0' && c <= '9'; -} - -/* - * Return the numeric value of a two digit ASCII sequence. - */ -static char * -two_digits(char c, char *s, 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(char *s) -{ - Tm *tp; - char **n; - Tm now; - int year; - - tp = &now; - - n = days; - - for (;;) - { - if (*n == NULLSTR) - goto disaster; - - if (strncmp(s, *n, 3) == 0) - { - tp->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->mon = n - months; - break; - } - - n++; - } - - s += 3; - - if (*s != ' ') - goto disaster; - - if (digit(*++s)) - { - if ((s = two_digits(' ', --s, &tp->mday)) == NULLSTR) - goto disaster; - } - else if (*s++ == ' ') - tp->mday = *s++ - '0'; - else - goto disaster; - - if ((s = two_digits(' ', s, &tp->hour)) == NULLSTR) - goto disaster; - - if ((s = two_digits(':', s, &tp->min)) == NULLSTR) - goto disaster; - - if (*s == ':') - { - if ((s = two_digits(':', s, &tp->sec)) == NULLSTR) - goto disaster; - } - else if (*s == ' ') - tp->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->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(long t, conf *cf, char *box, char *id) -{ - 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 */ - ); - - sprint - ( - mid, -#ifdef unix - "%c%d%02d%02d%02d%02d%c%d%c%s%c%s%c%s%c", -#else - "%c%d%.2d%.2d%.2d%.2d%c%d%c%s%c%s%c%s%c", -#endif - RFC_SPEC_LANGLE, - tp->year + YEAR_OFFSET, - tp->mon + 1, - tp->mday, - tp->hour, - tp->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(char *s, 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(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; -} //GO.SYSIN DD rfc.c echo run.c sed 's/.//' >run.c <<'//GO.SYSIN DD run.c' -/* - * Fork/exec an argument vector using rc(1). - */ - -#ifndef lint -static char sccsid[] = "@(#)run.c 1.30"; -#endif lint - -#include "mace.h" - -char * -run(char *argv[]) -{ - int pid; - char *rc; - static Waitmsg w; - - switch (pid = fork()) - { - case SYSERROR: - could_not("fork", argv[0]); - /* NOTREACHED */ - - case 0: - rc = RC; - - execl(rc, basename(rc), "-c", splice(argv, " "), NULLSTR); - could_not("exec", argv[0]); - /* NOTREACHED */ - - default: - break; - } - - if (atnotify(noints, 1) == SYSERROR) - { - fatal("run notify"); - /* NOTREACHED */ - } - - procwait(pid, &w); - - if (atnotify(noints, 0) == SYSERROR) - { - fatal("run de-notify"); - /* NOTREACHED */ - } - - return w.msg[0] == '\0' ? NULLSTR : w.msg; -} //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 lint - -#include "mace.h" - -char * -concat(char *s1, char *s2) -{ - register int l; - register char *s; - - l = strlen(s1) + strlen(s2) + 1; - - s = salloc(l); - - (void)strcat(strcpy(s, s1), s2); - - return s; -} - -char * -concat3(char *s1, char *s2, char *s3) -{ - register int l; - register char *s; - - l = strlen(s1) + strlen(s2) + strlen(s3) + 1; - - s = salloc(l); - - (void)strcat(strcat(strcpy(s, s1), s2), s3); - - return s; -} - -char * -newstr(char *s) -{ - - return strcpy(salloc(strlen(s) + 1), s); -} - -char * -basename(char *s) -{ - register char *p; - - if ((p = strrchr(s, '/')) == NULLSTR || *++p == '\0') - p = s; - - return p; -} - -char * -splice(char *v[], 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(char *s, char *t) -{ - register char *p; - - 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 lint - -#include "mace.h" - -char * -sysmess(void) -{ - static char ans[ERRLEN + 1]; - - if (errstr(ans) == SYSERROR) - return "broken errstr"; - - return ans; -} //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 lint - -#include "mace.h" - -msg_idx -mess_index(mbox *m, 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 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 lint - -#include "mace.h" - -void -vec_init(vec *v, int n) -{ - v->v_count = 0; - v->v_size = v->v_incr = n; - v->v_list = (char **)salloc(n * sizeof(char *)); -} - -char * -vec_str(vec *v, 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(vec *v, 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(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 lint - -#include "mace.h" - -int -write_file(char *f, char *s) -{ - register int fd; - register long l; - int ok; - - if ((fd = create(f, OWRITE, 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 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.36"; -#endif lint - -#include "mace.h" -#include "message.h" -#include "headers.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(char **m1, char **m2) -{ - return strcmp(*m1, *m2); -} - -int -show(char **v) -{ - while (*v != NULLSTR) - print("%c%s\n", BOX_CHAR, *v++); -} - -int -newbox(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(char **v) -{ - int ok; - - ok = 0; - - while (*v != NULLSTR) - { - if (delete_box(*v)) - ok = 1; - - v++; - } - - return ok; -} - -int -list(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; - } - - print("%c%-20s", BOX_CHAR, m->m_name); - - if (m->m_messid == NULLSTR) - { - for (i = 0; i < ID_LEN; i++) - print("%c", '?'); - } - else - print("%s", m->m_messid); - - if (m->m_count != 0) - print(" %4d %s", m->m_count, m->m_count == 1 ? "message" : "messages"); - else - print(" empty"); - - print("%c", '\n'); - v++; - - (void)free_box(m); - } - - return ok; -} - -int -set(char **v) -{ - return set_box(v[0]); -} - -int -analyse(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) - { - fprint(2, "%s: No current message in \"%c%s\".\n", my_name, BOX_CHAR, 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, 1, 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(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)) - { - free_box(mb); - errs = 1; - } - } - - return errs; -} - -void -validate(char **v, 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 - { - fprint(2, "%s: \"%s\" is not a box.\n", my_name, *n); - - if (*tp != NULLSTR && strcmp(*tp, *n) == 0) - *tp = NULLSTR; - } - } - - *v = NULLSTR; -} - -void -usage(void) -{ - fprint(2, "usage: %s [ -acdilmorst ] [ [%c]%cbox... ]\n", my_name, BOX_CHAR, BOX_CHAR); - exits("usage"); -} - -/* - * Choose the current box, `incoming', or `outgoing'. - */ -char * -select_box(void) -{ - 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) - { - fprint(2, "%s: No current box.\n", my_name); - exits("no current box"); - /* NOTREACHED */ - } - - return newstr(p); -} - -int -main(char argc, char *argv[]) -{ - register int i; - register int j; - int all; - vec bvec; - char *target; - int (*action)(char **); - - 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 = newbox; - 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 == newbox) - { - 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) - { - fprint(2, "%s: You have no boxes.\n", my_name); - exits("no boxes"); - /* 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 != newbox) - { - validate(bvec.v_list, &target); - - if (bvec.v_list[0] == NULLSTR) - exits("no valid boxes"); - } - else - (*action)(bvec.v_list); - - if - ( - (target != NULLSTR && set_box(target)) - || - (action != newbox && (*action)(bvec.v_list)) - ) - { - exits("box operation failed"); - /* NOTREACHED */ - } - - exits(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[] = "@(#)com.c 1.49"; -#endif lint - -#include "mace.h" -#include "message.h" -#include "headers.h" -#include "conf.h" -#include "line.h" -#include "addr.h" - -vec to; -vec cc; -char *subject = NULLSTR; -char *message_id = NULLSTR; -char *my_address = NULLSTR; -match *removeit = (match *)0; - -int sender = 0; -int include_current = 0; -int replying = 0; - -char *current; - -msg_idx -find_msg(mbox *m, char *s) -{ - msg_idx i; - - if (*s == '\0') - { - if (m->m_current == NULLMSG) - fprint(2, "%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) - fprint(2, "%s: No such message qualifier as \"%s\".\n", my_name, s); - - return i; -} - -mbox * -current_box(char *id) -{ - static mbox *mb = NULLBOX; - msg_idx idx; - char *box; - - if (mb != NULLBOX) - return mb; - - if ((box = curr_box()) == NULLSTR) - { - fprint(2, "%s: No current box.\n", my_name); - exits("no current box"); - /* NOTREACHED */ - } - - if ((mb = read_box(box)) == NULLBOX) - { - no_box(box); - exits("non-existant box"); - /* NOTREACHED */ - } - - (void)free(box); - - if (id != NULLSTR) - { - if ((idx = find_msg(mb, id)) == NULLMSG) - { - exits("non-existant message"); - /* 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) - { - fprint(2, "%s: No current message in \"%s\".\n", my_name, mb->m_name); - exits("no current message"); - /* NOTREACHED */ - } - - return mb; -} - -int -open_msg(char *id) -{ - mbox *mb; - char *msg; - int fd; - - mb = current_box(id); - - msg = concat3(mb->m_path, "/", mb->m_messid); - - if ((fd = open(msg, OREAD)) == SYSERROR) - { - could_not("open", msg); - /* NOTREACHED */ - } - - current = msg; - - return fd; -} - -/* - * Compare two addresses. - */ -int -same_address(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(vec *vp, char *s) -{ - char *p; - Addr *ap; - Addr *addrs; - - if ((p = parse_address(&addrs, s)) != NULLSTR) - { - fprint(2, "%s: \"%s\" %s.\n", my_name, s, p); - exits(p); - /* NOTREACHED */ - } - - 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, (Resub *)0, 0) == 0) - { - if (reg_error != NULLSTR) - fprint(2, "%s: Regular expression \"%s\" %s\n", my_name, removeit->m_re, reg_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); - } - } -} - -void -set_recipients(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) - { - fprint(2, "%s: No current message in \"%s\".\n", my_name, mb->m_name); - exits("no current message"); - /* 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 - ) - { - fprint(2, "%s: Missing \"%s\" or \"%s\" line in \"%s\".\n", my_name, RFC_REPLY_TO, RFC_FROM, mb->m_messid); - exits("no reply address"); - /* NOTREACHED */ - } - - if ((ht = header_text(*h)) == NULLSTR) - { - fprint(2, "%s: Malformed \"%s\" line in \"%s\".\n", my_name, p, mb->m_messid); - exits("broken header"); - /* NOTREACHED */ - } - - add_recipient(&to, ht); - - if ((h = find_header(&mp->ms_headers.v_list[0], RFC_TO)) != (char **)NULLSTR) - { - if ((ht = header_text(*h)) == NULLSTR) - { - fprint(2, "%s: Malformed \"%s\" line in \"%s\".\n", my_name, RFC_TO, mb->m_messid); - exits("broken header"); - /* NOTREACHED */ - } - - add_recipient(&to, ht); - } - - if ((h = find_header(&mp->ms_headers.v_list[0], RFC_CC)) != (char **)NULLSTR) - { - if ((ht = header_text(*h)) == NULLSTR) - { - fprint(2, "%s: Malformed \"%s\" line in \"%s\".\n", my_name, RFC_CC, mb->m_messid); - exits("broken header"); - /* NOTREACHED */ - } - - add_recipient(&cc, ht); - } - - 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); - - (void)free_mess(mp); -} - -void -tack_address(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(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; - - 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(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_mess(p)) != 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(char *msg, int ifd, int tfd) -{ - char *p; - lineio ld; - int e; - - (void)lopen(&ld, ifd, LREAD); - e = 0; - - if (seek(tfd, 0, 2) != SYSERROR) - { - while (e == 0 && (p = lread(&ld)) != NULLSTR) - { - e = fprint(tfd, "%s%s\n", FWD_LEADER, p) == SYSERROR; - (void)free(p); - } - - if (e == 0) - fprint(tfd, "\n"); - } - else - would_not("seek on", msg); - - if (lclose(&ld)) - { - (void)close(ifd); - (void)close(tfd); - (void)remove(msg); - could_not("read", current); - /* NOTREACHED */ - } - - if (close(ifd) == SYSERROR) - { - (void)close(tfd); - (void)remove(msg); - could_not("close", current); - /* NOTREACHED */ - } - - if (e) - { - (void)close(tfd); - (void)remove(msg); - could_not("write", msg); - /* NOTREACHED */ - } - - if (close(tfd) == SYSERROR) - { - (void)remove(msg); - could_not("close", msg); - /* NOTREACHED */ - } -} - -void -address(conf *cf) -{ - static char at[2] = { RFC_SPEC_AT, '\0' }; - static char dot[2] = { RFC_SPEC_DOT, '\0' }; - - my_address = concat3(user(), at, cf->c_address); -} - -void -usage(void) -{ - fprint(2, "usage: %s [ -is ] [ %cbox ] [ message ]\n", my_name, BOX_CHAR); - exits("usage"); - /* NOTREACHED */ -} - -int -main(int argc, char *argv[]) -{ - char *s; - char *box; - conf *cf; - mbox *mb; - int i; - int mfd; - int tfd; - char *id; - char *msg; - vec args; - vec proto; - char *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 's': - sender = 1; - continue; - - case 'i': - include_current = 1; - continue; - - default: - usage(); - /* NOTREACHED */ - } - - break; - } - } - - mfd = SYSERROR; - - if (strcmp(my_name, "com") == 0 && id != NULLSTR) - fprint(2, "%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") == 0) - { - replying = 1; - set_recipients(id); - } - - if (strcmp(my_name, "fwd") == 0 || include_current) - mfd = open_msg(id); - - /* - * If the box isn't specified choose one. - * - * If the current box is "inbox" or unknown - * choose "outbox", otherwise use the current box. - */ - if (box == NULLSTR) - { - if ((box = curr_box()) == NULLSTR || strcmp(box, cf->c_inbox) == 0) - box = cf->c_outbox; - } - - if ((mb = read_box(box)) == NULLBOX) - { - no_box(box); - exits("non-existant box"); - /* 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 && (tfd = create(msg, OWRITE, CREAT_MODE)) == SYSERROR) - { - could_not("open", msg); - /* NOTREACHED */ - } - - if (write_file(msg, s = splice(proto.v_list, "\n"))) - { - (void)remove(msg); - could_not("write", msg); - /* NOTREACHED */ - } - - (void)free(s); - vec_free(&proto); - - if (mfd != SYSERROR) - interpolate(msg, mfd, tfd); - - vec_init(&args, 4); - vec_str(&args, newstr(defenv(ENV_EDITOR, DEF_EDITOR))); - vec_str(&args, msg); - vec_str(&args, NULLSTR); - - if (set_state(msg, MESG_COMP)) - exits("set state"); - - /* - * Set a hint to deliver the message. - */ - s = salloc(sizeof DEL_STR + 1 + 1 + strlen(box) + 1 + strlen(id)); - sprint(s, "%s %c%s %s", DEL_STR, BOX_CHAR, box, id); - hint(s); - - ok = run(args.v_list); - - if (set_box(mb->m_name) || set_current(mb->m_name, id)) - { - if (ok == NULLSTR) - ok = "set current"; - } - - exits(ok); -} //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 lint - -#include "mace.h" - -#define MAILF_MODE 0622 -#define DELETE_STR "-delete" - -void -usage(void) -{ - fprint(2, "usage: %s [ %s ] [ -f mailfile ]\n", my_name, DELETE_STR); - exits("usage"); - /* NOTREACHED */ -} - -void -main(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; - } - } - - if (mail_check(mail, 1) == 0) - exits("no mail"); - - if (mail == NULLSTR) - mail = mail_name(); - - if ((fd = open(mail, OREAD)) == SYSERROR) - { - would_not("open", mail); - exits("open"); - } - - for (;;) - { - register long n; - - switch (n = read(fd, buf, sizeof buf)) - { - case SYSERROR: - would_not("read", mail); - exits("read"); - /* NOTREACHED */ - - case 0: - if (close(fd) == SYSERROR) - { - would_not("close", mail); - exits("close"); - /* NOTREACHED */ - } - break; - - default: - if (write(1, buf, n) != n) - { - would_not("write", ""); - exits("write"); - /* NOTREACHED */ - } - - continue; - } - - break; - } - - if (delete) - { - Dir dirb; - - (void)remove(mail); - - if ((fd = create(mail, ORDWR, CHAPPEND | CHEXCL | MAILF_MODE)) == SYSERROR) - { - would_not("create", mail); - exits("create"); - } - - if (dirfstat(fd, &dirb) == SYSERROR) - { - would_not("dirfstat", mail); - exits("dirfstat"); - } - - dirb.mode &= ~0777; - dirb.mode |= MAILF_MODE; - - if (dirfwstat(fd, &dirb) == SYSERROR) - { - would_not("dirfwstat", mail); - exits("dirfwstat"); - } - - if (close(fd) == SYSERROR) - { - would_not("close", mail); - exits("close"); - } - } - - exits(NULLSTR); -} //GO.SYSIN DD despool.c echo mace.c sed 's/.//' >mace.c <<'//GO.SYSIN DD mace.c' -/* - * mace [ -ds ] [ -f mailfile ] - * - * Mace your mail-file & extract the mail. - */ - -#ifndef lint -static char sccsid[] = "@(#)mace.c 1.46"; -#endif lint - -#include "mace.h" -#include "conf.h" -#include "line.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; -}; - -char *header_order[] = -{ - RFC_FROM, - RFC_DATE, - RFC_TO, - RFC_CC, - RFC_BCC, - RFC_SUBJECT, - NULLSTR, -}; - -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(lineio *lp, char *id) -{ - if (lp->l_fd != SYSERROR) - { - if (lclose(lp)) - { - fprint(2, "%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(lineio *lp, 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 = create(p, OWRITE, 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; -} - -/* - * Snarf away a regex match's private data. - */ -void -add_match(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(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++) - { - reg_error = NULLSTR; - - if (regexec(mp->m_cre, *n, (Resub *)0, 0) == 0) - { - if (reg_error != NULLSTR) - { - fprint(2, "%s: Regular expression \"%s\" %s\n", my_name, mp->m_re, reg_error); - break; - } - - continue; - } - - add_match(mlp, box, id, mp->m_action); - } - - mp = mp->m_next; - } -} - -/* - * Expand a string containing `exec' CE_SPECIAL substitutions. - */ -char * -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; -} - -/* - * Take a list of matches and run the corresponding commands. - */ -void -run_matches(matches **mp) -{ - matches *p; - int fd; - lineio l; - char *av[2]; - - av[0] = RC; - av[1] = NULLSTR; - - if ((fd = pipe_exec(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, 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) != NULLSTR) - would_not("close pipe to", av[0]); -} - -/* - * Re-order the headers in a message so they are in this order: - * - * From: - * Date: - * To: - * Cc: - * Bcc: - * Subject: - */ -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; - - if ((n = find_header(h->v_list, *hp)) != (char **)0) - { - 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; -} - -/* - * Simple RFC 822 canonical processing. - */ -int -rfc_peruse(conf *cf, char *box, char *id, char **ps) -{ - register char *p; - register char *q; - register char *s; - static char *agent = DELIVERY_AGENT; - static Reprog *re = (Reprog *)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'}; - - s = *ps; - - if (hdr.v_size == 0) - vec_init(&hdr, 64); - - if (agent != NULLSTR && re == (Reprog *)0) - { - if ((re = regcomp(agent)) == (Reprog *)0) - { - fprint(2, "%s: Regular expression \"%s\" %s\n", my_name, agent, reg_error); - agent = NULLSTR; - } - } - - if (*s == UNIX_FWD_CHAR) - { - 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) - { - fprint(2, "%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'; - - reg_error = NULLSTR; - - if (re == (Reprog *)0 || regexec(re, p, (Resub *)0, 0) == 0) - { - if (reg_error != NULLSTR) - { - fprint(2, "%s: Regular expression \"%s\" %s\n", my_name, agent, reg_error); - re = (Reprog *)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: - { - 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); - - 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, 1, 0, 0); - - first = 0; - } - - *ps = splice(&hdr.v_list[0], "\n"); - - 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(conf *cf, lineio *mlp, char *box, char *id) -{ - char *s; - - s = newstr(""); - - (void)rfc_peruse(cf, box, id, &s); - - if ((mlp->l_flag & LERROR) == 0 && lwrite(mlp, s) == NULLSTR) - fprint(2, "%s: Warning - \"%s\" may be incomplete. %s\n", my_name, id, sysmess()); - - (void)free(s); - - return (mlp->l_flag & LERROR) != 0; -} - -char * -mace(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; - - if ((mb = read_box(cf->c_inbox)) == NULLBOX) - { - fprint(2, "%s: Incoming box \"%c%s\" does not exist.\n", my_name, BOX_CHAR, cf->c_inbox); - return "no incoming box"; - } - - audit = concat3(mace_dir(), "/", AUDIT); - - if (!mail_check(mf, 0)) - return "no mail"; - - if (set_box(cf->c_inbox)) - return "can't set incoming box current"; - - if (do_audit) - { - if ((fd = open(audit, OWRITE)) == SYSERROR) - { - if ((fd = create(audit, OWRITE, CHAPPEND | CHEXCL | CREAT_MODE)) == SYSERROR) - { - could_not("create", audit); - exits("create"); - } - } - else - { - Dir dirb; - - if (dirfstat(fd, &dirb) == SYSERROR) - { - could_not("dirfstat", audit); - exits("dirfstat"); - } - - if ((dirb.mode & (CHAPPEND | CHEXCL)) != (CHAPPEND | CHEXCL)) - { - fprint(2, "%s: Audit file \"%s\" is not an autolocking append file.\n", my_name, audit); - exits("weird audit file"); - } - } - - (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); - } - - (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) - { -#ifdef MORF - if (strcmp(s, MORF) == 0) - { - (void)free(s); - continue; - } -#endif MORF - - if ((mld.l_flag & LERROR) == 0 && lwrite(&mld, s) == NULLSTR) - { - fprint(2, "%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)) - { - fprint(2, "%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) - { - fprint(2, "%s: \"%s\" line close error.\n", my_name, cf->c_despool, sysmess()); - fail = 1; - } - - if (pipe_close(fd) != 0) - { - fprint(2, "%s: \"%s\" despooling error.\n", my_name, cf->c_despool, sysmess()); - fail = 1; - } - - (void)free(audit); - - run_matches(&cmds); - - return fail ? "trouble" : NULLSTR; -} - -void -usage(void) -{ - fprint(2, "usage: %s [ -ds ] [ -f mailfile ]\n", my_name); - exits("usage"); - /* NOTREACHED */ -} - -void -main(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 '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; - } - } - - /* - * Here's hoping... - */ - if (atnotify(nonotes, 1) == SYSERROR) - { - would_not("atnotify", "notes"); - exits("atnotify"); - } - - exits(mace(read_config(), mail_file, delete)); -} //GO.SYSIN DD mace.c echo mad.c sed 's/.//' >mad.c <<'//GO.SYSIN DD mad.c' -/* - * mad|mcp +box messages... - * - * mad - add messages to a box - * - * mcp - copy messages to a box - */ - -#ifndef lint -static char sccsid[] = "@(#)mad.c 1.29"; -#endif lint - -#include "mace.h" -#include "message.h" - -int -mcp(char *s, char *t) -{ - int rfd; - int wfd; - long n; - char buf[FS_BLKZ]; - int state; - - if ((rfd = open(s, OREAD)) == SYSERROR) - { - would_not("open", s); - return 1; - } - - if ((wfd = create(t, OWRITE, CREAT_MODE)) == SYSERROR) - { - (void)close(rfd); - would_not("create", t); - return 1; - } - - /* propagate message state */ - if (get_state(s, &state) || set_state(t, state)) - goto disaster; - - 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)remove(t); - return 1; - } - - if (close(wfd) == SYSERROR) - { - (void)remove(t); - return 1; - } - - return 0; - -disaster: - (void)close(rfd); - (void)close(wfd); - (void)remove(t); - - return 1; -} - -int -mad(char *s, char *t) -{ - if - ( - mcp(s, t) - || - remove(s) == SYSERROR - ) - { - would_not("move", s); - (void)remove(t); - return 1; - } - - return 0; -} - -/* - * Ignore interrupts and hangups. - */ -int -nonotes(void *r, char *s) -{ - USED(r); - return strcmp(s, "interrupt") == 0 || strcmp(s, "hangup") == 0; -} - -void -usage(void) -{ - fprint(2, "usage: %s %cbox messages...\n", my_name, BOX_CHAR); - exits("usage"); - /* NOTREACHED */ -} - -void -main(int argc, char *argv[]) -{ - mbox *mb; - int i; - char *id; - int (*action)(char *, char *); - 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 - { - fprint(2, "%s: Invocation error.\n", my_name); - exits("invocation error"); - } - - if (argc < 3 || argv[1][0] != BOX_CHAR || argv[1][1] == '\0') - { - usage(); - /* NOTREACHED */ - } - - box = &argv[1][1]; - - if ((mb = read_box(box)) == NULLBOX) - { - fprint(2, "%s: No such box as \"%s\".\n", my_name, box); - exits("no such box"); - } - - 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); - - if (atnotify(nonotes, 1) == SYSERROR) - { - would_not("atnotify", "notes"); - exits("atnotify"); - } - - if ((*action)(argv[i], p)) - ok = 1; - else if (set_current(mb->m_name, id)) - ok = 1; - - if (atnotify(nonotes, 0) == SYSERROR) - { - would_not("atnotify", "notes"); - exits("de-atnotify"); - } - - free(p); - p = id; - id = nextid(id); - free(p); - } - - exits(ok ? "mad anomaly" : NULLSTR); -} //GO.SYSIN DD mad.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.28"; -#endif lint - -#include "mace.h" -#include "conf.h" -#include "line.h" -#include "headers.h" -#include "message.h" -#include "addr.h" - -#ifndef RFC_DELIVERER - -/* - * Turn an RFC 822 address into a network address argument. - */ -char * -net_address(vec*vp, 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; -} - -/* - * Pipe the message into the delivery agent after some validation. - */ -int -deliver(char *d, char *m) -{ - register char *p; - register message *mp; - register char **h; - lineio mld; - lineio pld; - vec args; - int mfd; - int pfd; - int headers; - - /* - * Read its headers. - */ - if ((mp = parse_mess(m)) == NULLMESS) - { - would_not("open", m); - return 1; - } - - /* - * Date field? - */ - if - ( - (h = find_header(&mp->ms_headers.v_list[0], RFC_DATE)) == (char **)NULLSTR - || - header_text(*h) == NULLSTR - ) - { - fprint(2, "%s: \"%s\": Missing \"%s\" field.\n", my_name, m, RFC_DATE); - free_mess(mp); - return 1; - } - - /* - * From field? - */ - if - ( - (h = find_header(&mp->ms_headers.v_list[0], RFC_FROM)) == (char **)NULLSTR - || - (p = header_text(*h)) == NULLSTR - ) - { - fprint(2, "%s: \"%s\": Missing \"%s\" field.\n", my_name, m, RFC_FROM); - free_mess(mp); - return 1; - } - - vec_init(&args, 32); - - /* - * From field addresses ok? - */ - if ((p = net_address(&args, p)) != NULLSTR) - { - fprint(2, "%s: \"%s\": \"%s\" address error; %s\n", my_name, m, RFC_FROM, p); - vec_free(&args); - free_mess(mp); - return 1; - } - - /* - * If there's no Sender field ther can only be one From field. - */ - if - ( - (h = find_header(&mp->ms_headers.v_list[0], RFC_SENDER)) == (char **)NULLSTR - || - (p = header_text(*h)) == NULLSTR - ) - { - if (args.v_count > 1) - { - fprint(2, "%s: \"%s\": Multiple \"%s\" addresses require a \"%s\" field.\n", my_name, m, RFC_FROM, RFC_SENDER); - vec_free(&args); - free_mess(mp); - return 1; - } - } - - vec_free(&args); - - /* - * To field? - */ - if ((h = find_header(&mp->ms_headers.v_list[0], RFC_TO)) == (char **)NULLSTR) - { - fprint(2, "%s: \"%s\": Missing \"%s\" field.\n", my_name, m, RFC_TO); - free_mess(mp); - return 1; - } - - vec_init(&args, 32); - vec_str(&args, d); - - if ((p = header_text(*h)) == NULLSTR) - { - fprint(2, "%s: \"%s\": No recipients specified by \"%s\" field.\n", my_name, m, RFC_TO); - goto disaster; - } - - if ((p = net_address(&args, p)) != NULLSTR) - { - fprint(2, "%s: \"%s\": \"%s\" address error; %s\n", my_name, m, RFC_TO, p); - goto disaster; - } - - /* - * Cc field? - */ - if - ( - (h = find_header(&mp->ms_headers.v_list[0], RFC_CC)) != (char **)NULLSTR - && - (p = header_text(*h)) != NULLSTR - ) - { - if ((p = net_address(&args, p)) != NULLSTR) - { - fprint(2, "%s: \"%s\": \"%s\" address error; %s\n", my_name, m, RFC_CC, p); - goto disaster; - } - } - - /* - * Bcc field? - */ - if - ( - (h = find_header(&mp->ms_headers.v_list[0], RFC_BCC)) != (char **)NULLSTR - && - (p = header_text(*h)) != NULLSTR - ) - { - if ((p = net_address(&args, p)) != NULLSTR) - { - fprint(2, "%s: \"%s\": \"%s\" address error; %s\n", my_name, m, RFC_BCC, p); - goto disaster; - } - } - - vec_str(&args, NULLSTR); - - /* - * Pipe it into the deliver agent. - */ - if ((mfd = open(m, OREAD)) == SYSERROR) - { - would_not("open", m); - goto disaster; - } - - (void)lopen(&mld, mfd, LREAD); - - if ((pfd = pipe_exec(args.v_list, 'w')) == SYSERROR) - { - 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 ((p = pipe_close(pfd)) != NULLSTR) - { - fprint(2, "%s: Could not deliver \"%s\": %s\n", my_name, m, p); - goto disaster; - } - - free_mess(mp); - vec_free(&args); - return 0; - -disaster: - free_mess(mp); - vec_free(&args); - return 1; -} - -#else RFC_DELIVERER - -#ifdef RFC_VALIDATE - -/* - * Check that the suplied 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(char *m) -{ - register char **cp; - register message *mp; - int ok; - static char *check[] = - { - RFC_FROM, - RFC_TO, - RFC_CC, - RFC_BCC, - NULLSTR, - }; - - ok = 0; - - /* - * Read its headers. - */ - if ((mp = parse_mess(m)) == NULLMESS) - { - would_not("open", m); - return 1; - } - - /* - * Check the specified headers. - */ - for (cp = check; *cp != NULLSTR; cp++) - { - register char **h; - register char *p; - Addr *ap; - - /* - * Grab headers. - */ - if ((h = find_header(&mp->ms_headers.v_list[0], *cp)) == (char **)0) - continue; - - /* - * Snarf header text. - */ - if ((p = header_text(*h)) == NULLSTR) - { - fprint(2, "%s: \"%s\": Null \"%s\" header.\n", my_name, m, *cp); - ok = 1; - continue; - } - - /* - * Parse the address and check that it's legal. - */ - if ((p = parse_address(&ap, p)) == NULLSTR) - continue; - - fprint(2, "%s: \"%s\": \"%s\" address error; %s\n", my_name, m, *cp, p); - ok = 1; - } - - (void)free_mess(mp); - - return ok; -} - -#endif RFC_VALIDATE - -/* - * The delivery agent understands about the recipients - * being embedded in the message itself. - */ -int -deliver(char *d, char *m) -{ - int fd; - int ok; - char *agent = DELIVERER; - char *argv[2]; - - if (agent == NULLSTR) - { - fatal("deliver"); - /* NOTREACHED */ - } - - (void)close(0); - - if ((fd = open(m, OREAD)) != 0) - { - would_not("open", m); - (void)close(fd); - return 1; - } - -#ifdef RFC_VALIDATE - if (headers_ok(m)) - { - (void)close(fd); - return 1; - } -#endif RFC_VALIDATE - - argv[0] = d; - argv[1] = NULLSTR; - - ok = run(argv) != NULLSTR; - - if (close(0) == SYSERROR) - { - would_not("close", m); - ok = 1; - } - - return ok; -} - -#endif RFC_DELIVERER - -void -usage(void) -{ - fprint(2, "usage: %s messages...\n", my_name); - exits("usage"); - /* NOTREACHED */ -} - -void -main(int argc, char *argv[]) -{ - int i; - conf *cf; - 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; - } - - exits(ok ? "delivery error" : NULLSTR); -} //GO.SYSIN DD mda.c echo msg.c sed 's/.//' >msg.c <<'//GO.SYSIN DD msg.c' -/* - * msg - show messages - */ - -#ifndef lint -static char sccsid[] = "@(#)msg.c 1.37"; -#endif lint - -#include "mace.h" -#include "flex.h" -#include "message.h" - -char *target = NULLSTR; /* target box for mov|cop */ -char *new_box = NULLSTR; /* new current box */ - -int -apply(char *it, 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) != NULLSTR; - - (void)free((char *)argv); - - return s != 0; -} - -int -msg(vec *v) -{ - return apply(defenv(ENV_PAGER, DEF_PAGER), v); -} - -int -med(vec *v) -{ - return apply(defenv(ENV_EDITOR, DEF_EDITOR), v); -} - -int -rem(vec *v) -{ - register int i; - int ok; - - ok = 0; - - for (i = 0; i < v->v_count; i++) - { - if (remove(v->v_list[i]) == SYSERROR) - { - would_not("remove", v->v_list[i]); - ok = 1; - } - } - - return ok; -} - -int -invoke_alias(char *s, 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(vec *v) -{ - return invoke_alias(MAD_STR, v); -} - -int -cop(vec *v) -{ - return invoke_alias(MCP_STR, v); -} - -int -del(vec *v) -{ - return apply(MDA_STR, v); -} - -void -usage(void) -{ - fprint(2, "usage: %s [ [%c]%cbox ] [ first|previous|current|next|last|id|all ] ...\n", my_name, BOX_CHAR, BOX_CHAR); - exits("usage"); -} - -void -busage(void) -{ - fprint(2, "usage: %s [ [%c]%cbox ] [ first|previous|current|next|last|id|all ] ... [%c]%cbox\n", my_name, BOX_CHAR, BOX_CHAR, BOX_CHAR, BOX_CHAR); - exits("usage"); -} - -int -main(int argc, char *argv[]) -{ - register int i; - int (*action)(vec *); - vec mvec; - - name(argv[0]); - - if (strcmp(my_name, "msg") == 0) - action = msg; - else if (strcmp(my_name, "rem") == 0) - action = rem; - else if (strcmp(my_name, "med") == 0) - action = med; - else if (strcmp(my_name, "mov") == 0) - action = mov; - else if (strcmp(my_name, "del") == 0) - action = del; - else if (strcmp(my_name, "cop") == 0) - action = cop; - else - { - fprint(2, "%s: Invocation error.\n", my_name); - exits("invocation error"); - /* NOTREACHED */ - } - - vec_init(&mvec, 64); - - if (action == mov || action == cop) - { - 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) - { - fprint(2, "%s: No such box as \"%s\".\n", my_name, target); - exits("non-existant box"); - } - - (void)free(p); - } - - args_to_messages(argc, argv, &mvec, &new_box); - - /* - * If it's a single message set a hint to point to it. - */ - if (mvec.v_count == 1) - { - char s[1024]; - char *box; - char *id; - - path_to_mess(mvec.v_list[0], &box, &id); - sprint(s, "rem %c%s %s ; rep %c%s %s ; msg %c%s prev ; msg %c%s next", BOX_CHAR, box, id, BOX_CHAR, box, id, BOX_CHAR, box, BOX_CHAR, box); - hint(s); - } - - if - ( - (new_box != NULLSTR && set_box(new_box)) - || - mvec.v_count == 0 - || - (*action)(&mvec) - ) - { - exits("message operation failed"); - /* 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; - - exits(ok ? "current message not set" : NULLSTR); - /* NOTREACHED */ - } -} //GO.SYSIN DD msg.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.2"; -#endif lint - -#ifdef unix -#include -#endif -#include -#include -#include "mace.h" -#include "message.h" - -void -usage(void) -{ - fprint(2, "usage: %s\n", my_name); - exits("usage"); - /* NOTREACHED */ -} - -int -set(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 - { - no_box(box); - ok = 1; - } - - return ok; -} - -main(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) - { - exits("mark file missing"); - /* 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') - { - fprint(2, "%s: \"%s\": missing message-id.\n", my_name, p, BOX_CHAR); - ok = 1; - m++; - break; - } - - m++; - } - } - else - { - fprint(2, "%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 (remove(p) == SYSERROR) - { - would_not("remove", p); - ok = 1; - } - - return ok; -} //GO.SYSIN DD ret.c