From 5b62e993b0af39700031c2875d7f6654e6a02850 Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Tue, 14 Feb 2006 13:41:33 +0000 Subject: [PATCH 1/1] Import ezmlm 0.53 --- BIN | 11 + BLURB | 50 ++++ CHANGES | 4 + FILES | 279 +++++++++++++++++ INSTALL | 52 ++++ MAN | 27 ++ Makefile | 909 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ README | 31 ++ SYSDEPS | 7 + THANKS | 14 + TODO | 7 + VERSION | 1 + alloc.3 | 62 ++++ alloc.c | 32 ++ alloc.h | 8 + alloc=0 | 1 + alloc=l | 2 + alloc_re.c | 17 ++ auto-str.c | 44 +++ auto-str=x | 3 + auto_bin.c.do | 3 + auto_bin.h | 6 + auto_qmail.c.do | 3 + auto_qmail.h | 6 + byte.h | 13 + byte_chr.c | 20 ++ byte_copy.c | 14 + byte_cr.c | 16 + byte_diff.c | 16 + byte_rchr.c | 23 ++ byte_zero.c | 13 + case.3 | 100 +++++++ case.h | 13 + case=0 | 1 + case=l | 3 + case_diffb.c | 21 ++ case_lowerb.c | 14 + case_startb.c | 21 ++ conf-bin | 3 + conf-cc | 3 + conf-ld | 3 + conf-man | 5 + conf-qmail | 3 + constmap.c | 114 +++++++ constmap.h | 20 ++ cookie.c | 47 +++ cookie.h | 8 + date822fmt.c | 29 ++ date822fmt.h | 7 + datetime.3 | 73 +++++ datetime.c | 55 ++++ datetime.h | 20 ++ datetime=0 | 1 + default.0.do | 9 + default.a.do | 10 + default.do | 76 +++++ default.o.do | 15 + direntry.3 | 36 +++ direntry.h.do | 7 + direntry.h1 | 8 + direntry.h2 | 8 + direntry=0 | 1 + env.3 | 31 ++ env.h | 17 ++ env=0 | 1 + env=l | 1 + envread.c | 30 ++ error.3 | 45 +++ error.c | 95 ++++++ error.h | 23 ++ error=0 | 1 + error=l | 2 + error_str.3 | 19 ++ error_str.c | 276 +++++++++++++++++ error_str=0 | 1 + error_temp.3 | 27 ++ error_temp=0 | 1 + exit.h | 6 + ezmlm-list.1 | 22 ++ ezmlm-list.c | 62 ++++ ezmlm-list=0 | 1 + ezmlm-list=x | 8 + ezmlm-make.1 | 87 ++++++ ezmlm-make.c | 435 +++++++++++++++++++++++++++ ezmlm-make=0 | 1 + ezmlm-make=x | 9 + ezmlm-manage.1 | 129 ++++++++ ezmlm-manage.c | 403 +++++++++++++++++++++++++ ezmlm-manage=0 | 1 + ezmlm-manage=x | 29 ++ ezmlm-reject.1 | 32 ++ ezmlm-reject.c | 82 +++++ ezmlm-reject=0 | 1 + ezmlm-reject=x | 9 + ezmlm-return.1 | 71 +++++ ezmlm-return.c | 364 +++++++++++++++++++++++ ezmlm-return=0 | 1 + ezmlm-return=x | 23 ++ ezmlm-send.1 | 86 ++++++ ezmlm-send.c | 319 ++++++++++++++++++++ ezmlm-send=0 | 1 + ezmlm-send=x | 21 ++ ezmlm-sub.1 | 38 +++ ezmlm-sub.c | 33 ++ ezmlm-sub=0 | 1 + ezmlm-sub=x | 14 + ezmlm-unsub.1 | 35 +++ ezmlm-unsub.c | 34 +++ ezmlm-unsub=0 | 1 + ezmlm-unsub=x | 14 + ezmlm-warn.1 | 39 +++ ezmlm-warn.c | 254 ++++++++++++++++ ezmlm-warn=0 | 1 + ezmlm-warn=x | 26 ++ ezmlm-weed.1 | 109 +++++++ ezmlm-weed.c | 94 ++++++ ezmlm-weed=0 | 1 + ezmlm-weed=x | 7 + ezmlm.5 | 317 ++++++++++++++++++++ ezmlm=0 | 1 + fd.h | 7 + fd=l | 2 + fd_copy.3 | 44 +++ fd_copy.c | 13 + fd_copy=0 | 1 + fd_move.3 | 41 +++ fd_move.c | 11 + fd_move=0 | 1 + find-systype.sh | 144 +++++++++ fmt.h | 25 ++ fmt_str.c | 12 + fmt_uint.c | 6 + fmt_uint0.c | 10 + fmt_ulong.c | 13 + fork.h.do | 7 + fork.h1 | 7 + fork.h2 | 7 + fs=l | 6 + gen_alloc.h | 7 + gen_allocdefs.h | 34 +++ getconf.c | 61 ++++ getconf.h | 7 + getln.3 | 51 ++++ getln.c | 20 ++ getln.h | 7 + getln2.3 | 64 ++++ getln2.c | 31 ++ getln2=0 | 1 + getln=0 | 1 + getln=l | 2 + getopt.3 | 235 +++++++++++++++ getopt=0 | 1 + getopt=l | 2 + hasflock.h.do | 7 + hassgact.h.do | 7 + install.c | 140 +++++++++ install=x | 9 + issub.c | 87 ++++++ issub.h | 10 + it.do | 4 + lock.h | 8 + lock=l | 1 + lock_ex.c | 11 + log.c | 37 +++ log.h | 6 + make-compile.sh | 1 + make-load.sh | 2 + make-makelib.sh | 16 + man.do | 31 ++ now.3 | 14 + now.c | 8 + now.h | 8 + now=0 | 1 + open.h | 10 + open=l | 3 + open_append.c | 6 + open_read.c | 6 + open_trunc.c | 6 + qmail.c | 103 +++++++ qmail.h | 36 +++ quote.c | 82 +++++ quote.h | 8 + readwrite.h | 7 + scan.h | 27 ++ scan_8long.c | 11 + scan_ulong.c | 11 + seek.h | 15 + seek=l | 1 + seek_set.c | 7 + setup.do | 5 + sgetopt.3 | 28 ++ sgetopt.c | 54 ++++ sgetopt.h | 21 ++ sgetopt=0 | 1 + sig.h | 43 +++ sig=l | 2 + sig_catch.c | 18 ++ sig_pipe.c | 5 + slurp.c | 19 ++ slurp.h | 6 + slurpclose.c | 19 ++ slurpclose.h | 6 + str.h | 14 + str=l | 13 + str_chr.c | 19 ++ str_cpy.c | 16 + str_diff.c | 17 ++ str_diffn.c | 18 ++ str_len.c | 15 + str_rchr.c | 22 ++ str_start.c | 15 + stralloc.3 | 160 ++++++++++ stralloc.h | 21 ++ stralloc=0 | 1 + stralloc=l | 9 + stralloc_arts.c | 12 + stralloc_cat.c | 9 + stralloc_catb.c | 15 + stralloc_cats.c | 10 + stralloc_copy.c | 9 + stralloc_eady.c | 6 + stralloc_opyb.c | 14 + stralloc_opys.c | 10 + stralloc_pend.c | 5 + strerr.c | 22 ++ strerr.h | 80 +++++ strerr=l | 3 + strerr_die.c | 37 +++ strerr_sys.c | 12 + subfd.3 | 61 ++++ subfd.h | 15 + subfd=0 | 1 + subfderr.c | 7 + subgetopt.3 | 357 ++++++++++++++++++++++ subgetopt.c | 79 +++++ subgetopt.h | 24 ++ subgetopt=0 | 1 + subscribe.c | 127 ++++++++ subscribe.h | 10 + substdi.c | 91 ++++++ substdio.3 | 115 +++++++ substdio.c | 15 + substdio.h | 47 +++ substdio=0 | 1 + substdio=l | 5 + substdio_copy.3 | 41 +++ substdio_copy.c | 18 ++ substdio_copy=0 | 1 + substdio_in.3 | 140 +++++++++ substdio_in=0 | 1 + substdio_out.3 | 99 ++++++ substdio_out=0 | 1 + substdo.c | 108 +++++++ surf.3 | 23 ++ surf.c | 27 ++ surf.h | 6 + surf=0 | 1 + surf=l | 2 + surfpcs.3 | 69 +++++ surfpcs.c | 58 ++++ surfpcs.h | 20 ++ surfpcs=0 | 1 + targets.do | 1 + trycpp.c | 7 + trydrent.c | 8 + tryflock.c | 8 + trysgact.c | 10 + tryulong32.c | 11 + tryvfork.c | 4 + trywaitp.c | 7 + uint32.h.do | 7 + uint32.h1 | 6 + uint32.h2 | 6 + wait.3 | 93 ++++++ wait.h | 14 + wait=0 | 1 + wait=l | 1 + wait_pid.c | 13 + warn-auto.sh | 2 + 279 files changed, 10430 insertions(+) create mode 100644 BIN create mode 100644 BLURB create mode 100644 CHANGES create mode 100644 FILES create mode 100644 INSTALL create mode 100644 MAN create mode 100644 Makefile create mode 100644 README create mode 100644 SYSDEPS create mode 100644 THANKS create mode 100644 TODO create mode 100644 VERSION create mode 100644 alloc.3 create mode 100644 alloc.c create mode 100644 alloc.h create mode 100644 alloc=0 create mode 100644 alloc=l create mode 100644 alloc_re.c create mode 100644 auto-str.c create mode 100644 auto-str=x create mode 100644 auto_bin.c.do create mode 100644 auto_bin.h create mode 100644 auto_qmail.c.do create mode 100644 auto_qmail.h create mode 100644 byte.h create mode 100644 byte_chr.c create mode 100644 byte_copy.c create mode 100644 byte_cr.c create mode 100644 byte_diff.c create mode 100644 byte_rchr.c create mode 100644 byte_zero.c create mode 100644 case.3 create mode 100644 case.h create mode 100644 case=0 create mode 100644 case=l create mode 100644 case_diffb.c create mode 100644 case_lowerb.c create mode 100644 case_startb.c create mode 100644 conf-bin create mode 100644 conf-cc create mode 100644 conf-ld create mode 100644 conf-man create mode 100644 conf-qmail create mode 100644 constmap.c create mode 100644 constmap.h create mode 100644 cookie.c create mode 100644 cookie.h create mode 100644 date822fmt.c create mode 100644 date822fmt.h create mode 100644 datetime.3 create mode 100644 datetime.c create mode 100644 datetime.h create mode 100644 datetime=0 create mode 100644 default.0.do create mode 100644 default.a.do create mode 100644 default.do create mode 100644 default.o.do create mode 100644 direntry.3 create mode 100644 direntry.h.do create mode 100644 direntry.h1 create mode 100644 direntry.h2 create mode 100644 direntry=0 create mode 100644 env.3 create mode 100644 env.h create mode 100644 env=0 create mode 100644 env=l create mode 100644 envread.c create mode 100644 error.3 create mode 100644 error.c create mode 100644 error.h create mode 100644 error=0 create mode 100644 error=l create mode 100644 error_str.3 create mode 100644 error_str.c create mode 100644 error_str=0 create mode 100644 error_temp.3 create mode 100644 error_temp=0 create mode 100644 exit.h create mode 100644 ezmlm-list.1 create mode 100644 ezmlm-list.c create mode 100644 ezmlm-list=0 create mode 100644 ezmlm-list=x create mode 100644 ezmlm-make.1 create mode 100644 ezmlm-make.c create mode 100644 ezmlm-make=0 create mode 100644 ezmlm-make=x create mode 100644 ezmlm-manage.1 create mode 100644 ezmlm-manage.c create mode 100644 ezmlm-manage=0 create mode 100644 ezmlm-manage=x create mode 100644 ezmlm-reject.1 create mode 100644 ezmlm-reject.c create mode 100644 ezmlm-reject=0 create mode 100644 ezmlm-reject=x create mode 100644 ezmlm-return.1 create mode 100644 ezmlm-return.c create mode 100644 ezmlm-return=0 create mode 100644 ezmlm-return=x create mode 100644 ezmlm-send.1 create mode 100644 ezmlm-send.c create mode 100644 ezmlm-send=0 create mode 100644 ezmlm-send=x create mode 100644 ezmlm-sub.1 create mode 100644 ezmlm-sub.c create mode 100644 ezmlm-sub=0 create mode 100644 ezmlm-sub=x create mode 100644 ezmlm-unsub.1 create mode 100644 ezmlm-unsub.c create mode 100644 ezmlm-unsub=0 create mode 100644 ezmlm-unsub=x create mode 100644 ezmlm-warn.1 create mode 100644 ezmlm-warn.c create mode 100644 ezmlm-warn=0 create mode 100644 ezmlm-warn=x create mode 100644 ezmlm-weed.1 create mode 100644 ezmlm-weed.c create mode 100644 ezmlm-weed=0 create mode 100644 ezmlm-weed=x create mode 100644 ezmlm.5 create mode 100644 ezmlm=0 create mode 100644 fd.h create mode 100644 fd=l create mode 100644 fd_copy.3 create mode 100644 fd_copy.c create mode 100644 fd_copy=0 create mode 100644 fd_move.3 create mode 100644 fd_move.c create mode 100644 fd_move=0 create mode 100644 find-systype.sh create mode 100644 fmt.h create mode 100644 fmt_str.c create mode 100644 fmt_uint.c create mode 100644 fmt_uint0.c create mode 100644 fmt_ulong.c create mode 100644 fork.h.do create mode 100644 fork.h1 create mode 100644 fork.h2 create mode 100644 fs=l create mode 100644 gen_alloc.h create mode 100644 gen_allocdefs.h create mode 100644 getconf.c create mode 100644 getconf.h create mode 100644 getln.3 create mode 100644 getln.c create mode 100644 getln.h create mode 100644 getln2.3 create mode 100644 getln2.c create mode 100644 getln2=0 create mode 100644 getln=0 create mode 100644 getln=l create mode 100644 getopt.3 create mode 100644 getopt=0 create mode 100644 getopt=l create mode 100644 hasflock.h.do create mode 100644 hassgact.h.do create mode 100644 install.c create mode 100644 install=x create mode 100644 issub.c create mode 100644 issub.h create mode 100644 it.do create mode 100644 lock.h create mode 100644 lock=l create mode 100644 lock_ex.c create mode 100644 log.c create mode 100644 log.h create mode 100644 make-compile.sh create mode 100644 make-load.sh create mode 100644 make-makelib.sh create mode 100644 man.do create mode 100644 now.3 create mode 100644 now.c create mode 100644 now.h create mode 100644 now=0 create mode 100644 open.h create mode 100644 open=l create mode 100644 open_append.c create mode 100644 open_read.c create mode 100644 open_trunc.c create mode 100644 qmail.c create mode 100644 qmail.h create mode 100644 quote.c create mode 100644 quote.h create mode 100644 readwrite.h create mode 100644 scan.h create mode 100644 scan_8long.c create mode 100644 scan_ulong.c create mode 100644 seek.h create mode 100644 seek=l create mode 100644 seek_set.c create mode 100644 setup.do create mode 100644 sgetopt.3 create mode 100644 sgetopt.c create mode 100644 sgetopt.h create mode 100644 sgetopt=0 create mode 100644 sig.h create mode 100644 sig=l create mode 100644 sig_catch.c create mode 100644 sig_pipe.c create mode 100644 slurp.c create mode 100644 slurp.h create mode 100644 slurpclose.c create mode 100644 slurpclose.h create mode 100644 str.h create mode 100644 str=l create mode 100644 str_chr.c create mode 100644 str_cpy.c create mode 100644 str_diff.c create mode 100644 str_diffn.c create mode 100644 str_len.c create mode 100644 str_rchr.c create mode 100644 str_start.c create mode 100644 stralloc.3 create mode 100644 stralloc.h create mode 100644 stralloc=0 create mode 100644 stralloc=l create mode 100644 stralloc_arts.c create mode 100644 stralloc_cat.c create mode 100644 stralloc_catb.c create mode 100644 stralloc_cats.c create mode 100644 stralloc_copy.c create mode 100644 stralloc_eady.c create mode 100644 stralloc_opyb.c create mode 100644 stralloc_opys.c create mode 100644 stralloc_pend.c create mode 100644 strerr.c create mode 100644 strerr.h create mode 100644 strerr=l create mode 100644 strerr_die.c create mode 100644 strerr_sys.c create mode 100644 subfd.3 create mode 100644 subfd.h create mode 100644 subfd=0 create mode 100644 subfderr.c create mode 100644 subgetopt.3 create mode 100644 subgetopt.c create mode 100644 subgetopt.h create mode 100644 subgetopt=0 create mode 100644 subscribe.c create mode 100644 subscribe.h create mode 100644 substdi.c create mode 100644 substdio.3 create mode 100644 substdio.c create mode 100644 substdio.h create mode 100644 substdio=0 create mode 100644 substdio=l create mode 100644 substdio_copy.3 create mode 100644 substdio_copy.c create mode 100644 substdio_copy=0 create mode 100644 substdio_in.3 create mode 100644 substdio_in=0 create mode 100644 substdio_out.3 create mode 100644 substdio_out=0 create mode 100644 substdo.c create mode 100644 surf.3 create mode 100644 surf.c create mode 100644 surf.h create mode 100644 surf=0 create mode 100644 surf=l create mode 100644 surfpcs.3 create mode 100644 surfpcs.c create mode 100644 surfpcs.h create mode 100644 surfpcs=0 create mode 100644 targets.do create mode 100644 trycpp.c create mode 100644 trydrent.c create mode 100644 tryflock.c create mode 100644 trysgact.c create mode 100644 tryulong32.c create mode 100644 tryvfork.c create mode 100644 trywaitp.c create mode 100644 uint32.h.do create mode 100644 uint32.h1 create mode 100644 uint32.h2 create mode 100644 wait.3 create mode 100644 wait.h create mode 100644 wait=0 create mode 100644 wait=l create mode 100644 wait_pid.c create mode 100644 warn-auto.sh diff --git a/BIN b/BIN new file mode 100644 index 0000000..76f0320 --- /dev/null +++ b/BIN @@ -0,0 +1,11 @@ +d:::755::: +c:::755:/:ezmlm-make: +c:::755:/:ezmlm-manage: +c:::755:/:ezmlm-send: +c:::755:/:ezmlm-reject: +c:::755:/:ezmlm-return: +c:::755:/:ezmlm-warn: +c:::755:/:ezmlm-weed: +c:::755:/:ezmlm-list: +c:::755:/:ezmlm-sub: +c:::755:/:ezmlm-unsub: diff --git a/BLURB b/BLURB new file mode 100644 index 0000000..a9ca479 --- /dev/null +++ b/BLURB @@ -0,0 +1,50 @@ +ezmlm is an easy-to-use, high-speed mailing list manager for qmail. + +ezmlm lets users set up their own mailing lists within qmail's address +hierarchy. A user, Joe, types + + ezmlm-make ~/SOS ~/.qmail-sos joe-sos isp.net + +and instantly has a functioning mailing list, joe-sos@isp.net, with all +relevant information stored in a new ~/SOS directory. + +ezmlm sets up joe-sos-subscribe and joe-sos-unsubscribe for automatic +processing of subscription and unsubscription requests. Any message to +joe-sos-subscribe will work; Joe doesn't have to explain any tricky +command formats. ezmlm will send back instructions if a subscriber sends +a message to joe-sos-request or joe-sos-help. + +ezmlm automatically archives new messages. Messages are labelled with +sequence numbers; a subscriber can fetch message 123 by sending mail to +joe-sos-get.123. The archive format supports fast message retrieval even +when there are thousands of messages. + +ezmlm takes advantage of qmail's VERPs to reliably determine the +recipient address and message number for every incoming bounce message. +It waits ten days and then sends the subscriber a list of message +numbers that bounced. If that warning bounces, ezmlm sends a probe; if +the probe bounces, ezmlm automatically removes the subscriber from the +mailing list. + +ezmlm is easy for users to control. Joe can edit ~/SOS/text/* to change +any of the administrative messages sent to subscribers. He can remove +~/SOS/public and ~/SOS/archived to disable automatic subscription and +archiving. He can put his own address into ~/SOS/editor to set up a +moderated mailing list. He can edit ~/SOS/{headeradd,headerremove} to +control outgoing headers. ezmlm has several utilities to manually +inspect and manage mailing lists. + +ezmlm uses Delivered-To to stop forwarding loops, Mailing-List to +protect other mailing lists against false subscription requests, and +real cryptographic cookies to protect normal users against false +subscription requests. ezmlm can also be used for a sublist, +redistributing messages from another list. + +ezmlm is reliable, even in the face of system crashes. It writes each +new subscription and each new message safely to disk before it reports +success to qmail. + +ezmlm doesn't mind huge mailing lists. Lists don't even have to fit into +memory. ezmlm hashes the subscription list into a set of independent +files so that it can handle subscription requests quickly. ezmlm uses +qmail for blazingly fast parallel SMTP deliveries. diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..4badf63 --- /dev/null +++ b/CHANGES @@ -0,0 +1,4 @@ +19970629 ezmlm 0.53, alpha. +19970406 ezmlm 0.52, alpha. +19970222 ezmlm 0.51, alpha. +19970203 ezmlm 0.50, alpha. diff --git a/FILES b/FILES new file mode 100644 index 0000000..d3ae087 --- /dev/null +++ b/FILES @@ -0,0 +1,279 @@ +BLURB +README +INSTALL +TODO +THANKS +CHANGES +FILES +BIN +MAN +VERSION +SYSDEPS +Makefile +ezmlm=0 +ezmlm.5 +ezmlm-make=0 +ezmlm-make.1 +ezmlm-make=x +ezmlm-make.c +ezmlm-send=0 +ezmlm-send.1 +ezmlm-send=x +ezmlm-send.c +ezmlm-reject=0 +ezmlm-reject.1 +ezmlm-reject=x +ezmlm-reject.c +ezmlm-list=0 +ezmlm-list.1 +ezmlm-list=x +ezmlm-list.c +ezmlm-sub=0 +ezmlm-sub.1 +ezmlm-sub=x +ezmlm-sub.c +ezmlm-unsub=0 +ezmlm-unsub.1 +ezmlm-unsub=x +ezmlm-unsub.c +ezmlm-manage=0 +ezmlm-manage.1 +ezmlm-manage=x +ezmlm-manage.c +ezmlm-return=0 +ezmlm-return.1 +ezmlm-return=x +ezmlm-return.c +ezmlm-warn=0 +ezmlm-warn.1 +ezmlm-warn=x +ezmlm-warn.c +ezmlm-weed=0 +ezmlm-weed.1 +ezmlm-weed=x +ezmlm-weed.c +getconf.h +getconf.c +log.h +log.c +issub.h +issub.c +subscribe.h +subscribe.c +cookie.h +cookie.c +auto-str=x +auto-str.c +conf-bin +auto_bin.c.do +auto_bin.h +conf-man +install=x +install.c +setup.do +man.do +it.do +targets.do +default.do +default.a.do +default.o.do +default.0.do +conf-cc +conf-ld +find-systype.sh +make-compile.sh +make-load.sh +make-makelib.sh +trycpp.c +warn-auto.sh +fork.h.do +fork.h1 +fork.h2 +tryvfork.c +wait.3 +wait=0 +wait=l +wait.h +wait_pid.c +trywaitp.c +error.3 +error=0 +error_str.3 +error_str=0 +error_temp.3 +error_temp=0 +error=l +error.h +error.c +error_str.c +substdio.3 +substdio=0 +substdio_copy.3 +substdio_copy=0 +substdio_in.3 +substdio_in=0 +substdio_out.3 +substdio_out=0 +substdio=l +substdio.h +substdio.c +substdi.c +substdo.c +substdio_copy.c +subfd.3 +subfd=0 +subfd.h +subfderr.c +readwrite.h +exit.h +str=l +byte.h +byte_chr.c +byte_copy.c +byte_cr.c +byte_diff.c +byte_rchr.c +byte_zero.c +str.h +str_chr.c +str_cpy.c +str_diff.c +str_diffn.c +str_len.c +str_rchr.c +str_start.c +getopt.3 +getopt=0 +sgetopt.3 +sgetopt=0 +subgetopt.3 +subgetopt=0 +getopt=l +sgetopt.h +sgetopt.c +subgetopt.h +subgetopt.c +strerr=l +strerr.h +strerr.c +strerr_sys.c +strerr_die.c +stralloc=l +gen_alloc.h +gen_allocdefs.h +stralloc.3 +stralloc=0 +stralloc.h +stralloc_eady.c +stralloc_pend.c +stralloc_copy.c +stralloc_opyb.c +stralloc_opys.c +stralloc_cat.c +stralloc_catb.c +stralloc_cats.c +stralloc_arts.c +alloc=0 +alloc.3 +alloc=l +alloc.h +alloc.c +alloc_re.c +open=l +open.h +open_append.c +open_read.c +open_trunc.c +uint32.h.do +uint32.h1 +uint32.h2 +tryulong32.c +case.3 +case=0 +case=l +case.h +case_diffb.c +case_lowerb.c +case_startb.c +fs=l +fmt.h +fmt_str.c +fmt_uint.c +fmt_uint0.c +fmt_ulong.c +scan.h +scan_ulong.c +scan_8long.c +lock=l +hasflock.h.do +lock.h +lock_ex.c +tryflock.c +env.3 +env=0 +env=l +env.h +envread.c +slurpclose.h +slurpclose.c +sig=l +sig.h +sig_catch.c +sig_pipe.c +hassgact.h.do +trysgact.c +datetime.3 +datetime=0 +datetime.h +datetime.c +date822fmt.h +date822fmt.c +now.3 +now=0 +now.h +now.c +quote.h +quote.c +seek=l +seek.h +seek_set.c +conf-qmail +auto_qmail.c.do +auto_qmail.h +qmail.h +qmail.c +direntry.3 +direntry=0 +direntry.h.do +direntry.h1 +direntry.h2 +trydrent.c +getln=0 +getln2=0 +getln=l +getln.3 +getln.h +getln.c +getln2.3 +getln2.c +fd=l +fd_copy=0 +fd_move=0 +fd.h +fd_copy.3 +fd_copy.c +fd_move.3 +fd_move.c +surf=0 +surfpcs=0 +surf=l +surf.3 +surf.h +surf.c +surfpcs.3 +surfpcs.h +surfpcs.c +slurp.h +slurp.c +constmap.h +constmap.c diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..a85e9cb --- /dev/null +++ b/INSTALL @@ -0,0 +1,52 @@ +Like any other piece of software (and information generally), ezmlm +comes with NO WARRANTY. + + +Things you have to decide before starting: + +* Where programs will be installed, normally /usr/local/bin/ezmlm. To +change this directory, edit conf-bin now. + +* Where man pages will be installed, normally /usr/local/man. To change +this directory, edit conf-man now. + +* Where the qmail home directory is, normally /var/qmail. To change this +directory, edit conf-qmail now. + + +How to install: + + 1. Compile the programs: + % make + 2. Format the man pages: + % make man + 3. Install the programs and man pages: + # make setup + + +How to test: + + 4. Make sure ezmlm-make is in your path. Create a mailing list: + % ezmlm-make ~/testlist ~/.qmail-testlist me-testlist host + Replace ``me'' and ``host'' with your e-mail address. + 5. Subscribe yourself to the list manually: + % ezmlm-sub ~/testlist me@host + 6. Send a message to the list: + % echo subject:testing | qmail-inject me-testlist@host + You should receive a copy of the message at me@host. + 7. View the list membership: + % ezmlm-list ~/testlist + You should see just one line, containing your address. + 8. Unsubscribe yourself through e-mail: + % qmail-inject me-testlist-unsubscribe@host < /dev/null + When you receive the confirmation number, reply to complete your + unsubscription. Use ezmlm-list to check that the list is empty. + 9. Retrieve the first message from the archive: + % qmail-inject me-testlist-get.1@host < /dev/null + You should receive a copy of your subject:testing message. + + +That's it! To report success: + % ( echo 'First M. Last'; cat `cat SYSDEPS` ) \ + | mail djb-qst@koobera.math.uic.edu +Replace First M. Last with your name. diff --git a/MAN b/MAN new file mode 100644 index 0000000..df7b2a7 --- /dev/null +++ b/MAN @@ -0,0 +1,27 @@ +d:::755::: +d:::755:/man1:: +d:::755:/man5:: +c:::644:/man5/:ezmlm.5: +c:::644:/man1/:ezmlm-list.1: +c:::644:/man1/:ezmlm-make.1: +c:::644:/man1/:ezmlm-manage.1: +c:::644:/man1/:ezmlm-reject.1: +c:::644:/man1/:ezmlm-return.1: +c:::644:/man1/:ezmlm-send.1: +c:::644:/man1/:ezmlm-sub.1: +c:::644:/man1/:ezmlm-unsub.1: +c:::644:/man1/:ezmlm-warn.1: +c:::644:/man1/:ezmlm-weed.1: +d:::755:/cat1:: +d:::755:/cat5:: +c:::644:/cat5/:ezmlm.0: +c:::644:/cat1/:ezmlm-list.0: +c:::644:/cat1/:ezmlm-make.0: +c:::644:/cat1/:ezmlm-manage.0: +c:::644:/cat1/:ezmlm-reject.0: +c:::644:/cat1/:ezmlm-return.0: +c:::644:/cat1/:ezmlm-send.0: +c:::644:/cat1/:ezmlm-sub.0: +c:::644:/cat1/:ezmlm-unsub.0: +c:::644:/cat1/:ezmlm-warn.0: +c:::644:/cat1/:ezmlm-weed.0: diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..111a542 --- /dev/null +++ b/Makefile @@ -0,0 +1,909 @@ +SHELL=/bin/sh + +default: it + +alloc.0: \ +alloc.3 + nroff -man alloc.3 > alloc.0 + +alloc.a: \ +makelib alloc.o alloc_re.o + ./makelib alloc.a alloc.o alloc_re.o + +alloc.o: \ +compile alloc.c alloc.h alloc.c error.h alloc.c + ./compile alloc.c + +alloc_re.o: \ +compile alloc_re.c alloc.h alloc_re.c byte.h alloc_re.c + ./compile alloc_re.c + +auto-ccld.sh: \ +conf-cc conf-ld warn-auto.sh + ( cat warn-auto.sh; \ + echo CC=\'`head -1 conf-cc`\'; \ + echo LD=\'`head -1 conf-ld`\' \ + ) > auto-ccld.sh + +auto-str: \ +load auto-str.o substdio.a error.a str.a + ./load auto-str substdio.a error.a str.a + +auto-str.o: \ +compile auto-str.c substdio.h auto-str.c readwrite.h auto-str.c \ +exit.h auto-str.c + ./compile auto-str.c + +auto_bin.c: \ +auto-str conf-bin + ./auto-str auto_bin `head -1 conf-bin` > auto_bin.c + +auto_bin.o: \ +compile auto_bin.c + ./compile auto_bin.c + +auto_qmail.c: \ +auto-str conf-qmail + ./auto-str auto_qmail `head -1 conf-qmail` > auto_qmail.c + +auto_qmail.o: \ +compile auto_qmail.c + ./compile auto_qmail.c + +byte_chr.o: \ +compile byte_chr.c byte.h byte_chr.c + ./compile byte_chr.c + +byte_copy.o: \ +compile byte_copy.c byte.h byte_copy.c + ./compile byte_copy.c + +byte_cr.o: \ +compile byte_cr.c byte.h byte_cr.c + ./compile byte_cr.c + +byte_diff.o: \ +compile byte_diff.c byte.h byte_diff.c + ./compile byte_diff.c + +byte_rchr.o: \ +compile byte_rchr.c byte.h byte_rchr.c + ./compile byte_rchr.c + +byte_zero.o: \ +compile byte_zero.c byte.h byte_zero.c + ./compile byte_zero.c + +case.0: \ +case.3 + nroff -man case.3 > case.0 + +case.a: \ +makelib case_diffb.o case_lowerb.o case_startb.o + ./makelib case.a case_diffb.o case_lowerb.o case_startb.o + +case_diffb.o: \ +compile case_diffb.c case.h case_diffb.c + ./compile case_diffb.c + +case_lowerb.o: \ +compile case_lowerb.c case.h case_lowerb.c + ./compile case_lowerb.c + +case_startb.o: \ +compile case_startb.c case.h case_startb.c + ./compile case_startb.c + +compile: \ +make-compile warn-auto.sh systype + ( cat warn-auto.sh; ./make-compile "`cat systype`" ) > \ + compile + chmod 755 compile + +constmap.o: \ +compile constmap.c constmap.h constmap.c alloc.h constmap.c case.h \ +constmap.c + ./compile constmap.c + +cookie.o: \ +compile cookie.c cookie.h cookie.c str.h cookie.c uint32.h cookie.c \ +surfpcs.h uint32.h surfpcs.h cookie.c + ./compile cookie.c + +date822fmt.o: \ +compile date822fmt.c datetime.h date822fmt.c fmt.h date822fmt.c \ +date822fmt.h date822fmt.c + ./compile date822fmt.c + +datetime.0: \ +datetime.3 + nroff -man datetime.3 > datetime.0 + +datetime.o: \ +compile datetime.c datetime.h datetime.c + ./compile datetime.c + +direntry.0: \ +direntry.3 + nroff -man direntry.3 > direntry.0 + +direntry.h: \ +compile trydrent.c direntry.h1 direntry.h2 + ( ./compile trydrent.c >/dev/null 2>&1 \ + && cat direntry.h2 || cat direntry.h1 ) > direntry.h + rm -f trydrent.o + +env.0: \ +env.3 + nroff -man env.3 > env.0 + +env.a: \ +makelib envread.o + ./makelib env.a envread.o + +envread.o: \ +compile envread.c env.h envread.c str.h envread.c + ./compile envread.c + +error.0: \ +error.3 + nroff -man error.3 > error.0 + +error.a: \ +makelib error.o error_str.o + ./makelib error.a error.o error_str.o + +error.o: \ +compile error.c error.c error.h error.c + ./compile error.c + +error_str.0: \ +error_str.3 + nroff -man error_str.3 > error_str.0 + +error_str.o: \ +compile error_str.c error_str.c error.h error_str.c + ./compile error_str.c + +error_temp.0: \ +error_temp.3 + nroff -man error_temp.3 > error_temp.0 + +ezmlm-list: \ +load ezmlm-list.o strerr.a getln.a substdio.a stralloc.a alloc.a \ +error.a open.a str.a + ./load ezmlm-list strerr.a getln.a substdio.a stralloc.a \ + alloc.a error.a open.a str.a + +ezmlm-list.0: \ +ezmlm-list.1 + nroff -man ezmlm-list.1 > ezmlm-list.0 + +ezmlm-list.o: \ +compile ezmlm-list.c stralloc.h gen_alloc.h stralloc.h ezmlm-list.c \ +substdio.h ezmlm-list.c getln.h ezmlm-list.c strerr.h ezmlm-list.c \ +error.h ezmlm-list.c readwrite.h ezmlm-list.c exit.h ezmlm-list.c \ +open.h ezmlm-list.c + ./compile ezmlm-list.c + +ezmlm-make: \ +load ezmlm-make.o auto_bin.o open.a getopt.a substdio.a strerr.a \ +stralloc.a alloc.a error.a str.a + ./load ezmlm-make auto_bin.o open.a getopt.a substdio.a \ + strerr.a stralloc.a alloc.a error.a str.a + +ezmlm-make.0: \ +ezmlm-make.1 + nroff -man ezmlm-make.1 > ezmlm-make.0 + +ezmlm-make.o: \ +compile ezmlm-make.c ezmlm-make.c ezmlm-make.c sgetopt.h subgetopt.h \ +sgetopt.h ezmlm-make.c stralloc.h gen_alloc.h stralloc.h ezmlm-make.c \ +strerr.h ezmlm-make.c exit.h ezmlm-make.c readwrite.h ezmlm-make.c \ +open.h ezmlm-make.c substdio.h ezmlm-make.c str.h ezmlm-make.c \ +auto_bin.h ezmlm-make.c ezmlm-make.c ezmlm-make.c ezmlm-make.c \ +ezmlm-make.c + ./compile ezmlm-make.c + +ezmlm-manage: \ +load ezmlm-manage.o auto_qmail.o getconf.o subscribe.o log.o cookie.o \ +now.o datetime.o date822fmt.o slurpclose.o slurp.o qmail.o quote.o \ +surf.a getln.a env.a sig.a strerr.a substdio.a stralloc.a alloc.a \ +error.a str.a fs.a case.a open.a seek.a wait.a lock.a fd.a + ./load ezmlm-manage auto_qmail.o getconf.o subscribe.o \ + log.o cookie.o now.o datetime.o date822fmt.o slurpclose.o \ + slurp.o qmail.o quote.o surf.a getln.a env.a sig.a strerr.a \ + substdio.a stralloc.a alloc.a error.a str.a fs.a case.a \ + open.a seek.a wait.a lock.a fd.a + +ezmlm-manage.0: \ +ezmlm-manage.1 + nroff -man ezmlm-manage.1 > ezmlm-manage.0 + +ezmlm-manage.o: \ +compile ezmlm-manage.c ezmlm-manage.c ezmlm-manage.c error.h \ +ezmlm-manage.c stralloc.h gen_alloc.h stralloc.h ezmlm-manage.c str.h \ +ezmlm-manage.c env.h ezmlm-manage.c sig.h ezmlm-manage.c slurp.h \ +ezmlm-manage.c getconf.h ezmlm-manage.c strerr.h ezmlm-manage.c \ +byte.h ezmlm-manage.c getln.h ezmlm-manage.c case.h ezmlm-manage.c \ +qmail.h substdio.h qmail.h ezmlm-manage.c substdio.h substdio.h \ +ezmlm-manage.c readwrite.h ezmlm-manage.c seek.h ezmlm-manage.c \ +quote.h ezmlm-manage.c datetime.h ezmlm-manage.c now.h datetime.h \ +datetime.h now.h ezmlm-manage.c date822fmt.h ezmlm-manage.c fmt.h \ +ezmlm-manage.c subscribe.h strerr.h strerr.h subscribe.h \ +ezmlm-manage.c cookie.h ezmlm-manage.c + ./compile ezmlm-manage.c + +ezmlm-reject: \ +load ezmlm-reject.o getln.a strerr.a substdio.a error.a stralloc.a \ +alloc.a str.a getopt.a case.a + ./load ezmlm-reject getln.a strerr.a substdio.a error.a \ + stralloc.a alloc.a str.a getopt.a case.a + +ezmlm-reject.0: \ +ezmlm-reject.1 + nroff -man ezmlm-reject.1 > ezmlm-reject.0 + +ezmlm-reject.o: \ +compile ezmlm-reject.c strerr.h ezmlm-reject.c substdio.h \ +ezmlm-reject.c readwrite.h ezmlm-reject.c stralloc.h gen_alloc.h \ +stralloc.h ezmlm-reject.c getln.h ezmlm-reject.c sgetopt.h \ +subgetopt.h sgetopt.h ezmlm-reject.c + ./compile ezmlm-reject.c + +ezmlm-return: \ +load ezmlm-return.o quote.o getconf.o issub.o subscribe.o log.o \ +slurpclose.o slurp.o now.o cookie.o surf.a lock.a env.a sig.a \ +strerr.a getln.a substdio.a stralloc.a alloc.a error.a str.a fs.a \ +case.a open.a + ./load ezmlm-return quote.o getconf.o issub.o subscribe.o \ + log.o slurpclose.o slurp.o now.o cookie.o surf.a lock.a \ + env.a sig.a strerr.a getln.a substdio.a stralloc.a alloc.a \ + error.a str.a fs.a case.a open.a + +ezmlm-return.0: \ +ezmlm-return.1 + nroff -man ezmlm-return.1 > ezmlm-return.0 + +ezmlm-return.o: \ +compile ezmlm-return.c stralloc.h gen_alloc.h stralloc.h \ +ezmlm-return.c str.h ezmlm-return.c env.h ezmlm-return.c sig.h \ +ezmlm-return.c slurp.h ezmlm-return.c getconf.h ezmlm-return.c \ +strerr.h ezmlm-return.c byte.h ezmlm-return.c case.h ezmlm-return.c \ +getln.h ezmlm-return.c substdio.h ezmlm-return.c error.h \ +ezmlm-return.c quote.h ezmlm-return.c readwrite.h ezmlm-return.c \ +fmt.h ezmlm-return.c now.h datetime.h now.h ezmlm-return.c cookie.h \ +ezmlm-return.c subscribe.h strerr.h strerr.h subscribe.h \ +ezmlm-return.c issub.h strerr.h strerr.h issub.h ezmlm-return.c + ./compile ezmlm-return.c + +ezmlm-send: \ +load ezmlm-send.o auto_qmail.o getconf.o qmail.o constmap.o slurp.o \ +slurpclose.o wait.a getln.a strerr.a sig.a env.a open.a lock.a \ +substdio.a stralloc.a alloc.a error.a str.a fd.a case.a fs.a + ./load ezmlm-send auto_qmail.o getconf.o qmail.o \ + constmap.o slurp.o slurpclose.o wait.a getln.a strerr.a \ + sig.a env.a open.a lock.a substdio.a stralloc.a alloc.a \ + error.a str.a fd.a case.a fs.a + +ezmlm-send.0: \ +ezmlm-send.1 + nroff -man ezmlm-send.1 > ezmlm-send.0 + +ezmlm-send.o: \ +compile ezmlm-send.c stralloc.h gen_alloc.h stralloc.h ezmlm-send.c \ +subfd.h substdio.h subfd.h ezmlm-send.c strerr.h ezmlm-send.c error.h \ +ezmlm-send.c qmail.h substdio.h substdio.h qmail.h ezmlm-send.c env.h \ +ezmlm-send.c lock.h ezmlm-send.c sig.h ezmlm-send.c open.h \ +ezmlm-send.c getln.h ezmlm-send.c case.h ezmlm-send.c scan.h \ +ezmlm-send.c str.h ezmlm-send.c fmt.h ezmlm-send.c readwrite.h \ +ezmlm-send.c exit.h ezmlm-send.c substdio.h substdio.h ezmlm-send.c \ +getconf.h ezmlm-send.c constmap.h ezmlm-send.c + ./compile ezmlm-send.c + +ezmlm-sub: \ +load ezmlm-sub.o subscribe.o log.o now.o fs.a strerr.a getln.a \ +substdio.a stralloc.a alloc.a error.a str.a case.a open.a lock.a + ./load ezmlm-sub subscribe.o log.o now.o fs.a strerr.a \ + getln.a substdio.a stralloc.a alloc.a error.a str.a case.a \ + open.a lock.a + +ezmlm-sub.0: \ +ezmlm-sub.1 + nroff -man ezmlm-sub.1 > ezmlm-sub.0 + +ezmlm-sub.o: \ +compile ezmlm-sub.c strerr.h ezmlm-sub.c subscribe.h strerr.h \ +strerr.h subscribe.h ezmlm-sub.c log.h ezmlm-sub.c + ./compile ezmlm-sub.c + +ezmlm-unsub: \ +load ezmlm-unsub.o subscribe.o log.o now.o fs.a strerr.a getln.a \ +substdio.a stralloc.a alloc.a error.a str.a case.a open.a lock.a + ./load ezmlm-unsub subscribe.o log.o now.o fs.a strerr.a \ + getln.a substdio.a stralloc.a alloc.a error.a str.a case.a \ + open.a lock.a + +ezmlm-unsub.0: \ +ezmlm-unsub.1 + nroff -man ezmlm-unsub.1 > ezmlm-unsub.0 + +ezmlm-unsub.o: \ +compile ezmlm-unsub.c strerr.h ezmlm-unsub.c subscribe.h strerr.h \ +strerr.h subscribe.h ezmlm-unsub.c log.h ezmlm-unsub.c + ./compile ezmlm-unsub.c + +ezmlm-warn: \ +load ezmlm-warn.o auto_qmail.o getconf.o cookie.o issub.o now.o \ +slurpclose.o slurp.o quote.o datetime.o date822fmt.o qmail.o surf.a \ +case.a strerr.a sig.a getln.a substdio.a stralloc.a alloc.a error.a \ +open.a lock.a str.a fs.a fd.a wait.a + ./load ezmlm-warn auto_qmail.o getconf.o cookie.o issub.o \ + now.o slurpclose.o slurp.o quote.o datetime.o date822fmt.o \ + qmail.o surf.a case.a strerr.a sig.a getln.a substdio.a \ + stralloc.a alloc.a error.a open.a lock.a str.a fs.a fd.a \ + wait.a + +ezmlm-warn.0: \ +ezmlm-warn.1 + nroff -man ezmlm-warn.1 > ezmlm-warn.0 + +ezmlm-warn.o: \ +compile ezmlm-warn.c ezmlm-warn.c ezmlm-warn.c direntry.h direntry.h \ +direntry.h ezmlm-warn.c readwrite.h ezmlm-warn.c getln.h ezmlm-warn.c \ +substdio.h ezmlm-warn.c stralloc.h gen_alloc.h stralloc.h \ +ezmlm-warn.c slurp.h ezmlm-warn.c getconf.h ezmlm-warn.c byte.h \ +ezmlm-warn.c error.h ezmlm-warn.c str.h ezmlm-warn.c strerr.h \ +ezmlm-warn.c sig.h ezmlm-warn.c now.h datetime.h now.h ezmlm-warn.c \ +datetime.h datetime.h ezmlm-warn.c date822fmt.h ezmlm-warn.c fmt.h \ +ezmlm-warn.c cookie.h ezmlm-warn.c qmail.h substdio.h substdio.h \ +qmail.h ezmlm-warn.c + ./compile ezmlm-warn.c + +ezmlm-weed: \ +load ezmlm-weed.o getln.a strerr.a substdio.a error.a stralloc.a \ +alloc.a str.a + ./load ezmlm-weed getln.a strerr.a substdio.a error.a \ + stralloc.a alloc.a str.a + +ezmlm-weed.0: \ +ezmlm-weed.1 + nroff -man ezmlm-weed.1 > ezmlm-weed.0 + +ezmlm-weed.o: \ +compile ezmlm-weed.c stralloc.h gen_alloc.h stralloc.h ezmlm-weed.c \ +str.h ezmlm-weed.c byte.h ezmlm-weed.c readwrite.h ezmlm-weed.c \ +substdio.h ezmlm-weed.c getln.h ezmlm-weed.c strerr.h ezmlm-weed.c + ./compile ezmlm-weed.c + +ezmlm.0: \ +ezmlm.5 + nroff -man ezmlm.5 > ezmlm.0 + +fd.a: \ +makelib fd_copy.o fd_move.o + ./makelib fd.a fd_copy.o fd_move.o + +fd_copy.0: \ +fd_copy.3 + nroff -man fd_copy.3 > fd_copy.0 + +fd_copy.o: \ +compile fd_copy.c fd_copy.c fd.h fd_copy.c + ./compile fd_copy.c + +fd_move.0: \ +fd_move.3 + nroff -man fd_move.3 > fd_move.0 + +fd_move.o: \ +compile fd_move.c fd.h fd_move.c + ./compile fd_move.c + +find-systype: \ +find-systype.sh auto-ccld.sh + cat auto-ccld.sh find-systype.sh > find-systype + chmod 755 find-systype + +fmt_str.o: \ +compile fmt_str.c fmt.h fmt_str.c + ./compile fmt_str.c + +fmt_uint.o: \ +compile fmt_uint.c fmt.h fmt_uint.c + ./compile fmt_uint.c + +fmt_uint0.o: \ +compile fmt_uint0.c fmt.h fmt_uint0.c + ./compile fmt_uint0.c + +fmt_ulong.o: \ +compile fmt_ulong.c fmt.h fmt_ulong.c + ./compile fmt_ulong.c + +fork.h: \ +compile load tryvfork.c fork.h1 fork.h2 + ( ( ./compile tryvfork.c && ./load tryvfork ) >/dev/null \ + 2>&1 \ + && cat fork.h2 || cat fork.h1 ) > fork.h + rm -f tryvfork.o tryvfork + +fs.a: \ +makelib fmt_str.o fmt_uint.o fmt_uint0.o fmt_ulong.o scan_ulong.o \ +scan_8long.o + ./makelib fs.a fmt_str.o fmt_uint.o fmt_uint0.o \ + fmt_ulong.o scan_ulong.o scan_8long.o + +getconf.o: \ +compile getconf.c stralloc.h gen_alloc.h stralloc.h getconf.c slurp.h \ +getconf.c strerr.h getconf.c getconf.h getconf.c + ./compile getconf.c + +getln.0: \ +getln.3 + nroff -man getln.3 > getln.0 + +getln.a: \ +makelib getln.o getln2.o + ./makelib getln.a getln.o getln2.o + +getln.o: \ +compile getln.c substdio.h getln.c byte.h getln.c stralloc.h \ +gen_alloc.h stralloc.h getln.c getln.h getln.c + ./compile getln.c + +getln2.0: \ +getln2.3 + nroff -man getln2.3 > getln2.0 + +getln2.o: \ +compile getln2.c substdio.h getln2.c stralloc.h gen_alloc.h \ +stralloc.h getln2.c byte.h getln2.c getln.h getln2.c + ./compile getln2.c + +getopt.0: \ +getopt.3 + nroff -man getopt.3 > getopt.0 + +getopt.a: \ +makelib subgetopt.o sgetopt.o + ./makelib getopt.a subgetopt.o sgetopt.o + +hasflock.h: \ +tryflock.c compile load + ( ( ./compile tryflock.c && ./load tryflock ) >/dev/null \ + 2>&1 \ + && echo \#define HASFLOCK 1 || exit 0 ) > hasflock.h + rm -f tryflock.o tryflock + +hassgact.h: \ +trysgact.c compile load + ( ( ./compile trysgact.c && ./load trysgact ) >/dev/null \ + 2>&1 \ + && echo \#define HASSIGACTION 1 || exit 0 ) > hassgact.h + rm -f trysgact.o trysgact + +install: \ +load install.o getln.a strerr.a substdio.a stralloc.a alloc.a open.a \ +error.a str.a fs.a + ./load install getln.a strerr.a substdio.a stralloc.a \ + alloc.a open.a error.a str.a fs.a + +install.o: \ +compile install.c substdio.h install.c stralloc.h gen_alloc.h \ +stralloc.h install.c getln.h install.c readwrite.h install.c exit.h \ +install.c open.h install.c error.h install.c strerr.h install.c \ +byte.h install.c + ./compile install.c + +issub.o: \ +compile issub.c stralloc.h gen_alloc.h stralloc.h issub.c getln.h \ +issub.c readwrite.h issub.c substdio.h issub.c open.h issub.c byte.h \ +issub.c case.h issub.c lock.h issub.c error.h issub.c issub.h \ +strerr.h issub.h issub.c uint32.h issub.c + ./compile issub.c + +it: \ +ezmlm-make ezmlm-manage ezmlm-send ezmlm-reject ezmlm-return \ +ezmlm-warn ezmlm-weed ezmlm-list ezmlm-sub ezmlm-unsub + +load: \ +make-load warn-auto.sh systype + ( cat warn-auto.sh; ./make-load "`cat systype`" ) > load + chmod 755 load + +lock.a: \ +makelib lock_ex.o + ./makelib lock.a lock_ex.o + +lock_ex.o: \ +compile lock_ex.c lock_ex.c lock_ex.c lock_ex.c hasflock.h lock_ex.c \ +lock.h lock_ex.c + ./compile lock_ex.c + +log.o: \ +compile log.c substdio.h log.c readwrite.h log.c stralloc.h \ +gen_alloc.h stralloc.h log.c log.h log.c now.h datetime.h now.h log.c \ +fmt.h log.c open.h log.c + ./compile log.c + +make-compile: \ +make-compile.sh auto-ccld.sh + cat auto-ccld.sh make-compile.sh > make-compile + chmod 755 make-compile + +make-load: \ +make-load.sh auto-ccld.sh + cat auto-ccld.sh make-load.sh > make-load + chmod 755 make-load + +make-makelib: \ +make-makelib.sh auto-ccld.sh + cat auto-ccld.sh make-makelib.sh > make-makelib + chmod 755 make-makelib + +makelib: \ +make-makelib warn-auto.sh systype + ( cat warn-auto.sh; ./make-makelib "`cat systype`" ) > \ + makelib + chmod 755 makelib + +man: \ +ezmlm.0 ezmlm-make.0 ezmlm-manage.0 ezmlm-send.0 ezmlm-reject.0 \ +ezmlm-return.0 ezmlm-warn.0 ezmlm-weed.0 ezmlm-list.0 ezmlm-sub.0 \ +ezmlm-unsub.0 alloc.0 case.0 datetime.0 direntry.0 env.0 error.0 \ +error_str.0 error_temp.0 ezmlm.0 fd_copy.0 fd_move.0 getln.0 getln2.0 \ +getopt.0 now.0 sgetopt.0 stralloc.0 subfd.0 subgetopt.0 substdio.0 \ +substdio_copy.0 substdio_in.0 substdio_out.0 surf.0 surfpcs.0 wait.0 + +now.0: \ +now.3 + nroff -man now.3 > now.0 + +now.o: \ +compile now.c now.c datetime.h now.c now.h datetime.h datetime.h \ +now.h now.c + ./compile now.c + +open.a: \ +makelib open_append.o open_read.o open_trunc.o + ./makelib open.a open_append.o open_read.o open_trunc.o + +open_append.o: \ +compile open_append.c open_append.c open_append.c open.h \ +open_append.c + ./compile open_append.c + +open_read.o: \ +compile open_read.c open_read.c open_read.c open.h open_read.c + ./compile open_read.c + +open_trunc.o: \ +compile open_trunc.c open_trunc.c open_trunc.c open.h open_trunc.c + ./compile open_trunc.c + +qmail.o: \ +compile qmail.c substdio.h qmail.c readwrite.h qmail.c wait.h qmail.c \ +exit.h qmail.c fork.h qmail.c fd.h qmail.c qmail.h substdio.h \ +substdio.h qmail.h qmail.c auto_qmail.h qmail.c + ./compile qmail.c + +quote.o: \ +compile quote.c stralloc.h gen_alloc.h stralloc.h quote.c str.h \ +quote.c quote.h quote.c + ./compile quote.c + +scan_8long.o: \ +compile scan_8long.c scan.h scan_8long.c + ./compile scan_8long.c + +scan_ulong.o: \ +compile scan_ulong.c scan.h scan_ulong.c + ./compile scan_ulong.c + +seek.a: \ +makelib seek_set.o + ./makelib seek.a seek_set.o + +seek_set.o: \ +compile seek_set.c seek_set.c seek.h seek_set.c + ./compile seek_set.c + +setup: \ +it man install conf-bin conf-man + ./install "`head -1 conf-bin`" < BIN + ./install "`head -1 conf-man`" < MAN + +sgetopt.0: \ +sgetopt.3 + nroff -man sgetopt.3 > sgetopt.0 + +sgetopt.o: \ +compile sgetopt.c substdio.h sgetopt.c subfd.h substdio.h substdio.h \ +subfd.h sgetopt.c sgetopt.h sgetopt.h subgetopt.h sgetopt.h sgetopt.c \ +subgetopt.h subgetopt.h sgetopt.c + ./compile sgetopt.c + +shar: \ +FILES BLURB README INSTALL TODO THANKS CHANGES FILES BIN MAN VERSION \ +SYSDEPS Makefile ezmlm.5 ezmlm-make.1 ezmlm-make.c ezmlm-send.1 \ +ezmlm-send.c ezmlm-reject.1 ezmlm-reject.c ezmlm-list.1 ezmlm-list.c \ +ezmlm-sub.1 ezmlm-sub.c ezmlm-unsub.1 ezmlm-unsub.c ezmlm-manage.1 \ +ezmlm-manage.c ezmlm-return.1 ezmlm-return.c ezmlm-warn.1 \ +ezmlm-warn.c ezmlm-weed.1 ezmlm-weed.c getconf.h getconf.c log.h \ +log.c issub.h issub.c subscribe.h subscribe.c cookie.h cookie.c \ +auto-str.c conf-bin auto_bin.h conf-man install.c conf-cc conf-ld \ +find-systype.sh make-compile.sh make-load.sh make-makelib.sh trycpp.c \ +warn-auto.sh fork.h1 fork.h2 tryvfork.c wait.3 wait.h wait_pid.c \ +trywaitp.c error.3 error_str.3 error_temp.3 error.h error.c \ +error_str.c substdio.3 substdio_copy.3 substdio_in.3 substdio_out.3 \ +substdio.h substdio.c substdi.c substdo.c substdio_copy.c subfd.3 \ +subfd.h subfderr.c readwrite.h exit.h byte.h byte_chr.c byte_copy.c \ +byte_cr.c byte_diff.c byte_rchr.c byte_zero.c str.h str_chr.c \ +str_cpy.c str_diff.c str_diffn.c str_len.c str_rchr.c str_start.c \ +getopt.3 sgetopt.3 subgetopt.3 sgetopt.h sgetopt.c subgetopt.h \ +subgetopt.c strerr.h strerr.c strerr_sys.c strerr_die.c gen_alloc.h \ +gen_allocdefs.h stralloc.3 stralloc.h stralloc_eady.c stralloc_pend.c \ +stralloc_copy.c stralloc_opyb.c stralloc_opys.c stralloc_cat.c \ +stralloc_catb.c stralloc_cats.c stralloc_arts.c alloc.3 alloc.h \ +alloc.c alloc_re.c open.h open_append.c open_read.c open_trunc.c \ +uint32.h1 uint32.h2 tryulong32.c case.3 case.h case_diffb.c \ +case_lowerb.c case_startb.c fmt.h fmt_str.c fmt_uint.c fmt_uint0.c \ +fmt_ulong.c scan.h scan_ulong.c scan_8long.c lock.h lock_ex.c \ +tryflock.c env.3 env.h envread.c slurpclose.h slurpclose.c sig.h \ +sig_catch.c sig_pipe.c trysgact.c datetime.3 datetime.h datetime.c \ +date822fmt.h date822fmt.c now.3 now.h now.c quote.h quote.c seek.h \ +seek_set.c conf-qmail auto_qmail.h qmail.h qmail.c direntry.3 \ +direntry.h1 direntry.h2 trydrent.c getln.3 getln.h getln.c getln2.3 \ +getln2.c fd.h fd_copy.3 fd_copy.c fd_move.3 fd_move.c surf.3 surf.h \ +surf.c surfpcs.3 surfpcs.h surfpcs.c slurp.h slurp.c constmap.h \ +constmap.c + shar -m `cat FILES` > shar + chmod 400 shar + +sig.a: \ +makelib sig_catch.o sig_pipe.o + ./makelib sig.a sig_catch.o sig_pipe.o + +sig_catch.o: \ +compile sig_catch.c sig_catch.c sig.h sig_catch.c hassgact.h \ +sig_catch.c + ./compile sig_catch.c + +sig_pipe.o: \ +compile sig_pipe.c sig_pipe.c sig.h sig_pipe.c + ./compile sig_pipe.c + +slurp.o: \ +compile slurp.c stralloc.h gen_alloc.h stralloc.h slurp.c slurp.h \ +slurp.c error.h slurp.c open.h slurp.c + ./compile slurp.c + +slurpclose.o: \ +compile slurpclose.c stralloc.h gen_alloc.h stralloc.h slurpclose.c \ +readwrite.h slurpclose.c slurpclose.h slurpclose.c error.h \ +slurpclose.c + ./compile slurpclose.c + +str.a: \ +makelib str_len.o str_diff.o str_diffn.o str_cpy.o str_chr.o \ +str_rchr.o str_start.o byte_chr.o byte_rchr.o byte_diff.o byte_copy.o \ +byte_cr.o byte_zero.o + ./makelib str.a str_len.o str_diff.o str_diffn.o str_cpy.o \ + str_chr.o str_rchr.o str_start.o byte_chr.o byte_rchr.o \ + byte_diff.o byte_copy.o byte_cr.o byte_zero.o + +str_chr.o: \ +compile str_chr.c str.h str_chr.c + ./compile str_chr.c + +str_cpy.o: \ +compile str_cpy.c str.h str_cpy.c + ./compile str_cpy.c + +str_diff.o: \ +compile str_diff.c str.h str_diff.c + ./compile str_diff.c + +str_diffn.o: \ +compile str_diffn.c str.h str_diffn.c + ./compile str_diffn.c + +str_len.o: \ +compile str_len.c str.h str_len.c + ./compile str_len.c + +str_rchr.o: \ +compile str_rchr.c str.h str_rchr.c + ./compile str_rchr.c + +str_start.o: \ +compile str_start.c str.h str_start.c + ./compile str_start.c + +stralloc.0: \ +stralloc.3 + nroff -man stralloc.3 > stralloc.0 + +stralloc.a: \ +makelib stralloc_eady.o stralloc_pend.o stralloc_copy.o \ +stralloc_opys.o stralloc_opyb.o stralloc_cat.o stralloc_cats.o \ +stralloc_catb.o stralloc_arts.o + ./makelib stralloc.a stralloc_eady.o stralloc_pend.o \ + stralloc_copy.o stralloc_opys.o stralloc_opyb.o \ + stralloc_cat.o stralloc_cats.o stralloc_catb.o \ + stralloc_arts.o + +stralloc_arts.o: \ +compile stralloc_arts.c byte.h stralloc_arts.c str.h stralloc_arts.c \ +stralloc.h gen_alloc.h stralloc.h stralloc_arts.c + ./compile stralloc_arts.c + +stralloc_cat.o: \ +compile stralloc_cat.c byte.h stralloc_cat.c stralloc.h gen_alloc.h \ +stralloc.h stralloc_cat.c + ./compile stralloc_cat.c + +stralloc_catb.o: \ +compile stralloc_catb.c stralloc.h gen_alloc.h stralloc.h \ +stralloc_catb.c byte.h stralloc_catb.c + ./compile stralloc_catb.c + +stralloc_cats.o: \ +compile stralloc_cats.c byte.h stralloc_cats.c str.h stralloc_cats.c \ +stralloc.h gen_alloc.h stralloc.h stralloc_cats.c + ./compile stralloc_cats.c + +stralloc_copy.o: \ +compile stralloc_copy.c byte.h stralloc_copy.c stralloc.h gen_alloc.h \ +stralloc.h stralloc_copy.c + ./compile stralloc_copy.c + +stralloc_eady.o: \ +compile stralloc_eady.c alloc.h stralloc_eady.c stralloc.h \ +gen_alloc.h stralloc.h stralloc_eady.c gen_allocdefs.h \ +gen_allocdefs.h gen_allocdefs.h stralloc_eady.c + ./compile stralloc_eady.c + +stralloc_opyb.o: \ +compile stralloc_opyb.c stralloc.h gen_alloc.h stralloc.h \ +stralloc_opyb.c byte.h stralloc_opyb.c + ./compile stralloc_opyb.c + +stralloc_opys.o: \ +compile stralloc_opys.c byte.h stralloc_opys.c str.h stralloc_opys.c \ +stralloc.h gen_alloc.h stralloc.h stralloc_opys.c + ./compile stralloc_opys.c + +stralloc_pend.o: \ +compile stralloc_pend.c alloc.h stralloc_pend.c stralloc.h \ +gen_alloc.h stralloc.h stralloc_pend.c gen_allocdefs.h \ +gen_allocdefs.h gen_allocdefs.h stralloc_pend.c + ./compile stralloc_pend.c + +strerr.a: \ +makelib strerr.o strerr_sys.o strerr_die.o + ./makelib strerr.a strerr.o strerr_sys.o strerr_die.o + +strerr.o: \ +compile strerr.c stralloc.h gen_alloc.h stralloc.h strerr.c strerr.h \ +strerr.c + ./compile strerr.c + +strerr_die.o: \ +compile strerr_die.c substdio.h strerr_die.c subfd.h substdio.h \ +substdio.h subfd.h strerr_die.c exit.h strerr_die.c strerr.h \ +strerr_die.c + ./compile strerr_die.c + +strerr_sys.o: \ +compile strerr_sys.c error.h strerr_sys.c strerr.h strerr_sys.c + ./compile strerr_sys.c + +subfd.0: \ +subfd.3 + nroff -man subfd.3 > subfd.0 + +subfderr.o: \ +compile subfderr.c readwrite.h subfderr.c substdio.h subfderr.c \ +subfd.h substdio.h substdio.h subfd.h subfderr.c + ./compile subfderr.c + +subgetopt.0: \ +subgetopt.3 + nroff -man subgetopt.3 > subgetopt.0 + +subgetopt.o: \ +compile subgetopt.c subgetopt.h subgetopt.h subgetopt.c + ./compile subgetopt.c + +subscribe.o: \ +compile subscribe.c stralloc.h gen_alloc.h stralloc.h subscribe.c \ +getln.h subscribe.c readwrite.h subscribe.c substdio.h subscribe.c \ +strerr.h subscribe.c open.h subscribe.c byte.h subscribe.c case.h \ +subscribe.c lock.h subscribe.c error.h subscribe.c uint32.h \ +subscribe.c subscribe.h strerr.h strerr.h subscribe.h subscribe.c + ./compile subscribe.c + +substdi.o: \ +compile substdi.c substdio.h substdi.c byte.h substdi.c error.h \ +substdi.c + ./compile substdi.c + +substdio.0: \ +substdio.3 + nroff -man substdio.3 > substdio.0 + +substdio.a: \ +makelib substdio.o substdi.o substdo.o subfderr.o substdio_copy.o + ./makelib substdio.a substdio.o substdi.o substdo.o \ + subfderr.o substdio_copy.o + +substdio.o: \ +compile substdio.c substdio.h substdio.c + ./compile substdio.c + +substdio_copy.0: \ +substdio_copy.3 + nroff -man substdio_copy.3 > substdio_copy.0 + +substdio_copy.o: \ +compile substdio_copy.c substdio.h substdio_copy.c + ./compile substdio_copy.c + +substdio_in.0: \ +substdio_in.3 + nroff -man substdio_in.3 > substdio_in.0 + +substdio_out.0: \ +substdio_out.3 + nroff -man substdio_out.3 > substdio_out.0 + +substdo.o: \ +compile substdo.c substdio.h substdo.c str.h substdo.c byte.h \ +substdo.c error.h substdo.c + ./compile substdo.c + +surf.0: \ +surf.3 + nroff -man surf.3 > surf.0 + +surf.a: \ +makelib surf.o surfpcs.o + ./makelib surf.a surf.o surfpcs.o + +surf.o: \ +compile surf.c surf.h surf.c uint32.h surf.c + ./compile surf.c + +surfpcs.0: \ +surfpcs.3 + nroff -man surfpcs.3 > surfpcs.0 + +surfpcs.o: \ +compile surfpcs.c surf.h surfpcs.c surfpcs.h uint32.h surfpcs.h \ +surfpcs.c + ./compile surfpcs.c + +systype: \ +find-systype trycpp.c + ./find-systype > systype + +uint32.h: \ +tryulong32.c compile load uint32.h1 uint32.h2 + ( ( ./compile tryulong32.c && ./load tryulong32 && \ + ./tryulong32 ) >/dev/null 2>&1 \ + && cat uint32.h2 || cat uint32.h1 ) > uint32.h + rm -f tryulong32.o tryulong32 + +wait.0: \ +wait.3 + nroff -man wait.3 > wait.0 + +wait.a: \ +makelib wait_pid.o + ./makelib wait.a wait_pid.o + +wait_pid.o: \ +compile wait_pid.c wait_pid.c wait_pid.c error.h wait_pid.c + ./compile wait_pid.c diff --git a/README b/README new file mode 100644 index 0000000..f1a5806 --- /dev/null +++ b/README @@ -0,0 +1,31 @@ +ezmlm 0.53, alpha. +19970629 +Copyright 1997 +D. J. Bernstein, djb@pobox.com + +ezmlm is an easy-to-use, high-speed mailing list manager for qmail. See +BLURB for a more detailed advertisement. + +INSTALL says how to set up and test ezmlm. + +See http://pobox.com/~djb/ezmlm.html for the latest information about +ezmlm. + +The rest of this file is a list of systypes where various versions of +ezmlm have been reported to work. + +0.52: aix-4-1-:-:-:00910033a000-:- (tnx KJJ) +0.52: freebsd-2.1.6-release-:i386-:-:-:- (tnx TM) +0.52: freebsd-2.2-stable-:i386-:-:pentium-:- (tnx fedi=???) +0.52: linux-2.0.18-:i386-:-:ppro-:- (tnx MAN) +0.52: linux-2.0.28-osfmach3-:-:-:ppc-:- (tnx CWG) +0.52: linux-2.0.29-:i386-:-:i486-:- (tnx FPL) +0.52: linux-2.0.29-:i386-:-:pentium-:- (tnx AG) +0.52: linux-2.0.30-:i386-:-:pentium-:- (tnx CH) +0.52: linux-2.0.30-:i386-:-:pentium-:- (tnx LMB) +0.52: linux-2.1.32-:i386-:-:pentium-:- (tnx JF) +0.52: netbsd-1.2c-:i386-:-:intel.pentium.(p54c).(586-class)-:- (tnx GW) +0.52: news-os-6.1.2-#2-:news5000-:-:news5000-:- (tnx yamada=???) +0.52: openbsd-2.0-generic#0-:openbsd.m68k-:-:mac68k-:- (tnx GS) +0.52: sunos-5.5-generic_103093-06-:sparc-:sun4-:sun4d-:sun4d- (tnx KT) +0.52: sunos-5.5.1-generic-:sparc-:sun4-:sun4c-:sun4c- (tnx CWG) diff --git a/SYSDEPS b/SYSDEPS new file mode 100644 index 0000000..c358b69 --- /dev/null +++ b/SYSDEPS @@ -0,0 +1,7 @@ +VERSION +systype +direntry.h +fork.h +hasflock.h +hassgact.h +uint32.h diff --git a/THANKS b/THANKS new file mode 100644 index 0000000..d26ef09 --- /dev/null +++ b/THANKS @@ -0,0 +1,14 @@ +LMB = Lars Marowsky-Bree +EC = Evan Champion +JF = Janos Farkas +PGF = Paul Fox +CWG = Chris Garrigues +AG = Andi Gutmans +CH = Christian Hudon +KJJ = Kevin J. Johnson +FPL = Frederik P. Lindberg +TM = Toshinori Maeno +MAN = Mark Nowlin +GS = Glen Stewart +KT = Karsten Thygesen +GW = Geoff Wing diff --git a/TODO b/TODO new file mode 100644 index 0000000..1afaa05 --- /dev/null +++ b/TODO @@ -0,0 +1,7 @@ +think about how to disable ezmlm-return, ezmlm-warn +test generally +test ezmlm-warn deleting ancient files in bounce/ +test Delivered-To handling +test cookie expiration for ezmlm-return +test ezmlm-warn only handling susbcribers +test ezmlm-return only handling susbcribers diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..6049539 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +ezmlm 0.53 diff --git a/alloc.3 b/alloc.3 new file mode 100644 index 0000000..58b4432 --- /dev/null +++ b/alloc.3 @@ -0,0 +1,62 @@ +.TH alloc 3 +.SH NAME +alloc \- allocate memory +.SH SYNTAX +.B #include + +char *\fBalloc\fP(\fInew\fR); + +void \fBalloc_free\fP(\fIx\fR); + +void \fBalloc_re\fP(&\fIx\fR,\fIold\fR,\fInew\fR); + +char *\fIx\fR; +.br +unsigned int \fIold\fR; +.br +unsigned int \fInew\fR; +.SH DESCRIPTION +.B alloc +allocates enough space from the heap for +.I new +bytes of data, +adequately aligned for any data type. +.I new +may be 0. +.B alloc +returns a pointer to the space. +If space is not available, +.B alloc +returns 0, +setting +.B errno +appropriately. + +.B alloc_free +returns space to the heap. + +.B alloc_re +expands the space allocated to +.I x +from +.I old +bytes to +.I new +bytes. +It allocates new space, +copies +.I old +bytes from the old space to the new space, +returns the old space to the heap, +and changes +.I x +to point to the new space. +It then returns 1. +If space is not available, +.B alloc_re +returns 0, +leaving the old space alone. +.SH "SEE ALSO" +sbrk(2), +malloc(3), +error(3) diff --git a/alloc.c b/alloc.c new file mode 100644 index 0000000..c661453 --- /dev/null +++ b/alloc.c @@ -0,0 +1,32 @@ +#include "alloc.h" +#include "error.h" +extern char *malloc(); +extern void free(); + +#define ALIGNMENT 16 /* XXX: assuming that this alignment is enough */ +#define SPACE 4096 /* must be multiple of ALIGNMENT */ + +typedef union { char irrelevant[ALIGNMENT]; double d; } aligned; +static aligned realspace[SPACE / ALIGNMENT]; +#define space ((char *) realspace) +static unsigned int avail = SPACE; /* multiple of ALIGNMENT; 0<=avail<=SPACE */ + +/*@null@*//*@out@*/char *alloc(n) +unsigned int n; +{ + char *x; + n = ALIGNMENT + n - (n & (ALIGNMENT - 1)); /* XXX: could overflow */ + if (n <= avail) { avail -= n; return space + avail; } + x = malloc(n); + if (!x) errno = error_nomem; + return x; +} + +void alloc_free(x) +char *x; +{ + if (x >= space) + if (x < space + SPACE) + return; /* XXX: assuming that pointers are flat */ + free(x); +} diff --git a/alloc.h b/alloc.h new file mode 100644 index 0000000..1b1d893 --- /dev/null +++ b/alloc.h @@ -0,0 +1,8 @@ +#ifndef ALLOC_H +#define ALLOC_H + +extern /*@null@*//*@out@*/char *alloc(); +extern void alloc_free(); +extern int alloc_re(); + +#endif diff --git a/alloc=0 b/alloc=0 new file mode 100644 index 0000000..5974100 --- /dev/null +++ b/alloc=0 @@ -0,0 +1 @@ +alloc.3 diff --git a/alloc=l b/alloc=l new file mode 100644 index 0000000..6dc62ab --- /dev/null +++ b/alloc=l @@ -0,0 +1,2 @@ +alloc.o +alloc_re.o diff --git a/alloc_re.c b/alloc_re.c new file mode 100644 index 0000000..feb8b49 --- /dev/null +++ b/alloc_re.c @@ -0,0 +1,17 @@ +#include "alloc.h" +#include "byte.h" + +int alloc_re(x,m,n) +char **x; +unsigned int m; +unsigned int n; +{ + char *y; + + y = alloc(n); + if (!y) return 0; + byte_copy(y,m,*x); + alloc_free(*x); + *x = y; + return 1; +} diff --git a/auto-str.c b/auto-str.c new file mode 100644 index 0000000..acc3d60 --- /dev/null +++ b/auto-str.c @@ -0,0 +1,44 @@ +#include "substdio.h" +#include "readwrite.h" +#include "exit.h" + +char buf1[256]; +substdio ss1 = SUBSTDIO_FDBUF(write,1,buf1,sizeof(buf1)); + +void puts(s) +char *s; +{ + if (substdio_puts(&ss1,s) == -1) _exit(111); +} + +void main(argc,argv) +int argc; +char **argv; +{ + char *name; + char *value; + unsigned char ch; + char octal[4]; + + name = argv[1]; + if (!name) _exit(100); + value = argv[2]; + if (!value) _exit(100); + + puts("char "); + puts(name); + puts("[] = \"\\\n"); + + while (ch = *value++) { + puts("\\"); + octal[3] = 0; + octal[2] = '0' + (ch & 7); ch >>= 3; + octal[1] = '0' + (ch & 7); ch >>= 3; + octal[0] = '0' + (ch & 7); + puts(octal); + } + + puts("\\\n\";\n"); + if (substdio_flush(&ss1) == -1) _exit(111); + _exit(0); +} diff --git a/auto-str=x b/auto-str=x new file mode 100644 index 0000000..f3e9229 --- /dev/null +++ b/auto-str=x @@ -0,0 +1,3 @@ +substdio.a +error.a +str.a diff --git a/auto_bin.c.do b/auto_bin.c.do new file mode 100644 index 0000000..8b51408 --- /dev/null +++ b/auto_bin.c.do @@ -0,0 +1,3 @@ +dependon auto-str conf-bin +formake './auto-str auto_bin `head -1 conf-bin` > auto_bin.c' +./auto-str auto_bin `head -1 conf-bin` diff --git a/auto_bin.h b/auto_bin.h new file mode 100644 index 0000000..8c30166 --- /dev/null +++ b/auto_bin.h @@ -0,0 +1,6 @@ +#ifndef AUTO_BIN_H +#define AUTO_BIN_H + +extern char auto_bin[]; + +#endif diff --git a/auto_qmail.c.do b/auto_qmail.c.do new file mode 100644 index 0000000..c072bf3 --- /dev/null +++ b/auto_qmail.c.do @@ -0,0 +1,3 @@ +dependon auto-str conf-qmail +formake './auto-str auto_qmail `head -1 conf-qmail` > auto_qmail.c' +./auto-str auto_qmail `head -1 conf-qmail` diff --git a/auto_qmail.h b/auto_qmail.h new file mode 100644 index 0000000..0c56001 --- /dev/null +++ b/auto_qmail.h @@ -0,0 +1,6 @@ +#ifndef AUTO_QMAIL_H +#define AUTO_QMAIL_H + +extern char auto_qmail[]; + +#endif diff --git a/byte.h b/byte.h new file mode 100644 index 0000000..de06c69 --- /dev/null +++ b/byte.h @@ -0,0 +1,13 @@ +#ifndef BYTE_H +#define BYTE_H + +extern unsigned int byte_chr(); +extern unsigned int byte_rchr(); +extern void byte_copy(); +extern void byte_copyr(); +extern int byte_diff(); +extern void byte_zero(); + +#define byte_equal(s,n,t) (!byte_diff((s),(n),(t))) + +#endif diff --git a/byte_chr.c b/byte_chr.c new file mode 100644 index 0000000..f81dde8 --- /dev/null +++ b/byte_chr.c @@ -0,0 +1,20 @@ +#include "byte.h" + +unsigned int byte_chr(s,n,c) +char *s; +register unsigned int n; +int c; +{ + register char ch; + register char *t; + + ch = c; + t = s; + for (;;) { + if (!n) break; if (*t == ch) break; ++t; --n; + if (!n) break; if (*t == ch) break; ++t; --n; + if (!n) break; if (*t == ch) break; ++t; --n; + if (!n) break; if (*t == ch) break; ++t; --n; + } + return t - s; +} diff --git a/byte_copy.c b/byte_copy.c new file mode 100644 index 0000000..eaad11b --- /dev/null +++ b/byte_copy.c @@ -0,0 +1,14 @@ +#include "byte.h" + +void byte_copy(to,n,from) +register char *to; +register unsigned int n; +register char *from; +{ + for (;;) { + if (!n) return; *to++ = *from++; --n; + if (!n) return; *to++ = *from++; --n; + if (!n) return; *to++ = *from++; --n; + if (!n) return; *to++ = *from++; --n; + } +} diff --git a/byte_cr.c b/byte_cr.c new file mode 100644 index 0000000..3e7a1d5 --- /dev/null +++ b/byte_cr.c @@ -0,0 +1,16 @@ +#include "byte.h" + +void byte_copyr(to,n,from) +register char *to; +register unsigned int n; +register char *from; +{ + to += n; + from += n; + for (;;) { + if (!n) return; *--to = *--from; --n; + if (!n) return; *--to = *--from; --n; + if (!n) return; *--to = *--from; --n; + if (!n) return; *--to = *--from; --n; + } +} diff --git a/byte_diff.c b/byte_diff.c new file mode 100644 index 0000000..cdbd760 --- /dev/null +++ b/byte_diff.c @@ -0,0 +1,16 @@ +#include "byte.h" + +int byte_diff(s,n,t) +register char *s; +register unsigned int n; +register char *t; +{ + for (;;) { + if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; + if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; + if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; + if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; + } + return ((int)(unsigned int)(unsigned char) *s) + - ((int)(unsigned int)(unsigned char) *t); +} diff --git a/byte_rchr.c b/byte_rchr.c new file mode 100644 index 0000000..476bc22 --- /dev/null +++ b/byte_rchr.c @@ -0,0 +1,23 @@ +#include "byte.h" + +unsigned int byte_rchr(s,n,c) +char *s; +register unsigned int n; +int c; +{ + register char ch; + register char *t; + register char *u; + + ch = c; + t = s; + u = 0; + for (;;) { + if (!n) break; if (*t == ch) u = t; ++t; --n; + if (!n) break; if (*t == ch) u = t; ++t; --n; + if (!n) break; if (*t == ch) u = t; ++t; --n; + if (!n) break; if (*t == ch) u = t; ++t; --n; + } + if (!u) u = t; + return u - s; +} diff --git a/byte_zero.c b/byte_zero.c new file mode 100644 index 0000000..92009ba --- /dev/null +++ b/byte_zero.c @@ -0,0 +1,13 @@ +#include "byte.h" + +void byte_zero(s,n) +char *s; +register unsigned int n; +{ + for (;;) { + if (!n) break; *s++ = 0; --n; + if (!n) break; *s++ = 0; --n; + if (!n) break; *s++ = 0; --n; + if (!n) break; *s++ = 0; --n; + } +} diff --git a/case.3 b/case.3 new file mode 100644 index 0000000..58bd724 --- /dev/null +++ b/case.3 @@ -0,0 +1,100 @@ +.TH case 3 +.SH NAME +case \- convert ASCII uppercase bytes to lowercase +.SH SYNTAX +.B #include + +void \fBcase_lowers\fP(\fIs\fR); +.br +void \fBcase_lowerb\fP(\fIs\fR,\fIlen\fR); + +int \fBcase_diffs\fP(\fIs\fR,\fIt\fR); +.br +int \fBcase_equals\fP(\fIs\fR,\fIt\fR); +.br +int \fBcase_starts\fP(\fIs\fR,\fIt\fR); + +int \fBcase_diffb\fP(\fIs\fR,\fIlen\fR,\fIt\fR); +.br +int \fBcase_startb\fP(\fIs\fR,\fIlen\fR,\fIt\fR); + +char *\fIs\fR; +.br +char *\fIt\fR; +.br +unsigned int \fIlen\fR; +.SH DESCRIPTION +.B case_lowers +converts each uppercase byte in the string +.I s +to lowercase. +.I s +must be 0-terminated. + +.B case_lowerb +converts each uppercase byte in the buffer +.IR s , +of length +.IR len , +to lowercase. + +.B case_diffs +lexicographically compares lowercase versions of the strings +.I s +and +.IR t . +It returns something positive, negative, or zero +when the first is larger than, smaller than, or equal to the second. +.I s +and +.I t +must be 0-terminated. + +.B case_equals +means +.BR !case_diffs . + +.B case_starts +returns 1 if a lowercase version of +.I s +starts with a lowercase version of +.IR t . +.I s +and +.I t +must be 0-terminated. + +.B case_diffb +lexicographically compares lowercase versions of the buffers +.I s +and +.IR t , +each of length +.IR len . +It returns something positive, negative, or zero +when the first is larger than, smaller than, or equal to the second. + +.B case_startb +returns 1 if a lowercase version of the buffer +.IR s , +of length +.IR len , +starts with a lowercase version of the string +.IR t . +.I t +must be 0-terminated. + +The +.B case +routines +are ASCII-specific. +They are suitable for programs that handle +case-independent networking protocols. + +All comparisons are performed on unsigned bytes. +.SH "SEE ALSO" +byte_diff(3), +byte_equal(3), +str_diff(3), +str_equal(3), +str_start(3) diff --git a/case.h b/case.h new file mode 100644 index 0000000..35a2434 --- /dev/null +++ b/case.h @@ -0,0 +1,13 @@ +#ifndef CASE_H +#define CASE_H + +extern void case_lowers(); +extern void case_lowerb(); +extern int case_diffs(); +extern int case_diffb(); +extern int case_starts(); +extern int case_startb(); + +#define case_equals(s,t) (!case_diffs((s),(t))) + +#endif diff --git a/case=0 b/case=0 new file mode 100644 index 0000000..4750e7f --- /dev/null +++ b/case=0 @@ -0,0 +1 @@ +case.3 diff --git a/case=l b/case=l new file mode 100644 index 0000000..9e09750 --- /dev/null +++ b/case=l @@ -0,0 +1,3 @@ +case_diffb.o +case_lowerb.o +case_startb.o diff --git a/case_diffb.c b/case_diffb.c new file mode 100644 index 0000000..9064b8a --- /dev/null +++ b/case_diffb.c @@ -0,0 +1,21 @@ +#include "case.h" + +int case_diffb(s,len,t) +register char *s; +unsigned int len; +register char *t; +{ + register unsigned char x; + register unsigned char y; + + while (len > 0) { + --len; + x = *s++ - 'A'; + if (x <= 'Z' - 'A') x += 'a'; else x += 'A'; + y = *t++ - 'A'; + if (y <= 'Z' - 'A') y += 'a'; else y += 'A'; + if (x != y) + return ((int)(unsigned int) x) - ((int)(unsigned int) y); + } + return 0; +} diff --git a/case_lowerb.c b/case_lowerb.c new file mode 100644 index 0000000..4034c14 --- /dev/null +++ b/case_lowerb.c @@ -0,0 +1,14 @@ +#include "case.h" + +void case_lowerb(s,len) +char *s; +unsigned int len; +{ + unsigned char x; + while (len > 0) { + --len; + x = *s - 'A'; + if (x <= 'Z' - 'A') *s = x + 'a'; + ++s; + } +} diff --git a/case_startb.c b/case_startb.c new file mode 100644 index 0000000..ee88efe --- /dev/null +++ b/case_startb.c @@ -0,0 +1,21 @@ +#include "case.h" + +int case_startb(s,len,t) +register char *s; +unsigned int len; +register char *t; +{ + register unsigned char x; + register unsigned char y; + + for (;;) { + y = *t++ - 'A'; + if (y <= 'Z' - 'A') y += 'a'; else y += 'A'; + if (!y) return 1; + if (!len) return 0; + --len; + x = *s++ - 'A'; + if (x <= 'Z' - 'A') x += 'a'; else x += 'A'; + if (x != y) return 0; + } +} diff --git a/conf-bin b/conf-bin new file mode 100644 index 0000000..813dc94 --- /dev/null +++ b/conf-bin @@ -0,0 +1,3 @@ +/usr/local/bin/ezmlm + +Programs will be installed in this directory. diff --git a/conf-cc b/conf-cc new file mode 100644 index 0000000..e58fb9b --- /dev/null +++ b/conf-cc @@ -0,0 +1,3 @@ +cc -O2 + +This will be used to compile .c files. diff --git a/conf-ld b/conf-ld new file mode 100644 index 0000000..a9e796a --- /dev/null +++ b/conf-ld @@ -0,0 +1,3 @@ +cc -s + +This will be used to link .o files into an executable. diff --git a/conf-man b/conf-man new file mode 100644 index 0000000..b4e70a4 --- /dev/null +++ b/conf-man @@ -0,0 +1,5 @@ +/usr/local/man + +Man pages will be installed in subdirectories of this directory. An +unformatted man page foo.1 will go into .../man1/foo.1; a formatted man +page foo.0 will go into .../cat1/foo.0. diff --git a/conf-qmail b/conf-qmail new file mode 100644 index 0000000..6acc5a5 --- /dev/null +++ b/conf-qmail @@ -0,0 +1,3 @@ +/var/qmail + +This is the qmail home directory. diff --git a/constmap.c b/constmap.c new file mode 100644 index 0000000..722e3b8 --- /dev/null +++ b/constmap.c @@ -0,0 +1,114 @@ +#include "constmap.h" +#include "alloc.h" +#include "case.h" + +static constmap_hash hash(s,len) +char *s; +int len; +{ + unsigned char ch; + constmap_hash h; + h = 5381; + while (len > 0) { + ch = *s++ - 'A'; + if (ch <= 'Z' - 'A') ch += 'a' - 'A'; + h = ((h << 5) + h) ^ ch; + --len; + } + return h; +} + +char *constmap(cm,s,len) +struct constmap *cm; +char *s; +int len; +{ + constmap_hash h; + int pos; + h = hash(s,len); + pos = cm->first[h & cm->mask]; + while (pos != -1) { + if (h == cm->hash[pos]) + if (len == cm->inputlen[pos]) + if (!case_diffb(cm->input[pos],len,s)) + return cm->input[pos] + cm->inputlen[pos] + 1; + pos = cm->next[pos]; + } + return 0; +} + +int constmap_init(cm,s,len,flagcolon) +struct constmap *cm; +char *s; +int len; +int flagcolon; +{ + int i; + int j; + int k; + int pos; + constmap_hash h; + + cm->num = 0; + for (j = 0;j < len;++j) if (!s[j]) ++cm->num; + + h = 64; + while (h && (h < cm->num)) h += h; + cm->mask = h - 1; + + cm->first = (int *) alloc(sizeof(int) * h); + if (cm->first) { + cm->input = (char **) alloc(sizeof(char *) * cm->num); + if (cm->input) { + cm->inputlen = (int *) alloc(sizeof(int) * cm->num); + if (cm->inputlen) { + cm->hash = (constmap_hash *) alloc(sizeof(constmap_hash) * cm->num); + if (cm->hash) { + cm->next = (int *) alloc(sizeof(int) * cm->num); + if (cm->next) { + for (h = 0;h <= cm->mask;++h) + cm->first[h] = -1; + pos = 0; + i = 0; + for (j = 0;j < len;++j) + if (!s[j]) { + k = j - i; + if (flagcolon) { + for (k = i;k < j;++k) + if (s[k] == ':') + break; + if (k >= j) { i = j + 1; continue; } + k -= i; + } + cm->input[pos] = s + i; + cm->inputlen[pos] = k; + h = hash(s + i,k); + cm->hash[pos] = h; + h &= cm->mask; + cm->next[pos] = cm->first[h]; + cm->first[h] = pos; + ++pos; + i = j + 1; + } + return 1; + } + alloc_free(cm->hash); + } + alloc_free(cm->inputlen); + } + alloc_free(cm->input); + } + alloc_free(cm->first); + } + return 0; +} + +void constmap_free(cm) +struct constmap *cm; +{ + alloc_free(cm->next); + alloc_free(cm->hash); + alloc_free(cm->inputlen); + alloc_free(cm->input); + alloc_free(cm->first); +} diff --git a/constmap.h b/constmap.h new file mode 100644 index 0000000..3f29179 --- /dev/null +++ b/constmap.h @@ -0,0 +1,20 @@ +#ifndef CONSTMAP_H +#define CONSTMAP_H + +typedef unsigned long constmap_hash; + +struct constmap { + int num; + constmap_hash mask; + constmap_hash *hash; + int *first; + int *next; + char **input; + int *inputlen; +} ; + +extern int constmap_init(); +extern void constmap_free(); +extern char *constmap(); + +#endif diff --git a/cookie.c b/cookie.c new file mode 100644 index 0000000..59089c1 --- /dev/null +++ b/cookie.c @@ -0,0 +1,47 @@ +#include "cookie.h" +#include "str.h" +#include "uint32.h" +#include "surfpcs.h" + +void cookie(hash,key,keylen,date,addr,action) +char *hash; +char *key; +unsigned int keylen; +char *date; +char *addr; +char *action; +{ + surfpcs s; + uint32 seed[32]; + unsigned char out[32]; + int i; + int j; + +/* +step 1: create seed from key. note that this doesn't have to be +cryptographic; it simply has to avoid destroying the user's entropy. +if speed turns out to be a problem, switch to a CRC. +*/ + for (i = 0;i < 32;++i) seed[i] = 0; + for (j = 0;j < 4;++j) { + surfpcs_init(&s,seed); + surfpcs_add(&s,key,keylen); + surfpcs_out(&s,out); + for (i = 0;i < 32;++i) seed[i] = (seed[i] << 8) + out[i]; + } + +/* +step 2: apply SURF. +*/ + surfpcs_init(&s,seed); + surfpcs_add(&s,date,str_len(date) + 1); + surfpcs_add(&s,addr,str_len(addr) + 1); + surfpcs_add(&s,action,1); + surfpcs_out(&s,out); + +/* +step 3: extract a readable cookie from the SURF output. +*/ + for (i = 0;i < 20;++i) + hash[i] = 'a' + (out[i] & 15); +} diff --git a/cookie.h b/cookie.h new file mode 100644 index 0000000..041cb6a --- /dev/null +++ b/cookie.h @@ -0,0 +1,8 @@ +#ifndef COOKIE_H +#define COOKIE_H + +#define COOKIE 20 + +extern void cookie(); + +#endif diff --git a/date822fmt.c b/date822fmt.c new file mode 100644 index 0000000..7674bd1 --- /dev/null +++ b/date822fmt.c @@ -0,0 +1,29 @@ +#include "datetime.h" +#include "fmt.h" +#include "date822fmt.h" + +static char *montab[12] = { +"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" +}; + +unsigned int date822fmt(s,dt) +char *s; +struct datetime *dt; +{ + unsigned int i; + unsigned int len; + len = 0; + i = fmt_uint(s,dt->mday); len += i; if (s) s += i; + i = fmt_str(s," "); len += i; if (s) s += i; + i = fmt_str(s,montab[dt->mon]); len += i; if (s) s += i; + i = fmt_str(s," "); len += i; if (s) s += i; + i = fmt_uint(s,dt->year + 1900); len += i; if (s) s += i; + i = fmt_str(s," "); len += i; if (s) s += i; + i = fmt_uint0(s,dt->hour,2); len += i; if (s) s += i; + i = fmt_str(s,":"); len += i; if (s) s += i; + i = fmt_uint0(s,dt->min,2); len += i; if (s) s += i; + i = fmt_str(s,":"); len += i; if (s) s += i; + i = fmt_uint0(s,dt->sec,2); len += i; if (s) s += i; + i = fmt_str(s," -0000\n"); len += i; if (s) s += i; + return len; +} diff --git a/date822fmt.h b/date822fmt.h new file mode 100644 index 0000000..1848e5a --- /dev/null +++ b/date822fmt.h @@ -0,0 +1,7 @@ +#ifndef DATE822FMT_H +#define DATE822FMT_H + +extern unsigned int date822fmt(); +#define DATE822FMT 60 + +#endif diff --git a/datetime.3 b/datetime.3 new file mode 100644 index 0000000..33a623f --- /dev/null +++ b/datetime.3 @@ -0,0 +1,73 @@ +.TH datetime 3 +.SH NAME +datetime \- convert between TAI labels and seconds +.SH SYNTAX +.B #include + +void \fBdatetime_tai\fP(&\fIdt\fR,\fIt\fR); + +datetime_sec \fBdatetime_untai\fP(&\fIdt\fR); + +struct datetime \fIdt\fR; +.br +datetime_sec \fIt\fR; +.SH DESCRIPTION +International Atomic Time, TAI, +is the fundamental unit for time measurements. +TAI has one label for every second of real time, +without complications such as leap seconds. + +A +struct datetime +variable, +such as +.IR dt , +stores a TAI label. +.I dt\fB.year +is the year number minus 1900; +.I dt\fB.mon +is the month number, from 0 (January) through 11 (December); +.I dt\fB.mday +is the day of the month, from 1 through 31; +.I dt\fB.hour +is the hour, from 0 through 23; +.I dt\fB.min +is the minute, from 0 through 59; +.I dt\fB.sec +is the second, from 0 through 59; +.I dt\fB.wday +is the day of the week, from 0 (Sunday) through 6 (Saturday); +.I dt\fB.yday +is the day of the year, from 0 through 365. + +The +.B datetime +library supports more convenient TAI manipulation with +the datetime_sec type. +A datetime_sec value, such as +.IR t , +is an integer referring to the +.IR t th +second after the beginning of 1970 TAI. +The first second of 1970 TAI was 0; +the next second was 1; +the last second of 1969 TAI was -1. +The difference between two datetime_sec values is a number +of real-time seconds. + +.B datetime_tai +converts a datetime_sec to a TAI label. + +.B datetime_untai +reads a TAI label +(specifically +.IR dt\fB.year , +.IR dt\fB.mon , +.IR dt\fB.mday , +.IR dt\fB.hour , +.IR dt\fB.min , +and +.IR dt\fB.sec ) +and returns a datetime_sec. +.SH "SEE ALSO" +now(3) diff --git a/datetime.c b/datetime.c new file mode 100644 index 0000000..7b8a803 --- /dev/null +++ b/datetime.c @@ -0,0 +1,55 @@ +/* 19950925 */ +#include "datetime.h" + +void datetime_tai(dt,t) +struct datetime *dt; +datetime_sec t; +{ + int day; + int tod; + int year; + int yday; + int wday; + int mon; + + tod = t % 86400; + day = t / 86400; + if (tod < 0) { tod += 86400; --day; } + + dt->hour = tod / 3600; + tod %= 3600; + dt->min = tod / 60; + dt->sec = tod % 60; + + wday = (day + 4) % 7; if (wday < 0) wday += 7; + dt->wday = wday; + + day -= 11017; + /* day 0 is march 1, 2000 */ + year = 5 + day / 146097; + day = day % 146097; if (day < 0) { day += 146097; --year; } + /* from now on, day is nonnegative */ + year *= 4; + if (day == 146096) { year += 3; day = 36524; } + else { year += day / 36524; day %= 36524; } + year *= 25; + year += day / 1461; + day %= 1461; + year *= 4; + yday = (day < 306); + if (day == 1460) { year += 3; day = 365; } + else { year += day / 365; day %= 365; } + yday += day; + + day *= 10; + mon = (day + 5) / 306; + day = day + 5 - 306 * mon; + day /= 10; + if (mon >= 10) { yday -= 306; ++year; mon -= 10; } + else { yday += 59; mon += 2; } + + dt->yday = yday; + dt->year = year - 1900; + dt->mon = mon; + dt->mday = day + 1; +} diff --git a/datetime.h b/datetime.h new file mode 100644 index 0000000..cde2a9b --- /dev/null +++ b/datetime.h @@ -0,0 +1,20 @@ +#ifndef DATETIME_H +#define DATETIME_H + +struct datetime { + int hour; + int min; + int sec; + int wday; + int mday; + int yday; + int mon; + int year; +} ; + +typedef long datetime_sec; + +extern void datetime_tai(); +extern datetime_sec datetime_untai(); + +#endif diff --git a/datetime=0 b/datetime=0 new file mode 100644 index 0000000..8a4bea1 --- /dev/null +++ b/datetime=0 @@ -0,0 +1 @@ +datetime.3 diff --git a/default.0.do b/default.0.do new file mode 100644 index 0000000..e40b50c --- /dev/null +++ b/default.0.do @@ -0,0 +1,9 @@ +if test -r "$2=0" +then + dependon "$2=0" + dependon `cat "$2=0"` + nroff -man `cat "$2=0"` + formake nroff -man `cat "$2=0"` '>' $1 +else + nosuchtarget +fi diff --git a/default.a.do b/default.a.do new file mode 100644 index 0000000..b61fc5c --- /dev/null +++ b/default.a.do @@ -0,0 +1,10 @@ +if test -r "$2=l" +then + dependon "$2=l" + dependon makelib `cat "$2=l"` + directtarget + formake ./makelib $1 `cat "$2=l"` + ./makelib $1 `cat "$2=l"` +else + nosuchtarget +fi diff --git a/default.do b/default.do new file mode 100644 index 0000000..792917f --- /dev/null +++ b/default.do @@ -0,0 +1,76 @@ +if test -r $1=x +then + dependon $1=x + libs=`grep '\.lib *$' "$1=x"` + libscat='' + for i in $libs + do + libscat="$libscat "'`'"cat $i"'`' + done + objs=`grep -v '\.lib *$' "$1=x"` + dependon load $1.o $objs $libs + directtarget + formake ./load $1 $objs "$libscat" + eval ./load $1 $objs $libscat + exit 0 +fi + +if test -r $1=s +then + dependon $1=s warn-auto.sh $1.sh + formake cat warn-auto.sh $1.sh '>' $1 + formake chmod 755 $1 + cat warn-auto.sh $1.sh + chmod 755 $3 + exit 0 +fi + +case "$1" in + shar) + dependon FILES `cat FILES` + formake 'shar -m `cat FILES` > shar' + formake 'chmod 400 shar' + shar -m `cat FILES` + chmod 400 $3 + ;; + compile|load|makelib) + dependon make-$1 warn-auto.sh systype + formake "( cat warn-auto.sh; ./make-$1 "'"`cat systype`"'" ) > $1" + formake "chmod 755 $1" + cat warn-auto.sh + ./make-$1 "`cat systype`" + chmod 755 $3 + ;; + make-compile|make-load|make-makelib) + dependon $1.sh auto-ccld.sh + formake "cat auto-ccld.sh $1.sh > $1" + formake "chmod 755 $1" + cat auto-ccld.sh $1.sh + chmod 755 $3 + ;; + systype) + dependon find-systype trycpp.c + formake './find-systype > systype' + ./find-systype + ;; + find-systype) + dependon find-systype.sh auto-ccld.sh + formake 'cat auto-ccld.sh find-systype.sh > find-systype' + formake 'chmod 755 find-systype' + cat auto-ccld.sh find-systype.sh + chmod 755 $3 + ;; + auto-ccld.sh) + dependon conf-cc conf-ld warn-auto.sh + formake '( cat warn-auto.sh; \' + formake 'echo CC=\'\''`head -1 conf-cc`\'\''; \' + formake 'echo LD=\'\''`head -1 conf-ld`\'\'' \' + formake ') > auto-ccld.sh' + cat warn-auto.sh + echo CC=\'`head -1 conf-cc`\' + echo LD=\'`head -1 conf-ld`\' + ;; + *) + nosuchtarget + ;; +esac diff --git a/default.o.do b/default.o.do new file mode 100644 index 0000000..5d5ee1e --- /dev/null +++ b/default.o.do @@ -0,0 +1,15 @@ +if test -r $2=m +then + dependon $2=m $2.s + directtarget + as -o $1 $2.s + formake as -o $1 $2.s + exit 0 +fi +depend -$2=m + +directtarget +dependon compile +dependcc $2.c +formake ./compile $2.c +./compile $2.c diff --git a/direntry.3 b/direntry.3 new file mode 100644 index 0000000..8928fbb --- /dev/null +++ b/direntry.3 @@ -0,0 +1,36 @@ +.TH direntry 3 +.SH NAME +direntry \- read directory entries +.SH SYNTAX +.B #include + +DIR *\fBopendir\fP(\fIfn\fR); + +struct direntry *\fBreaddir\fP(\fIdir\fP); + +void \fBclosedir\fP(\fIdir\fP); + +DIR *\fIdir\fR; +.br +char *\fIfn\fR; +.SH DESCRIPTION +The point of +.B direntry.h +is to provide a uniform interface to BSD's +.B sys/dir.h +and POSIX's +.BR dirent.h . + +The +.B readdir +interface is highly unsatisfactory. +It does not distinguish between I/O errors and end-of-directory. +It uses +.BR malloc . +The return type for +.B closedir +varies: some implementations return the +.B close +return value. +.SH "SEE ALSO" +readdir(3) diff --git a/direntry.h.do b/direntry.h.do new file mode 100644 index 0000000..4470197 --- /dev/null +++ b/direntry.h.do @@ -0,0 +1,7 @@ +dependon compile trydrent.c direntry.h1 direntry.h2 +./compile trydrent.c >/dev/null 2>&1 \ +&& cat direntry.h2 || cat direntry.h1 +rm -f trydrent.o +formake '( ./compile trydrent.c >/dev/null 2>&1 \' +formake '&& cat direntry.h2 || cat direntry.h1 ) > direntry.h' +formake 'rm -f trydrent.o' diff --git a/direntry.h1 b/direntry.h1 new file mode 100644 index 0000000..f737676 --- /dev/null +++ b/direntry.h1 @@ -0,0 +1,8 @@ +#ifndef DIRENTRY_H +#define DIRENTRY_H + +#include +#include +#define direntry struct direct + +#endif diff --git a/direntry.h2 b/direntry.h2 new file mode 100644 index 0000000..0302ebe --- /dev/null +++ b/direntry.h2 @@ -0,0 +1,8 @@ +#ifndef DIRENTRY_H +#define DIRENTRY_H + +#include +#include +#define direntry struct dirent + +#endif diff --git a/direntry=0 b/direntry=0 new file mode 100644 index 0000000..6086256 --- /dev/null +++ b/direntry=0 @@ -0,0 +1 @@ +direntry.3 diff --git a/env.3 b/env.3 new file mode 100644 index 0000000..53a5f89 --- /dev/null +++ b/env.3 @@ -0,0 +1,31 @@ +.TH env 3 +.SH NAME +env \- manage the environment +.SH SYNTAX +.B #include + +char **\fBenviron\fP; + +char *\fBenv_get\fP(\fIname\fR); +.br +char *\fBenv_pick\fP(); + +char *\fIname\fR; +.SH DESCRIPTION +The environment, +.BR environ , +is a 0-terminated array of 0-terminated strings, +called environment variables. +Each environment variable is of the form +.IR name\fB=\fIvalue . + +.B env_get +returns the value of the first variable whose name is +.IR name , +or 0 if there is no such variable. + +.B env_pick +returns any variable in the environment, +or 0 if the environment is empty. +.SH "SEE ALSO" +environ(7) diff --git a/env.h b/env.h new file mode 100644 index 0000000..9befc79 --- /dev/null +++ b/env.h @@ -0,0 +1,17 @@ +#ifndef ENV_H +#define ENV_H + +extern int env_isinit; + +extern int env_init(); +extern int env_put(); +extern int env_put2(); +extern int env_unset(); +extern /*@null@*/char *env_get(); +extern char *env_pick(); +extern void env_clear(); +extern char *env_findeq(); + +extern char **environ; + +#endif diff --git a/env=0 b/env=0 new file mode 100644 index 0000000..567ab81 --- /dev/null +++ b/env=0 @@ -0,0 +1 @@ +env.3 diff --git a/env=l b/env=l new file mode 100644 index 0000000..21db6c5 --- /dev/null +++ b/env=l @@ -0,0 +1 @@ +envread.o diff --git a/envread.c b/envread.c new file mode 100644 index 0000000..80185de --- /dev/null +++ b/envread.c @@ -0,0 +1,30 @@ +#include "env.h" +#include "str.h" + +extern /*@null@*/char *env_get(s) +char *s; +{ + int i; + unsigned int slen; + char *envi; + + slen = str_len(s); + for (i = 0;envi = environ[i];++i) + if ((!str_diffn(s,envi,slen)) && (envi[slen] == '=')) + return envi + slen + 1; + return 0; +} + +extern char *env_pick() +{ + return environ[0]; +} + +extern char *env_findeq(s) +char *s; +{ + for (;*s;++s) + if (*s == '=') + return s; + return 0; +} diff --git a/error.3 b/error.3 new file mode 100644 index 0000000..e955b35 --- /dev/null +++ b/error.3 @@ -0,0 +1,45 @@ +.TH error 3 +.SH NAME +error \- syscall error codes +.SH SYNTAX +.B #include + +extern int \fBerrno\fP; + +extern int \fBerror_intr\fP; +.br +extern int \fBerror_nomem\fP; +.br +extern int \fBerror_noent\fP; +.br +extern int \fBerror_txtbsy\fP; +.br +extern int \fBerror_io\fP; +.br +extern int \fBerror_exist\fP; +.br +extern int \fBerror_timeout\fP; +.br +extern int \fBerror_inprogress\fP; +.br +extern int \fBerror_wouldblock\fP; +.br +extern int \fBerror_again\fP; +.br +extern int \fBerror_pipe\fP; +.br +extern int \fBerror_perm\fP; +.br +extern int \fBerror_acces\fP; +.SH DESCRIPTION +UNIX syscalls provide detailed error codes in the +.B errno +variable. +The +.B error +library provides portable names for a variety of possible +.B errno +values. +.SH "SEE ALSO" +error_str(3), +error_temp(3) diff --git a/error.c b/error.c new file mode 100644 index 0000000..d51304f --- /dev/null +++ b/error.c @@ -0,0 +1,95 @@ +#include +#include "error.h" + +/* warning: as coverage improves here, should update error_{str,temp} */ + +int error_intr = +#ifdef EINTR +EINTR; +#else +-1; +#endif + +int error_nomem = +#ifdef ENOMEM +ENOMEM; +#else +-2; +#endif + +int error_noent = +#ifdef ENOENT +ENOENT; +#else +-3; +#endif + +int error_txtbsy = +#ifdef ETXTBSY +ETXTBSY; +#else +-4; +#endif + +int error_io = +#ifdef EIO +EIO; +#else +-5; +#endif + +int error_exist = +#ifdef EEXIST +EEXIST; +#else +-6; +#endif + +int error_timeout = +#ifdef ETIMEDOUT +ETIMEDOUT; +#else +-7; +#endif + +int error_inprogress = +#ifdef EINPROGRESS +EINPROGRESS; +#else +-8; +#endif + +int error_wouldblock = +#ifdef EWOULDBLOCK +EWOULDBLOCK; +#else +-9; +#endif + +int error_again = +#ifdef EAGAIN +EAGAIN; +#else +-10; +#endif + +int error_pipe = +#ifdef EPIPE +EPIPE; +#else +-11; +#endif + +int error_perm = +#ifdef EPERM +EPERM; +#else +-12; +#endif + +int error_acces = +#ifdef EACCES +EACCES; +#else +-13; +#endif diff --git a/error.h b/error.h new file mode 100644 index 0000000..01bd3dc --- /dev/null +++ b/error.h @@ -0,0 +1,23 @@ +#ifndef ERROR_H +#define ERROR_H + +extern int errno; + +extern int error_intr; +extern int error_nomem; +extern int error_noent; +extern int error_txtbsy; +extern int error_io; +extern int error_exist; +extern int error_timeout; +extern int error_inprogress; +extern int error_wouldblock; +extern int error_again; +extern int error_pipe; +extern int error_perm; +extern int error_acces; + +extern char *error_str(); +extern int error_temp(); + +#endif diff --git a/error=0 b/error=0 new file mode 100644 index 0000000..d7bbc09 --- /dev/null +++ b/error=0 @@ -0,0 +1 @@ +error.3 diff --git a/error=l b/error=l new file mode 100644 index 0000000..2a9cb84 --- /dev/null +++ b/error=l @@ -0,0 +1,2 @@ +error.o +error_str.o diff --git a/error_str.3 b/error_str.3 new file mode 100644 index 0000000..62043c4 --- /dev/null +++ b/error_str.3 @@ -0,0 +1,19 @@ +.TH error_str 3 +.SH NAME +error_str \- names for syscall error codes +.SH SYNTAX +.B #include + +char *\fBerror_str\fP(\fIe\fR); + +int \fIe\fR; +.SH DESCRIPTION +.B error_str +returns a printable string describing syscall error code +.IR e . +Normally +.I e +is +.BR errno . +.SH "SEE ALSO" +error(3) diff --git a/error_str.c b/error_str.c new file mode 100644 index 0000000..804d1fa --- /dev/null +++ b/error_str.c @@ -0,0 +1,276 @@ +#include +#include "error.h" + +#define X(e,s) if (i == e) return s; + +char *error_str(i) +int i; +{ + X(0,"no error") + X(error_intr,"interrupted system call") + X(error_nomem,"out of memory") + X(error_noent,"file does not exist") + X(error_txtbsy,"text busy") + X(error_io,"input/output error") + X(error_exist,"file already exists") + X(error_timeout,"timed out") + X(error_inprogress,"operation in progress") + X(error_again,"temporary failure") + X(error_wouldblock,"input/output would block") + X(error_pipe,"broken pipe") + X(error_perm,"permission denied") + X(error_acces,"access denied") +#ifdef ESRCH + X(ESRCH,"no such process") +#endif +#ifdef ENXIO + X(ENXIO,"device not configured") +#endif +#ifdef E2BIG + X(E2BIG,"argument list too long") +#endif +#ifdef ENOEXEC + X(ENOEXEC,"exec format error") +#endif +#ifdef EBADF + X(EBADF,"file descriptor not open") +#endif +#ifdef ECHILD + X(ECHILD,"no child processes") +#endif +#ifdef EDEADLK + X(EDEADLK,"operation would cause deadlock") +#endif +#ifdef EFAULT + X(EFAULT,"bad address") +#endif +#ifdef ENOTBLK + X(ENOTBLK,"not a block device") +#endif +#ifdef EBUSY + X(EBUSY,"device busy") +#endif +#ifdef EXDEV + X(EXDEV,"cross-device link") +#endif +#ifdef ENODEV + X(ENODEV,"device does not support operation") +#endif +#ifdef ENOTDIR + X(ENOTDIR,"not a directory") +#endif +#ifdef EISDIR + X(EISDIR,"is a directory") +#endif +#ifdef EINVAL + X(EINVAL,"invalid argument") +#endif +#ifdef ENFILE + X(ENFILE,"system cannot open more files") +#endif +#ifdef EMFILE + X(EMFILE,"process cannot open more files") +#endif +#ifdef ENOTTY + X(ENOTTY,"not a tty") +#endif +#ifdef EFBIG + X(EFBIG,"file too big") +#endif +#ifdef ENOSPC + X(ENOSPC,"out of disk space") +#endif +#ifdef ESPIPE + X(ESPIPE,"unseekable descriptor") +#endif +#ifdef EROFS + X(EROFS,"read-only file system") +#endif +#ifdef EMLINK + X(EMLINK,"too many links") +#endif +#ifdef EDOM + X(EDOM,"input out of range") +#endif +#ifdef ERANGE + X(ERANGE,"output out of range") +#endif +#ifdef EALREADY + X(EALREADY,"operation already in progress") +#endif +#ifdef ENOTSOCK + X(ENOTSOCK,"not a socket") +#endif +#ifdef EDESTADDRREQ + X(EDESTADDRREQ,"destination address required") +#endif +#ifdef EMSGSIZE + X(EMSGSIZE,"message too long") +#endif +#ifdef EPROTOTYPE + X(EPROTOTYPE,"incorrect protocol type") +#endif +#ifdef ENOPROTOOPT + X(ENOPROTOOPT,"protocol not available") +#endif +#ifdef EPROTONOSUPPORT + X(EPROTONOSUPPORT,"protocol not supported") +#endif +#ifdef ESOCKTNOSUPPORT + X(ESOCKTNOSUPPORT,"socket type not supported") +#endif +#ifdef EOPNOTSUPP + X(EOPNOTSUPP,"operation not supported") +#endif +#ifdef EPFNOSUPPORT + X(EPFNOSUPPORT,"protocol family not supported") +#endif +#ifdef EAFNOSUPPORT + X(EAFNOSUPPORT,"address family not supported") +#endif +#ifdef EADDRINUSE + X(EADDRINUSE,"address already used") +#endif +#ifdef EADDRNOTAVAIL + X(EADDRNOTAVAIL,"address not available") +#endif +#ifdef ENETDOWN + X(ENETDOWN,"network down") +#endif +#ifdef ENETUNREACH + X(ENETUNREACH,"network unreachable") +#endif +#ifdef ENETRESET + X(ENETRESET,"network reset") +#endif +#ifdef ECONNABORTED + X(ECONNABORTED,"connection aborted") +#endif +#ifdef ECONNRESET + X(ECONNRESET,"connection reset") +#endif +#ifdef ENOBUFS + X(ENOBUFS,"out of buffer space") +#endif +#ifdef EISCONN + X(EISCONN,"already connected") +#endif +#ifdef ENOTCONN + X(ENOTCONN,"not connected") +#endif +#ifdef ESHUTDOWN + X(ESHUTDOWN,"socket shut down") +#endif +#ifdef ETOOMANYREFS + X(ETOOMANYREFS,"too many references") +#endif +#ifdef ECONNREFUSED + X(ECONNREFUSED,"connection refused") +#endif +#ifdef ELOOP + X(ELOOP,"symbolic link loop") +#endif +#ifdef ENAMETOOLONG + X(ENAMETOOLONG,"file name too long") +#endif +#ifdef EHOSTDOWN + X(EHOSTDOWN,"host down") +#endif +#ifdef EHOSTUNREACH + X(EHOSTUNREACH,"host unreachable") +#endif +#ifdef ENOTEMPTY + X(ENOTEMPTY,"directory not empty") +#endif +#ifdef EPROCLIM + X(EPROCLIM,"too many processes") +#endif +#ifdef EUSERS + X(EUSERS,"too many users") +#endif +#ifdef EDQUOT + X(EDQUOT,"disk quota exceeded") +#endif +#ifdef ESTALE + X(ESTALE,"stale NFS file handle") +#endif +#ifdef EREMOTE + X(EREMOTE,"too many levels of remote in path") +#endif +#ifdef EBADRPC + X(EBADRPC,"RPC structure is bad") +#endif +#ifdef ERPCMISMATCH + X(ERPCMISMATCH,"RPC version mismatch") +#endif +#ifdef EPROGUNAVAIL + X(EPROGUNAVAIL,"RPC program unavailable") +#endif +#ifdef EPROGMISMATCH + X(EPROGMISMATCH,"program version mismatch") +#endif +#ifdef EPROCUNAVAIL + X(EPROCUNAVAIL,"bad procedure for program") +#endif +#ifdef ENOLCK + X(ENOLCK,"no locks available") +#endif +#ifdef ENOSYS + X(ENOSYS,"system call not available") +#endif +#ifdef EFTYPE + X(EFTYPE,"bad file type") +#endif +#ifdef EAUTH + X(EAUTH,"authentication error") +#endif +#ifdef ENEEDAUTH + X(ENEEDAUTH,"not authenticated") +#endif +#ifdef ENOSTR + X(ENOSTR,"not a stream device") +#endif +#ifdef ETIME + X(ETIME,"timer expired") +#endif +#ifdef ENOSR + X(ENOSR,"out of stream resources") +#endif +#ifdef ENOMSG + X(ENOMSG,"no message of desired type") +#endif +#ifdef EBADMSG + X(EBADMSG,"bad message type") +#endif +#ifdef EIDRM + X(EIDRM,"identifier removed") +#endif +#ifdef ENONET + X(ENONET,"machine not on network") +#endif +#ifdef ERREMOTE + X(ERREMOTE,"object not local") +#endif +#ifdef ENOLINK + X(ENOLINK,"link severed") +#endif +#ifdef EADV + X(EADV,"advertise error") +#endif +#ifdef ESRMNT + X(ESRMNT,"srmount error") +#endif +#ifdef ECOMM + X(ECOMM,"communication error") +#endif +#ifdef EPROTO + X(EPROTO,"protocol error") +#endif +#ifdef EMULTIHOP + X(EMULTIHOP,"multihop attempted") +#endif +#ifdef EREMCHG + X(EREMCHG,"remote address changed") +#endif + return "unknown error"; +} diff --git a/error_str=0 b/error_str=0 new file mode 100644 index 0000000..3f2616e --- /dev/null +++ b/error_str=0 @@ -0,0 +1 @@ +error_str.3 diff --git a/error_temp.3 b/error_temp.3 new file mode 100644 index 0000000..2f8229d --- /dev/null +++ b/error_temp.3 @@ -0,0 +1,27 @@ +.TH error_temp 3 +.SH NAME +error_temp \- identify soft syscall error codes +.SH SYNTAX +.B #include + +int \fBerror_temp\fP(\fIe\fR); + +int \fIe\fR; +.SH DESCRIPTION +.B error_temp +returns 1 if syscall error code +.I e +is a soft error, 0 if it is a hard error. +Normally +.I e +is +.BR errno . + +A hard error is persistent: +file not found, read-only file system, symbolic link loop, etc. + +A soft error is usually transient: +out of memory, out of disk space, I/O error, disk quota exceeded, +connection refused, host unreachable, etc. +.SH "SEE ALSO" +error(3) diff --git a/error_temp=0 b/error_temp=0 new file mode 100644 index 0000000..9b5ad0f --- /dev/null +++ b/error_temp=0 @@ -0,0 +1 @@ +error_temp.3 diff --git a/exit.h b/exit.h new file mode 100644 index 0000000..39011c8 --- /dev/null +++ b/exit.h @@ -0,0 +1,6 @@ +#ifndef EXIT_H +#define EXIT_H + +extern void _exit(); + +#endif diff --git a/ezmlm-list.1 b/ezmlm-list.1 new file mode 100644 index 0000000..38e140a --- /dev/null +++ b/ezmlm-list.1 @@ -0,0 +1,22 @@ +.TH ezmlm-list 1 +.SH NAME +ezmlm-list \- show the addresses on a mailing list +.SH SYNOPSIS +.B ezmlm-list +.I dir +.SH DESCRIPTION +.B ezmlm-list +prints the subscriber list for the mailing list stored in +.IR dir , +one address per line. + +.B WARNING: +Unless you have disabled automatic subscriptions, +the addresses in a mailing list are under the control +of a possibly malicious remote user. +.B ezmlm-list +does not strip control characters. +.SH "SEE ALSO" +ezmlm-sub(1), +ezmlm-unsub(1), +ezmlm(5) diff --git a/ezmlm-list.c b/ezmlm-list.c new file mode 100644 index 0000000..c6ec801 --- /dev/null +++ b/ezmlm-list.c @@ -0,0 +1,62 @@ +#include "stralloc.h" +#include "substdio.h" +#include "getln.h" +#include "strerr.h" +#include "error.h" +#include "readwrite.h" +#include "exit.h" +#include "open.h" + +#define FATAL "ezmlm-list: fatal: " +void die_write() +{ + strerr_die2sys(111,FATAL,"unable to write: "); +} + +char outbuf[1024]; +substdio out = SUBSTDIO_FDBUF(write,1,outbuf,sizeof(outbuf)); +char inbuf[1024]; +substdio in; + +stralloc line = {0}; + +char fn[14] = "subscribers/?"; + +void main(argc,argv) +int argc; +char **argv; +{ + char *dir; + int fd; + int match; + + dir = argv[1]; + if (!dir) strerr_die1x(100,"ezmlm-list: usage: ezmlm-list dir"); + + if (chdir(dir) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",dir,": "); + + for (fn[12] = 64;fn[12] < 64 + 53;++fn[12]) { + fd = open_read(fn); + if (fd == -1) { + if (errno != error_noent) + strerr_die4sys(111,FATAL,"unable to open ",fn,": "); + } + else { + substdio_fdbuf(&in,read,fd,inbuf,sizeof(inbuf)); + for (;;) { + if (getln(&in,&line,&match,'\0') == -1) + strerr_die4sys(111,FATAL,"unable to read ",fn,": "); + if (!match) break; + if (line.s[str_chr(line.s,'\n')]) + strerr_die3x(111,FATAL,"newline in ",fn); + if (substdio_puts(&out,line.s + 1)) die_write(); + if (substdio_put(&out,"\n",1) == -1) die_write(); + } + } + + } + + if (substdio_flush(&out) == -1) die_write(); + _exit(0); +} diff --git a/ezmlm-list=0 b/ezmlm-list=0 new file mode 100644 index 0000000..a4c12ea --- /dev/null +++ b/ezmlm-list=0 @@ -0,0 +1 @@ +ezmlm-list.1 diff --git a/ezmlm-list=x b/ezmlm-list=x new file mode 100644 index 0000000..acaa3c7 --- /dev/null +++ b/ezmlm-list=x @@ -0,0 +1,8 @@ +strerr.a +getln.a +substdio.a +stralloc.a +alloc.a +error.a +open.a +str.a diff --git a/ezmlm-make.1 b/ezmlm-make.1 new file mode 100644 index 0000000..834feed --- /dev/null +++ b/ezmlm-make.1 @@ -0,0 +1,87 @@ +.TH ezmlm-make 1 +.SH NAME +ezmlm-make \- create a new mailing list +.SH SYNOPSIS +.B ezmlm-make +[ +.B \-aApP +] +.I dir +.I dot +.I local +.I host +.SH DESCRIPTION +.B ezmlm-make +sets up a new mailing list, +.IR local\fB@\fIhost , +along with several extra addresses to handle administrative requests. + +All mailing list information is stored in a new directory, +.IR dir . +.I dir +must be an absolute pathname, starting with a slash. + +.B ezmlm-make +sets up four +.B .qmail +files: +.IR dot , +.IR dot\fB-owner , +.IR dot\fB-return-default , +and +.IR dot\fB-default . +You should make sure that messages to +.IR local\fB@\fIhost , +.IR local\fB-owner@\fIhost , +etc. are controlled by +these +.B .qmail +files. + +Typical use of +.B ezmlm-make +by a normal user: + +.EX + ezmlm-make ~/SOS ~/.qmail-sos joe-sos isp.net +.EE + +Typical use of +.B ezmlm-make +by +.BR alias : + +.EX + ezmlm-make ~alias/SOS ~alias/.qmail-sos sos isp.net +.EE +.SH OPTIONS +.TP 5 +.B \-a +(Default.) Archived. +.B ezmlm-make +will touch +.IR dir\fB/archived , +so that +.B ezmlm-send +will archive new messages. +.TP +.B \-A +Not archived. +.TP 5 +.B \-p +(Default.) Public. +.B ezmlm-make +will touch +.IR dir\fB/public , +so that +.B ezmlm-manage +will respond to administrative requests. +.TP +.B \-P +Private. +.SH "SEE ALSO" +ezmlm-manage(1), +ezmlm-send(1), +ezmlm-sub(1), +ezmlm-unsub(1), +ezmlm(5) diff --git a/ezmlm-make.c b/ezmlm-make.c new file mode 100644 index 0000000..09d2b3e --- /dev/null +++ b/ezmlm-make.c @@ -0,0 +1,435 @@ +#include +#include +#include "sgetopt.h" +#include "stralloc.h" +#include "strerr.h" +#include "exit.h" +#include "readwrite.h" +#include "open.h" +#include "substdio.h" +#include "str.h" +#include "auto_bin.h" + +#define FATAL "ezmlm-make: fatal: " + +void die_usage() +{ + strerr_die1x(100,"ezmlm-make: usage: ezmlm-make [ -aApP ] dir dot local host"); +} +void die_relative() +{ + strerr_die2x(100,FATAL,"dir must start with slash"); +} +void die_newline() +{ + strerr_die2x(100,FATAL,"newlines not allowed"); +} +void die_quote() +{ + strerr_die2x(100,FATAL,"quotes not allowed"); +} +void die_nomem() +{ + strerr_die2x(111,FATAL,"out of memory"); +} + +stralloc key = {0}; +struct timeval tv; + +void keyadd(u) +unsigned long u; +{ + char ch; + ch = u; if (!stralloc_append(&key,&ch)) die_nomem(); u >>= 8; + ch = u; if (!stralloc_append(&key,&ch)) die_nomem(); u >>= 8; + ch = u; if (!stralloc_append(&key,&ch)) die_nomem(); u >>= 8; + ch = u; if (!stralloc_append(&key,&ch)) die_nomem(); +} + +void keyaddtime() +{ + gettimeofday(&tv,(struct timezone *) 0); + keyadd(tv.tv_usec); +} + +char *dir; +char *dot; +char *local; +char *host; + +stralloc dotplus = {0}; +stralloc dirplus = {0}; + +void dirplusmake(slash) +char *slash; +{ + if (!stralloc_copys(&dirplus,dir)) die_nomem(); + if (!stralloc_cats(&dirplus,slash)) die_nomem(); + if (!stralloc_0(&dirplus)) die_nomem(); +} + +void linkdotdir(dash,slash) +char *dash; +char *slash; +{ + if (!stralloc_copys(&dotplus,dot)) die_nomem(); + if (!stralloc_cats(&dotplus,dash)) die_nomem(); + if (!stralloc_0(&dotplus)) die_nomem(); + dirplusmake(slash); + if (symlink(dirplus.s,dotplus.s) == -1) + strerr_die4sys(111,FATAL,"unable to create ",dotplus.s,": "); + keyaddtime(); +} + +void dcreate(slash) +char *slash; +{ + dirplusmake(slash); + if (mkdir(dirplus.s,0755) == -1) + strerr_die4sys(111,FATAL,"unable to create ",dirplus.s,": "); + keyaddtime(); +} + +substdio ss; +char ssbuf[SUBSTDIO_OUTSIZE]; + +void fopen(slash) +char *slash; +{ + int fd; + + dirplusmake(slash); + fd = open_trunc(dirplus.s); + if (fd == -1) + strerr_die4sys(111,FATAL,"unable to create ",dirplus.s,": "); + + substdio_fdbuf(&ss,write,fd,ssbuf,sizeof(ssbuf)); +} + +void fput(buf,len) +char *buf; +unsigned int len; +{ + if (substdio_bput(&ss,buf,len) == -1) + strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": "); +} +void fputs(buf) +char *buf; +{ + if (substdio_bputs(&ss,buf) == -1) + strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": "); +} + +void fclose() +{ + if (substdio_flush(&ss) == -1) + strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": "); + if (fsync(ss.fd) == -1) + strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": "); + if (close(ss.fd) == -1) /* NFS stupidity */ + strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": "); + keyaddtime(); +} + +void main(argc,argv) +int argc; +char **argv; +{ + int opt; + int flagarchived; + int flagpublic; + + keyadd(getpid()); + keyadd(getppid()); + keyadd(getuid()); + keyadd(getgid()); + gettimeofday(&tv,(struct timezone *) 0); + keyadd(tv.tv_sec); + + umask(077); + + flagarchived = 1; + flagpublic = 1; + + while ((opt = getopt(argc,argv,"aApP")) != opteof) + switch(opt) { + case 'a': flagarchived = 1; break; + case 'A': flagarchived = 0; break; + case 'p': flagpublic = 1; break; + case 'P': flagpublic = 0; break; + default: + die_usage(); + } + argv += optind; + + if (!(dir = *argv++)) die_usage(); + if (!(dot = *argv++)) die_usage(); + if (!(local = *argv++)) die_usage(); + if (!(host = *argv++)) die_usage(); + + if (dir[0] != '/') die_relative(); + if (dir[str_chr(dir,'\'')]) die_quote(); + if (dir[str_chr(dir,'\n')]) die_newline(); + if (local[str_chr(local,'\n')]) die_newline(); + if (host[str_chr(host,'\n')]) die_newline(); + + dcreate(""); + dcreate("/archive"); + dcreate("/subscribers"); + dcreate("/bounce"); + dcreate("/text"); + + + linkdotdir("-owner","/owner"); + linkdotdir("-default","/manager"); + linkdotdir("-return-default","/bouncer"); + linkdotdir("","/editor"); + + fopen("/lock"); fclose(); + fopen("/lockbounce"); fclose(); + if (flagpublic) { + fopen("/public"); fclose(); + } + if (flagarchived) { + fopen("/archived"); fclose(); + } + fopen("/num"); fputs("0\n"); fclose(); + fopen("/inhost"); fputs(host); fputs("\n"); fclose(); + fopen("/outhost"); fputs(host); fputs("\n"); fclose(); + fopen("/inlocal"); fputs(local); fputs("\n"); fclose(); + fopen("/outlocal"); fputs(local); fputs("\n"); fclose(); + + fopen("/mailinglist"); + fputs("contact "); + fputs(local); fputs("-help@"); fputs(host); fputs("; run by ezmlm\n"); + fclose(); + + fopen("/owner"); + fputs(dir); fputs("/Mailbox\n"); + fputs("|"); fputs(auto_bin); fputs("/ezmlm-warn '"); fputs(dir); + fputs("' || exit 0\n"); + fclose(); + + fopen("/manager"); + fputs("|"); fputs(auto_bin); fputs("/ezmlm-manage '"); fputs(dir); fputs("'\n"); + fputs("|"); fputs(auto_bin); fputs("/ezmlm-warn '"); fputs(dir); + fputs("' || exit 0\n"); + fclose(); + + fopen("/editor"); + fputs("|"); fputs(auto_bin); fputs("/ezmlm-reject\n"); + fputs("|"); fputs(auto_bin); fputs("/ezmlm-send '"); fputs(dir); fputs("'\n"); + fputs("|"); fputs(auto_bin); fputs("/ezmlm-warn '"); fputs(dir); + fputs("' || exit 0\n"); + fclose(); + + fopen("/bouncer"); + fputs("|"); fputs(auto_bin); fputs("/ezmlm-warn '"); fputs(dir); + fputs("' || exit 0\n"); + fputs("|"); fputs(auto_bin); fputs("/ezmlm-weed\n"); + fputs("|"); fputs(auto_bin); fputs("/ezmlm-return '"); fputs(dir); fputs("'\n"); + fclose(); + + fopen("/headerremove"); + fputs("\ +return-path\n\ +return-receipt-to\n\ +content-length\n\ +"); + fclose(); + + fopen("/headeradd"); + fclose(); + + + fopen("/text/top"); + fputs("Hi! This is the ezmlm program. I'm managing the\n"); + fputs(local); fputs("@"); fputs(host); fputs(" mailing list.\n\n"); + fclose(); + + fopen("/text/bottom"); + fputs("\n--- Here are the ezmlm command addresses.\n\ +\n\ +I can handle administrative requests automatically.\n\ +Just send an empty note to any of these addresses:\n\n <"); + fputs(local); fputs("-subscribe@"); fputs(host); fputs(">:\n"); + fputs(" Receive future messages sent to the mailing list.\n\n <"); + fputs(local); fputs("-unsubscribe@"); fputs(host); fputs(">:\n"); + fputs(" Stop receiving messages.\n\n <"); + fputs(local); fputs("-get.12345@"); fputs(host); fputs(">:\n"); + fputs(" Retrieve a copy of message 12345 from the archive.\n\ +\n\ +DO NOT SEND ADMINISTRATIVE REQUESTS TO THE MAILING LIST!\n\ +If you do, I won't see them, and subscribers will yell at you.\n\ +\n\ +To specify God@heaven.af.mil as your subscription address, send mail\n\ +to <"); + fputs(local); fputs("-subscribe-God=heaven.af.mil@"); fputs(host); + fputs(">.\n\ +I'll send a confirmation message to that address; when you receive that\n\ +message, simply reply to it to complete your subscription.\n\ +\n"); + fputs("\n--- Below this line is a copy of the request I received.\n\n"); + fclose(); + + fopen("/text/sub-confirm"); + fputs("To confirm that you would like\n\ +\n\ +!A\n\ +\n\ +added to this mailing list, please send an empty reply to this address:\n\ +\n\ +!R\n\ +\n\ +Your mailer should have a Reply feature that uses this address automatically.\n\ +\n\ +This confirmation serves two purposes. First, it verifies that I am able\n\ +to get mail through to you. Second, it protects you in case someone\n\ +forges a subscription request in your name.\n\ +\n"); + fclose(); + + fopen("/text/unsub-confirm"); + fputs("To confirm that you would like\n\ +\n\ +!A\n\ +\n\ +removed from this mailing list, please send an empty reply to this address:\n\ +\n\ +!R\n\ +\n\ +Your mailer should have a Reply feature that uses this address automatically.\n\ +\n\ +I haven't checked whether your address is currently on the mailing list.\n\ +To see what address you used to subscribe, look at the messages you are\n\ +receiving from the mailing list. Each message has your address hidden\n\ +inside its return path; for example, God@heaven.af.mil receives messages\n\ +with return path ...-God=heaven.af.mil.\n\ +\n"); + fclose(); + + fopen("/text/sub-ok"); + fputs("Acknowledgment: I have added the address\n\ +\n\ +!A\n\ +\n\ +to this mailing list.\n\ +\n"); + fclose(); + + fopen("/text/unsub-ok"); + fputs("Acknowledgment: I have removed the address\n\ +\n\ +!A\n\ +\n\ +from this mailing list.\n\ +\n"); + fclose(); + + fopen("/text/sub-nop"); + fputs("Acknowledgment: The address\n\ +\n\ +!A\n\ +\n\ +is on this mailing list.\n\ +\n"); + fclose(); + + fopen("/text/unsub-nop"); + fputs("Acknowledgment: The address\n\ +\n\ +!A\n\ +\n\ +is not on this mailing list.\n\ +\n"); + fclose(); + + fopen("/text/sub-bad"); + fputs("Oops, that confirmation number appears to be invalid.\n\ +\n\ +The most common reason for invalid numbers is expiration. I have to\n\ +receive confirmation of each request within ten days.\n\ +\n\ +I've set up a new confirmation number. To confirm that you would like\n\ +\n\ +!A\n\ +\n\ +added to this mailing list, please send an empty reply to this address:\n\ +\n\ +!R\n\ +\n\ +Sorry for the trouble.\n\ +\n"); + fclose(); + + fopen("/text/unsub-bad"); + fputs("Oops, that confirmation number appears to be invalid.\n\ +\n\ +The most common reason for invalid numbers is expiration. I have to\n\ +receive confirmation of each request within ten days.\n\ +\n\ +I've set up a new confirmation number. To confirm that you would like\n\ +\n\ +!A\n\ +\n\ +removed from this mailing list, please send an empty reply to this address:\n\ +\n\ +!R\n\ +\n\ +Sorry for the trouble.\n\ +\n"); + fclose(); + + fopen("/text/get-bad"); + fputs("Sorry, I don't see that message.\n\n"); + fclose(); + + fopen("/text/bounce-bottom"); + fputs("\n\ +--- Below this line is a copy of the bounce message I received.\n\n"); + fclose(); + + fopen("/text/bounce-warn"); + fputs("\n\ +Messages to you seem to have been bouncing. I've attached a copy of\n\ +the first bounce message I received.\n\ +\n\ +If this message bounces too, I will send you a probe. If the probe bounces,\n\ +I will remove your address from the mailing list, without further notice.\n\ +\n"); + fclose(); + + fopen("/text/bounce-probe"); + fputs("\n\ +Messages to you seem to have been bouncing. I sent you a warning\n\ +message, but it bounced. I've attached a copy of the bounce message.\n\ +\n\ +This is a probe to check whether your address is reachable. If this\n\ +probe bounces, I will remove your address from the mailing list, without\n\ +further notice.\n\ +\n"); + fclose(); + + fopen("/text/bounce-num"); + fputs("\n\ +I've kept a list of which messages bounced from your address. Copies of\n\ +these messages may be in the archive. To get message 12345 from the\n\ +archive, send an empty note to "); + fputs(local); fputs("-get.12345@"); fputs(host); fputs(".\n\ +Here are the message numbers:\n\ +\n"); + fclose(); + + fopen("/text/help"); + fputs("\ +This is a generic help message. The message I received wasn't sent to\n\ +any of my command addresses.\n\ +\n"); + fclose(); + + fopen("/key"); + fput(key.s,key.len); + fclose(); + + _exit(0); +} diff --git a/ezmlm-make=0 b/ezmlm-make=0 new file mode 100644 index 0000000..d49ded8 --- /dev/null +++ b/ezmlm-make=0 @@ -0,0 +1 @@ +ezmlm-make.1 diff --git a/ezmlm-make=x b/ezmlm-make=x new file mode 100644 index 0000000..1295af4 --- /dev/null +++ b/ezmlm-make=x @@ -0,0 +1,9 @@ +auto_bin.o +open.a +getopt.a +substdio.a +strerr.a +stralloc.a +alloc.a +error.a +str.a diff --git a/ezmlm-manage.1 b/ezmlm-manage.1 new file mode 100644 index 0000000..a68438f --- /dev/null +++ b/ezmlm-manage.1 @@ -0,0 +1,129 @@ +.TH ezmlm-manage 1 +.SH NAME +ezmlm-manage \- automatically manage a mailing list +.SH SYNOPSIS +.B ezmlm-manage +.I dir +.SH DESCRIPTION +.B ezmlm-manage +handles administrative requests for the mailing list +stored in +.IR dir . + +.B ezmlm-manage +is normally invoked from a +.B .qmail +file. +It reads a mail message from its standard input, +and a mail envelope from the +.BR SENDER , +.BR LOCAL , +and +.BR HOST +environment variables. + +.B ezmlm-manage +expects +.B LOCAL +to be of the form +.IR list\fB-\fIaction\fB-\fIbox\fB=\fIdomain . +Here +.I list +is the first line of +.IR dir\fB/inlocal , +.I action +is a request, +and +.I box\fB@\fIdomain +is the target of the request. +.B ezmlm-manage +sends a response to the target. +It attaches the original message to the end of its response. + +.B LOCAL +may instead be of the form +.IR list\fB-\fIaction . +Then the envelope sender +is used as the target. + +.B ezmlm-manage +expects +.B HOST +to match the first line of +.IR dir\fB/inhost . + +.B ezmlm-manage +copies +.I dir\fB/mailinglist +into a +.B Mailing-List +field in its response. +If the incoming message has a +.B Mailing-List +field, +.B ezmlm-manage +refuses to respond. +.B ezmlm-manage +also refuses to respond to bounce messages. +.SH SUBSCRIPTIONS +If +.I action +is +.BR sc.\fIcookie , +where +.I cookie +is an appropriate code +(depending on the target, the approximate time, and other factors), +.B ezmlm-manage +adds the target to the mailing list. + +If +.I action +is +.BR subscribe , +.B ezmlm-manage +does not subscribe the target, +but it identifies the right +.BR sc.\fIcookie +address in its response. + +This confirmation mechanism +(1) verifies that the target is reachable +and +(2) protects the target against forged subscription requests. + +Actions of +.B uc.\fIcookie +and +.B unsubscribe +are used in the same way to delete the target from the mailing list. + +If +.I dir\fB/public +does not exist, +.B ezmlm-manage +rejects all subscription and unsubscription attempts. +.SH "ARCHIVE RETRIEVALS" +If +.I action +is +.BR get.\fInum , +.B ezmlm-manage +sends back message +.I num +from +.IR dir\fB/archive . + +If +.I dir\fB/public +does not exist, +.B ezmlm-manage +rejects all archive retrieval attempts. +.SH "SEE ALSO" +ezmlm-make(1), +ezmlm-return(1), +ezmlm-send(1), +ezmlm-sub(1), +ezmlm-unsub(1), +ezmlm(5), +qmail-command(8) diff --git a/ezmlm-manage.c b/ezmlm-manage.c new file mode 100644 index 0000000..d40ba0f --- /dev/null +++ b/ezmlm-manage.c @@ -0,0 +1,403 @@ +#include +#include +#include "error.h" +#include "stralloc.h" +#include "str.h" +#include "env.h" +#include "sig.h" +#include "slurp.h" +#include "getconf.h" +#include "strerr.h" +#include "byte.h" +#include "getln.h" +#include "case.h" +#include "qmail.h" +#include "substdio.h" +#include "readwrite.h" +#include "seek.h" +#include "quote.h" +#include "datetime.h" +#include "now.h" +#include "date822fmt.h" +#include "fmt.h" +#include "subscribe.h" +#include "cookie.h" + +#define FATAL "ezmlm-manage: fatal: " +void die_usage() { strerr_die1x(100,"ezmlm-manage: usage: ezmlm-manage dir"); } +void die_nomem() { strerr_die2x(111,FATAL,"out of memory"); } +void die_badaddr() +{ + strerr_die2x(100,FATAL,"I do not accept messages at this address (#5.1.1)"); +} + +stralloc inhost = {0}; +stralloc outhost = {0}; +stralloc inlocal = {0}; +stralloc outlocal = {0}; +stralloc key = {0}; +stralloc mailinglist = {0}; + +datetime_sec when; +struct datetime dt; + +char strnum[FMT_ULONG]; +char date[DATE822FMT]; +char hash[COOKIE]; +datetime_sec hashdate; +stralloc target = {0}; +stralloc confirm = {0}; +stralloc line = {0}; +stralloc quoted = {0}; + +int hashok(action) +char *action; +{ + char *x; + unsigned long u; + + x = action + 4; + x += scan_ulong(x,&u); + hashdate = u; + if (hashdate > when) return 0; + if (hashdate < when - 1000000) return 0; + + u = hashdate; + strnum[fmt_ulong(strnum,u)] = 0; + cookie(hash,key.s,key.len,strnum,target.s,action + 1); + + if (*x == '.') ++x; + if (str_len(x) != COOKIE) return 0; + return byte_equal(hash,COOKIE,x); +} + +struct qmail qq; +int qqwrite(fd,buf,len) int fd; char *buf; unsigned int len; +{ + qmail_put(&qq,buf,len); + return len; +} +char qqbuf[1]; +substdio ssqq = SUBSTDIO_FDBUF(qqwrite,-1,qqbuf,sizeof(qqbuf)); + +char inbuf[1024]; +substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,sizeof(inbuf)); +substdio ssin2 = SUBSTDIO_FDBUF(read,0,inbuf,sizeof(inbuf)); + +substdio sstext; +char textbuf[1024]; + +void copy(fn) +char *fn; +{ + int fd; + int match; + + fd = open_read(fn); + if (fd == -1) + strerr_die4sys(111,FATAL,"unable to open ",fn,": "); + + substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf)); + for (;;) { + if (getln(&sstext,&line,&match,'\n') == -1) + strerr_die4sys(111,FATAL,"unable to read ",fn,": "); + + if (match) + if (line.s[0] == '!') { + if (line.s[1] == 'R') { + qmail_puts(&qq," "); + qmail_puts(&qq,confirm.s); + qmail_puts(&qq,"\n"); + continue; + } + if (line.s[1] == 'A') { + qmail_puts(&qq," "); + qmail_puts(&qq,target.s); + qmail_puts(&qq,"\n"); + continue; + } + } + + qmail_put(&qq,line.s,line.len); + + if (!match) + break; + } + + close(fd); +} + +stralloc mydtline = {0}; + +void main(argc,argv) +int argc; +char **argv; +{ + char *dir; + char *sender; + char *host; + char *local; + char *action; + int fd; + int i; + int flagconfirm; + int flaghashok; + int flaggoodfield; + int match; + + umask(022); + sig_pipeignore(); + when = now(); + + dir = argv[1]; + if (!dir) die_usage(); + + sender = env_get("SENDER"); + if (!sender) strerr_die2x(100,FATAL,"SENDER not set"); + local = env_get("LOCAL"); + if (!local) strerr_die2x(100,FATAL,"LOCAL not set"); + host = env_get("HOST"); + if (!host) strerr_die2x(100,FATAL,"HOST not set"); + + if (!*sender) + strerr_die2x(100,FATAL,"I don't reply to bounce messages (#5.7.2)"); + if (!sender[str_chr(sender,'@')]) + strerr_die2x(100,FATAL,"I don't reply to senders without host names (#5.7.2)"); + if (str_equal(sender,"#@[]")) + strerr_die2x(100,FATAL,"I don't reply to bounce messages (#5.7.2)"); + + if (chdir(dir) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",dir,": "); + + switch(slurp("key",&key,32)) { + case -1: + strerr_die4sys(111,FATAL,"unable to read ",dir,"/key: "); + case 0: + strerr_die3x(100,FATAL,dir,"/key does not exist"); + } + getconf_line(&mailinglist,"mailinglist",1,FATAL,dir); + getconf_line(&inhost,"inhost",1,FATAL,dir); + getconf_line(&inlocal,"inlocal",1,FATAL,dir); + getconf_line(&outhost,"outhost",1,FATAL,dir); + getconf_line(&outlocal,"outlocal",1,FATAL,dir); + + if (inhost.len != str_len(host)) die_badaddr(); + if (case_diffb(inhost.s,inhost.len,host)) die_badaddr(); + if (inlocal.len > str_len(local)) die_badaddr(); + if (case_diffb(inlocal.s,inlocal.len,local)) die_badaddr(); + + action = local + inlocal.len; + + switch(slurp("public",&line,1)) { + case -1: + strerr_die4sys(111,FATAL,"unable to read ",dir,"/public: "); + case 0: + strerr_die2x(100,FATAL,"sorry, I've been told to reject all requests (#5.7.2)"); + } + + if (!stralloc_copys(&target,sender)) die_nomem(); + if (action[0]) { + i = 1 + str_chr(action + 1,'-'); + if (action[i]) { + action[i] = 0; + if (!stralloc_copys(&target,action + i + 1)) die_nomem(); + i = byte_rchr(target.s,target.len,'='); + if (i < target.len) + target.s[i] = '@'; + } + } + if (!stralloc_0(&target)) die_nomem(); + if (!stralloc_copys(&confirm,"")) die_nomem(); + + if (qmail_open(&qq) == -1) + strerr_die2sys(111,FATAL,"unable to run qmail-queue: "); + + qmail_puts(&qq,"Mailing-List: "); + qmail_put(&qq,mailinglist.s,mailinglist.len); + qmail_puts(&qq,"\nDate: "); + datetime_tai(&dt,when); + qmail_put(&qq,date,date822fmt(date,&dt)); + qmail_puts(&qq,"Message-ID: <"); + qmail_put(&qq,strnum,fmt_ulong(strnum,(unsigned long) when)); + qmail_puts(&qq,"."); + qmail_put(&qq,strnum,fmt_ulong(strnum,(unsigned long) getpid())); + qmail_puts(&qq,".ezmlm@"); + qmail_put(&qq,outhost.s,outhost.len); + qmail_puts(&qq,">\nFrom: "); + if (!quote("ed,&outlocal)) die_nomem(); + qmail_put(&qq,quoted.s,quoted.len); + qmail_puts(&qq,"-help@"); + qmail_put(&qq,outhost.s,outhost.len); + qmail_puts(&qq,"\nTo: "); + if (!quote2("ed,target.s)) die_nomem(); + qmail_put(&qq,quoted.s,quoted.len); + qmail_puts(&qq,"\n"); + + flaghashok = 1; + if (str_start(action,"-sc.")) flaghashok = hashok(action); + if (str_start(action,"-uc.")) flaghashok = hashok(action); + + flagconfirm = 0; + if (str_equal(action,"-subscribe")) flagconfirm = 1; + if (str_equal(action,"-unsubscribe")) flagconfirm = 1; + if (!flaghashok) flagconfirm = 1; + + if (flagconfirm) { + strnum[fmt_ulong(strnum,(unsigned long) when)] = 0; + cookie(hash,key.s,key.len,strnum,target.s,action + 1); + if (!stralloc_copy(&confirm,&outlocal)) die_nomem(); + if (!stralloc_cats(&confirm,"-")) die_nomem(); + if (!stralloc_catb(&confirm,action + 1,1)) die_nomem(); + if (!stralloc_cats(&confirm,"c.")) die_nomem(); + if (!stralloc_cats(&confirm,strnum)) die_nomem(); + if (!stralloc_cats(&confirm,".")) die_nomem(); + if (!stralloc_catb(&confirm,hash,COOKIE)) die_nomem(); + if (!stralloc_cats(&confirm,"-")) die_nomem(); + i = str_rchr(target.s,'@'); + if (!stralloc_catb(&confirm,target.s,i)) die_nomem(); + if (target.s[i]) { + if (!stralloc_cats(&confirm,"=")) die_nomem(); + if (!stralloc_cats(&confirm,target.s + i + 1)) die_nomem(); + } + if (!stralloc_cats(&confirm,"@")) die_nomem(); + if (!stralloc_cat(&confirm,&outhost)) die_nomem(); + if (!stralloc_0(&confirm)) die_nomem(); + + qmail_puts(&qq,"Reply-To: "); + if (!quote2("ed,confirm.s)) die_nomem(); + qmail_put(&qq,quoted.s,quoted.len); + qmail_puts(&qq,"\n"); + } + if (!stralloc_0(&confirm)) die_nomem(); + + qmail_puts(&qq,"Subject: ezmlm response\n"); + + if (!stralloc_copys(&mydtline,"Delivered-To: responder for ")) die_nomem(); + if (!stralloc_catb(&mydtline,outlocal.s,outlocal.len)) die_nomem(); + if (!stralloc_cats(&mydtline,"@")) die_nomem(); + if (!stralloc_catb(&mydtline,outhost.s,outhost.len)) die_nomem(); + if (!stralloc_cats(&mydtline,"\n")) die_nomem(); + + qmail_put(&qq,mydtline.s,mydtline.len); + + flaggoodfield = 0; + for (;;) { + if (getln(&ssin,&line,&match,'\n') == -1) + strerr_die2sys(111,FATAL,"unable to read input: "); + if (!match) break; + if (line.len == 1) break; + if ((line.s[0] != ' ') && (line.s[0] != '\t')) { + flaggoodfield = 0; + if (case_startb(line.s,line.len,"mailing-list:")) + strerr_die2x(100,FATAL,"incoming message has Mailing-List (#5.7.2)"); + if (line.len == mydtline.len) + if (byte_equal(line.s,line.len,mydtline.s)) + strerr_die2x(100,FATAL,"this message is looping: it already has my Delivered-To line (#5.4.6)"); + if (case_startb(line.s,line.len,"delivered-to:")) + flaggoodfield = 1; + if (case_startb(line.s,line.len,"received:")) + flaggoodfield = 1; + } + if (flaggoodfield) + qmail_put(&qq,line.s,line.len); + } + if (seek_begin(0) == -1) + strerr_die2sys(111,FATAL,"unable to seek input: "); + + qmail_puts(&qq,"\n"); + copy("text/top"); + if (str_equal(action,"-subscribe")) + copy("text/sub-confirm"); + else if (str_equal(action,"-unsubscribe")) + copy("text/unsub-confirm"); + else if (str_start(action,"-sc.")) { + if (!flaghashok) + copy("text/sub-bad"); + else + switch(subscribe(target.s,1)) { + case -1: strerr_die1(111,FATAL,&subscribe_err); + case -2: strerr_die1(100,FATAL,&subscribe_err); + case 1: log("+",target.s); copy("text/sub-ok"); break; + default: copy("text/sub-nop"); break; + } + } + else if (str_start(action,"-uc.")) { + if (!flaghashok) + copy("text/unsub-bad"); + else + switch(subscribe(target.s,0)) { + case -1: strerr_die1(111,FATAL,&subscribe_err); + case -2: strerr_die1(100,FATAL,&subscribe_err); + case 1: log("-",target.s); copy("text/unsub-ok"); break; + default: copy("text/unsub-nop"); break; + } + } + else if (str_start(action,"-get.")) { + unsigned long u; + struct stat st; + char ch; + int r; + + scan_ulong(action + 5,&u); + + if (!stralloc_copys(&line,"archive/")) die_nomem(); + if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,u / 100))) die_nomem(); + if (!stralloc_cats(&line,"/")) die_nomem(); + if (!stralloc_catb(&line,strnum,fmt_uint0(strnum,(unsigned int) (u % 100),2))) die_nomem(); + if (!stralloc_0(&line)) die_nomem(); + + fd = open_read(line.s); + if (fd == -1) + if (errno != error_noent) + strerr_die4sys(111,FATAL,"unable to open ",line.s,": "); + else + copy("text/get-bad"); + else { + if (fstat(fd,&st) == -1) + copy("text/get-bad"); + else if (!(st.st_mode & 0100)) + copy("text/get-bad"); + else { + substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf)); + qmail_puts(&qq,"> "); + for (;;) { + r = substdio_get(&sstext,&ch,1); + if (r == -1) strerr_die4sys(111,FATAL,"unable to read ",line.s,": "); + if (r == 0) break; + qmail_put(&qq,&ch,1); + if (ch == '\n') qmail_puts(&qq,"> "); + } + qmail_puts(&qq,"\n"); + } + close(fd); + } + } + else + copy("text/help"); + + copy("text/bottom"); + + qmail_puts(&qq,"Return-Path: <"); + if (!quote2("ed,sender)) die_nomem(); + qmail_put(&qq,quoted.s,quoted.len); + qmail_puts(&qq,">\n"); + if (substdio_copy(&ssqq,&ssin2) != 0) + strerr_die2sys(111,FATAL,"unable to read input: "); + + if (!stralloc_copy(&line,&outlocal)) die_nomem(); + if (!stralloc_cats(&line,"-return-@")) die_nomem(); + if (!stralloc_cat(&line,&outhost)) die_nomem(); + if (!stralloc_0(&line)) die_nomem(); + qmail_from(&qq,line.s); + + qmail_to(&qq,target.s); + + switch(qmail_close(&qq)) { + case 0: + strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0; + strerr_die2x(0,"ezmlm-manage: info: qp ",strnum); + default: + /* don't worry about undoing actions; everything is idempotent */ + strerr_die2x(111,FATAL,"temporary qmail-queue error"); + } +} diff --git a/ezmlm-manage=0 b/ezmlm-manage=0 new file mode 100644 index 0000000..844327b --- /dev/null +++ b/ezmlm-manage=0 @@ -0,0 +1 @@ +ezmlm-manage.1 diff --git a/ezmlm-manage=x b/ezmlm-manage=x new file mode 100644 index 0000000..c51b445 --- /dev/null +++ b/ezmlm-manage=x @@ -0,0 +1,29 @@ +auto_qmail.o +getconf.o +subscribe.o +log.o +cookie.o +now.o +datetime.o +date822fmt.o +slurpclose.o +slurp.o +qmail.o +quote.o +surf.a +getln.a +env.a +sig.a +strerr.a +substdio.a +stralloc.a +alloc.a +error.a +str.a +fs.a +case.a +open.a +seek.a +wait.a +lock.a +fd.a diff --git a/ezmlm-reject.1 b/ezmlm-reject.1 new file mode 100644 index 0000000..cb8cb7a --- /dev/null +++ b/ezmlm-reject.1 @@ -0,0 +1,32 @@ +.TH ezmlm-reject 1 +.SH NAME +ezmlm-reject \- reject messages unsuitable for distribution +.SH SYNOPSIS +.B ezmlm-reject +[ +.B \-cCsS +] +.SH DESCRIPTION +.B ezmlm-reject +reads a mail message from its standard input. +It rejects the message if it sees something it doesn't like. +.SH OPTIONS +.TP +.B \-c +(Default.) +Commands are not permitted in the Subject line. +A Subject line consisting solely of HELP, SUBSCRIBE, or UNSUBSCRIBE +is rejected. +.TP +.B \-C +Commands are permitted in the subject line. +.TP +.B \-s +(Default.) +A nonempty Subject line is required. +.TP +.B \-S +A Subject line is not required. +.SH "SEE ALSO" +ezmlm-send(1), +qmail-command(8) diff --git a/ezmlm-reject.c b/ezmlm-reject.c new file mode 100644 index 0000000..ffeea99 --- /dev/null +++ b/ezmlm-reject.c @@ -0,0 +1,82 @@ +#include "strerr.h" +#include "substdio.h" +#include "readwrite.h" +#include "stralloc.h" +#include "getln.h" +#include "sgetopt.h" + +int flagrejectcommands = 1; +int flagneedsubject = 1; + +int flaghavesubject = 0; +int flaghavecommand = 0; + +char buf0[256]; +substdio ss0 = SUBSTDIO_FDBUF(read,0,buf0,sizeof(buf0)); +stralloc line = {0}; + +void main(argc,argv) +int argc; +char **argv; +{ + int opt; + char *x; + int len; + int match; + + while ((opt = getopt(argc,argv,"cCsS")) != opteof) + switch(opt) { + case 'c': flagrejectcommands = 1; break; + case 'C': flagrejectcommands = 0; break; + case 's': flagneedsubject = 1; break; + case 'S': flagneedsubject = 0; break; + default: + strerr_die1x(100,"ezmlm-reject: usage: ezmlm-reject [ -cCsS ]"); + } + + for (;;) { + if (getln(&ss0,&line,&match,'\n') == -1) + strerr_die2sys(111,"ezmlm-reject: fatal: ","unable to read input: "); + if (!match) break; + if (line.len == 1) break; + + x = line.s; len = line.len - 1; + while (len && ((x[len - 1] == ' ') || (x[len - 1] == '\t'))) --len; + + if (case_startb(x,len,"subject:")) { + x += 8; len -= 8; + while (len && ((*x == ' ') || (*x == '\t'))) { ++x; --len; } + if (len) { + flaghavesubject = 1; + + if (len == 4) + if (!case_diffb("help",4,x)) + flaghavecommand = 1; + + if (len == 9) + if (!case_diffb("subscribe",9,x)) + flaghavecommand = 1; + + if (len == 11) + if (!case_diffb("unsubscribe",11,x)) + flaghavecommand = 1; + } + } + } + + if (flagneedsubject && !flaghavesubject) + strerr_die1x(100,"\ +ezmlm-reject: fatal: I need a nonempty Subject line in every message.\n\ +If you are trying to subscribe or unsubscribe, WRONG ADDRESS!\n\ +Do not send administrative requests to the mailing list.\n\ +Send an empty message to ...-help@... for automated assistance."); + + if (flagrejectcommands && flaghavecommand) + strerr_die1x(100,"\ +ezmlm-reject: fatal: Your Subject line looks like a command word.\n\ +If you are trying to subscribe or unsubscribe, WRONG ADDRESS!\n\ +Do not send administrative requests to the mailing list.\n\ +Send an empty message to ...-help@... for automated assistance."); + + _exit(0); +} diff --git a/ezmlm-reject=0 b/ezmlm-reject=0 new file mode 100644 index 0000000..92fa5a2 --- /dev/null +++ b/ezmlm-reject=0 @@ -0,0 +1 @@ +ezmlm-reject.1 diff --git a/ezmlm-reject=x b/ezmlm-reject=x new file mode 100644 index 0000000..166f429 --- /dev/null +++ b/ezmlm-reject=x @@ -0,0 +1,9 @@ +getln.a +strerr.a +substdio.a +error.a +stralloc.a +alloc.a +str.a +getopt.a +case.a diff --git a/ezmlm-return.1 b/ezmlm-return.1 new file mode 100644 index 0000000..3f84989 --- /dev/null +++ b/ezmlm-return.1 @@ -0,0 +1,71 @@ +.TH ezmlm-return 1 +.SH NAME +ezmlm-return \- handle mailing list bounces +.SH SYNOPSIS +.B ezmlm-return +.I dir +.SH DESCRIPTION +.B ezmlm-return +handles bounces for the mailing list +stored in +.IR dir . + +.B ezmlm-return +is normally invoked from a +.B .qmail +file. +It reads a mail message from its standard input, +and a mail envelope from the +.BR SENDER , +.BR LOCAL , +and +.BR HOST +environment variables. +.SH ADDRESSES +.B ezmlm-return +handles mail sent to any of the following addresses: +.TP +.I local\fB\-return\- +Trash. +A help message or subscription acknowledgment bounced. +.TP +.I local\fB\-return\-\fImsg\fB\-\fIbox\fB=\fIdomain +Distribution bounce. +Message number +.I msg +was lost on the way to +.IR box\fB@\fIdomain . +.TP +.I local\fB\-return\-\fImsg\fB\- +Pre-VERP distribution bounce, in QSBMF format. +Message number +.I msg +was lost on the way to one or more addresses; +.B ezmlm-return +will parse the bounce to figure out the addresses. +.TP +.I local\fB\-return\-warn\-\fIcookie\fB-\fIbox\fB=\fIdomain +Warning bounce. +A warning message from +.B ezmlm-warn +bounced. +.TP +.I local\fB\-return\-probe\-\fIcookie\fB-\fIbox\fB=\fIdomain +Probe bounce. +A probe from +.B ezmlm-warn +bounced. +.B ezmlm-return +will remove +.I box\fB@\fIdomain +from the mailing list. +.SH "SEE ALSO" +ezmlm-manage(1), +ezmlm-make(1), +ezmlm-send(1), +ezmlm-sub(1), +ezmlm-unsub(1), +ezmlm-warn(1), +ezmlm-weed(1), +ezmlm(5), +qmail-command(8) diff --git a/ezmlm-return.c b/ezmlm-return.c new file mode 100644 index 0000000..3bc2421 --- /dev/null +++ b/ezmlm-return.c @@ -0,0 +1,364 @@ +#include "stralloc.h" +#include "str.h" +#include "env.h" +#include "sig.h" +#include "slurp.h" +#include "getconf.h" +#include "strerr.h" +#include "byte.h" +#include "case.h" +#include "getln.h" +#include "substdio.h" +#include "error.h" +#include "quote.h" +#include "readwrite.h" +#include "fmt.h" +#include "now.h" +#include "cookie.h" +#include "subscribe.h" +#include "issub.h" + +#define FATAL "ezmlm-return: fatal: " +void die_usage() { strerr_die1x(100,"ezmlm-return: usage: ezmlm-return dir"); } +void die_nomem() { strerr_die2x(111,FATAL,"out of memory"); } +void die_badaddr() +{ + strerr_die2x(100,FATAL,"I do not accept messages at this address (#5.1.1)"); +} +void die_trash() +{ + strerr_die1x(0,"ezmlm-return: info: trash address"); +} + +char outbuf[1024]; +substdio ssout; +char inbuf[1024]; +substdio ssin; + +char strnum[FMT_ULONG]; +char hash[COOKIE]; +char hashcopy[COOKIE]; +unsigned long cookiedate; +stralloc fndate = {0}; +stralloc fndatenew = {0}; +stralloc fnhash = {0}; +stralloc fnhashnew = {0}; + +stralloc quoted = {0}; +char *sender; + +void die_hashnew() +{ strerr_die4sys(111,FATAL,"unable to write ",fnhashnew.s,": "); } +void die_datenew() +{ strerr_die4sys(111,FATAL,"unable to write ",fndatenew.s,": "); } +void die_msgin() +{ strerr_die2sys(111,FATAL,"unable to read input: "); } + +void dowit(addr,when,bounce) +char *addr; +unsigned long when; +stralloc *bounce; +{ + int fd; + + if (!issub(addr)) return; + + if (!stralloc_copys(&fndate,"bounce/w")) die_nomem(); + if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,when))) die_nomem(); + if (!stralloc_cats(&fndate,".")) die_nomem(); + if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem(); + if (!stralloc_0(&fndate)) die_nomem(); + if (!stralloc_copy(&fndatenew,&fndate)) die_nomem(); + fndatenew.s[7] = 'W'; + + fd = open_trunc(fndatenew.s); + if (fd == -1) die_datenew(); + substdio_fdbuf(&ssout,write,fd,outbuf,sizeof(outbuf)); + if (substdio_puts(&ssout,addr) == -1) die_datenew(); + if (substdio_put(&ssout,"",1) == -1) die_datenew(); + if (substdio_puts(&ssout,"Return-Path: <") == -1) die_datenew(); + if (!quote2("ed,sender)) die_nomem(); + if (substdio_put(&ssout,quoted.s,quoted.len) == -1) die_datenew(); + if (substdio_puts(&ssout,">\n") == -1) die_datenew(); + if (substdio_put(&ssout,bounce->s,bounce->len) == -1) die_datenew(); + if (substdio_flush(&ssout) == -1) die_datenew(); + if (fsync(fd) == -1) die_datenew(); + if (close(fd) == -1) die_datenew(); /* NFS stupidity */ + + if (rename(fndatenew.s,fndate.s) == -1) + strerr_die6sys(111,FATAL,"unable to rename ",fndatenew.s," to ",fndate.s,": "); +} + +void doit(addr,msgnum,when,bounce) +char *addr; +unsigned long msgnum; +unsigned long when; +stralloc *bounce; +{ + int fd; + int fdnew; + + if (!issub(addr)) return; + + if (!stralloc_copys(&fndate,"bounce/d")) die_nomem(); + if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,when))) die_nomem(); + if (!stralloc_cats(&fndate,".")) die_nomem(); + if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem(); + if (!stralloc_0(&fndate)) die_nomem(); + if (!stralloc_copy(&fndatenew,&fndate)) die_nomem(); + fndatenew.s[7] = 'D'; + + fd = open_trunc(fndatenew.s); + if (fd == -1) die_datenew(); + substdio_fdbuf(&ssout,write,fd,outbuf,sizeof(outbuf)); + if (substdio_puts(&ssout,addr) == -1) die_datenew(); + if (substdio_put(&ssout,"",1) == -1) die_datenew(); + if (substdio_puts(&ssout,"Return-Path: <") == -1) die_datenew(); + if (!quote2("ed,sender)) die_nomem(); + if (substdio_put(&ssout,quoted.s,quoted.len) == -1) die_datenew(); + if (substdio_puts(&ssout,">\n") == -1) die_datenew(); + if (substdio_put(&ssout,bounce->s,bounce->len) == -1) die_datenew(); + if (substdio_flush(&ssout) == -1) die_datenew(); + if (fsync(fd) == -1) die_datenew(); + if (close(fd) == -1) die_datenew(); /* NFS stupidity */ + + cookie(hash,"",0,"",addr,""); + if (!stralloc_copys(&fnhash,"bounce/h")) die_nomem(); + if (!stralloc_catb(&fnhash,hash,COOKIE)) die_nomem(); + if (!stralloc_0(&fnhash)) die_nomem(); + if (!stralloc_copy(&fnhashnew,&fnhash)) die_nomem(); + fnhashnew.s[7] = 'H'; + + fdnew = open_trunc(fnhashnew.s); + if (fdnew == -1) die_hashnew(); + substdio_fdbuf(&ssout,write,fdnew,outbuf,sizeof(outbuf)); + + fd = open_read(fnhash.s); + if (fd == -1) { + if (errno != error_noent) + strerr_die4sys(111,FATAL,"unable to read ",fnhash.s,": "); + if (rename(fndatenew.s,fndate.s) == -1) + strerr_die6sys(111,FATAL,"unable to rename ",fndatenew.s," to ",fndate.s,": "); + } + else { + substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf)); + switch(substdio_copy(&ssout,&ssin)) { + case -2: die_msgin(); + case -3: die_hashnew(); + } + close(fd); + if (unlink(fndatenew.s) == -1) + strerr_die4sys(111,FATAL,"unable to unlink ",fndatenew.s,": "); + } + if (substdio_puts(&ssout," ") == -1) die_hashnew(); + if (substdio_put(&ssout,strnum,fmt_ulong(strnum,msgnum)) == -1) die_hashnew(); + if (substdio_puts(&ssout,"\n") == -1) die_hashnew(); + if (substdio_flush(&ssout) == -1) die_hashnew(); + if (fsync(fdnew) == -1) die_hashnew(); + if (close(fdnew) == -1) die_hashnew(); /* NFS stupidity */ + + if (rename(fnhashnew.s,fnhash.s) == -1) + strerr_die6sys(111,FATAL,"unable to rename ",fnhashnew.s," to ",fnhash.s,": "); +} + +stralloc bounce = {0}; +stralloc line = {0}; +stralloc header = {0}; +stralloc intro = {0}; +stralloc failure = {0}; +stralloc paragraph = {0}; +int flaghaveheader; +int flaghaveintro; + +stralloc key = {0}; +stralloc inhost = {0}; +stralloc outhost = {0}; +stralloc inlocal = {0}; +stralloc outlocal = {0}; + +char msginbuf[1024]; +substdio ssmsgin; + +void main(argc,argv) +int argc; +char **argv; +{ + char *dir; + char *host; + char *local; + char *action; + unsigned long msgnum; + unsigned long cookiedate; + unsigned long when; + int match; + int i; + int fdlock; + + umask(022); + sig_pipeignore(); + when = (unsigned long) now(); + + dir = argv[1]; + if (!dir) die_usage(); + + sender = env_get("SENDER"); + if (!sender) strerr_die2x(100,FATAL,"SENDER not set"); + local = env_get("LOCAL"); + if (!local) strerr_die2x(100,FATAL,"LOCAL not set"); + host = env_get("HOST"); + if (!host) strerr_die2x(100,FATAL,"HOST not set"); + + if (chdir(dir) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",dir,": "); + + switch(slurp("key",&key,32)) { + case -1: + strerr_die4sys(111,FATAL,"unable to read ",dir,"/key: "); + case 0: + strerr_die3x(100,FATAL,dir,"/key does not exist"); + } + getconf_line(&inhost,"inhost",1,FATAL,dir); + getconf_line(&inlocal,"inlocal",1,FATAL,dir); + getconf_line(&outhost,"outhost",1,FATAL,dir); + getconf_line(&outlocal,"outlocal",1,FATAL,dir); + + if (inhost.len != str_len(host)) die_badaddr(); + if (case_diffb(inhost.s,inhost.len,host)) die_badaddr(); + if (inlocal.len > str_len(local)) die_badaddr(); + if (case_diffb(inlocal.s,inlocal.len,local)) die_badaddr(); + + action = local + inlocal.len; + + if (!str_start(action,"-return-")) die_badaddr(); + action += 8; + + if (!*action) die_trash(); + + if (str_start(action,"probe-")) { + action += 6; + action += scan_ulong(action,&cookiedate); + if (now() - cookiedate > 3000000) die_trash(); + if (*action++ != '.') die_trash(); + i = str_chr(action,'-'); + if (i != COOKIE) die_trash(); + byte_copy(hashcopy,COOKIE,action); + action += COOKIE; + if (*action++ != '-') die_trash(); + i = str_rchr(action,'='); + if (!stralloc_copyb(&line,action,i)) die_nomem(); + if (action[i]) { + if (!stralloc_cats(&line,"@")) die_nomem(); + if (!stralloc_cats(&line,action + i + 1)) die_nomem(); + } + if (!stralloc_0(&line)) die_nomem(); + strnum[fmt_ulong(strnum,cookiedate)] = 0; + cookie(hash,key.s,key.len,strnum,line.s,"P"); + if (byte_diff(hash,COOKIE,hashcopy)) die_trash(); + + if (subscribe(line.s,0) == 1) log("-probe",line.s); + _exit(0); + } + + fdlock = open_append("lockbounce"); + if (fdlock == -1) + strerr_die4sys(111,FATAL,"unable to open ",dir,"/lockbounce: "); + if (lock_ex(fdlock) == -1) + strerr_die4sys(111,FATAL,"unable to lock ",dir,"/lockbounce: "); + + if (str_start(action,"warn-")) { + action += 5; + action += scan_ulong(action,&cookiedate); + if (now() - cookiedate > 3000000) die_trash(); + if (*action++ != '.') die_trash(); + i = str_chr(action,'-'); + if (i != COOKIE) die_trash(); + byte_copy(hashcopy,COOKIE,action); + action += COOKIE; + if (*action++ != '-') die_trash(); + i = str_rchr(action,'='); + if (!stralloc_copyb(&line,action,i)) die_nomem(); + if (action[i]) { + if (!stralloc_cats(&line,"@")) die_nomem(); + if (!stralloc_cats(&line,action + i + 1)) die_nomem(); + } + if (!stralloc_0(&line)) die_nomem(); + strnum[fmt_ulong(strnum,cookiedate)] = 0; + cookie(hash,key.s,key.len,strnum,line.s,"W"); + if (byte_diff(hash,COOKIE,hashcopy)) die_trash(); + + if (slurpclose(0,&bounce,1024) == -1) die_msgin(); + dowit(line.s,when,&bounce); + _exit(0); + } + + action += scan_ulong(action,&msgnum); + if (*action != '-') die_badaddr(); + ++action; + + if (*action) { + if (slurpclose(0,&bounce,1024) == -1) die_msgin(); + + i = str_rchr(action,'='); + if (!stralloc_copyb(&line,action,i)) die_nomem(); + if (action[i]) { + if (!stralloc_cats(&line,"@")) die_nomem(); + if (!stralloc_cats(&line,action + i + 1)) die_nomem(); + } + if (!stralloc_0(&line)) die_nomem(); + doit(line.s,msgnum,when,&bounce); + _exit(0); + } + + /* pre-VERP bounce, in QSBMF format */ + + substdio_fdbuf(&ssmsgin,read,0,msginbuf,sizeof(msginbuf)); + + flaghaveheader = 0; + flaghaveintro = 0; + + for (;;) { + if (!stralloc_copys(¶graph,"")) die_nomem(); + for (;;) { + if (getln(&ssmsgin,&line,&match,'\n') == -1) die_msgin(); + if (!match) die_trash(); + if (!stralloc_cat(¶graph,&line)) die_nomem(); + if (line.len <= 1) break; + } + + if (!flaghaveheader) { + if (!stralloc_copy(&header,¶graph)) die_nomem(); + flaghaveheader = 1; + continue; + } + + if (!flaghaveintro) { + if (paragraph.len < 15) die_trash(); + if (str_diffn(paragraph.s,"Hi. This is the",15)) die_trash(); + if (!stralloc_copy(&intro,¶graph)) die_nomem(); + flaghaveintro = 1; + continue; + } + + if (paragraph.s[0] == '-') + break; + + if (paragraph.s[0] == '<') { + if (!stralloc_copy(&failure,¶graph)) die_nomem(); + + if (!stralloc_copy(&bounce,&header)) die_nomem(); + if (!stralloc_cat(&bounce,&intro)) die_nomem(); + if (!stralloc_cat(&bounce,&failure)) die_nomem(); + + i = byte_chr(failure.s,failure.len,'\n'); + if (i < 3) die_trash(); + + if (!stralloc_copyb(&line,failure.s + 1,i - 3)) die_nomem(); + if (byte_chr(line.s,line.len,'\0') == line.len) { + if (!stralloc_0(&line)) die_nomem(); + doit(line.s,msgnum,when,&bounce); + } + } + } + + _exit(0); +} diff --git a/ezmlm-return=0 b/ezmlm-return=0 new file mode 100644 index 0000000..0eaa248 --- /dev/null +++ b/ezmlm-return=0 @@ -0,0 +1 @@ +ezmlm-return.1 diff --git a/ezmlm-return=x b/ezmlm-return=x new file mode 100644 index 0000000..7f99f7f --- /dev/null +++ b/ezmlm-return=x @@ -0,0 +1,23 @@ +quote.o +getconf.o +issub.o +subscribe.o +log.o +slurpclose.o +slurp.o +now.o +cookie.o +surf.a +lock.a +env.a +sig.a +strerr.a +getln.a +substdio.a +stralloc.a +alloc.a +error.a +str.a +fs.a +case.a +open.a diff --git a/ezmlm-send.1 b/ezmlm-send.1 new file mode 100644 index 0000000..ff70976 --- /dev/null +++ b/ezmlm-send.1 @@ -0,0 +1,86 @@ +.TH ezmlm-send 1 +.SH NAME +ezmlm-send \- distribute a message to a mailing list +.SH SYNOPSIS +.B ezmlm-send +.I dir +.SH DESCRIPTION +.B ezmlm-send +reads a mail message and +sends it to the mailing list stored in +.IR dir . +If +.I dir\fB/archived +exists, +.B ezmlm-send +records a copy of the message in the +.I dir\fB/archive +directory. + +At the beginning of the message, +.B ezmlm-send +prints a new +.B Mailing-List +field with the contents of +.IR dir\fB/mailinglist . +It rejects the message if there is already a +.B Mailing-List +field. + +.B ezmlm-send +then prints all the new fields listed in +.IR dir\fB/headeradd , +followed by an appropriate +.B Delivered-To +line. + +.B ezmlm-send +deletes any incoming fields with names listed in +.IR dir\fB/headerremove . + +.B ezmlm-send +does not distribute bounce messages: +if the environment variable +.B SENDER +is set, and is either empty or +.BR #@[] , +.B ezmlm-send +rejects the message. +.SH "SUBLISTS" +If +.I dir\fB/sublist +exists, +.B ezmlm-send +changes its behavior in several ways. + +First, if +.B SENDER +is set, +and the first line of +.I dir\fB/sublist +has the form +.IR parent\fB@\fIparenthost , +.B ezmlm-send +insists that +.B SENDER +have the form +.IR parent\fB...@\fIparenthost . + +Second, +.B ezmlm-send +demands that the message already have a +.B Mailing-List +field. + +Third, +.B ezmlm-send +does not add its own +.B Mailing-List +field. +.SH "SEE ALSO" +ezmlm-manage(1), +ezmlm-make(1), +ezmlm-sub(1), +ezmlm-unsub(1), +ezmlm-reject(1), +ezmlm(5) diff --git a/ezmlm-send.c b/ezmlm-send.c new file mode 100644 index 0000000..5748891 --- /dev/null +++ b/ezmlm-send.c @@ -0,0 +1,319 @@ +#include "stralloc.h" +#include "subfd.h" +#include "strerr.h" +#include "error.h" +#include "qmail.h" +#include "env.h" +#include "lock.h" +#include "sig.h" +#include "open.h" +#include "getln.h" +#include "case.h" +#include "scan.h" +#include "str.h" +#include "fmt.h" +#include "readwrite.h" +#include "exit.h" +#include "substdio.h" +#include "getconf.h" +#include "constmap.h" + +#define FATAL "ezmlm-send: fatal: " + +void die_usage() +{ + strerr_die1x(100,"ezmlm-send: usage: ezmlm-send dir"); +} +void die_nomem() +{ + strerr_die2x(111,FATAL,"out of memory"); +} + +char strnum[FMT_ULONG]; + +stralloc fnadir = {0}; +stralloc fnaf = {0}; +stralloc fnsub = {0}; +stralloc line = {0}; + +int flagarchived; +int fdarchive; +substdio ssarchive; +char archivebuf[1024]; + +int flagsublist; +stralloc sublist = {0}; +stralloc mailinglist = {0}; +stralloc outlocal = {0}; +stralloc outhost = {0}; +stralloc headerremove = {0}; +struct constmap headerremovemap; +stralloc headeradd = {0}; + +struct qmail qq; +substdio ssin; +char inbuf[1024]; +substdio ssout; +char outbuf[1]; + +int mywrite(fd,buf,len) +int fd; +char *buf; +unsigned int len; +{ + qmail_put(&qq,buf,len); + return len; +} + +void die_archive() +{ + strerr_die4sys(111,FATAL,"unable to write to ",fnaf.s,": "); +} +void die_numnew() +{ + strerr_die2sys(111,FATAL,"unable to create numnew: "); +} + +void put(buf,len) char *buf; int len; +{ + qmail_put(&qq,buf,len); + if (flagarchived) + if (substdio_put(&ssarchive,buf,len) == -1) die_archive(); +} + +void puts(buf) char *buf; +{ + qmail_puts(&qq,buf); + if (flagarchived) + if (substdio_puts(&ssarchive,buf) == -1) die_archive(); +} + +int sublistmatch(sender) +char *sender; +{ + int i; + int j; + + j = str_len(sender); + if (j < sublist.len) return 0; + + i = byte_rchr(sublist.s,sublist.len,'@'); + if (i == sublist.len) return 1; + + if (byte_diff(sublist.s,i,sender)) return 0; + if (case_diffb(sublist.s + i,sublist.len - i,sender + j - (sublist.len - i))) + return 0; + + return 1; +} + +substdio ssnumnew; +char numnewbuf[16]; +unsigned long msgnum; +stralloc num = {0}; + +char buf0[256]; +substdio ss0 = SUBSTDIO_FDBUF(read,0,buf0,sizeof(buf0)); + +void numwrite() +{ + int fd; + + fd = open_trunc("numnew"); + if (fd == -1) die_numnew(); + substdio_fdbuf(&ssnumnew,write,fd,numnewbuf,sizeof(numnewbuf)); + if (substdio_put(&ssnumnew,strnum,fmt_ulong(strnum,msgnum)) == -1) + die_numnew(); + if (substdio_puts(&ssnumnew,"\n") == -1) die_numnew(); + if (substdio_flush(&ssnumnew) == -1) die_numnew(); + if (fsync(fd) == -1) die_numnew(); + if (close(fd) == -1) die_numnew(); /* NFS stupidity */ + if (rename("numnew","num") == -1) + strerr_die2sys(111,FATAL,"unable to move numnew to num: "); +} + +stralloc mydtline = {0}; + +void main(argc,argv) +int argc; +char **argv; +{ + int fd; + char *dir; + int fdlock; + char *sender; + int flagmlwasthere; + int match; + int i; + char ch; + int flaginheader; + int flagbadfield; + + umask(022); + sig_pipeignore(); + + dir = argv[1]; + if (!dir) die_usage(); + + sender = env_get("SENDER"); + + if (chdir(dir) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",dir,": "); + + fdlock = open_append("lock"); + if (fdlock == -1) + strerr_die4sys(111,FATAL,"unable to open ",dir,"/lock: "); + if (lock_ex(fdlock) == -1) + strerr_die4sys(111,FATAL,"unable to obtain ",dir,"/lock: "); + + if (qmail_open(&qq) == -1) + strerr_die2sys(111,FATAL,"unable to run qmail-queue: "); + + flagarchived = getconf_line(&line,"archived",0,FATAL,dir); + + getconf_line(&num,"num",1,FATAL,dir); + if (!stralloc_0(&num)) die_nomem(); + scan_ulong(num.s,&msgnum); + ++msgnum; + + getconf_line(&outhost,"outhost",1,FATAL,dir); + getconf_line(&outlocal,"outlocal",1,FATAL,dir); + getconf_line(&mailinglist,"mailinglist",1,FATAL,dir); + flagsublist = getconf_line(&sublist,"sublist",0,FATAL,dir); + + getconf(&headerremove,"headerremove",1,FATAL,dir); + constmap_init(&headerremovemap,headerremove.s,headerremove.len,0); + + getconf(&headeradd,"headeradd",1,FATAL,dir); + for (i = 0;i < headeradd.len;++i) + if (!headeradd.s[i]) + headeradd.s[i] = '\n'; + + if (!stralloc_copys(&mydtline,"Delivered-To: mailing list ")) die_nomem(); + if (!stralloc_catb(&mydtline,outlocal.s,outlocal.len)) die_nomem(); + if (!stralloc_cats(&mydtline,"@")) die_nomem(); + if (!stralloc_catb(&mydtline,outhost.s,outhost.len)) die_nomem(); + if (!stralloc_cats(&mydtline,"\n")) die_nomem(); + + if (sender) { + if (!*sender) + strerr_die2x(100,FATAL,"I don't distribute bounce messages (#5.7.2)"); + if (str_equal(sender,"#@[]")) + strerr_die2x(100,FATAL,"I don't distribute bounce messages (#5.7.2)"); + if (flagsublist) + if (!sublistmatch(sender)) + strerr_die2x(100,FATAL,"this message is not from my parent list (#5.7.2)"); + } + + if (flagarchived) { + if (!stralloc_copys(&fnadir,"archive/")) die_nomem(); + if (!stralloc_catb(&fnadir,strnum,fmt_ulong(strnum,msgnum / 100))) die_nomem(); + if (!stralloc_copy(&fnaf,&fnadir)) die_nomem(); + if (!stralloc_cats(&fnaf,"/")) die_nomem(); + if (!stralloc_catb(&fnaf,strnum,fmt_uint0(strnum,(unsigned int) (msgnum % 100),2))) die_nomem(); + if (!stralloc_0(&fnadir)) die_nomem(); + if (!stralloc_0(&fnaf)) die_nomem(); + + if (mkdir(fnadir.s,0755) == -1) + if (errno != error_exist) + strerr_die4sys(111,FATAL,"unable to create ",fnadir.s,": "); + fdarchive = open_trunc(fnaf.s); + if (fdarchive == -1) + strerr_die4sys(111,FATAL,"unable to write ",fnaf.s,": "); + + substdio_fdbuf(&ssarchive,write,fdarchive,archivebuf,sizeof(archivebuf)); + } + + if (!flagsublist) { + puts("Mailing-List: "); + put(mailinglist.s,mailinglist.len); + puts("\n"); + } + put(headeradd.s,headeradd.len); + put(mydtline.s,mydtline.len); + + flagmlwasthere = 0; + flaginheader = 1; + flagbadfield = 0; + + for (;;) { + if (getln(&ss0,&line,&match,'\n') == -1) + strerr_die2sys(111,FATAL,"unable to read input: "); + + if (flaginheader && match) { + if (line.len == 1) + flaginheader = 0; + if ((line.s[0] != ' ') && (line.s[0] != '\t')) { + flagbadfield = 0; + if (constmap(&headerremovemap,line.s,byte_chr(line.s,line.len,':'))) + flagbadfield = 1; + if (case_startb(line.s,line.len,"mailing-list:")) + flagmlwasthere = 1; + if (line.len == mydtline.len) + if (!byte_diff(line.s,line.len,mydtline.s)) + strerr_die2x(100,FATAL,"this message is looping: it already has my Delivered-To line (#5.4.6)"); + } + } + + if (!(flaginheader && flagbadfield)) + put(line.s,line.len); + + if (!match) + break; + } + + if (flagsublist) + if (!flagmlwasthere) + strerr_die2x(100,FATAL,"sublist messages must have Mailing-List (#5.7.2)"); + if (!flagsublist) + if (flagmlwasthere) + strerr_die2x(100,FATAL,"message already has Mailing-List (#5.7.2)"); + + if (flagarchived) { + if (substdio_flush(&ssarchive) == -1) die_archive(); + if (fsync(fdarchive) == -1) die_archive(); + if (fchmod(fdarchive,0744) == -1) die_archive(); + if (close(fdarchive) == -1) die_archive(); /* NFS stupidity */ + } + + numwrite(); + + if (!stralloc_copy(&line,&outlocal)) die_nomem(); + if (!stralloc_cats(&line,"-return-")) die_nomem(); + if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,msgnum))) die_nomem(); + if (!stralloc_cats(&line,"-@")) die_nomem(); + if (!stralloc_cat(&line,&outhost)) die_nomem(); + if (!stralloc_cats(&line,"-@[]")) die_nomem(); + if (!stralloc_0(&line)) die_nomem(); + + qmail_from(&qq,line.s); + + for (i = 0;i < 53;++i) { + ch = 64 + i; + if (!stralloc_copys(&fnsub,"subscribers/")) die_nomem(); + if (!stralloc_catb(&fnsub,&ch,1)) strerr_die2x(111,FATAL,"out of memory"); + if (!stralloc_0(&fnsub)) strerr_die2x(111,FATAL,"out of memory"); + fd = open_read(fnsub.s); + if (fd == -1) { + if (errno != error_noent) + strerr_die4sys(111,FATAL,"unable to read ",fnsub.s,": "); + } + else { + substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf)); + substdio_fdbuf(&ssout,mywrite,-1,outbuf,sizeof(outbuf)); + if (substdio_copy(&ssout,&ssin) != 0) + strerr_die4sys(111,FATAL,"unable to read ",fnsub.s,": "); + close(fd); + } + } + + switch(qmail_close(&qq)) { + case 0: + strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0; + strerr_die2x(0,"ezmlm-send: info: qp ",strnum); + default: + --msgnum; + numwrite(); + strerr_die2x(111,FATAL,"temporary qmail-queue error"); + } +} diff --git a/ezmlm-send=0 b/ezmlm-send=0 new file mode 100644 index 0000000..40a6d36 --- /dev/null +++ b/ezmlm-send=0 @@ -0,0 +1 @@ +ezmlm-send.1 diff --git a/ezmlm-send=x b/ezmlm-send=x new file mode 100644 index 0000000..2ba0ed9 --- /dev/null +++ b/ezmlm-send=x @@ -0,0 +1,21 @@ +auto_qmail.o +getconf.o +qmail.o +constmap.o +slurp.o +slurpclose.o +wait.a +getln.a +strerr.a +sig.a +env.a +open.a +lock.a +substdio.a +stralloc.a +alloc.a +error.a +str.a +fd.a +case.a +fs.a diff --git a/ezmlm-sub.1 b/ezmlm-sub.1 new file mode 100644 index 0000000..219b88f --- /dev/null +++ b/ezmlm-sub.1 @@ -0,0 +1,38 @@ +.TH ezmlm-sub 1 +.SH NAME +ezmlm-sub \- manually add addresses to a mailing list +.SH SYNOPSIS +.B ezmlm-sub +.I dir +[ +.I box\fB@\fIdomain ... +] +.SH DESCRIPTION +.B ezmlm-sub +adds each address +.I box\fB@\fIdomain +to the mailing list stored in +.IR dir . + +If +.I box\fB@\fIdomain +is already on the mailing list, +.B ezmlm-sub +leaves it there. + +.B ezmlm-sub +converts +.I domain +to lowercase before adding +.I box\fB@\fIdomain +to the mailing list. + +.I box\fB@\fIdomain +cannot be longer than 400 characters. +.SH "SEE ALSO" +ezmlm-list(1), +ezmlm-manage(1), +ezmlm-make(1), +ezmlm-send(1), +ezmlm-unsub(1), +ezmlm(5) diff --git a/ezmlm-sub.c b/ezmlm-sub.c new file mode 100644 index 0000000..85fce6a --- /dev/null +++ b/ezmlm-sub.c @@ -0,0 +1,33 @@ +#include "strerr.h" +#include "subscribe.h" +#include "log.h" + +#define FATAL "ezmlm-sub: fatal: " +#define WARNING "ezmlm-sub: warning: " + +void main(argc,argv) +int argc; +char **argv; +{ + char *dir; + char *addr; + + dir = argv[1]; + if (!dir) + strerr_die1x(100,"ezmlm-sub: usage: ezmlm-sub dir box@domain ..."); + if (chdir(dir) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",dir,": "); + + argv += 2; + while (addr = *argv++) + switch(subscribe(addr,1)) { + case -1: + strerr_die1(111,FATAL,&subscribe_err); + case -2: + strerr_warn4(WARNING,"cannot subscribe ",addr,": ",&subscribe_err); + break; + case 1: + log("+manual",addr); + } + _exit(0); +} diff --git a/ezmlm-sub=0 b/ezmlm-sub=0 new file mode 100644 index 0000000..2d4630f --- /dev/null +++ b/ezmlm-sub=0 @@ -0,0 +1 @@ +ezmlm-sub.1 diff --git a/ezmlm-sub=x b/ezmlm-sub=x new file mode 100644 index 0000000..9218d9a --- /dev/null +++ b/ezmlm-sub=x @@ -0,0 +1,14 @@ +subscribe.o +log.o +now.o +fs.a +strerr.a +getln.a +substdio.a +stralloc.a +alloc.a +error.a +str.a +case.a +open.a +lock.a diff --git a/ezmlm-unsub.1 b/ezmlm-unsub.1 new file mode 100644 index 0000000..7223ae9 --- /dev/null +++ b/ezmlm-unsub.1 @@ -0,0 +1,35 @@ +.TH ezmlm-unsub 1 +.SH NAME +ezmlm-unsub \- manually remove addresses from a mailing list +.SH SYNOPSIS +.B ezmlm-unsub +.I dir +[ +.I box\fB@\fIdomain ... +] +.SH DESCRIPTION +.B ezmlm-unsub +removes each address +.I box\fB@\fIdomain +from the mailing list stored in +.IR dir . + +If +.I box\fB@\fIdomain +is not on the mailing list, +.B ezmlm-unsub +keeps it off. + +.B ezmlm-unsub +converts +.I domain +to lowercase before removing +.I box\fB@\fIdomain +from the mailing list. +.SH "SEE ALSO" +ezmlm-list(1), +ezmlm-manage(1), +ezmlm-make(1), +ezmlm-send(1), +ezmlm-sub(1), +ezmlm(5) diff --git a/ezmlm-unsub.c b/ezmlm-unsub.c new file mode 100644 index 0000000..3f53890 --- /dev/null +++ b/ezmlm-unsub.c @@ -0,0 +1,34 @@ +#include "strerr.h" +#include "subscribe.h" +#include "log.h" + +#define FATAL "ezmlm-unsub: fatal: " +#define WARNING "ezmlm-unsub: warning: " + +void main(argc,argv) +int argc; +char **argv; +{ + char *dir; + char *addr; + + dir = argv[1]; + if (!dir) + strerr_die1x(100,"ezmlm-unsub: usage: ezmlm-unsub dir box@domain ..."); + if (chdir(dir) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",dir,": "); + + argv += 2; + while (addr = *argv++) + switch(subscribe(addr,0)) { + case -1: + strerr_die1(111,FATAL,&subscribe_err); + case -2: + strerr_warn4(WARNING,"cannot unsubscribe ",addr,": ",&subscribe_err); + break; + case 1: + log("-manual",addr); + } + + _exit(0); +} diff --git a/ezmlm-unsub=0 b/ezmlm-unsub=0 new file mode 100644 index 0000000..b651717 --- /dev/null +++ b/ezmlm-unsub=0 @@ -0,0 +1 @@ +ezmlm-unsub.1 diff --git a/ezmlm-unsub=x b/ezmlm-unsub=x new file mode 100644 index 0000000..9218d9a --- /dev/null +++ b/ezmlm-unsub=x @@ -0,0 +1,14 @@ +subscribe.o +log.o +now.o +fs.a +strerr.a +getln.a +substdio.a +stralloc.a +alloc.a +error.a +str.a +case.a +open.a +lock.a diff --git a/ezmlm-warn.1 b/ezmlm-warn.1 new file mode 100644 index 0000000..06fd0b0 --- /dev/null +++ b/ezmlm-warn.1 @@ -0,0 +1,39 @@ +.TH ezmlm-warn 1 +.SH NAME +ezmlm-warn \- send out bounce warnings +.SH SYNOPSIS +.B ezmlm-warn +.I dir +.SH DESCRIPTION +.B ezmlm-warn +sends out warning messages +for the mailing list stored in +.IR dir . + +.B ezmlm-warn +scans +.I dir\fB/bounce +for bounce messages received by +.BR ezmlm-return . +If it sees a distribution bounce for +.I box\fB@\fIdomain +received more than ten days ago, +it sends +.I box\fB@\fIdomain +a list of all the message numbers missed recently, +and deletes the bounce. +If it sees a warning bounce for +.I box\fB@\fIdomain +received more than ten days ago, +it sends +.I box\fB@\fIdomain +a probe, +and deletes the bounce. + +.B ezmlm-warn +will not send a warning or probe to an address that is +not currently a subscriber. +.SH "SEE ALSO" +ezmlm-make(1), +ezmlm-return(1), +ezmlm(5) diff --git a/ezmlm-warn.c b/ezmlm-warn.c new file mode 100644 index 0000000..3140976 --- /dev/null +++ b/ezmlm-warn.c @@ -0,0 +1,254 @@ +#include +#include +#include "direntry.h" +#include "readwrite.h" +#include "getln.h" +#include "substdio.h" +#include "stralloc.h" +#include "slurp.h" +#include "getconf.h" +#include "byte.h" +#include "error.h" +#include "str.h" +#include "strerr.h" +#include "sig.h" +#include "now.h" +#include "datetime.h" +#include "date822fmt.h" +#include "fmt.h" +#include "cookie.h" +#include "qmail.h" + +#define FATAL "ezmlm-warn: fatal: " +void die_usage() { strerr_die1x(100,"ezmlm-warn: usage: ezmlm-warn dir"); } +void die_nomem() { strerr_die2x(111,FATAL,"out of memory"); } + +stralloc key = {0}; +stralloc outhost = {0}; +stralloc outlocal = {0}; +stralloc mailinglist = {0}; + +unsigned long when; +char *dir; +stralloc fn = {0}; +struct stat st; + +void die_read() { strerr_die6sys(111,FATAL,"unable to read ",dir,"/",fn.s,": "); } + +char inbuf[1024]; +substdio ssin; +char textbuf[1024]; +substdio sstext; + +stralloc addr = {0}; +char strnum[FMT_ULONG]; +char hash[COOKIE]; +stralloc fnhash = {0}; +stralloc quoted = {0}; +stralloc line = {0}; + +struct qmail qq; +int qqwrite(fd,buf,len) int fd; char *buf; unsigned int len; +{ + qmail_put(&qq,buf,len); + return len; +} +char qqbuf[1]; +substdio ssqq = SUBSTDIO_FDBUF(qqwrite,-1,qqbuf,sizeof(qqbuf)); +struct datetime dt; +char date[DATE822FMT]; + +void copy(fn) +char *fn; +{ + int fd; + int match; + + fd = open_read(fn); + if (fd == -1) + strerr_die4sys(111,FATAL,"unable to open ",fn,": "); + + substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf)); + for (;;) { + if (getln(&sstext,&line,&match,'\n') == -1) + strerr_die4sys(111,FATAL,"unable to read ",fn,": "); + if (!match) + break; + qmail_put(&qq,line.s,line.len); + } + + close(fd); +} + +void doit(flagw) +int flagw; +{ + int i; + int fd; + int match; + int fdhash; + datetime_sec msgwhen; + + fd = open_read(fn.s); + if (fd == -1) die_read(); + substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf)); + + if (getln(&ssin,&addr,&match,'\0') == -1) die_read(); + if (!match) { close(fd); return; } + + if (!issub(addr.s)) { close(fd); /*XXX*/unlink(fn.s); return; } + + cookie(hash,"",0,"",addr.s,""); + if (!stralloc_copys(&fnhash,"bounce/h")) die_nomem(); + if (!stralloc_catb(&fnhash,hash,COOKIE)) die_nomem(); + if (!stralloc_0(&fnhash)) die_nomem(); + + if (qmail_open(&qq) == -1) + strerr_die2sys(111,FATAL,"unable to run qmail-queue: "); + + msgwhen = now(); + qmail_puts(&qq,"Mailing-List: "); + qmail_put(&qq,mailinglist.s,mailinglist.len); + qmail_puts(&qq,"\nDate: "); + datetime_tai(&dt,msgwhen); + qmail_put(&qq,date,date822fmt(date,&dt)); + qmail_puts(&qq,"Message-ID: <"); + qmail_put(&qq,strnum,fmt_ulong(strnum,(unsigned long) msgwhen)); + qmail_puts(&qq,"."); + qmail_put(&qq,strnum,fmt_ulong(strnum,(unsigned long) getpid())); + qmail_puts(&qq,".ezmlm-warn@"); + qmail_put(&qq,outhost.s,outhost.len); + qmail_puts(&qq,">\nFrom: "); + if (!quote("ed,&outlocal)) die_nomem(); + qmail_put(&qq,quoted.s,quoted.len); + qmail_puts(&qq,"-help@"); + qmail_put(&qq,outhost.s,outhost.len); + qmail_puts(&qq,"\nTo: "); + if (!quote2("ed,addr.s)) die_nomem(); + qmail_put(&qq,quoted.s,quoted.len); + qmail_puts(&qq,flagw ? "\nSubject: ezmlm probe\n\n" : "\nSubject: ezmlm warning\n\n"); + + copy("text/top"); + copy(flagw ? "text/bounce-probe" : "text/bounce-warn"); + + if (!flagw) { + fdhash = open_read(fnhash.s); + if (fdhash == -1) { + if (errno != error_noent) + strerr_die6sys(111,FATAL,"unable to open ",dir,"/",fnhash.s,": "); + } + else { + copy("text/bounce-num"); + substdio_fdbuf(&sstext,read,fdhash,textbuf,sizeof(textbuf)); + if (substdio_copy(&ssqq,&sstext) < 0) + strerr_die6sys(111,FATAL,"unable to read ",dir,"/",fnhash.s,": "); + close(fdhash); + } + } + + copy("text/bounce-bottom"); + if (substdio_copy(&ssqq,&ssin) < 0) die_read(); + close(fd); + + strnum[fmt_ulong(strnum,when)] = 0; + cookie(hash,key.s,key.len,strnum,addr.s,flagw ? "P" : "W"); + if (!stralloc_copy(&line,&outlocal)) die_nomem(); + if (!stralloc_cats(&line,flagw ? "-return-probe-" : "-return-warn-")) die_nomem(); + if (!stralloc_cats(&line,strnum)) die_nomem(); + if (!stralloc_cats(&line,".")) die_nomem(); + if (!stralloc_catb(&line,hash,COOKIE)) die_nomem(); + if (!stralloc_cats(&line,"-")) die_nomem(); + i = str_chr(addr.s,'@'); + if (!stralloc_catb(&line,addr.s,i)) die_nomem(); + if (addr.s[i]) { + if (!stralloc_cats(&line,"=")) die_nomem(); + if (!stralloc_cats(&line,addr.s + i + 1)) die_nomem(); + } + if (!stralloc_cats(&line,"@")) die_nomem(); + if (!stralloc_cat(&line,&outhost)) die_nomem(); + if (!stralloc_0(&line)) die_nomem(); + qmail_from(&qq,line.s); + + qmail_to(&qq,addr.s); + if (qmail_close(&qq) != 0) + strerr_die2x(111,FATAL,"temporary qmail-queue error"); + + strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0; + strerr_warn2("ezmlm-warn: info: qp ",strnum,0); + + if (!flagw) { + if (unlink(fnhash.s) == -1) + if (errno != error_noent) + strerr_die6sys(111,FATAL,"unable to remove ",dir,"/",fnhash.s,": "); + } + if (unlink(fn.s) == -1) + strerr_die6sys(111,FATAL,"unable to remove ",dir,"/",fn.s,": "); +} + +void main(argc,argv) +int argc; +char **argv; +{ + DIR *bouncedir; + direntry *d; + unsigned long bouncedate; + int fdlock; + + umask(022); + sig_pipeignore(); + when = (unsigned long) now(); + + dir = argv[1]; + if (!dir) die_usage(); + + if (chdir(dir) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",dir,": "); + + switch(slurp("key",&key,32)) { + case -1: + strerr_die4sys(111,FATAL,"unable to read ",dir,"/key: "); + case 0: + strerr_die3x(100,FATAL,dir,"/key does not exist"); + } + getconf_line(&outhost,"outhost",1,FATAL,dir); + getconf_line(&outlocal,"outlocal",1,FATAL,dir); + getconf_line(&mailinglist,"mailinglist",1,FATAL,dir); + + fdlock = open_append("lockbounce"); + if (fdlock == -1) + strerr_die4sys(111,FATAL,"unable to open ",dir,"/lockbounce: "); + if (lock_ex(fdlock) == -1) + strerr_die4sys(111,FATAL,"unable to lock ",dir,"/lockbounce: "); + + bouncedir = opendir("bounce"); + if (!bouncedir) + strerr_die4sys(111,FATAL,"unable to open ",dir,"/bounce: "); + + while (d = readdir(bouncedir)) { + if (str_equal(d->d_name,".")) continue; + if (str_equal(d->d_name,"..")) continue; + + if (!stralloc_copys(&fn,"bounce/")) die_nomem(); + if (!stralloc_cats(&fn,d->d_name)) die_nomem(); + if (!stralloc_0(&fn)) die_nomem(); + + if (stat(fn.s,&st) == -1) { + if (errno == error_noent) continue; + strerr_die6sys(111,FATAL,"unable to stat ",dir,"/",fn.s,": "); + } + + if (when > st.st_mtime + 3000000) + if (unlink(fn.s) == -1) + strerr_die6sys(111,FATAL,"unable to remove ",dir,"/",fn.s,": "); + + if ((d->d_name[0] == 'd') || (d->d_name[0] == 'w')) { + scan_ulong(d->d_name + 1,&bouncedate); + if (when > bouncedate + 1000000) + doit(d->d_name[0] == 'w'); + } + } + + closedir(bouncedir); + + _exit(0); +} diff --git a/ezmlm-warn=0 b/ezmlm-warn=0 new file mode 100644 index 0000000..e171750 --- /dev/null +++ b/ezmlm-warn=0 @@ -0,0 +1 @@ +ezmlm-warn.1 diff --git a/ezmlm-warn=x b/ezmlm-warn=x new file mode 100644 index 0000000..4425236 --- /dev/null +++ b/ezmlm-warn=x @@ -0,0 +1,26 @@ +auto_qmail.o +getconf.o +cookie.o +issub.o +now.o +slurpclose.o +slurp.o +quote.o +datetime.o +date822fmt.o +qmail.o +surf.a +case.a +strerr.a +sig.a +getln.a +substdio.a +stralloc.a +alloc.a +error.a +open.a +lock.a +str.a +fs.a +fd.a +wait.a diff --git a/ezmlm-weed.1 b/ezmlm-weed.1 new file mode 100644 index 0000000..5a5911f --- /dev/null +++ b/ezmlm-weed.1 @@ -0,0 +1,109 @@ +.TH ezmlm-weed 1 +.SH NAME +ezmlm-weed \- weed out useless messages +.SH SYNOPSIS +.B ezmlm-weed +.SH DESCRIPTION +.B ezmlm-weed +reads a mail message from its standard input. +If it recognizes the message as an MTA warning message or success message, +it exits 99; +this will cause +.B qmail-alias +to skip all further delivery instructions if +.B ezmlm-weed +is run from a +.B .qmail +file. +If the message seems innocent, +.B ezmlm-weed +exits 0. +.B ezmlm-weed +exits 111 if it runs out of memory. +.SH "RECOGNIZED FORMATS" +Generic success message, recommended for all MTAs: + +.EX + Subject: success notice +.EE + +Generic warning message, recommended for all MTAs: + +.EX + Subject: deferral notice +.EE + +Warning message from sendmail, MIME form: + +.EX + From: Mail Delivery Subsystem +.EE +.br +.EX + Subject: Warning +.EE +.br +.EX + Auto-Submitted: auto-generated (warning-timeout) +.EE +.br +.EX + This is a MIME-encapsulated message +.EE +.br +.EX + THIS IS A WARNING MESSAGE ONLY +.EE + +Non-MIME form: + +.EX + From: Mail Delivery Subsystem +.EE +.br +.EX + Subject: Warning +.EE +.br +.EX + Auto-Submitted: auto-generated (warning-timeout) +.EE +.br +.EX + THIS IS A WARNING MESSAGE ONLY +.EE + +Warning message from older version of sendmail: + +.EX + From: Mail Delivery Subsystem +.EE +.br +.EX + Subject: Returned mail: warning +.EE +.br +.EX + This is a MIME-encapsulated message +.EE +.br +.EX + THIS IS A WARNING MESSAGE ONLY +.EE + +Non-MIME form: + +.EX + From: Mail Delivery Subsystem +.EE +.br +.EX + Subject: Returned mail: warning +.EE +.br +.EX + THIS IS A WARNING MESSAGE ONLY +.EE +.SH "SEE ALSO" +ezmlm-return(1), +qmail-command(8) diff --git a/ezmlm-weed.c b/ezmlm-weed.c new file mode 100644 index 0000000..777fa03 --- /dev/null +++ b/ezmlm-weed.c @@ -0,0 +1,94 @@ +#include "stralloc.h" +#include "str.h" +#include "byte.h" +#include "readwrite.h" +#include "substdio.h" +#include "getln.h" +#include "strerr.h" + +char buf0[256]; +substdio ss0 = SUBSTDIO_FDBUF(read,0,buf0,sizeof(buf0)); + +#define FATAL "ezmlm-weed: fatal: " + +void get(sa) +stralloc *sa; +{ + int match; + if (getln(&ss0,sa,&match,'\n') == -1) + strerr_die2sys(111,FATAL,"unable to read input: "); + if (!match) _exit(0); +} + +stralloc line = {0}; +stralloc line1 = {0}; +stralloc line2 = {0}; +stralloc line3 = {0}; +stralloc line4 = {0}; +stralloc line5 = {0}; +stralloc line6 = {0}; +stralloc line7 = {0}; +stralloc line8 = {0}; + +char warn1[] = " **********************************************"; +char warn2[] = " ** THIS IS A WARNING MESSAGE ONLY **"; +char warn3[] = " ** YOU DO NOT NEED TO RESEND YOUR MESSAGE **"; +char warn4[] = " **********************************************"; + +int flagmds = 0; +int flagsw = 0; +int flagsr = 0; +int flagas = 0; +int flagbw = 0; + +void main() +{ + int match; + + for (;;) { + get(&line); + if (line.len == 1) break; + + if (stralloc_starts(&line,"Subject: success notice")) + _exit(99); + if (stralloc_starts(&line,"Subject: deferral notice")) + _exit(99); + + if (stralloc_starts(&line,"From: Mail Delivery Subsystem + +int \fBfd_copy\fP(\fIto\fR,\fIfrom\fR); + +int \fIto\fR; +.br +int \fIfrom\fR; +.SH DESCRIPTION +.B fd_copy +copies +descriptor +.I from +to descriptor +.IR to . +If +.I to +was already open, +.B fd_copy +closes it. +.B fd_copy +always leaves +.I from +intact; +if +.I to +and +.I from +are the same number, +.B fd_copy +does nothing. + +.B fd_copy +returns 0 on success, -1 on error. +.B fd_copy +does not guarantee that +.I to +will remain open, if it was open, in case of error. +.SH "SEE ALSO" +dup(2), +fd_move(3) diff --git a/fd_copy.c b/fd_copy.c new file mode 100644 index 0000000..b9f7167 --- /dev/null +++ b/fd_copy.c @@ -0,0 +1,13 @@ +#include +#include "fd.h" + +int fd_copy(to,from) +int to; +int from; +{ + if (to == from) return 0; + if (fcntl(from,F_GETFL,0) == -1) return -1; + close(to); + if (fcntl(from,F_DUPFD,to) == -1) return -1; + return 0; +} diff --git a/fd_copy=0 b/fd_copy=0 new file mode 100644 index 0000000..f8a195e --- /dev/null +++ b/fd_copy=0 @@ -0,0 +1 @@ +fd_copy.3 diff --git a/fd_move.3 b/fd_move.3 new file mode 100644 index 0000000..94aa1b7 --- /dev/null +++ b/fd_move.3 @@ -0,0 +1,41 @@ +.TH fd_move 3 +.SH NAME +fd_move \- renumber a descriptor +.SH SYNTAX +.B #include + +int \fBfd_move\fP(\fIto\fR,\fIfrom\fR); + +int \fIto\fR; +.br +int \fIfrom\fR; +.SH DESCRIPTION +.B fd_move +moves +descriptor +.I from +to descriptor +.IR to . +If +.I to +was already open, +.B fd_move +closes it. +If the move is successful, +.B fd_move +closes +.IR from . +Exception: +if +.I to +and +.I from +are the same number, +.B fd_move +does nothing. + +.B fd_move +returns 0 on success, -1 on error. +.SH "SEE ALSO" +dup(2), +fd_copy(3) diff --git a/fd_move.c b/fd_move.c new file mode 100644 index 0000000..1aa557f --- /dev/null +++ b/fd_move.c @@ -0,0 +1,11 @@ +#include "fd.h" + +int fd_move(to,from) +int to; +int from; +{ + if (to == from) return 0; + if (fd_copy(to,from) == -1) return -1; + close(from); + return 0; +} diff --git a/fd_move=0 b/fd_move=0 new file mode 100644 index 0000000..c2c8185 --- /dev/null +++ b/fd_move=0 @@ -0,0 +1 @@ +fd_move.3 diff --git a/find-systype.sh b/find-systype.sh new file mode 100644 index 0000000..16266d3 --- /dev/null +++ b/find-systype.sh @@ -0,0 +1,144 @@ +# oper-:arch-:syst-:chip-:kern- +# oper = operating system type; e.g., sunos-4.1.4 +# arch = machine language; e.g., sparc +# syst = which binaries can run; e.g., sun4 +# chip = chip model; e.g., micro-2-80 +# kern = kernel version; e.g., sun4m +# dependence: arch --- chip +# \ \ +# oper --- syst --- kern +# so, for example, syst is interpreted in light of oper, but chip is not. +# anyway, no slashes, no extra colons, no uppercase letters. +# the point of the extra -'s is to ease parsing: can add hierarchies later. +# e.g., *:i386-*:*:pentium-*:* would handle pentium-100 as well as pentium, +# and i386-486 (486s do have more instructions, you know) as well as i386. +# the idea here is to include ALL useful available information. + +exec 2>/dev/null +sys="`uname -s | tr '/:[A-Z]' '..[a-z]'`" +if [ x"$sys" != x ] +then + unamer="`uname -r | tr /: ..`" + unamem="`uname -m | tr /: ..`" + unamev="`uname -v | tr /: ..`" + + case "$sys" in + bsd.os) + # in bsd 4.4, uname -v does not have useful info. + # in bsd 4.4, uname -m is arch, not chip. + oper="$sys-$unamer" + arch="$unamem" + syst="" + chip="`sysctl -n hw.model`" + kern="" + ;; + freebsd) + # see above about bsd 4.4 + oper="$sys-$unamer" + arch="$unamem" + syst="" + chip="`sysctl -n hw.model`" # hopefully + kern="" + ;; + netbsd) + # see above about bsd 4.4 + oper="$sys-$unamer" + arch="$unamem" + syst="" + chip="`sysctl -n hw.model`" # hopefully + kern="" + ;; + linux) + # as in bsd 4.4, uname -v does not have useful info. + oper="$sys-$unamer" + syst="" + chip="$unamem" + kern="" + case "$chip" in + i386|i486|i586|i686) + arch="i386" + ;; + alpha) + arch="alpha" + ;; + esac + ;; + aix) + # naturally IBM has to get uname -r and uname -v backwards. dorks. + oper="$sys-$unamev-$unamer" + arch="`arch | tr /: ..`" + syst="" + chip="$unamem" + kern="" + ;; + sunos) + oper="$sys-$unamer-$unamev" + arch="`(uname -p || mach) | tr /: ..`" + syst="`arch | tr /: ..`" + chip="$unamem" # this is wrong; is there any way to get the real info? + kern="`arch -k | tr /: ..`" + ;; + unix_sv) + oper="$sys-$unamer-$unamev" + arch="`uname -m`" + syst="" + chip="$unamem" + kern="" + ;; + *) + oper="$sys-$unamer-$unamev" + arch="`arch | tr /: ..`" + syst="" + chip="$unamem" + kern="" + ;; + esac +else + $CC -c trycpp.c + $LD -o trycpp trycpp.o + case `./trycpp` in + nextstep) + oper="nextstep-`hostinfo | sed -n 's/^[ ]*NeXT Mach \([^:]*\):.*$/\1/p'`" + arch="`hostinfo | sed -n 's/^Processor type: \(.*\) (.*)$/\1/p' | tr /: ..`" + syst="" + chip="`hostinfo | sed -n 's/^Processor type: .* (\(.*\))$/\1/p' | tr ' /:' '...'`" + kern="" + ;; + *) + oper="unknown" + arch="" + syst="" + chip="" + kern="" + ;; + esac + rm -f trycpp.o trycpp +fi + +case "$chip" in +80486) + # let's try to be consistent here. (BSD/OS) + chip=i486 + ;; +i486DX) + # respect the hyphen hierarchy. (FreeBSD) + chip=i486-dx + ;; +i486.DX2) + # respect the hyphen hierarchy. (FreeBSD) + chip=i486-dx2 + ;; +Intel.586) + # no, you nitwits, there is no such chip. (NeXTStep) + chip=pentium + ;; +i586) + # no, you nitwits, there is no such chip. (Linux) + chip=pentium + ;; +i686) + # STOP SAYING THAT! (Linux) + chip=ppro +esac + +echo "$oper-:$arch-:$syst-:$chip-:$kern-" | tr ' [A-Z]' '.[a-z]' diff --git a/fmt.h b/fmt.h new file mode 100644 index 0000000..ba2fe16 --- /dev/null +++ b/fmt.h @@ -0,0 +1,25 @@ +#ifndef FMT_H +#define FMT_H + +#define FMT_ULONG 40 /* enough space to hold 2^128 - 1 in decimal, plus \0 */ +#define FMT_LEN ((char *) 0) /* convenient abbreviation */ + +extern unsigned int fmt_uint(); +extern unsigned int fmt_uint0(); +extern unsigned int fmt_xint(); +extern unsigned int fmt_nbbint(); +extern unsigned int fmt_ushort(); +extern unsigned int fmt_xshort(); +extern unsigned int fmt_nbbshort(); +extern unsigned int fmt_ulong(); +extern unsigned int fmt_xlong(); +extern unsigned int fmt_nbblong(); + +extern unsigned int fmt_plusminus(); +extern unsigned int fmt_minus(); +extern unsigned int fmt_0x(); + +extern unsigned int fmt_str(); +extern unsigned int fmt_strn(); + +#endif diff --git a/fmt_str.c b/fmt_str.c new file mode 100644 index 0000000..48930cf --- /dev/null +++ b/fmt_str.c @@ -0,0 +1,12 @@ +#include "fmt.h" + +unsigned int fmt_str(s,t) +register char *s; register char *t; +{ + register unsigned int len; + char ch; + len = 0; + if (s) { while (ch = t[len]) s[len++] = ch; } + else while (t[len]) len++; + return len; +} diff --git a/fmt_uint.c b/fmt_uint.c new file mode 100644 index 0000000..8595be8 --- /dev/null +++ b/fmt_uint.c @@ -0,0 +1,6 @@ +#include "fmt.h" + +unsigned int fmt_uint(s,u) register char *s; register unsigned int u; +{ + register unsigned long l; l = u; return fmt_ulong(s,l); +} diff --git a/fmt_uint0.c b/fmt_uint0.c new file mode 100644 index 0000000..81705f6 --- /dev/null +++ b/fmt_uint0.c @@ -0,0 +1,10 @@ +#include "fmt.h" + +unsigned int fmt_uint0(s,u,n) char *s; unsigned int u; unsigned int n; +{ + unsigned int len; + len = fmt_uint(FMT_LEN,u); + while (len < n) { if (s) *s++ = '0'; ++len; } + if (s) fmt_uint(s,u); + return len; +} diff --git a/fmt_ulong.c b/fmt_ulong.c new file mode 100644 index 0000000..ab12e8c --- /dev/null +++ b/fmt_ulong.c @@ -0,0 +1,13 @@ +#include "fmt.h" + +unsigned int fmt_ulong(s,u) register char *s; register unsigned long u; +{ + register unsigned int len; register unsigned long q; + len = 1; q = u; + while (q > 9) { ++len; q /= 10; } + if (s) { + s += len; + do { *--s = '0' + (u % 10); u /= 10; } while(u); /* handles u == 0 */ + } + return len; +} diff --git a/fork.h.do b/fork.h.do new file mode 100644 index 0000000..e095298 --- /dev/null +++ b/fork.h.do @@ -0,0 +1,7 @@ +dependon compile load tryvfork.c fork.h1 fork.h2 +( ./compile tryvfork.c && ./load tryvfork ) >/dev/null 2>&1 \ +&& cat fork.h2 || cat fork.h1 +rm -f tryvfork.o tryvfork +formake '( ( ./compile tryvfork.c && ./load tryvfork ) >/dev/null 2>&1 \' +formake '&& cat fork.h2 || cat fork.h1 ) > fork.h' +formake 'rm -f tryvfork.o tryvfork' diff --git a/fork.h1 b/fork.h1 new file mode 100644 index 0000000..b786255 --- /dev/null +++ b/fork.h1 @@ -0,0 +1,7 @@ +#ifndef FORK_H +#define FORK_H + +extern int fork(); +#define vfork fork + +#endif diff --git a/fork.h2 b/fork.h2 new file mode 100644 index 0000000..41773b6 --- /dev/null +++ b/fork.h2 @@ -0,0 +1,7 @@ +#ifndef FORK_H +#define FORK_H + +extern int fork(); +extern int vfork(); + +#endif diff --git a/fs=l b/fs=l new file mode 100644 index 0000000..9e09636 --- /dev/null +++ b/fs=l @@ -0,0 +1,6 @@ +fmt_str.o +fmt_uint.o +fmt_uint0.o +fmt_ulong.o +scan_ulong.o +scan_8long.o diff --git a/gen_alloc.h b/gen_alloc.h new file mode 100644 index 0000000..b94a956 --- /dev/null +++ b/gen_alloc.h @@ -0,0 +1,7 @@ +#ifndef GEN_ALLOC_H +#define GEN_ALLOC_H + +#define GEN_ALLOC_typedef(ta,type,field,len,a) \ + typedef struct ta { type *field; unsigned int len; unsigned int a; } ta; + +#endif diff --git a/gen_allocdefs.h b/gen_allocdefs.h new file mode 100644 index 0000000..783a9b1 --- /dev/null +++ b/gen_allocdefs.h @@ -0,0 +1,34 @@ +#ifndef GEN_ALLOC_DEFS_H +#define GEN_ALLOC_DEFS_H + +#define GEN_ALLOC_ready(ta,type,field,len,a,i,n,x,base,ta_ready) \ +int ta_ready(x,n) register ta *x; register unsigned int n; \ +{ register unsigned int i; \ + if (x->field) { \ + i = x->a; \ + if (n > i) { \ + x->a = base + n + (n >> 3); \ + if (alloc_re(&x->field,i * sizeof(type),x->a * sizeof(type))) return 1; \ + x->a = i; return 0; } \ + return 1; } \ + x->len = 0; \ + return !!(x->field = (type *) alloc((x->a = n) * sizeof(type))); } + +#define GEN_ALLOC_readyplus(ta,type,field,len,a,i,n,x,base,ta_rplus) \ +int ta_rplus(x,n) register ta *x; register unsigned int n; \ +{ register unsigned int i; \ + if (x->field) { \ + i = x->a; n += x->len; \ + if (n > i) { \ + x->a = base + n + (n >> 3); \ + if (alloc_re(&x->field,i * sizeof(type),x->a * sizeof(type))) return 1; \ + x->a = i; return 0; } \ + return 1; } \ + x->len = 0; \ + return !!(x->field = (type *) alloc((x->a = n) * sizeof(type))); } + +#define GEN_ALLOC_append(ta,type,field,len,a,i,n,x,base,ta_rplus,ta_append) \ +int ta_append(x,i) register ta *x; register type *i; \ +{ if (!ta_rplus(x,1)) return 0; x->field[x->len++] = *i; return 1; } + +#endif diff --git a/getconf.c b/getconf.c new file mode 100644 index 0000000..89b6d31 --- /dev/null +++ b/getconf.c @@ -0,0 +1,61 @@ +#include "stralloc.h" +#include "slurp.h" +#include "strerr.h" +#include "getconf.h" + +static stralloc data = {0}; + +void nomem(fatal) +char *fatal; +{ + strerr_die2x(111,fatal,"out of memory"); +} + +int getconf(sa,fn,flagrequired,fatal,dir) +stralloc *sa; +char *fatal; +int flagrequired; +char *dir; +char *fn; +{ + int i; + int j; + int k; + + if (!stralloc_copys(&data,"")) + nomem(fatal); + switch(slurp(fn,&data,128)) { + case -1: + strerr_die6sys(111,fatal,"unable to read ",dir,"/",fn,": "); + case 0: + if (!flagrequired) + return 0; + strerr_die5x(100,fatal,dir,"/",fn," does not exist"); + } + if (!stralloc_append(&data,"\n")) nomem(fatal); + if (!stralloc_copys(sa,"")) nomem(fatal); + i = 0; + for (j = 0;j < data.len;++j) + if (data.s[j] == '\n') { + k = j; + while ((k > i) && ((data.s[k-1] == ' ') || (data.s[k-1] == '\t'))) --k; + if ((k > i) && (data.s[i] != '#')) { + if (!stralloc_catb(sa,data.s + i,k - i)) nomem(fatal); + if (!stralloc_0(sa)) nomem(fatal); + } + i = j + 1; + } + return 1; +} + +int getconf_line(sa,fn,flagrequired,fatal,dir) +stralloc *sa; +char *fatal; +int flagrequired; +char *dir; +char *fn; +{ + if (!getconf(sa,fn,flagrequired,fatal,dir)) return 0; + sa->len = byte_chr(sa->s,sa->len,0); + return 1; +} diff --git a/getconf.h b/getconf.h new file mode 100644 index 0000000..20962f0 --- /dev/null +++ b/getconf.h @@ -0,0 +1,7 @@ +#ifndef GETCONF_H +#define GETCONF_H + +extern int getconf(); +extern int getconf_line(); + +#endif diff --git a/getln.3 b/getln.3 new file mode 100644 index 0000000..ffe1953 --- /dev/null +++ b/getln.3 @@ -0,0 +1,51 @@ +.TH getln 3 +.SH NAME +getln \- read one line of data +.SH SYNTAX +.B #include + +int \fBgetln\fP(&\fIss\fR,&\fIsa\fR,&\fImatch\fR,\fIsep\fR); + +substdio \fIss\fR; +.br +stralloc \fIsa\fR; +.br +int \fImatch\fR; +.br +int \fIsep\fR; +.SH DESCRIPTION +.B getln +reads a line of characters, terminated by a +.I sep +character, +from +.IR ss . +It returns the line in +.I sa +and sets +.I match +to 1. + +If +.B getln +sees end-of-input before it sees +.IR sep , +it returns the partial line in +.I sa +and sets +.I match +to 0. + +.B getln +normally returns 0. +If it runs out of memory, +or encounters an error from +.IR ss , +it returns -1, +setting +.B errno +appropriately. +.SH "SEE ALSO" +stralloc(3), +substdio(3), +getln2(3) diff --git a/getln.c b/getln.c new file mode 100644 index 0000000..c5cb097 --- /dev/null +++ b/getln.c @@ -0,0 +1,20 @@ +#include "substdio.h" +#include "byte.h" +#include "stralloc.h" +#include "getln.h" + +int getln(ss,sa,match,sep) +register substdio *ss; +register stralloc *sa; +int *match; +int sep; +{ + char *cont; + unsigned int clen; + + if (getln2(ss,sa,&cont,&clen,sep) == -1) return -1; + if (!clen) { *match = 0; return 0; } + if (!stralloc_catb(sa,cont,clen)) return -1; + *match = 1; + return 0; +} diff --git a/getln.h b/getln.h new file mode 100644 index 0000000..cf4f934 --- /dev/null +++ b/getln.h @@ -0,0 +1,7 @@ +#ifndef GETLN_H +#define GETLN_H + +extern int getln(); +extern int getln2(); + +#endif diff --git a/getln2.3 b/getln2.3 new file mode 100644 index 0000000..f95105a --- /dev/null +++ b/getln2.3 @@ -0,0 +1,64 @@ +.TH getln2 3 +.SH NAME +getln2 \- read one line of data +.SH SYNTAX +.B #include + +int \fBgetln2\fP(&\fIss\fR,&\fIsa\fR,&\fIcont\fR,&\fIclen\fR,\fIsep\fR); + +substdio \fIss\fR; +.br +stralloc \fIsa\fR; +.br +char *\fIcont\fR; +.br +unsigned int \fIclen\fR; +.br +int \fIsep\fR; +.SH DESCRIPTION +.B getln2 +reads a line of characters, terminated by a +.I sep +character, +from +.IR ss . + +The line is returned in two pieces. +The first piece is stored in +.IR sa . +The second piece is +.IR cont , +a pointer to +.I clen +characters inside the +.I ss +buffer. +The second piece must be copied somewhere else +before +.I ss +is used again. + +If +.B getln2 +sees end-of-input before it sees +.IR sep , +it sets +.I clen +to 0 and does not set +.IR cont . +It puts the partial line into +.IR sa . + +.B getln2 +normally returns 0. +If it runs out of memory, +or encounters an error from +.IR ss , +it returns -1, +setting +.B errno +appropriately. +.SH "SEE ALSO" +stralloc(3), +substdio(3), +getln(3) diff --git a/getln2.c b/getln2.c new file mode 100644 index 0000000..9e576e9 --- /dev/null +++ b/getln2.c @@ -0,0 +1,31 @@ +#include "substdio.h" +#include "stralloc.h" +#include "byte.h" +#include "getln.h" + +int getln2(ss,sa,cont,clen,sep) +register substdio *ss; +register stralloc *sa; +/*@out@*/char **cont; +/*@out@*/unsigned int *clen; +int sep; +{ + register char *x; + register unsigned int i; + int n; + + if (!stralloc_ready(sa,0)) return -1; + sa->len = 0; + + for (;;) { + n = substdio_feed(ss); + if (n < 0) return -1; + if (n == 0) { *clen = 0; return 0; } + x = substdio_PEEK(ss); + i = byte_chr(x,n,sep); + if (i < n) { substdio_SEEK(ss,*clen = i + 1); *cont = x; return 0; } + if (!stralloc_readyplus(sa,n)) return -1; + i = sa->len; + sa->len = i + substdio_get(ss,sa->s + i,n); + } +} diff --git a/getln2=0 b/getln2=0 new file mode 100644 index 0000000..ee6879c --- /dev/null +++ b/getln2=0 @@ -0,0 +1 @@ +getln2.3 diff --git a/getln=0 b/getln=0 new file mode 100644 index 0000000..68df95c --- /dev/null +++ b/getln=0 @@ -0,0 +1 @@ +getln.3 diff --git a/getln=l b/getln=l new file mode 100644 index 0000000..b0f37fa --- /dev/null +++ b/getln=l @@ -0,0 +1,2 @@ +getln.o +getln2.o diff --git a/getopt.3 b/getopt.3 new file mode 100644 index 0000000..ecbf50a --- /dev/null +++ b/getopt.3 @@ -0,0 +1,235 @@ +.TH getopt 3 +.SH NAME +getopt \- get option character from command line +.SH SYNTAX +.B #include + +char *\fBoptarg\fP; +.br +int \fBoptind\fP; +.br +int \fBoptpos\fP; +.br +int \fBopteof\fP; +.br +int \fBoptproblem\fP; +.br +char *\fBoptprogname\fP; +.br +int \fBopterr\fP; + +int \fBgetopt(\fP\fIargc,argv,opts\fR\fB)\fP; + +int \fIargc\fR; +.br +char **\fIargv\fR; +.br +char *\fIopts\fR; +.SH DESCRIPTION +This is a clone version of +the standard +.B getopt +library, +built on top of +.BR subgetopt(3) . + +See +.B subgetopt(3) +for a detailed description of +.B getopt +processing. +The main difference between +.B getopt +and +.B subgetopt +is that +.B getopt +prints error messages +in case of problems. +To turn off these error messages, set +.B opterr +(default nonzero) +to zero. + +This clone version of +.B getopt +also provides an +.B optprogname +variable. +There are two uses for this variable: + +(1) +By default +.B optprogname +is null. +When +.B getopt +sees this, +it +attempts to initialize +.B optprogname +from +.IR argv\fB[0] , +stripping the directory name. +The calling program can use +.B optprogname +after calling +.B getopt +at least once. +This is appropriate if the name of the program should be +determined from its command line. + +(2) +.B getopt +prints +.B optprogname +at the beginning +of any error messages. +So the calling program can, +before calling +.BR getopt , +initialize +.B optprogname +as desired. +This is appropriate if the name of the program should not be +determined from its command line. +.SH "COMPATIBILITY" +Old versions of +.B getopt +do not include +.BR opterr . +.BR optpos , +.BR opteof , +.BR optproblem , +and +.B optprogname +are specific to this clone version of +.BR getopt . + +Many features of this clone version of +.B getopt +are poorly defined, if available at all, +in most versions of +.BR getopt . +For example, the standard +.B getopt +interface does not define +.B optind +until the end of the option list. +And +.B optarg +is not defined +unless +.B getopt +has just returned +an option which takes an argument. +In this clone version, +.B optind +and +.B optpos +always indicate the next character to be read, +and +.B optarg +is null whenever +the current option does not take an argument. +See +.B subgetopt(3) +for precise definitions of the parsing procedure. + +When it reaches the end of the option list, +this version of +.B getopt +always returns +.BR opteof , +which is the same as +.BR subgetoptdone , +which is initialized to +.BR SUBGETOPTDONE , +which is defined as \-1. +The standard behavior is to return +EOF +from +.B stdio(3). +This is incompatible +on any weird machine where +EOF is different from \-1. +The calling program could set +.B opteof +to EOF to imitate the standard behavior. + +Like most versions of +.BR getopt , +this clone version allows, but does not demand, that +option arguments be +separated from the option by whitespace, i.e., be +in the next command-line argument. + +Some versions of +.B getopt +provide an +.B optopt +variable. +.B optopt +is incompatible across systems: +for example, +GNU +.B getopt +uses it the same way that this clone version uses +.BR optproblem , +while +BSD +.B getopt +uses it to +indicate the last option character returned by +.BR getopt . +This clone version does not provide +.BR optopt . +The use of +.B optopt +is strongly discouraged. + +Some versions of +.B getopt +do not recognize a double hyphen as the end of arguments. +This version allows a double hyphen, or in fact any argument beginning +with two hyphens. + +A lone hyphen is always recognized as the end of arguments. +Some versions of +.B getopt +allow lone hyphens as options. +This practice is wrong and is strongly discouraged. +.SH "SYNTAX NOTE" +.B getopt +is actually a macro abbreviation for +.BR getoptmine . +The external +.B opterr +and +.B optprogname +variables +are macros for +.B getopterr +and +.BR getoptprogname . +All the other +.B opt +variables are macros +for +.BR subgetopt . +These macros are defined in +.BR , +unless +.B GETOPTNOSHORT +is defined. +Further macros are defined in +.BR , +which is included by +.BR , +unless +.B SUBGETOPTNOSHORT +is defined. +.SH VERSION +getopt version 1.9, 931129. +.SH AUTHOR +Placed into the public domain by Daniel J. Bernstein. diff --git a/getopt=0 b/getopt=0 new file mode 100644 index 0000000..52e530c --- /dev/null +++ b/getopt=0 @@ -0,0 +1 @@ +getopt.3 diff --git a/getopt=l b/getopt=l new file mode 100644 index 0000000..a667e1e --- /dev/null +++ b/getopt=l @@ -0,0 +1,2 @@ +subgetopt.o +sgetopt.o diff --git a/hasflock.h.do b/hasflock.h.do new file mode 100644 index 0000000..c7d8678 --- /dev/null +++ b/hasflock.h.do @@ -0,0 +1,7 @@ +dependon tryflock.c compile load +( ./compile tryflock.c && ./load tryflock ) >/dev/null 2>&1 \ +&& echo \#define HASFLOCK 1 +rm -f tryflock.o tryflock +formake '( ( ./compile tryflock.c && ./load tryflock ) >/dev/null 2>&1 \' +formake '&& echo \#define HASFLOCK 1 || exit 0 ) > hasflock.h' +formake 'rm -f tryflock.o tryflock' diff --git a/hassgact.h.do b/hassgact.h.do new file mode 100644 index 0000000..df277d5 --- /dev/null +++ b/hassgact.h.do @@ -0,0 +1,7 @@ +dependon trysgact.c compile load +( ./compile trysgact.c && ./load trysgact ) >/dev/null 2>&1 \ +&& echo \#define HASSIGACTION 1 +rm -f trysgact.o trysgact +formake '( ( ./compile trysgact.c && ./load trysgact ) >/dev/null 2>&1 \' +formake '&& echo \#define HASSIGACTION 1 || exit 0 ) > hassgact.h' +formake 'rm -f trysgact.o trysgact' diff --git a/install.c b/install.c new file mode 100644 index 0000000..24f0916 --- /dev/null +++ b/install.c @@ -0,0 +1,140 @@ +#include "substdio.h" +#include "stralloc.h" +#include "getln.h" +#include "readwrite.h" +#include "exit.h" +#include "open.h" +#include "error.h" +#include "strerr.h" +#include "byte.h" + +stralloc target = {0}; +char *to; + +#define FATAL "install: fatal: " +void nomem() { strerr_die2x(111,FATAL,"out of memory"); } + +char inbuf[SUBSTDIO_INSIZE]; +char outbuf[SUBSTDIO_OUTSIZE]; +substdio ssin; +substdio ssout; + +void doit(line) +stralloc *line; +{ + char *x; + unsigned int xlen; + unsigned int i; + char *type; + char *uidstr; + char *gidstr; + char *modestr; + char *mid; + char *name; + unsigned long uid; + unsigned long gid; + unsigned long mode; + int fdin; + int fdout; + + x = line->s; xlen = line->len; + + type = x; + i = byte_chr(x,xlen,':'); if (i == xlen) return; + x[i++] = 0; x += i; xlen -= i; + + uidstr = x; + i = byte_chr(x,xlen,':'); if (i == xlen) return; + x[i++] = 0; x += i; xlen -= i; + + gidstr = x; + i = byte_chr(x,xlen,':'); if (i == xlen) return; + x[i++] = 0; x += i; xlen -= i; + + modestr = x; + i = byte_chr(x,xlen,':'); if (i == xlen) return; + x[i++] = 0; x += i; xlen -= i; + + mid = x; + i = byte_chr(x,xlen,':'); if (i == xlen) return; + x[i++] = 0; x += i; xlen -= i; + + name = x; + i = byte_chr(x,xlen,':'); if (i == xlen) return; + x[i++] = 0; x += i; xlen -= i; + + if (!stralloc_copys(&target,to)) nomem(); + if (!stralloc_cats(&target,mid)) nomem(); + if (!stralloc_cats(&target,name)) nomem(); + if (!stralloc_0(&target)) nomem(); + + uid = -1; if (*uidstr) scan_ulong(uidstr,&uid); + gid = -1; if (*gidstr) scan_ulong(gidstr,&gid); + scan_8long(modestr,&mode); + + switch(*type) { + case 'd': + if (mkdir(target.s,0700) == -1) + if (errno != error_exist) + strerr_die4sys(111,FATAL,"unable to mkdir ",target.s,": "); + break; + + case 'c': + fdin = open_read(name); + if (fdin == -1) + strerr_die4sys(111,FATAL,"unable to read ",name,": "); + substdio_fdbuf(&ssin,read,fdin,inbuf,sizeof(inbuf)); + + fdout = open_trunc(target.s); + if (fdout == -1) + strerr_die4sys(111,FATAL,"unable to write ",target.s,": "); + substdio_fdbuf(&ssout,write,fdout,outbuf,sizeof(outbuf)); + + switch(substdio_copy(&ssout,&ssin)) { + case -2: + strerr_die4sys(111,FATAL,"unable to read ",name,": "); + case -3: + strerr_die4sys(111,FATAL,"unable to write ",target.s,": "); + } + + close(fdin); + if (substdio_flush(&ssout) == -1) + strerr_die4sys(111,FATAL,"unable to write ",target.s,": "); + if (fsync(fdout) == -1) + strerr_die4sys(111,FATAL,"unable to write ",target.s,": "); + close(fdout); + break; + + default: + return; + } + + if (chown(target.s,uid,gid) == -1) + strerr_die4sys(111,FATAL,"unable to chown ",target.s,": "); + if (chmod(target.s,mode) == -1) + strerr_die4sys(111,FATAL,"unable to chmod ",target.s,": "); +} + +char buf[256]; +substdio in = SUBSTDIO_FDBUF(read,0,buf,sizeof(buf)); +stralloc line = {0}; + +void main(argc,argv) +int argc; +char **argv; +{ + int match; + + umask(077); + + to = argv[1]; + if (!to) strerr_die2x(100,FATAL,"install: usage: install dir"); + + for (;;) { + if (getln(&in,&line,&match,'\n') == -1) + strerr_die2sys(111,FATAL,"unable to read input: "); + doit(&line); + if (!match) + _exit(0); + } +} diff --git a/install=x b/install=x new file mode 100644 index 0000000..6dc960b --- /dev/null +++ b/install=x @@ -0,0 +1,9 @@ +getln.a +strerr.a +substdio.a +stralloc.a +alloc.a +open.a +error.a +str.a +fs.a diff --git a/issub.c b/issub.c new file mode 100644 index 0000000..81ab6ad --- /dev/null +++ b/issub.c @@ -0,0 +1,87 @@ +#include "stralloc.h" +#include "getln.h" +#include "readwrite.h" +#include "substdio.h" +#include "open.h" +#include "byte.h" +#include "case.h" +#include "lock.h" +#include "error.h" +#include "issub.h" +#include "uint32.h" + +static stralloc addr = {0}; +static stralloc line = {0}; +static stralloc fn = {0}; +static int fd; +static substdio ss; +static char ssbuf[256]; + +static int doit(userhost) +char *userhost; +{ + int j; + uint32 h; + char ch; + int match; + + if (!stralloc_copys(&addr,"T")) return -2; + if (!stralloc_cats(&addr,userhost)) return -2; + + j = byte_rchr(addr.s,addr.len,'@'); + if (j == addr.len) return 0; + case_lowerb(addr.s + j + 1,addr.len - j - 1); + + h = 5381; + for (j = 0;j < addr.len;++j) + h = (h + (h << 5)) ^ (uint32) (unsigned char) addr.s[j]; + ch = 64 + (h % 53); + + if (!stralloc_0(&addr)) return -2; + + if (!stralloc_copys(&fn,"subscribers/")) return -2; + if (!stralloc_catb(&fn,&ch,1)) return -2; + if (!stralloc_0(&fn)) return -2; + + fd = open_read(fn.s); + if (fd == -1) { + if (errno != error_noent) return -3; + return 0; + } + substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); + + for (;;) { + if (getln(&ss,&line,&match,'\0') == -1) { close(fd); return -3; } + if (!match) break; + if (line.len == addr.len) + if (!byte_diff(line.s,line.len,addr.s)) { close(fd); return 1; } + } + + close(fd); + return 0; +} + +struct strerr issub_err; + +int issub(userhost) +char *userhost; +{ + int fdlock; + int r; + + fdlock = open_append("lock"); + if (fdlock == -1) + STRERR_SYS(-1,issub_err,"unable to open lock: ") + if (lock_ex(fdlock) == -1) { + close(fdlock); + STRERR_SYS(-1,issub_err,"unable to obtain lock: ") + } + + r = doit(userhost); + close(fdlock); + + if (r == -2) STRERR(-1,issub_err,"out of memory") + if (r == -3) STRERR_SYS3(-1,issub_err,"unable to read ",fn.s,": ") + + return r; +} diff --git a/issub.h b/issub.h new file mode 100644 index 0000000..71fb379 --- /dev/null +++ b/issub.h @@ -0,0 +1,10 @@ +#ifndef ISSUB_H +#define ISSUB_H + +#include "strerr.h" + +extern struct strerr issub_err; + +extern int issub(); + +#endif diff --git a/it.do b/it.do new file mode 100644 index 0000000..667603f --- /dev/null +++ b/it.do @@ -0,0 +1,4 @@ +dependon \ +ezmlm-make ezmlm-manage ezmlm-send ezmlm-reject \ +ezmlm-return ezmlm-warn ezmlm-weed \ +ezmlm-list ezmlm-sub ezmlm-unsub diff --git a/lock.h b/lock.h new file mode 100644 index 0000000..a7dee41 --- /dev/null +++ b/lock.h @@ -0,0 +1,8 @@ +#ifndef LOCK_H +#define LOCK_H + +extern int lock_ex(); +extern int lock_un(); +extern int lock_exnb(); + +#endif diff --git a/lock=l b/lock=l new file mode 100644 index 0000000..9927cef --- /dev/null +++ b/lock=l @@ -0,0 +1 @@ +lock_ex.o diff --git a/lock_ex.c b/lock_ex.c new file mode 100644 index 0000000..a3351c9 --- /dev/null +++ b/lock_ex.c @@ -0,0 +1,11 @@ +#include +#include +#include +#include "hasflock.h" +#include "lock.h" + +#ifdef HASFLOCK +int lock_ex(fd) int fd; { return flock(fd,LOCK_EX); } +#else +int lock_ex(fd) int fd; { return lockf(fd,1,0); } +#endif diff --git a/log.c b/log.c new file mode 100644 index 0000000..15e732e --- /dev/null +++ b/log.c @@ -0,0 +1,37 @@ +#include "substdio.h" +#include "readwrite.h" +#include "stralloc.h" +#include "log.h" +#include "now.h" +#include "fmt.h" +#include "open.h" + +static substdio ss; +static char buf[1]; +static char num[FMT_ULONG]; +static stralloc line = {0}; + +void log(event,addr) +char *event; +char *addr; +{ + char ch; + int fd; + + if (!stralloc_copyb(&line,num,fmt_ulong(num,(unsigned long) now()))) return; + if (!stralloc_cats(&line," ")) return; + if (!stralloc_cats(&line,event)) return; + if (!stralloc_cats(&line," ")) return; + while (ch = *addr++) { + if ((ch < 33) || (ch > 126)) ch = '?'; + if (!stralloc_append(&line,&ch)) return; + } + if (!stralloc_cats(&line,"\n")) return; + + fd = open_append("Log"); + if (fd == -1) return; + substdio_fdbuf(&ss,write,fd,buf,sizeof(buf)); + substdio_putflush(&ss,line.s,line.len); + close(fd); + return; +} diff --git a/log.h b/log.h new file mode 100644 index 0000000..d973be9 --- /dev/null +++ b/log.h @@ -0,0 +1,6 @@ +#ifndef LOG_H +#define LOG_H + +extern void log(); + +#endif diff --git a/make-compile.sh b/make-compile.sh new file mode 100644 index 0000000..a1eb501 --- /dev/null +++ b/make-compile.sh @@ -0,0 +1 @@ +echo exec "$CC" -c '${1+"$@"}' diff --git a/make-load.sh b/make-load.sh new file mode 100644 index 0000000..de07d2e --- /dev/null +++ b/make-load.sh @@ -0,0 +1,2 @@ +echo 'main="$1"; shift' +echo exec "$LD" '-o "$main" "$main".o ${1+"$@"}' diff --git a/make-makelib.sh b/make-makelib.sh new file mode 100644 index 0000000..d6b7c8c --- /dev/null +++ b/make-makelib.sh @@ -0,0 +1,16 @@ +echo 'main="$1"; shift' +echo 'rm -f "$main"' +echo 'ar cr "$main" ${1+"$@"}' + +case "$1" in +sunos-5.*) ;; +unix_sv*) ;; +irix64-*) ;; +irix-*) ;; +dgux-*) ;; +hp-ux-*) ;; +sco*) ;; +*) + echo 'ranlib "$main"' + ;; +esac diff --git a/man.do b/man.do new file mode 100644 index 0000000..d9e3f48 --- /dev/null +++ b/man.do @@ -0,0 +1,31 @@ +dependon \ +ezmlm.0 \ +ezmlm-make.0 ezmlm-manage.0 ezmlm-send.0 ezmlm-reject.0 \ +ezmlm-return.0 ezmlm-warn.0 ezmlm-weed.0 \ +ezmlm-list.0 ezmlm-sub.0 ezmlm-unsub.0 \ +alloc.0 \ +case.0 \ +datetime.0 \ +direntry.0 \ +env.0 \ +error.0 \ +error_str.0 \ +error_temp.0 \ +ezmlm.0 \ +fd_copy.0 \ +fd_move.0 \ +getln.0 \ +getln2.0 \ +getopt.0 \ +now.0 \ +sgetopt.0 \ +stralloc.0 \ +subfd.0 \ +subgetopt.0 \ +substdio.0 \ +substdio_copy.0 \ +substdio_in.0 \ +substdio_out.0 \ +surf.0 \ +surfpcs.0 \ +wait.0 diff --git a/now.3 b/now.3 new file mode 100644 index 0000000..3d845b1 --- /dev/null +++ b/now.3 @@ -0,0 +1,14 @@ +.TH now 3 +.SH NAME +now \- get current time, in seconds +.SH SYNTAX +.B #include + +datetime_sec \fBnow\fP(); +.SH DESCRIPTION +.B now +returns the number of real-time seconds that have elapsed +since the end of 1969 TAI. +.SH "SEE ALSO" +datetime(3), +time(3) diff --git a/now.c b/now.c new file mode 100644 index 0000000..5ce4d90 --- /dev/null +++ b/now.c @@ -0,0 +1,8 @@ +#include +#include "datetime.h" +#include "now.h" + +datetime_sec now() +{ + return time((long *) 0); +} diff --git a/now.h b/now.h new file mode 100644 index 0000000..b8be182 --- /dev/null +++ b/now.h @@ -0,0 +1,8 @@ +#ifndef NOW_H +#define NOW_H + +#include "datetime.h" + +extern datetime_sec now(); + +#endif diff --git a/now=0 b/now=0 new file mode 100644 index 0000000..3f02d34 --- /dev/null +++ b/now=0 @@ -0,0 +1 @@ +now.3 diff --git a/open.h b/open.h new file mode 100644 index 0000000..c903113 --- /dev/null +++ b/open.h @@ -0,0 +1,10 @@ +#ifndef OPEN_H +#define OPEN_H + +extern int open_read(); +extern int open_excl(); +extern int open_append(); +extern int open_trunc(); +extern int open_write(); + +#endif diff --git a/open=l b/open=l new file mode 100644 index 0000000..9104cd6 --- /dev/null +++ b/open=l @@ -0,0 +1,3 @@ +open_append.o +open_read.o +open_trunc.o diff --git a/open_append.c b/open_append.c new file mode 100644 index 0000000..93a0862 --- /dev/null +++ b/open_append.c @@ -0,0 +1,6 @@ +#include +#include +#include "open.h" + +int open_append(fn) char *fn; +{ return open(fn,O_WRONLY | O_NDELAY | O_APPEND | O_CREAT,0600); } diff --git a/open_read.c b/open_read.c new file mode 100644 index 0000000..f503e48 --- /dev/null +++ b/open_read.c @@ -0,0 +1,6 @@ +#include +#include +#include "open.h" + +int open_read(fn) char *fn; +{ return open(fn,O_RDONLY | O_NDELAY); } diff --git a/open_trunc.c b/open_trunc.c new file mode 100644 index 0000000..e275085 --- /dev/null +++ b/open_trunc.c @@ -0,0 +1,6 @@ +#include +#include +#include "open.h" + +int open_trunc(fn) char *fn; +{ return open(fn,O_WRONLY | O_NDELAY | O_TRUNC | O_CREAT,0644); } diff --git a/qmail.c b/qmail.c new file mode 100644 index 0000000..7484331 --- /dev/null +++ b/qmail.c @@ -0,0 +1,103 @@ +#include "substdio.h" +#include "readwrite.h" +#include "wait.h" +#include "exit.h" +#include "fork.h" +#include "fd.h" +#include "qmail.h" +#include "auto_qmail.h" + +static char *binqqargs[2] = { "bin/qmail-queue", 0 } ; + +int qmail_open(qq) +struct qmail *qq; +{ + int pim[2]; + int pie[2]; + + if (pipe(pim) == -1) return -1; + if (pipe(pie) == -1) { close(pim[0]); close(pim[1]); return -1; } + + switch(qq->pid = vfork()) { + case -1: + close(pim[0]); close(pim[1]); + close(pie[0]); close(pie[1]); + return -1; + case 0: + close(pim[1]); + close(pie[1]); + if (fd_move(0,pim[0]) == -1) _exit(120); + if (fd_move(1,pie[0]) == -1) _exit(120); + if (chdir(auto_qmail) == -1) _exit(120); + execv(*binqqargs,binqqargs); + _exit(120); + } + + qq->fdm = pim[1]; close(pim[0]); + qq->fde = pie[1]; close(pie[0]); + substdio_fdbuf(&qq->ss,write,qq->fdm,qq->buf,sizeof(qq->buf)); + qq->flagerr = 0; + return 0; +} + +unsigned long qmail_qp(qq) struct qmail *qq; +{ + return qq->pid; +} + +void qmail_fail(qq) struct qmail *qq; +{ + qq->flagerr = 1; +} + +void qmail_put(qq,s,len) struct qmail *qq; char *s; int len; +{ + if (!qq->flagerr) if (substdio_put(&qq->ss,s,len) == -1) qq->flagerr = 1; +} + +void qmail_puts(qq,s) struct qmail *qq; char *s; +{ + if (!qq->flagerr) if (substdio_puts(&qq->ss,s) == -1) qq->flagerr = 1; +} + +void qmail_from(qq,s) struct qmail *qq; char *s; +{ + if (substdio_flush(&qq->ss) == -1) qq->flagerr = 1; + close(qq->fdm); + substdio_fdbuf(&qq->ss,write,qq->fde,qq->buf,sizeof(qq->buf)); + qmail_put(qq,"F",1); + qmail_puts(qq,s); + qmail_put(qq,"",1); +} + +void qmail_to(qq,s) struct qmail *qq; char *s; +{ + qmail_put(qq,"T",1); + qmail_puts(qq,s); + qmail_put(qq,"",1); +} + +int qmail_close(qq) +struct qmail *qq; +{ + int wstat; + + qmail_put(qq,"",1); + if (!qq->flagerr) if (substdio_flush(&qq->ss) == -1) qq->flagerr = 1; + close(qq->fde); + + if (wait_pid(&wstat,qq->pid) != qq->pid) return QMAIL_WAITPID; + if (wait_crashed(wstat)) return QMAIL_CRASHED; + switch(wait_exitcode(wstat)) { + case 0: if (qq->flagerr) return QMAIL_BUG; return 0; + case 112: return QMAIL_USAGE; + case 115: return QMAIL_TOOLONG; + case 103: case 104: case 105: case 106: case 108: return QMAIL_SYS; + case 121: return QMAIL_READ; + case 122: return QMAIL_WRITE; + case 123: return QMAIL_NOMEM; + case 124: return QMAIL_TIMEOUT; + case 120: return QMAIL_EXECSOFT; + default: /* 101 or 102 */ return QMAIL_BUG; + } +} diff --git a/qmail.h b/qmail.h new file mode 100644 index 0000000..7864ea1 --- /dev/null +++ b/qmail.h @@ -0,0 +1,36 @@ +#ifndef QMAIL_H +#define QMAIL_H + +#include "substdio.h" + +struct qmail { + int flagerr; + unsigned long pid; + int fdm; + int fde; + substdio ss; + char buf[1024]; +} ; + +extern int qmail_open(); +extern void qmail_put(); +extern void qmail_puts(); +extern void qmail_from(); +extern void qmail_to(); +extern void qmail_fail(); +extern int qmail_close(); +extern unsigned long qmail_qp(); + +#define QMAIL_WAITPID -2 +#define QMAIL_CRASHED -3 +#define QMAIL_USAGE -4 +#define QMAIL_BUG -5 +#define QMAIL_SYS -6 +#define QMAIL_READ -7 +#define QMAIL_WRITE -8 +#define QMAIL_NOMEM -9 +#define QMAIL_EXECSOFT -11 +#define QMAIL_TIMEOUT -13 +#define QMAIL_TOOLONG -14 + +#endif diff --git a/quote.c b/quote.c new file mode 100644 index 0000000..9f97d93 --- /dev/null +++ b/quote.c @@ -0,0 +1,82 @@ +#include "stralloc.h" +#include "str.h" +#include "quote.h" + +/* +quote() encodes a box as per rfc 821 and rfc 822, +while trying to do as little quoting as possible. +no, 821 and 822 don't have the same encoding. they're not even close. +no special encoding here for bytes above 127. +*/ + +static char ok[128] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +,0,7,0,7,7,7,7,7,0,0,7,7,0,7,7,7 ,7,7,7,7,7,7,7,7,7,7,0,0,0,7,0,7 +,0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 ,7,7,7,7,7,7,7,7,7,7,7,0,0,0,7,7 +,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 ,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,0 +} ; + +static int doit(saout,sain) +stralloc *saout; +stralloc *sain; +{ + char ch; + int i; + int j; + + if (!stralloc_ready(saout,sain->len * 2 + 2)) return 0; + j = 0; + saout->s[j++] = '"'; + for (i = 0;i < sain->len;++i) + { + ch = sain->s[i]; + if ((ch == '\r') || (ch == '\n') || (ch == '"') || (ch == '\\')) + saout->s[j++] = '\\'; + saout->s[j++] = ch; + } + saout->s[j++] = '"'; + saout->len = j; + return 1; +} + +int quote_need(s,n) +char *s; +unsigned int n; +{ + unsigned char uch; + int i; + if (!n) return 0; + for (i = 0;i < n;++i) + { + uch = s[i]; + if (uch >= 128) return 1; + if (!ok[uch]) return 1; + } + if (s[0] == '.') return 1; + if (s[n - 1] == '.') return 1; + for (i = 0;i < n - 1;++i) if (s[i] == '.') if (s[i + 1] == '.') return 1; + return 0; +} + +int quote(saout,sain) +stralloc *saout; +stralloc *sain; +{ + if (quote_need(sain->s,sain->len)) return doit(saout,sain); + return stralloc_copy(saout,sain); +} + +static stralloc foo = {0}; + +int quote2(sa,s) +stralloc *sa; +char *s; +{ + int j; + j = str_rchr(s,'@'); + if (!stralloc_copys(&foo,s)) return 0; + if (!s[j]) return quote(sa,&foo); + foo.len = j; + if (!quote(sa,&foo)) return 0; + return stralloc_cats(sa,s + j); +} diff --git a/quote.h b/quote.h new file mode 100644 index 0000000..8ab7356 --- /dev/null +++ b/quote.h @@ -0,0 +1,8 @@ +#ifndef QUOTE_H +#define QUOTE_H + +extern int quote_need(); +extern int quote(); +extern int quote2(); + +#endif diff --git a/readwrite.h b/readwrite.h new file mode 100644 index 0000000..2a64968 --- /dev/null +++ b/readwrite.h @@ -0,0 +1,7 @@ +#ifndef READWRITE_H +#define READWRITE_H + +extern int read(); +extern int write(); + +#endif diff --git a/scan.h b/scan.h new file mode 100644 index 0000000..53ce703 --- /dev/null +++ b/scan.h @@ -0,0 +1,27 @@ +#ifndef SCAN_H +#define SCAN_H + +extern unsigned int scan_uint(); +extern unsigned int scan_xint(); +extern unsigned int scan_nbbint(); +extern unsigned int scan_ushort(); +extern unsigned int scan_xshort(); +extern unsigned int scan_nbbshort(); +extern unsigned int scan_ulong(); +extern unsigned int scan_xlong(); +extern unsigned int scan_nbblong(); + +extern unsigned int scan_plusminus(); +extern unsigned int scan_0x(); + +extern unsigned int scan_whitenskip(); +extern unsigned int scan_nonwhitenskip(); +extern unsigned int scan_charsetnskip(); +extern unsigned int scan_noncharsetnskip(); + +extern unsigned int scan_strncmp(); +extern unsigned int scan_memcmp(); + +extern unsigned int scan_long(); + +#endif diff --git a/scan_8long.c b/scan_8long.c new file mode 100644 index 0000000..8b3a6df --- /dev/null +++ b/scan_8long.c @@ -0,0 +1,11 @@ +#include "scan.h" + +unsigned int scan_8long(s,u) register char *s; register unsigned long *u; +{ + register unsigned int pos; register unsigned long result; + register unsigned long c; + pos = 0; result = 0; + while ((c = (unsigned long) (unsigned char) (s[pos] - '0')) < 8) + { result = result * 8 + c; ++pos; } + *u = result; return pos; +} diff --git a/scan_ulong.c b/scan_ulong.c new file mode 100644 index 0000000..27c41ea --- /dev/null +++ b/scan_ulong.c @@ -0,0 +1,11 @@ +#include "scan.h" + +unsigned int scan_ulong(s,u) register char *s; register unsigned long *u; +{ + register unsigned int pos; register unsigned long result; + register unsigned long c; + pos = 0; result = 0; + while ((c = (unsigned long) (unsigned char) (s[pos] - '0')) < 10) + { result = result * 10 + c; ++pos; } + *u = result; return pos; +} diff --git a/seek.h b/seek.h new file mode 100644 index 0000000..964fba3 --- /dev/null +++ b/seek.h @@ -0,0 +1,15 @@ +#ifndef SEEK_H +#define SEEK_H + +typedef unsigned long seek_pos; + +extern seek_pos seek_cur(); + +extern int seek_set(); +extern int seek_end(); + +extern int seek_trunc(); + +#define seek_begin(fd) (seek_set((fd),(seek_pos) 0)) + +#endif diff --git a/seek=l b/seek=l new file mode 100644 index 0000000..8f34e13 --- /dev/null +++ b/seek=l @@ -0,0 +1 @@ +seek_set.o diff --git a/seek_set.c b/seek_set.c new file mode 100644 index 0000000..f540664 --- /dev/null +++ b/seek_set.c @@ -0,0 +1,7 @@ +#include +#include "seek.h" + +#define SET 0 /* sigh */ + +int seek_set(fd,pos) int fd; seek_pos pos; +{ if (lseek(fd,(off_t) pos,SET) == -1) return -1; return 0; } diff --git a/setup.do b/setup.do new file mode 100644 index 0000000..d667234 --- /dev/null +++ b/setup.do @@ -0,0 +1,5 @@ +dependon it man install conf-bin conf-man BIN MAN +formake './install "`head -1 conf-bin`" < BIN' +formake './install "`head -1 conf-man`" < MAN' +./install "`head -1 conf-bin`" < BIN +./install "`head -1 conf-man`" < MAN diff --git a/sgetopt.3 b/sgetopt.3 new file mode 100644 index 0000000..bde0c2b --- /dev/null +++ b/sgetopt.3 @@ -0,0 +1,28 @@ +.TH sgetopt 3 +.SH NAME +sgetopt \- get option character from command line +.SH SYNTAX +.B #include +.SH DESCRIPTION +The +.B sgetopt +library is just like the +.B getopt +library, +except that it prints errors using +.B substdio +rather than +.BR stdio . + +See +.B getopt(3) +for interface details. +.SH VERSION +sgetopt version 1.9, 931201. +.SH AUTHOR +Placed into the public domain by Daniel J. Bernstein. +.SH "SEE ALSO" +getopt(3), +subgetopt(3), +subfd(3), +substdio(3) diff --git a/sgetopt.c b/sgetopt.c new file mode 100644 index 0000000..a8bffc0 --- /dev/null +++ b/sgetopt.c @@ -0,0 +1,54 @@ +/* sgetopt.c, sgetopt.h: (yet another) improved getopt clone, outer layer +D. J. Bernstein, djb@pobox.com. +Depends on subgetopt.h, substdio.h, subfd.h. +No system requirements. +19970208: Cleanups. +931201: Baseline. +No known patent problems. + +Documentation in sgetopt.3. +*/ + +#include "substdio.h" +#include "subfd.h" +#define SGETOPTNOSHORT +#include "sgetopt.h" +#define SUBGETOPTNOSHORT +#include "subgetopt.h" + +#define getopt sgetoptmine +#define optind subgetoptind +#define opterr sgetopterr +#define optproblem subgetoptproblem +#define optprogname sgetoptprogname + +int opterr = 1; +char *optprogname = 0; + +int getopt(argc,argv,opts) +int argc; +char **argv; +char *opts; +{ + int c; + char *s; + + if (!optprogname) { + optprogname = *argv; + if (!optprogname) optprogname = ""; + for (s = optprogname;*s;++s) if (*s == '/') optprogname = s + 1; + } + c = subgetopt(argc,argv,opts); + if (opterr) + if (c == '?') { + char chp[2]; chp[0] = optproblem; chp[1] = '\n'; + substdio_puts(subfderr,optprogname); + if (argv[optind] && (optind < argc)) + substdio_puts(subfderr,": illegal option -- "); + else + substdio_puts(subfderr,": option requires an argument -- "); + substdio_put(subfderr,chp,2); + substdio_flush(subfderr); + } + return c; +} diff --git a/sgetopt.h b/sgetopt.h new file mode 100644 index 0000000..5f89127 --- /dev/null +++ b/sgetopt.h @@ -0,0 +1,21 @@ +#ifndef SGETOPT_H +#define SGETOPT_H + +#ifndef SGETOPTNOSHORT +#define getopt sgetoptmine +#define optarg subgetoptarg +#define optind subgetoptind +#define optpos subgetoptpos +#define opterr sgetopterr +#define optproblem subgetoptproblem +#define optprogname sgetoptprogname +#define opteof subgetoptdone +#endif + +#include "subgetopt.h" + +extern int sgetoptmine(); +extern int sgetopterr; +extern char *sgetoptprogname; + +#endif diff --git a/sgetopt=0 b/sgetopt=0 new file mode 100644 index 0000000..7291e07 --- /dev/null +++ b/sgetopt=0 @@ -0,0 +1 @@ +sgetopt.3 diff --git a/sig.h b/sig.h new file mode 100644 index 0000000..9c3a28c --- /dev/null +++ b/sig.h @@ -0,0 +1,43 @@ +#ifndef SIG_H +#define SIG_H + +extern void sig_catch(); +extern void sig_block(); +extern void sig_unblock(); +extern void sig_blocknone(); +extern void sig_pause(); + +extern void sig_dfl(); + +extern void sig_miscignore(); +extern void sig_bugcatch(); + +extern void sig_pipeignore(); +extern void sig_pipedefault(); + +extern void sig_contblock(); +extern void sig_contunblock(); +extern void sig_contcatch(); +extern void sig_contdefault(); + +extern void sig_termblock(); +extern void sig_termunblock(); +extern void sig_termcatch(); +extern void sig_termdefault(); + +extern void sig_alarmblock(); +extern void sig_alarmunblock(); +extern void sig_alarmcatch(); +extern void sig_alarmdefault(); + +extern void sig_childblock(); +extern void sig_childunblock(); +extern void sig_childcatch(); +extern void sig_childdefault(); + +extern void sig_hangupblock(); +extern void sig_hangupunblock(); +extern void sig_hangupcatch(); +extern void sig_hangupdefault(); + +#endif diff --git a/sig=l b/sig=l new file mode 100644 index 0000000..a5456da --- /dev/null +++ b/sig=l @@ -0,0 +1,2 @@ +sig_catch.o +sig_pipe.o diff --git a/sig_catch.c b/sig_catch.c new file mode 100644 index 0000000..1888765 --- /dev/null +++ b/sig_catch.c @@ -0,0 +1,18 @@ +#include +#include "sig.h" +#include "hassgact.h" + +void sig_catch(sig,f) +int sig; +void (*f)(); +{ +#ifdef HASSIGACTION + struct sigaction sa; + sa.sa_handler = f; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sigaction(sig,&sa,(struct sigaction *) 0); +#else + signal(sig,f); /* won't work under System V, even nowadays---dorks */ +#endif +} diff --git a/sig_pipe.c b/sig_pipe.c new file mode 100644 index 0000000..594ae7d --- /dev/null +++ b/sig_pipe.c @@ -0,0 +1,5 @@ +#include +#include "sig.h" + +void sig_pipeignore() { sig_catch(SIGPIPE,SIG_IGN); } +void sig_pipedefault() { sig_catch(SIGPIPE,SIG_DFL); } diff --git a/slurp.c b/slurp.c new file mode 100644 index 0000000..7d50194 --- /dev/null +++ b/slurp.c @@ -0,0 +1,19 @@ +#include "stralloc.h" +#include "slurp.h" +#include "error.h" +#include "open.h" + +int slurp(fn,sa,bufsize) +char *fn; +stralloc *sa; +int bufsize; +{ + int fd; + fd = open_read(fn); + if (fd == -1) { + if (errno == error_noent) return 0; + return -1; + } + if (slurpclose(fd,sa,bufsize) == -1) return -1; + return 1; +} diff --git a/slurp.h b/slurp.h new file mode 100644 index 0000000..16aa656 --- /dev/null +++ b/slurp.h @@ -0,0 +1,6 @@ +#ifndef SLURP_H +#define SLURP_H + +extern int slurp(); + +#endif diff --git a/slurpclose.c b/slurpclose.c new file mode 100644 index 0000000..2fcef15 --- /dev/null +++ b/slurpclose.c @@ -0,0 +1,19 @@ +#include "stralloc.h" +#include "readwrite.h" +#include "slurpclose.h" +#include "error.h" + +int slurpclose(fd,sa,bufsize) +int fd; +stralloc *sa; +int bufsize; +{ + int r; + for (;;) { + if (!stralloc_readyplus(sa,bufsize)) { close(fd); return -1; } + r = read(fd,sa->s + sa->len,bufsize); + if (r == -1) if (errno == error_intr) continue; + if (r <= 0) { close(fd); return r; } + sa->len += r; + } +} diff --git a/slurpclose.h b/slurpclose.h new file mode 100644 index 0000000..57e9eec --- /dev/null +++ b/slurpclose.h @@ -0,0 +1,6 @@ +#ifndef SLURPCLOSE_H +#define SLURPCLOSE_H + +extern int slurpclose(); + +#endif diff --git a/str.h b/str.h new file mode 100644 index 0000000..e00773c --- /dev/null +++ b/str.h @@ -0,0 +1,14 @@ +#ifndef STR_H +#define STR_H + +extern unsigned int str_copy(); +extern int str_diff(); +extern int str_diffn(); +extern unsigned int str_len(); +extern unsigned int str_chr(); +extern unsigned int str_rchr(); +extern int str_start(); + +#define str_equal(s,t) (!str_diff((s),(t))) + +#endif diff --git a/str=l b/str=l new file mode 100644 index 0000000..e520d2c --- /dev/null +++ b/str=l @@ -0,0 +1,13 @@ +str_len.o +str_diff.o +str_diffn.o +str_cpy.o +str_chr.o +str_rchr.o +str_start.o +byte_chr.o +byte_rchr.o +byte_diff.o +byte_copy.o +byte_cr.o +byte_zero.o diff --git a/str_chr.c b/str_chr.c new file mode 100644 index 0000000..3691826 --- /dev/null +++ b/str_chr.c @@ -0,0 +1,19 @@ +#include "str.h" + +unsigned int str_chr(s,c) +register char *s; +int c; +{ + register char ch; + register char *t; + + ch = c; + t = s; + for (;;) { + if (!*t) break; if (*t == ch) break; ++t; + if (!*t) break; if (*t == ch) break; ++t; + if (!*t) break; if (*t == ch) break; ++t; + if (!*t) break; if (*t == ch) break; ++t; + } + return t - s; +} diff --git a/str_cpy.c b/str_cpy.c new file mode 100644 index 0000000..453d790 --- /dev/null +++ b/str_cpy.c @@ -0,0 +1,16 @@ +#include "str.h" + +unsigned int str_copy(s,t) +register char *s; +register char *t; +{ + register int len; + + len = 0; + for (;;) { + if (!(*s = *t)) return len; ++s; ++t; ++len; + if (!(*s = *t)) return len; ++s; ++t; ++len; + if (!(*s = *t)) return len; ++s; ++t; ++len; + if (!(*s = *t)) return len; ++s; ++t; ++len; + } +} diff --git a/str_diff.c b/str_diff.c new file mode 100644 index 0000000..18f8927 --- /dev/null +++ b/str_diff.c @@ -0,0 +1,17 @@ +#include "str.h" + +int str_diff(s,t) +register char *s; +register char *t; +{ + register char x; + + for (;;) { + x = *s; if (x != *t) break; if (!x) break; ++s; ++t; + x = *s; if (x != *t) break; if (!x) break; ++s; ++t; + x = *s; if (x != *t) break; if (!x) break; ++s; ++t; + x = *s; if (x != *t) break; if (!x) break; ++s; ++t; + } + return ((int)(unsigned int)(unsigned char) x) + - ((int)(unsigned int)(unsigned char) *t); +} diff --git a/str_diffn.c b/str_diffn.c new file mode 100644 index 0000000..89142f1 --- /dev/null +++ b/str_diffn.c @@ -0,0 +1,18 @@ +#include "str.h" + +int str_diffn(s,t,len) +register char *s; +register char *t; +unsigned int len; +{ + register char x; + + for (;;) { + if (!len--) return 0; x = *s; if (x != *t) break; if (!x) break; ++s; ++t; + if (!len--) return 0; x = *s; if (x != *t) break; if (!x) break; ++s; ++t; + if (!len--) return 0; x = *s; if (x != *t) break; if (!x) break; ++s; ++t; + if (!len--) return 0; x = *s; if (x != *t) break; if (!x) break; ++s; ++t; + } + return ((int)(unsigned int)(unsigned char) x) + - ((int)(unsigned int)(unsigned char) *t); +} diff --git a/str_len.c b/str_len.c new file mode 100644 index 0000000..2d2f88b --- /dev/null +++ b/str_len.c @@ -0,0 +1,15 @@ +#include "str.h" + +unsigned int str_len(s) +register char *s; +{ + register char *t; + + t = s; + for (;;) { + if (!*t) return t - s; ++t; + if (!*t) return t - s; ++t; + if (!*t) return t - s; ++t; + if (!*t) return t - s; ++t; + } +} diff --git a/str_rchr.c b/str_rchr.c new file mode 100644 index 0000000..1bf19d3 --- /dev/null +++ b/str_rchr.c @@ -0,0 +1,22 @@ +#include "str.h" + +unsigned int str_rchr(s,c) +register char *s; +int c; +{ + register char ch; + register char *t; + register char *u; + + ch = c; + t = s; + u = 0; + for (;;) { + if (!*t) break; if (*t == ch) u = t; ++t; + if (!*t) break; if (*t == ch) u = t; ++t; + if (!*t) break; if (*t == ch) u = t; ++t; + if (!*t) break; if (*t == ch) u = t; ++t; + } + if (!u) u = t; + return u - s; +} diff --git a/str_start.c b/str_start.c new file mode 100644 index 0000000..2750af8 --- /dev/null +++ b/str_start.c @@ -0,0 +1,15 @@ +#include "str.h" + +int str_start(s,t) +register char *s; +register char *t; +{ + register char x; + + for (;;) { + x = *t++; if (!x) return 1; if (x != *s++) return 0; + x = *t++; if (!x) return 1; if (x != *s++) return 0; + x = *t++; if (!x) return 1; if (x != *s++) return 0; + x = *t++; if (!x) return 1; if (x != *s++) return 0; + } +} diff --git a/stralloc.3 b/stralloc.3 new file mode 100644 index 0000000..3123521 --- /dev/null +++ b/stralloc.3 @@ -0,0 +1,160 @@ +.TH stralloc 3 +.SH NAME +stralloc \- dynamically allocated strings +.SH SYNTAX +.B #include + +int \fBstralloc_ready\fP(&\fIsa\fR,\fIlen\fR); +.br +int \fBstralloc_readyplus\fP(&\fIsa\fR,\fIlen\fR); + +int \fBstralloc_copy\fP(&\fIsa\fR,&\fIsa2\fR); +.br +int \fBstralloc_copys\fP(&\fIsa\fR,\fIbuf\fR); +.br +int \fBstralloc_copyb\fP(&\fIsa\fR,\fIbuf\fR,\fIlen\fR); + +int \fBstralloc_cat\fP(&\fIsa\fR,&\fIsa2\fR); +.br +int \fBstralloc_cats\fP(&\fIsa\fR,\fIbuf\fR); +.br +int \fBstralloc_catb\fP(&\fIsa\fR,\fIbuf\fR,\fIlen\fR); + +int \fBstralloc_append\fP(&\fIsa\fR,\fIbuf\fR); +.br +int \fBstralloc_0\fP(&\fIsa\fR); + +int \fBstralloc_starts\fP(&\fIsa\fR,\fIbuf\fR); + +stralloc \fIsa\fR = {0}; +.br +stralloc \fIsa2\fR = {0}; +.br +unsigned int \fIlen\fR; +.br +char *\fIbuf\fR; +.SH DESCRIPTION +A +.B stralloc +variable holds a string in dynamically allocated space. +String length is limited only by memory. +String contents are unrestricted. + +The +.B stralloc +structure has three components: +.I sa\fB.s +is a pointer to the string, or 0 if it is not allocated; +.I sa\fB.len +is the number of bytes in the string, if it is allocated; +.I sa\fB.a +is the number of bytes allocated for the string, if it is allocated. +A +.B stralloc +variable should be initialized to {0}, +meaning unallocated. + +.B stralloc_ready +makes sure that +.I sa +has enough space allocated for +.I len +characters. +It allocates extra space if necessary. + +.B stralloc_readyplus +makes sure that +.I sa +has enough space allocated for +.I len +characters more than its current length. +If +.I sa +is unallocated, +.B stralloc_readyplus +is the same as +.BR stralloc_ready . + +.B stralloc_copy +copies +.I sa2 +to +.IR sa , +allocating space if necessary. +Here +.I sa2 +is an allocated +.B stralloc +variable. + +.B stralloc_copys +copies a 0-terminated string, +.IR buf , +to +.IR sa , +without the 0. + +.B stralloc_copyb +copies +.I len +characters from +.I buf +to +.IR sa . + +.B stralloc_cat +appends +.I sa2 +to +.IR sa , +allocating space if necessary. +If +.I sa +is unallocated, +.B stralloc_cat +is the same as +.BR stralloc_copy . + +.B stralloc_cats +and +.B stralloc_catb +are analogous to +.B stralloc_copys +and +.BR stralloc_copyb . + +.B stralloc_append +adds a single character, +.IR *buf , +to +.IR sa , +allocating space if necessary. + +.B stralloc_0 +adds a single 0 character +to +.IR sa . + +.B stralloc_starts +returns 1 if the 0-terminated string +.IR buf , +without the 0, +is a prefix of +.IR sa . +.SH "ERROR HANDLING" +If a +.B stralloc +routine runs out of memory, +it leaves +.I sa +alone and returns 0, +setting +.B errno +appropriately. +On success it returns 1; +this guarantees that +.I sa +is allocated. +.SH "SEE ALSO" +alloc(3), +error(3) diff --git a/stralloc.h b/stralloc.h new file mode 100644 index 0000000..fca496c --- /dev/null +++ b/stralloc.h @@ -0,0 +1,21 @@ +#ifndef STRALLOC_H +#define STRALLOC_H + +#include "gen_alloc.h" + +GEN_ALLOC_typedef(stralloc,char,s,len,a) + +extern int stralloc_ready(); +extern int stralloc_readyplus(); +extern int stralloc_copy(); +extern int stralloc_cat(); +extern int stralloc_copys(); +extern int stralloc_cats(); +extern int stralloc_copyb(); +extern int stralloc_catb(); +extern int stralloc_append(); /* beware: this takes a pointer to 1 char */ +extern int stralloc_starts(); + +#define stralloc_0(sa) stralloc_append(sa,"") + +#endif diff --git a/stralloc=0 b/stralloc=0 new file mode 100644 index 0000000..12889aa --- /dev/null +++ b/stralloc=0 @@ -0,0 +1 @@ +stralloc.3 diff --git a/stralloc=l b/stralloc=l new file mode 100644 index 0000000..6aac39b --- /dev/null +++ b/stralloc=l @@ -0,0 +1,9 @@ +stralloc_eady.o +stralloc_pend.o +stralloc_copy.o +stralloc_opys.o +stralloc_opyb.o +stralloc_cat.o +stralloc_cats.o +stralloc_catb.o +stralloc_arts.o diff --git a/stralloc_arts.c b/stralloc_arts.c new file mode 100644 index 0000000..1ccb5a4 --- /dev/null +++ b/stralloc_arts.c @@ -0,0 +1,12 @@ +#include "byte.h" +#include "str.h" +#include "stralloc.h" + +int stralloc_starts(sa,s) +stralloc *sa; +char *s; +{ + int len; + len = str_len(s); + return (sa->len >= len) && byte_equal(s,len,sa->s); +} diff --git a/stralloc_cat.c b/stralloc_cat.c new file mode 100644 index 0000000..efbb112 --- /dev/null +++ b/stralloc_cat.c @@ -0,0 +1,9 @@ +#include "byte.h" +#include "stralloc.h" + +int stralloc_cat(sato,safrom) +stralloc *sato; +stralloc *safrom; +{ + return stralloc_catb(sato,safrom->s,safrom->len); +} diff --git a/stralloc_catb.c b/stralloc_catb.c new file mode 100644 index 0000000..67dbcc0 --- /dev/null +++ b/stralloc_catb.c @@ -0,0 +1,15 @@ +#include "stralloc.h" +#include "byte.h" + +int stralloc_catb(sa,s,n) +stralloc *sa; +char *s; +unsigned int n; +{ + if (!sa->s) return stralloc_copyb(sa,s,n); + if (!stralloc_readyplus(sa,n + 1)) return 0; + byte_copy(sa->s + sa->len,n,s); + sa->len += n; + sa->s[sa->len] = 'Z'; /* ``offensive programming'' */ + return 1; +} diff --git a/stralloc_cats.c b/stralloc_cats.c new file mode 100644 index 0000000..d300286 --- /dev/null +++ b/stralloc_cats.c @@ -0,0 +1,10 @@ +#include "byte.h" +#include "str.h" +#include "stralloc.h" + +int stralloc_cats(sa,s) +stralloc *sa; +char *s; +{ + return stralloc_catb(sa,s,str_len(s)); +} diff --git a/stralloc_copy.c b/stralloc_copy.c new file mode 100644 index 0000000..652aed6 --- /dev/null +++ b/stralloc_copy.c @@ -0,0 +1,9 @@ +#include "byte.h" +#include "stralloc.h" + +int stralloc_copy(sato,safrom) +stralloc *sato; +stralloc *safrom; +{ + return stralloc_copyb(sato,safrom->s,safrom->len); +} diff --git a/stralloc_eady.c b/stralloc_eady.c new file mode 100644 index 0000000..3a31f4b --- /dev/null +++ b/stralloc_eady.c @@ -0,0 +1,6 @@ +#include "alloc.h" +#include "stralloc.h" +#include "gen_allocdefs.h" + +GEN_ALLOC_ready(stralloc,char,s,len,a,i,n,x,30,stralloc_ready) +GEN_ALLOC_readyplus(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus) diff --git a/stralloc_opyb.c b/stralloc_opyb.c new file mode 100644 index 0000000..ac258b3 --- /dev/null +++ b/stralloc_opyb.c @@ -0,0 +1,14 @@ +#include "stralloc.h" +#include "byte.h" + +int stralloc_copyb(sa,s,n) +stralloc *sa; +char *s; +unsigned int n; +{ + if (!stralloc_ready(sa,n + 1)) return 0; + byte_copy(sa->s,n,s); + sa->len = n; + sa->s[n] = 'Z'; /* ``offensive programming'' */ + return 1; +} diff --git a/stralloc_opys.c b/stralloc_opys.c new file mode 100644 index 0000000..fdd7807 --- /dev/null +++ b/stralloc_opys.c @@ -0,0 +1,10 @@ +#include "byte.h" +#include "str.h" +#include "stralloc.h" + +int stralloc_copys(sa,s) +stralloc *sa; +char *s; +{ + return stralloc_copyb(sa,s,str_len(s)); +} diff --git a/stralloc_pend.c b/stralloc_pend.c new file mode 100644 index 0000000..a3443b8 --- /dev/null +++ b/stralloc_pend.c @@ -0,0 +1,5 @@ +#include "alloc.h" +#include "stralloc.h" +#include "gen_allocdefs.h" + +GEN_ALLOC_append(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus,stralloc_append) diff --git a/strerr.c b/strerr.c new file mode 100644 index 0000000..a6bc00c --- /dev/null +++ b/strerr.c @@ -0,0 +1,22 @@ +#include "stralloc.h" +#include "strerr.h" + +static stralloc sa = {0}; + +char *strerr(se) +struct strerr *se; +{ + strerr_sysinit(); + + if (!stralloc_copys(&sa,"")) return "out of memory"; + + while(se) { + if (se->x) if (!stralloc_cats(&sa,se->x)) return "out of memory"; + if (se->y) if (!stralloc_cats(&sa,se->y)) return "out of memory"; + if (se->z) if (!stralloc_cats(&sa,se->z)) return "out of memory"; + se = se->who; + } + + if (!stralloc_0(&sa)) return "out of memory"; + return sa.s; +} diff --git a/strerr.h b/strerr.h new file mode 100644 index 0000000..d18e833 --- /dev/null +++ b/strerr.h @@ -0,0 +1,80 @@ +#ifndef STRERR_H +#define STRERR_H + +struct strerr + { + struct strerr *who; + char *x; + char *y; + char *z; + } +; + +extern struct strerr strerr_sys; +extern void strerr_sysinit(); + +extern char *strerr(); +extern void strerr_warn(); +extern void strerr_die(); + +#define STRERR(r,se,a) \ +{ se.who = 0; se.x = a; se.y = 0; se.z = 0; return r; } + +#define STRERR_SYS(r,se,a) \ +{ se.who = &strerr_sys; se.x = a; se.y = 0; se.z = 0; return r; } +#define STRERR_SYS3(r,se,a,b,c) \ +{ se.who = &strerr_sys; se.x = a; se.y = b; se.z = c; return r; } + +#define strerr_warn6(x1,x2,x3,x4,x5,x6,se) \ +strerr_warn((x1),(x2),(x3),(x4),(x5),(x6),(struct strerr *) (se)) +#define strerr_warn5(x1,x2,x3,x4,x5,se) \ +strerr_warn((x1),(x2),(x3),(x4),(x5),(char *) 0,(struct strerr *) (se)) +#define strerr_warn4(x1,x2,x3,x4,se) \ +strerr_warn((x1),(x2),(x3),(x4),(char *) 0,(char *) 0,(struct strerr *) (se)) +#define strerr_warn3(x1,x2,x3,se) \ +strerr_warn((x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se)) +#define strerr_warn2(x1,x2,se) \ +strerr_warn((x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se)) +#define strerr_warn1(x1,se) \ +strerr_warn((x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se)) + +#define strerr_die6(e,x1,x2,x3,x4,x5,x6,se) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(struct strerr *) (se)) +#define strerr_die5(e,x1,x2,x3,x4,x5,se) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(char *) 0,(struct strerr *) (se)) +#define strerr_die4(e,x1,x2,x3,x4,se) \ +strerr_die((e),(x1),(x2),(x3),(x4),(char *) 0,(char *) 0,(struct strerr *) (se)) +#define strerr_die3(e,x1,x2,x3,se) \ +strerr_die((e),(x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se)) +#define strerr_die2(e,x1,x2,se) \ +strerr_die((e),(x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se)) +#define strerr_die1(e,x1,se) \ +strerr_die((e),(x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se)) + +#define strerr_die6sys(e,x1,x2,x3,x4,x5,x6) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),&strerr_sys) +#define strerr_die5sys(e,x1,x2,x3,x4,x5) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(char *) 0,&strerr_sys) +#define strerr_die4sys(e,x1,x2,x3,x4) \ +strerr_die((e),(x1),(x2),(x3),(x4),(char *) 0,(char *) 0,&strerr_sys) +#define strerr_die3sys(e,x1,x2,x3) \ +strerr_die((e),(x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,&strerr_sys) +#define strerr_die2sys(e,x1,x2) \ +strerr_die((e),(x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,&strerr_sys) +#define strerr_die1sys(e,x1) \ +strerr_die((e),(x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,&strerr_sys) + +#define strerr_die6x(e,x1,x2,x3,x4,x5,x6) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(struct strerr *) 0) +#define strerr_die5x(e,x1,x2,x3,x4,x5) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(char *) 0,(struct strerr *) 0) +#define strerr_die4x(e,x1,x2,x3,x4) \ +strerr_die((e),(x1),(x2),(x3),(x4),(char *) 0,(char *) 0,(struct strerr *) 0) +#define strerr_die3x(e,x1,x2,x3) \ +strerr_die((e),(x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,(struct strerr *) 0) +#define strerr_die2x(e,x1,x2) \ +strerr_die((e),(x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) 0) +#define strerr_die1x(e,x1) \ +strerr_die((e),(x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) 0) + +#endif diff --git a/strerr=l b/strerr=l new file mode 100644 index 0000000..f3580a1 --- /dev/null +++ b/strerr=l @@ -0,0 +1,3 @@ +strerr.o +strerr_sys.o +strerr_die.o diff --git a/strerr_die.c b/strerr_die.c new file mode 100644 index 0000000..6092020 --- /dev/null +++ b/strerr_die.c @@ -0,0 +1,37 @@ +#include "substdio.h" +#include "subfd.h" +#include "exit.h" +#include "strerr.h" + +void strerr_warn(x1,x2,x3,x4,x5,x6,se) +char *x1; char *x2; char *x3; char *x4; char *x5; char *x6; +struct strerr *se; +{ + strerr_sysinit(); + + if (x1) substdio_puts(subfderr,x1); + if (x2) substdio_puts(subfderr,x2); + if (x3) substdio_puts(subfderr,x3); + if (x4) substdio_puts(subfderr,x4); + if (x5) substdio_puts(subfderr,x5); + if (x6) substdio_puts(subfderr,x6); + + while(se) { + if (se->x) substdio_puts(subfderr,se->x); + if (se->y) substdio_puts(subfderr,se->y); + if (se->z) substdio_puts(subfderr,se->z); + se = se->who; + } + + substdio_puts(subfderr,"\n"); + substdio_flush(subfderr); +} + +void strerr_die(e,x1,x2,x3,x4,x5,x6,se) +int e; +char *x1; char *x2; char *x3; char *x4; char *x5; char *x6; +struct strerr *se; +{ + strerr_warn(x1,x2,x3,x4,x5,x6,se); + _exit(e); +} diff --git a/strerr_sys.c b/strerr_sys.c new file mode 100644 index 0000000..198198b --- /dev/null +++ b/strerr_sys.c @@ -0,0 +1,12 @@ +#include "error.h" +#include "strerr.h" + +struct strerr strerr_sys; + +void strerr_sysinit() +{ + strerr_sys.who = 0; + strerr_sys.x = error_str(errno); + strerr_sys.y = ""; + strerr_sys.z = ""; +} diff --git a/subfd.3 b/subfd.3 new file mode 100644 index 0000000..6859e64 --- /dev/null +++ b/subfd.3 @@ -0,0 +1,61 @@ +.TH subfd 3 +.SH NAME +subfd \- standard input, output, error for substdio +.SH SYNTAX +.B #include + +substdio *\fBsubfdin\fP; +.br +substdio *\fBsubfdout\fP; +.br +substdio *\fBsubfderr\fP; + +int \fBsubfd_read\fP(\fIfd\fR,\fIbuf\fR,\fIlen\fR); + +substdio *\fBsubfdinsmall\fP; +.br +substdio *\fBsubfdoutsmall\fP; + +int \fBsubfd_readsmall\fP(\fIfd\fR,\fIbuf\fR,\fIlen\fR); + +int \fIfd\fR; +.br +char *\fIbuf\fR; +.br +int \fIlen\fR; +.SH DESCRIPTION +.B subfderr +writes data to descriptor 2. + +.B subfdout +writes data to descriptor 1. + +.B subfdin +reads data from descriptor 0. +It coordinates with +.BR subfdout : +it flushes +.B subfdout +before refilling its buffer. +This eliminates the need for +.B subfdout +flushing in most programs. +To set up the same flushing mechanism for another input descriptor, +use +.B subfd_read +in place of +.BR read . + +.BR subfdoutsmall , +.BR subfd_readsmall , +and +.B subfdinsmall +behave the same way as +.BR subfdout , +.BR subfd_read , +and +.BR subfdin , +except that they use small (256-byte) buffers. +This is appropriate for programs that read data in small chunks. +.SH "SEE ALSO" +substdio(3) diff --git a/subfd.h b/subfd.h new file mode 100644 index 0000000..bcb2e1e --- /dev/null +++ b/subfd.h @@ -0,0 +1,15 @@ +#ifndef SUBFD_H +#define SUBFD_H + +#include "substdio.h" + +extern substdio *subfdin; +extern substdio *subfdinsmall; +extern substdio *subfdout; +extern substdio *subfdoutsmall; +extern substdio *subfderr; + +extern int subfd_read(); +extern int subfd_readsmall(); + +#endif diff --git a/subfd=0 b/subfd=0 new file mode 100644 index 0000000..9e10976 --- /dev/null +++ b/subfd=0 @@ -0,0 +1 @@ +subfd.3 diff --git a/subfderr.c b/subfderr.c new file mode 100644 index 0000000..011ab0f --- /dev/null +++ b/subfderr.c @@ -0,0 +1,7 @@ +#include "readwrite.h" +#include "substdio.h" +#include "subfd.h" + +char subfd_errbuf[256]; +static substdio it = SUBSTDIO_FDBUF(write,2,subfd_errbuf,256); +substdio *subfderr = ⁢ diff --git a/subgetopt.3 b/subgetopt.3 new file mode 100644 index 0000000..aae03aa --- /dev/null +++ b/subgetopt.3 @@ -0,0 +1,357 @@ +.TH subgetopt 3 +.SH NAME +subgetopt \- get option character from command line +.SH SYNTAX +.B #include + +char *\fBsgoptarg\fP; +.br +int \fBsgoptind\fP; +.br +int \fBsgoptpos\fP; +.br +int \fBsgoptdone\fP; +.br +int \fBsgoptproblem\fP; + +int \fBsgopt(\fP\fIargc,argv,opts\fR\fB)\fP; + +int \fIargc\fR; +.br +char **\fIargv\fR; +.br +char *\fIopts\fR; +.SH DESCRIPTION +.B sgopt +returns the next valid command-line option character +from +.IR argv . + +Valid option characters are listed in the +.I opts +string. +.I opts +may be empty. +A character in +.I opts +may be followed by a colon, +in which case it +takes an +.I option argument\fR. +Avoid using the characters ?, :, and \- as option characters. + +Below +.I option argument +is abbreviated +as +.I optarg +and +.I command-line argument +is abbreviated as +.IR cmdarg . + +Options are listed in cmdargs which begin with +a minus sign. +Several options which do not take optargs may be combined +into one cmdarg. + +An option which takes an optarg may be handled in two ways. +If it appears at the very end of a cmdarg, +then the entire next cmdarg is the optarg. +But if there are any characters in the cmdarg +after the option character, +then those characters form the optarg. +The optarg is returned in +.BR sgoptarg . +Next time +.B sgopt +looks at the cmdarg which follows the optarg. + +If a cmdarg does not begin with a hyphen, +or if it is a lone hyphen not followed by any characters, +or if it begins with two hyphens, +then it terminates option processing, +and +.B sgopt +returns an appropriate code. +If there are two hyphens, +.B sgopt +will advance attention to the next cmdarg, +so it can be called again to read further options. +.SH "PROPER USAGE" +.B sgoptproblem +should be used only when +.B sgopt +returns ?. +.B sgoptind +and +.B sgoptpos +are defined all the time. +.B sgoptarg +is defined all the time; +it is null unless +.B sgopt +has just returned an option with optarg. + +.B sgopt +is typically used as follows. + +.EX +#include + +main(argc,argv) int argc; char **argv; { int opt; + +while ((opt = sgopt(argc,argv,"a:s")) != sgoptdone) +.br + switch(opt) { +.br + case 'a': +.br + printf("opt a with optarg %s\\n",sgoptarg); break; +.br + case 's': +.br + printf("opt s with no optarg\\n"); break; +.br + case '?': +.br + if (argv[sgoptind] && (sgoptind < argc)) +.br + printf("illegal opt %c\\n",sgoptproblem); +.br + else +.br + printf("missing arg, opt %c\\n",sgoptproblem); +.br + exit(1); +.br + } + +argv += sgoptind; +.br +while (*argv) printf("argument %s\\n",*argv++); +.br +exit(0); +.br +} +.EE + +The end of the command line is +marked by either +.IR argc , +or a null pointer in +.IR argv , +whichever comes first. +Normally +these two markers coincide, +so it is redundant +to test for +both +.I argv\fB[sgoptind] +and +.B sgoptind < \fIargc\fR. +The above code shows both tests as an illustration. + +.B Multiple option sets: +One useful technique is to call +.B sgopt +with a primary +.I opts +until it returns EOF, +then call +.B sgopt +with a secondary +.I opts +until it returns EOF. +The user can provide primary options, then a double hyphen, +and then secondary options. +No special handling is needed if some or all of the options are +omitted. +The same technique can be used for any number of option sets +in series. + +.B Multiple command lines: +Before parsing a new +.BR argv , +make sure to +set +.B sgoptind +and +.B sgoptpos +back to +1 and 0. +.SH "PARSING STAGES" +.B sgopt +keeps track of its position in +.I argv +with +.B sgoptind +and +.BR sgoptpos , +which are initialized to 1 and 0. +It looks at +.I argv\fB[sgoptind][sgoptpos] +and following characters. + +.B sgopt +indicates +that no more options are available by +returning +.BR sgoptdone , +which is initialized to +.BR SUBGETOPTDONE , +which is defined as \-1. + +.B sgopt +begins by setting +.B optarg +to null. + +.B Ending conditions: +If +.I argv +is null, or +.B sgoptind +is larger than +.IR argc , +or the current cmdarg +.I argv\fB[sgoptind] +is null, +then +.B sgopt +returns +.BR optdone . + +.B Stage one: +If the current character +is zero, +.B sgopt +moves to the beginning of the next cmdarg. +It then checks the ending conditions again. + +.B Stage two: +If +the current position is the begining of the cmdarg, +.B sgopt +checks whether +the current character +is a minus sign. +If not it returns +.BR optdone . +It then +moves +to the next character. +If that character is zero, +.B sgopt +moves +back to the beginning of the cmdarg, +and returns +.BR sgoptdone . +If the character is a minus sign, +.B sgopt +moves to the beginning of the next cmdarg, +and returns +.BR sgoptdone . + +.B Stage three: +.B sgopt +records the current character, +.IR c , +and moves to the next character. +There are three possibilities: +(1) +.I c +is an option character without optarg in +.IR opts , +or +(2) +.I c +is an option character with optarg in +.IR opts , +or +(3) +.I c +does not appear in +.IR opts . + +(1) +If +.I c +appears as an option character without optarg in +.IR opts , +.B sgopt +returns +.IR c . + +(2) +If +.I c +appears as an option character with optarg in +.IR opts , +.B sgopt +sets +.B sgoptarg +to the current position, +and moves to the next cmdarg. +If +.B sgoptarg +is nonempty, +.B sgopt +returns +.IR c . + +Then +.B sgopt +sets +.B sgoptarg +to +the current cmdarg. +If +the current cmdarg is null, +or past +.IR argc , +.B sgopt +sets +.B sgoptproblem +to +.I c +and returns ?. +Otherwise +.B sgopt +moves to the next +argument +and returns +.IR c . + +(2) +If +.I c +does not appear in +.IR opts , +.B sgopt +sets +.B sgoptproblem +to +.I c +and returns ?. +.SH "SYNTAX NOTE" +.B sgopt +is actually a macro abbreviation for +.BR subgetopt . +The external +.B sg +variables are also macros +for +.BR subget . +These macros are defined in +.BR , +unless +.B SUBGETOPTNOSHORT +is defined +when +.B +is included. +.SH VERSION +subgetopt version 0.9, 931129. +.SH AUTHOR +Placed into the public domain by Daniel J. Bernstein. diff --git a/subgetopt.c b/subgetopt.c new file mode 100644 index 0000000..dacf376 --- /dev/null +++ b/subgetopt.c @@ -0,0 +1,79 @@ +/* subgetopt.c, subgetopt.h: (yet another) improved getopt clone, inner layer +D. J. Bernstein, djb@pobox.com. +No dependencies. +No system requirements. +19970228: Cleanups. +931129: Adapted from getopt.c. +No known patent problems. + +Documentation in subgetopt.3. +*/ + +#define SUBGETOPTNOSHORT +#include "subgetopt.h" + +#define sgopt subgetopt +#define optind subgetoptind +#define optpos subgetoptpos +#define optarg subgetoptarg +#define optproblem subgetoptproblem +#define optdone subgetoptdone + +int optind = 1; +int optpos = 0; +char *optarg = 0; +int optproblem = 0; +int optdone = SUBGETOPTDONE; + +int sgopt(argc,argv,opts) +int argc; +char **argv; +char *opts; +{ + int c; + char *s; + + optarg = 0; + if (!argv || (optind >= argc) || !argv[optind]) return optdone; + if (optpos && !argv[optind][optpos]) { + ++optind; + optpos = 0; + if ((optind >= argc) || !argv[optind]) return optdone; + } + if (!optpos) { + if (argv[optind][0] != '-') return optdone; + ++optpos; + c = argv[optind][1]; + if ((c == '-') || (c == 0)) { + if (c) ++optind; + optpos = 0; + return optdone; + } + /* otherwise c is reassigned below */ + } + c = argv[optind][optpos]; + ++optpos; + s = opts; + while (*s) { + if (c == *s) { + if (s[1] == ':') { + optarg = argv[optind] + optpos; + ++optind; + optpos = 0; + if (!*optarg) { + optarg = argv[optind]; + if ((optind >= argc) || !optarg) { /* argument past end */ + optproblem = c; + return '?'; + } + ++optind; + } + } + return c; + } + ++s; + if (*s == ':') ++s; + } + optproblem = c; + return '?'; +} diff --git a/subgetopt.h b/subgetopt.h new file mode 100644 index 0000000..d26c62a --- /dev/null +++ b/subgetopt.h @@ -0,0 +1,24 @@ +#ifndef SUBGETOPT_H +#define SUBGETOPT_H + +#ifndef SUBGETOPTNOSHORT +#define sgopt subgetopt +#define sgoptarg subgetoptarg +#define sgoptind subgetoptind +#define sgoptpos subgetoptpos +#define sgoptproblem subgetoptproblem +#define sgoptprogname subgetoptprogname +#define sgoptdone subgetoptdone +#endif + +#define SUBGETOPTDONE -1 + +extern int subgetopt(); +extern char *subgetoptarg; +extern int subgetoptind; +extern int subgetoptpos; +extern int subgetoptproblem; +extern char *subgetoptprogname; +extern int subgetoptdone; + +#endif diff --git a/subgetopt=0 b/subgetopt=0 new file mode 100644 index 0000000..38ed342 --- /dev/null +++ b/subgetopt=0 @@ -0,0 +1 @@ +subgetopt.3 diff --git a/subscribe.c b/subscribe.c new file mode 100644 index 0000000..fee21e2 --- /dev/null +++ b/subscribe.c @@ -0,0 +1,127 @@ +#include "stralloc.h" +#include "getln.h" +#include "readwrite.h" +#include "substdio.h" +#include "strerr.h" +#include "open.h" +#include "byte.h" +#include "case.h" +#include "lock.h" +#include "error.h" +#include "uint32.h" +#include "subscribe.h" + +static stralloc addr = {0}; +static stralloc line = {0}; +static stralloc fnnew = {0}; +static stralloc fn = {0}; + +static int fd; +static substdio ss; +static char ssbuf[256]; +static int fdnew; +static substdio ssnew; +static char ssnewbuf[256]; + +static int doit(userhost,flagadd) +char *userhost; +int flagadd; +{ + int j; + uint32 h; + char ch; + int match; + int flagwasthere; + + if (userhost[str_chr(userhost,'\n')]) return -8; + if (!stralloc_copys(&addr,"T")) return -2; + if (!stralloc_cats(&addr,userhost)) return -2; + if (addr.len > 401) return -7; + + j = byte_rchr(addr.s,addr.len,'@'); + if (j == addr.len) return -6; + case_lowerb(addr.s + j + 1,addr.len - j - 1); + + h = 5381; + for (j = 0;j < addr.len;++j) + h = (h + (h << 5)) ^ (uint32) (unsigned char) addr.s[j]; + ch = 64 + (h % 53); + + if (!stralloc_0(&addr)) return -2; + + if (!stralloc_copys(&fn,"subscribers/")) return -2; + if (!stralloc_catb(&fn,&ch,1)) return -2; + if (!stralloc_copy(&fnnew,&fn)) return -2; + if (!stralloc_cats(&fnnew,"n")) return -2; + if (!stralloc_0(&fnnew)) return -2; + if (!stralloc_0(&fn)) return -2; + + fdnew = open_trunc(fnnew.s); + if (fdnew == -1) return -4; + substdio_fdbuf(&ssnew,write,fdnew,ssnewbuf,sizeof(ssnewbuf)); + + flagwasthere = 0; + + fd = open_read(fn.s); + if (fd == -1) { + if (errno != error_noent) { close(fdnew); return -3; } + } + else { + substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); + + for (;;) { + if (getln(&ss,&line,&match,'\0') == -1) { close(fd); close(fdnew); return -3; } + if (!match) break; + if (line.len == addr.len) + if (!byte_diff(line.s,line.len,addr.s)) { + flagwasthere = 1; + if (!flagadd) + continue; + } + if (substdio_bput(&ssnew,line.s,line.len) == -1) { close(fd); close(fdnew); return -4; } + } + + close(fd); + } + + if (flagadd && !flagwasthere) + if (substdio_bput(&ssnew,addr.s,addr.len) == -1) { close(fdnew); return -4; } + + if (substdio_flush(&ssnew) == -1) { close(fdnew); return -4; } + if (fsync(fdnew) == -1) { close(fdnew); return -4; } + close(fdnew); + + if (rename(fnnew.s,fn.s) == -1) return -5; + return flagadd ^ flagwasthere; +} + +struct strerr subscribe_err; + +int subscribe(userhost,flagadd) +char *userhost; +int flagadd; +{ + int fdlock; + int r; + + fdlock = open_append("lock"); + if (fdlock == -1) + STRERR_SYS(-1,subscribe_err,"unable to open lock: ") + if (lock_ex(fdlock) == -1) { + close(fdlock); + STRERR_SYS(-1,subscribe_err,"unable to obtain lock: ") + } + + r = doit(userhost,flagadd); + close(fdlock); + + if (r == -2) STRERR(-1,subscribe_err,"out of memory") + if (r == -3) STRERR_SYS3(-1,subscribe_err,"unable to read ",fn.s,": ") + if (r == -4) STRERR_SYS3(-1,subscribe_err,"unable to write ",fnnew.s,": ") + if (r == -5) STRERR_SYS3(-1,subscribe_err,"unable to move temporary file to ",fn.s,": ") + if (r == -6) STRERR(-2,subscribe_err,"address does not contain @") + if (r == -7) STRERR(-2,subscribe_err,"address is too long") + if (r == -8) STRERR(-2,subscribe_err,"address contains newline") + + return r; +} diff --git a/subscribe.h b/subscribe.h new file mode 100644 index 0000000..48a2f1c --- /dev/null +++ b/subscribe.h @@ -0,0 +1,10 @@ +#ifndef SUBSCRIBE_H +#define SUBSCRIBE_H + +#include "strerr.h" + +extern struct strerr subscribe_err; + +extern int subscribe(); + +#endif diff --git a/substdi.c b/substdi.c new file mode 100644 index 0000000..42407a1 --- /dev/null +++ b/substdi.c @@ -0,0 +1,91 @@ +#include "substdio.h" +#include "byte.h" +#include "error.h" + +static int oneread(op,fd,buf,len) +register int (*op)(); +register int fd; +register char *buf; +register int len; +{ + register int r; + + for (;;) { + r = op(fd,buf,len); + if (r == -1) if (errno == error_intr) continue; + return r; + } +} + +static int getthis(s,buf,len) +register substdio *s; +register char *buf; +register int len; +{ + register int r; + register int q; + + r = s->p; + q = r - len; + if (q > 0) { r = len; s->p = q; } else s->p = 0; + byte_copy(buf,r,s->x + s->n); + s->n += r; + return r; +} + +int substdio_feed(s) +register substdio *s; +{ + register int r; + register int q; + + if (s->p) return s->p; + q = s->n; + r = oneread(s->op,s->fd,s->x,q); + if (r <= 0) return r; + s->p = r; + q -= r; + s->n = q; + if (q > 0) /* damn, gotta shift */ byte_copyr(s->x + q,r,s->x); + return r; +} + +int substdio_bget(s,buf,len) +register substdio *s; +register char *buf; +register int len; +{ + register int r; + + if (s->p > 0) return getthis(s,buf,len); + r = s->n; if (r <= len) return oneread(s->op,s->fd,buf,r); + r = substdio_feed(s); if (r <= 0) return r; + return getthis(s,buf,len); +} + +int substdio_get(s,buf,len) +register substdio *s; +register char *buf; +register int len; +{ + register int r; + + if (s->p > 0) return getthis(s,buf,len); + if (s->n <= len) return oneread(s->op,s->fd,buf,len); + r = substdio_feed(s); if (r <= 0) return r; + return getthis(s,buf,len); +} + +char *substdio_peek(s) +register substdio *s; +{ + return s->x + s->n; +} + +void substdio_seek(s,len) +register substdio *s; +register int len; +{ + s->n += len; + s->p -= len; +} diff --git a/substdio.3 b/substdio.3 new file mode 100644 index 0000000..2bb459d --- /dev/null +++ b/substdio.3 @@ -0,0 +1,115 @@ +.TH substdio 3 +.SH NAME +substdio \- the Sub-Standard Input/Output Library +.SH SYNTAX +.B #include + +void \fBsubstdio_fdbuf\fP(&\fIs\fR,\fIop\fR,\fIfd\fR,\fIbuf\fR,\fIlen\fR); + +int \fBsubstdio_fileno\fP(&\fIs\fR); + +substdio \fIs\fR; +.br +int (*\fIop\fR)(); +.br +int \fIfd\fR; +.br +char *\fIbuf\fR; +.br +int \fIlen\fR; +.SH DESCRIPTION +.B substdio +is the Sub-Standard I/O Library. +.B substdio +contains only a few of the features of stdio; +it is a fast, lightweight, low-level library, +suitable for use as a component of higher-level I/O libraries. + +The point of +.B substdio +is to provide buffered I/O. +The basic object in +.B substdio +is the +.B substdio +structure; +a +.B substdio +variable stores +an operation, +a descriptor, +and +a pointer into a buffer of some nonzero length. +The +.B substdio +operations read data from the buffer, +filling the buffer as necessary using the operation on the descriptor, +or write data to the buffer, +flushing the buffer as necessary using the operation on the descriptor. +Input and output operations cannot be mixed. + +.B substdio_fdbuf +initializes a +.B substdio +variable. +The operation is +.IR op . +The descriptor is +.IR fd . +The buffer is +.IR buf , +an array of +.I len +chars. + +.I op +will be called as +.I op\fR(\fIfd\fR,\fIx\fR,\fIn\fR). +Here +.I x +is a pointer to an array of characters of length +.IR n ; +.I op +must read some characters from +.I fd +to that array, or write some characters to +.I fd +from that array. +The return value from +.I op +must be the number of characters read or written. +0 characters read means end of input; +0 characters written means that the write operation +should be tried again immediately. +On error, +.I op +must return -1, +setting +.B errno +appropriately, without reading or writing anything. +Most errors are returned directly to the +.B substdio +caller, but an error of +.B error_intr +means that the operation should be tried again immediately. + +There is a +.B SUBSTDIO_FDBUF +macro that can be used to statically initialize a +.B substdio +variable: + +.EX + substdio s = SUBSTDIO_FDBUF(op,fd,buf,len); +.EE + +.B substdio_fileno +returns the +descriptor for an initialized +.B substdio +variable. +.SH "SEE ALSO" +substdio_in(3), +substdio_out(3), +substdio_copy(3), +error(3) diff --git a/substdio.c b/substdio.c new file mode 100644 index 0000000..d03dff2 --- /dev/null +++ b/substdio.c @@ -0,0 +1,15 @@ +#include "substdio.h" + +void substdio_fdbuf(s,op,fd,buf,len) +register substdio *s; +register int (*op)(); +register int fd; +register char *buf; +register int len; +{ + s->x = buf; + s->fd = fd; + s->op = op; + s->p = 0; + s->n = len; +} diff --git a/substdio.h b/substdio.h new file mode 100644 index 0000000..c3f7f7d --- /dev/null +++ b/substdio.h @@ -0,0 +1,47 @@ +#ifndef SUBSTDIO_H +#define SUBSTDIO_H + +typedef struct substdio { + char *x; + int p; + int n; + int fd; + int (*op)(); +} substdio; + +#define SUBSTDIO_FDBUF(op,fd,buf,len) { (buf), 0, (len), (fd), (op) } + +extern void substdio_fdbuf(); + +extern int substdio_flush(); +extern int substdio_put(); +extern int substdio_bput(); +extern int substdio_putflush(); +extern int substdio_puts(); +extern int substdio_bputs(); +extern int substdio_putsflush(); + +extern int substdio_get(); +extern int substdio_bget(); +extern int substdio_feed(); + +extern char *substdio_peek(); +extern void substdio_seek(); + +#define substdio_fileno(s) ((s)->fd) + +#define SUBSTDIO_INSIZE 8192 +#define SUBSTDIO_OUTSIZE 8192 + +#define substdio_PEEK(s) ( (s)->x + (s)->n ) +#define substdio_SEEK(s,len) ( ( (s)->p -= (len) ) , ( (s)->n += (len) ) ) + +#define substdio_BPUTC(s,c) \ + ( ((s)->n != (s)->p) \ + ? ( (s)->x[(s)->p++] = (c), 0 ) \ + : substdio_bput((s),&(c),1) \ + ) + +extern int substdio_copy(); + +#endif diff --git a/substdio=0 b/substdio=0 new file mode 100644 index 0000000..1da81e2 --- /dev/null +++ b/substdio=0 @@ -0,0 +1 @@ +substdio.3 diff --git a/substdio=l b/substdio=l new file mode 100644 index 0000000..074aa76 --- /dev/null +++ b/substdio=l @@ -0,0 +1,5 @@ +substdio.o +substdi.o +substdo.o +subfderr.o +substdio_copy.o diff --git a/substdio_copy.3 b/substdio_copy.3 new file mode 100644 index 0000000..6fc02e6 --- /dev/null +++ b/substdio_copy.3 @@ -0,0 +1,41 @@ +.TH substdio_copy 3 +.SH NAME +substdio_copy \- copy an entire input to an output +.SH SYNTAX +.B #include + +int \fBsubstdio_copy\fP(&\fIsout\fR,&\fIsin\fR); + +substdio \fIsout\fR; +.br +substdio \fIsin\fR; +.SH DESCRIPTION +.B substdio_copy +reads characters from +.I sin +until end of file, +writing each character to +.IR sout . +It then returns 0. +It does not flush +.IR sout . + +Upon a +.I sin +error, +.B substdio_copy +returns -2, +leaving +.B errno +set appropriately. + +Upon a +.I sout +error, +.B substdio_copy +returns -3, +leaving +.B errno +set appropriately. +.SH "SEE ALSO" +substdio(3) diff --git a/substdio_copy.c b/substdio_copy.c new file mode 100644 index 0000000..71cf200 --- /dev/null +++ b/substdio_copy.c @@ -0,0 +1,18 @@ +#include "substdio.h" + +int substdio_copy(ssout,ssin) +register substdio *ssout; +register substdio *ssin; +{ + register int n; + register char *x; + + for (;;) { + n = substdio_feed(ssin); + if (n < 0) return -2; + if (!n) return 0; + x = substdio_PEEK(ssin); + if (substdio_put(ssout,x,n) == -1) return -3; + substdio_SEEK(ssin,n); + } +} diff --git a/substdio_copy=0 b/substdio_copy=0 new file mode 100644 index 0000000..1af3455 --- /dev/null +++ b/substdio_copy=0 @@ -0,0 +1 @@ +substdio_copy.3 diff --git a/substdio_in.3 b/substdio_in.3 new file mode 100644 index 0000000..f81d7a8 --- /dev/null +++ b/substdio_in.3 @@ -0,0 +1,140 @@ +.TH substdio_in 3 +.SH NAME +substdio_in \- substdio input routines +.SH SYNTAX +.B #include + +int \fBsubstdio_get\fP(&\fIs\fR,\fIto\fR,\fIlen\fR); + +int \fBsubstdio_bget\fP(&\fIs\fR,\fIto\fR,\fIlen\fR); + +int \fBsubstdio_feed\fP(&\fIs\fR); + +char *\fBsubstdio_peek\fP(&\fIs\fR); + +void \fBsubstdio_seek\fP(&\fIs\fR,\fIlen\fR); + +substdio \fIs\fR; +.br +char *\fIto\fR; +.br +int \fIlen\fR; +.SH DESCRIPTION +.B substdio_get +reads at most +.I len +characters from +.I s +into the character array +.IR to . +It returns the number of characters read, +0 for end of file, +or -1 for error, +setting +.B errno +appropriately. + +.B substdio_bget +has the same function as +.BR substdio_get . +The difference is what happens when there is no buffered data and +.I len +exceeds the buffer size: +.B substdio_get +tries to read +.I len +characters, whereas +.B substdio_bget +tries to read one buffer of characters. +In some cases +.B substdio_bget +will be more efficient than +.BR substdio_get . + +.B substdio_feed +makes sure that there is buffered data, +so that the next +.B substdio_get +or +.B substdio_bget +will succeed. +If the buffer is empty, +.B substdio_feed +tries to fill it; +it returns 0 for end of file, -1 for error, +or the number of buffered characters on success. +If the buffer already had data, +.B substdio_feed +leaves it alone and returns the number of buffered characters. + +.B substdio_peek +returns a pointer to the buffered data. + +.B substdio_seek +throws away +.I len +buffered characters, +as if they had been read. +.I len +must be at least 0 and at most the amount of buffered data. + +The +.B substdio_PEEK +and +.B substdio_SEEK +macros behave the same way as +.B substdio_peek +and +.B substdio_seek +but may evaluate their arguments several times. + +The point of +.B substdio_peek +and +.B substdio_seek +is to read data without unnecessary copies. +Sample code: + +.EX + for (;;) { +.br + n = substdio_feed(s); +.br + if (n <= 0) return n; +.br + x = substdio_PEEK(s); +.br + handle(x,n); +.br + substdio_SEEK(s,n); +.br + } +.EE + +The +.B SUBSTDIO_INSIZE +macro is defined as a reasonably large input buffer size for +.BR substdio_fdbuf . +.SH "INTERNALS" +When a +.B substdio +variable +.I s +is used for input, +there is free buffer space from +.I s\fB.x +to +.I s\fB.x\fR + +.I s\fB.n\fR; +data is buffered from +.I s\fB.x\fR + +.I s\fB.n +to +.I s\fB.x\fR + +.I s\fB.n\fR + +.I s\fB.p\fR; +the total buffer length is +.I s\fB.n\fR + +.I s\fB.p\fR. +.SH "SEE ALSO" +substdio(3) diff --git a/substdio_in=0 b/substdio_in=0 new file mode 100644 index 0000000..93b4f71 --- /dev/null +++ b/substdio_in=0 @@ -0,0 +1 @@ +substdio_in.3 diff --git a/substdio_out.3 b/substdio_out.3 new file mode 100644 index 0000000..9371c9d --- /dev/null +++ b/substdio_out.3 @@ -0,0 +1,99 @@ +.TH substdio_out 3 +.SH NAME +substdio_out \- substdio output routines +.SH SYNTAX +.B #include + +int \fBsubstdio_put\fP(&\fIs\fR,\fIfrom\fR,\fIlen\fR); +.br +int \fBsubstdio_puts\fP(&\fIs\fR,\fIfrom\fR); + +int \fBsubstdio_bput\fP(&\fIs\fR,\fIfrom\fR,\fIlen\fR); +.br +int \fBsubstdio_bputs\fP(&\fIs\fR,\fIfrom\fR); + +int \fBsubstdio_flush\fP(&\fIs\fR); + +int \fBsubstdio_putflush\fP(&\fIs\fR,\fIfrom\fR,\fIlen\fR); +.br +int \fBsubstdio_putsflush\fP(&\fIs\fR,\fIfrom\fR); + +substdio \fIs\fR; +.br +char *\fIfrom\fR; +.br +int \fIlen\fR; +.SH DESCRIPTION +.B substdio_put +writes +.I len +characters to +.I s +out of the character array +.IR from . +It returns 0 on success, -1 on error. + +.B substdio_bput +has the same function as +.BR substdio_put . +The difference is how the buffer is flushed +when there isn't enough room for +.I len +characters: +.B substdio_put +flushes the buffered data before copying the new data, +whereas +.B substdio_bput +fills the buffer with new data before flushing. + +.B substdio_flush +forces all data to be written from the internal buffer. +It returns 0 on success, -1 on error. + +.B substdio_putflush +is similar to +.B substdio_put +followed by +.BR substdio_flush , +but it avoids all internal copies. + +.BR substdio_puts , +.BR substdio_bputs , +and +.B substdio_putsflush +are the same as +.BR substdio_put , +.BR substdio_bput , +and +.B substdio_putflush +except that +.I from +must be a 0-terminated string of characters. +The string, not including the 0, is written. + +The +.B SUBSTDIO_OUTSIZE +macro is defined as a reasonably large output buffer size for +.BR substdio_fdbuf . +.SH "INTERNALS" +When a +.B substdio +variable +.I s +is used for output, +data is buffered from +.I s\fB.x +to +.I s\fB.x\fR + +.I s\fB.p\fR; +there is free buffer space from +to +.I s\fB.x\fR + +.I s\fB.p +to +.I s\fB.x\fR + +.I s\fB.n\fR; +the total buffer length is +.I s\fB.n\fR. +.SH "SEE ALSO" +substdio(3) diff --git a/substdio_out=0 b/substdio_out=0 new file mode 100644 index 0000000..4124e68 --- /dev/null +++ b/substdio_out=0 @@ -0,0 +1 @@ +substdio_out.3 diff --git a/substdo.c b/substdo.c new file mode 100644 index 0000000..fb616f7 --- /dev/null +++ b/substdo.c @@ -0,0 +1,108 @@ +#include "substdio.h" +#include "str.h" +#include "byte.h" +#include "error.h" + +static int allwrite(op,fd,buf,len) +register int (*op)(); +register int fd; +register char *buf; +register int len; +{ + register int w; + + while (len) { + w = op(fd,buf,len); + if (w == -1) { + if (errno == error_intr) continue; + return -1; /* note that some data may have been written */ + } + if (w == 0) ; /* luser's fault */ + buf += w; + len -= w; + } + return 0; +} + +int substdio_flush(s) +register substdio *s; +{ + register int p; + + p = s->p; + if (!p) return 0; + s->p = 0; + return allwrite(s->op,s->fd,s->x,p); +} + +int substdio_bput(s,buf,len) +register substdio *s; +register char *buf; +register int len; +{ + register int n; + + while (len > (n = s->n - s->p)) { + byte_copy(s->x + s->p,n,buf); s->p += n; buf += n; len -= n; + if (substdio_flush(s) == -1) return -1; + } + /* now len <= s->n - s->p */ + byte_copy(s->x + s->p,len,buf); + s->p += len; + return 0; +} + +int substdio_put(s,buf,len) +register substdio *s; +register char *buf; +register int len; +{ + register int n; + + n = s->n; + if (len > n - s->p) { + if (substdio_flush(s) == -1) return -1; + /* now s->p == 0 */ + if (n < SUBSTDIO_OUTSIZE) n = SUBSTDIO_OUTSIZE; + while (len > s->n) { + if (n > len) n = len; + if (allwrite(s->op,s->fd,buf,n) == -1) return -1; + buf += n; + len -= n; + } + } + /* now len <= s->n - s->p */ + byte_copy(s->x + s->p,len,buf); + s->p += len; + return 0; +} + +int substdio_putflush(s,buf,len) +register substdio *s; +register char *buf; +register int len; +{ + if (substdio_flush(s) == -1) return -1; + return allwrite(s->op,s->fd,buf,len); +} + +int substdio_bputs(s,buf) +register substdio *s; +register char *buf; +{ + return substdio_bput(s,buf,str_len(buf)); +} + +int substdio_puts(s,buf) +register substdio *s; +register char *buf; +{ + return substdio_put(s,buf,str_len(buf)); +} + +int substdio_putsflush(s,buf) +register substdio *s; +register char *buf; +{ + return substdio_putflush(s,buf,str_len(buf)); +} diff --git a/surf.3 b/surf.3 new file mode 100644 index 0000000..ba8a520 --- /dev/null +++ b/surf.3 @@ -0,0 +1,23 @@ +.TH surf 3 +.SH NAME +surf \- Simple Unpredictable Random Function +.SH SYNTAX +.B #include + +void \fBsurf\fP(\fIout\fR,\fIin\fR,\fIseed\fR); + +uint32 \fIout\fR[8]; +.br +uint32 \fIin\fR[12]; +.br +uint32 \fIseed\fR[32]; +.SH DESCRIPTION +.B surf +changes a 384-bit input to a 256-bit output, +under control of a 1024-bit seed. +When the seed is secret, +.B surf +appears to be indistinguishable from a completely random +384-bit-to-256-bit function. +.SH "SEE ALSO" +surfpcs(3) diff --git a/surf.c b/surf.c new file mode 100644 index 0000000..c4a17d0 --- /dev/null +++ b/surf.c @@ -0,0 +1,27 @@ +/* 19970320, overlap allowed 19970406 */ + +#include "surf.h" +#include "uint32.h" + +#define ROTATE(x,b) (((x) << (b)) | ((x) >> (32 - (b)))) +#define MUSH(i,b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x,b)); + +void surf(out,in,seed) +uint32 out[8]; uint32 in[12]; uint32 seed[32]; +{ + uint32 t[12]; uint32 x; uint32 sum = 0; + int r; int i; int loop; + + for (i = 0;i < 12;++i) t[i] = in[i] ^ seed[12 + i]; + for (i = 0;i < 8;++i) out[i] = seed[24 + i]; + x = t[11]; + for (loop = 0;loop < 2;++loop) { + for (r = 0;r < 16;++r) { + sum += 0x9e3779b9; + MUSH(0,5) MUSH(1,7) MUSH(2,9) MUSH(3,13) + MUSH(4,5) MUSH(5,7) MUSH(6,9) MUSH(7,13) + MUSH(8,5) MUSH(9,7) MUSH(10,9) MUSH(11,13) + } + for (i = 0;i < 8;++i) out[i] ^= t[i + 4]; + } +} diff --git a/surf.h b/surf.h new file mode 100644 index 0000000..523f528 --- /dev/null +++ b/surf.h @@ -0,0 +1,6 @@ +#ifndef SURF_H +#define SURF_H + +extern void surf(); + +#endif diff --git a/surf=0 b/surf=0 new file mode 100644 index 0000000..4a4f676 --- /dev/null +++ b/surf=0 @@ -0,0 +1 @@ +surf.3 diff --git a/surf=l b/surf=l new file mode 100644 index 0000000..84b5dc8 --- /dev/null +++ b/surf=l @@ -0,0 +1,2 @@ +surf.o +surfpcs.o diff --git a/surfpcs.3 b/surfpcs.3 new file mode 100644 index 0000000..8bd0e11 --- /dev/null +++ b/surfpcs.3 @@ -0,0 +1,69 @@ +.TH surfpcs 3 +.SH NAME +surfpcs \- SURF protected counter sums +.SH SYNTAX +.B #include + +void \fBsurfpcs_init\fP(&\fIs\fR,\fIseed\fR); + +void \fBsurfpcs_add\fP(&\fIs\fR,\fIbuf\fR,\fIlen\fR); + +void \fBsurfpcs_out\fP(&\fIs\fR,\fIh\fR); + +surfpcs \fIs\fR; +.br +uint32 \fIseed\fR[32]; +.br +unsigned char *\fIbuf\fR; +.br +unsigned int \fIlen\fR; +.br +unsigned char \fIh\fR[SURFPCS_LEN]; +.SH DESCRIPTION +.B surfpcs +converts a character string to a 256-bit output, +under control of a 1024-bit seed. +When the seed is secret, +.B surfpcs +appears to be indistinguishable from a completely random +variable-length-to-256-bit function. + +Applying +.B surfpcs +takes three steps. +First, initialize a +.B surfpcs +variable, +.IR s , +with +.BR surfpcs_init . +The seed will be recorded inside +.IR s . + +Second, feed the input to +.BR surfpcs_add . +.I buf +is a pointer to +.I len +characters of input. +You can split the input across any number of +.B surfpcs_add +calls. + +Third, call +.BR surfpcs_out . +The output will be placed into +.IR h , +an array of +.B SURFPCS_LEN +bytes. +.B SURFPCS_LEN +is 32. + +To apply +.B surfpcs +to another input you must call +.B surfpcs_init +again. +.SH "SEE ALSO" +surf(3) diff --git a/surfpcs.c b/surfpcs.c new file mode 100644 index 0000000..92c3243 --- /dev/null +++ b/surfpcs.c @@ -0,0 +1,58 @@ +/* XXX: this needs testing */ + +#include "surf.h" +#include "surfpcs.h" + +void surfpcs_init(s,k) +surfpcs *s; +uint32 k[32]; +{ + int i; + for (i = 0;i < 32;++i) s->seed[i] = k[i]; + for (i = 0;i < 8;++i) s->sum[i] = 0; + for (i = 0;i < 12;++i) s->in[i] = 0; + s->todo = 0; +} + +static uint32 littleendian[8] = { + 50462976, 117835012, 185207048, 252579084, + 319951120, 387323156, 454695192, 522067228 +} ; +#define end ((unsigned char *) &littleendian) + +#define data ((unsigned char *) s->in) +#define outdata ((unsigned char *) s->out) + +void surfpcs_add(s,x,n) +surfpcs *s; +unsigned char *x; +unsigned int n; +{ + int i; + while (n--) { + data[end[s->todo++]] = *x++; + if (s->todo == 32) { + s->todo = 0; + if (!++s->in[8]) + if (!++s->in[9]) + if (!++s->in[10]) + ++s->in[11]; + surf(s->out,s->in,s->seed); + for (i = 0;i < 8;++i) + s->sum[i] += s->out[i]; + } + } +} + +void surfpcs_out(s,h) +surfpcs *s; +unsigned char h[32]; +{ + int i; + surfpcs_add(s,".",1); + while (s->todo) surfpcs_add(s,"",1); + for (i = 0;i < 8;++i) s->in[i] = s->sum[i]; + for (;i < 12;++i) s->in[i] = 0; + surf(s->out,s->in,s->seed); + for (i = 0;i < 32;++i) h[i] = outdata[end[i]]; +} diff --git a/surfpcs.h b/surfpcs.h new file mode 100644 index 0000000..6e1b60a --- /dev/null +++ b/surfpcs.h @@ -0,0 +1,20 @@ +#ifndef SURFPCS_H +#define SURFPCS_H + +#include "uint32.h" + +typedef struct { + uint32 seed[32]; + uint32 sum[8]; + uint32 out[8]; + uint32 in[12]; + int todo; +} surfpcs; + +#define SURFPCS_LEN 32 + +extern void surfpcs_init(); +extern void surfpcs_add(); +extern void surfpcs_out(); + +#endif diff --git a/surfpcs=0 b/surfpcs=0 new file mode 100644 index 0000000..ad052cc --- /dev/null +++ b/surfpcs=0 @@ -0,0 +1 @@ +surfpcs.3 diff --git a/targets.do b/targets.do new file mode 100644 index 0000000..38d1e7d --- /dev/null +++ b/targets.do @@ -0,0 +1 @@ +dependon it man install conf-bin conf-man diff --git a/trycpp.c b/trycpp.c new file mode 100644 index 0000000..d7d83ad --- /dev/null +++ b/trycpp.c @@ -0,0 +1,7 @@ +void main() +{ +#ifdef NeXT + printf("nextstep\n"); exit(0); +#endif + printf("unknown\n"); exit(0); +} diff --git a/trydrent.c b/trydrent.c new file mode 100644 index 0000000..c778176 --- /dev/null +++ b/trydrent.c @@ -0,0 +1,8 @@ +#include +#include + +void foo() +{ + DIR *dir; + struct dirent *d; +} diff --git a/tryflock.c b/tryflock.c new file mode 100644 index 0000000..8c8aa76 --- /dev/null +++ b/tryflock.c @@ -0,0 +1,8 @@ +#include +#include +#include + +void main() +{ + flock(0,LOCK_EX | LOCK_UN | LOCK_NB); +} diff --git a/trysgact.c b/trysgact.c new file mode 100644 index 0000000..263cb21 --- /dev/null +++ b/trysgact.c @@ -0,0 +1,10 @@ +#include + +void main() +{ + struct sigaction sa; + sa.sa_handler = 0; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sigaction(0,&sa,(struct sigaction *) 0); +} diff --git a/tryulong32.c b/tryulong32.c new file mode 100644 index 0000000..a108076 --- /dev/null +++ b/tryulong32.c @@ -0,0 +1,11 @@ +void main() +{ + unsigned long u; + u = 1; + u += u; u += u; u += u; u += u; u += u; u += u; u += u; u += u; + u += u; u += u; u += u; u += u; u += u; u += u; u += u; u += u; + u += u; u += u; u += u; u += u; u += u; u += u; u += u; u += u; + u += u; u += u; u += u; u += u; u += u; u += u; u += u; u += u; + if (!u) _exit(0); + _exit(1); +} diff --git a/tryvfork.c b/tryvfork.c new file mode 100644 index 0000000..21387e4 --- /dev/null +++ b/tryvfork.c @@ -0,0 +1,4 @@ +void main() +{ + vfork(); +} diff --git a/trywaitp.c b/trywaitp.c new file mode 100644 index 0000000..7e73bfa --- /dev/null +++ b/trywaitp.c @@ -0,0 +1,7 @@ +#include +#include + +void main() +{ + waitpid(0,0,0); +} diff --git a/uint32.h.do b/uint32.h.do new file mode 100644 index 0000000..b87401d --- /dev/null +++ b/uint32.h.do @@ -0,0 +1,7 @@ +dependon tryulong32.c compile load uint32.h1 uint32.h2 +( ./compile tryulong32.c && ./load tryulong32 && ./tryulong32 ) >/dev/null 2>&1 \ +&& cat uint32.h2 || cat uint32.h1 +rm -f tryulong32.o tryulong32 +formake '( ( ./compile tryulong32.c && ./load tryulong32 && ./tryulong32 ) >/dev/null 2>&1 \' +formake '&& cat uint32.h2 || cat uint32.h1 ) > uint32.h' +formake 'rm -f tryulong32.o tryulong32' diff --git a/uint32.h1 b/uint32.h1 new file mode 100644 index 0000000..6599aa0 --- /dev/null +++ b/uint32.h1 @@ -0,0 +1,6 @@ +#ifndef UINT32_H +#define UINT32_H + +typedef unsigned int uint32; + +#endif diff --git a/uint32.h2 b/uint32.h2 new file mode 100644 index 0000000..716430d --- /dev/null +++ b/uint32.h2 @@ -0,0 +1,6 @@ +#ifndef UINT32_H +#define UINT32_H + +typedef unsigned long uint32; + +#endif diff --git a/wait.3 b/wait.3 new file mode 100644 index 0000000..8c41f4b --- /dev/null +++ b/wait.3 @@ -0,0 +1,93 @@ +.TH wait 3 +.SH NAME +wait \- check child process status +.SH SYNTAX +.B #include + +int \fBwait_nohang\fP(&\fIwstat\fR); +.br +int \fBwait_stop\fP(&\fIwstat\fR); +.br +int \fBwait_stopnohang\fP(&\fIwstat\fR); +.br +int \fBwait_pid\fP(&\fIwstat\fR,\fIpid\fR); + +int \fBwait_exitcode\fP(\fIwstat\fR); +.br +int \fBwait_crashed\fP(\fIwstat\fR); +.br +int \fBwait_stopped\fP(\fIwstat\fR); +.br +int \fBwait_stopsig\fP(\fIwstat\fR); + +int \fIpid\fR; +.br +int \fIwstat\fR; +.SH DESCRIPTION +.B wait_nohang +looks for zombies (child processes that have exited). +If it sees a zombie, +it eliminates the zombie, +puts the zombie's exit status into +.IR wstat , +and returns the zombie's process ID. +If there are several zombies, +.B wait_nohang +picks one. +If there are children but no zombies, +.B wait_nohang +returns 0. +If there are no children, +.B wait_nohang +returns -1, +setting +.B errno +appropriately. + +.B wait_stopnohang +is similar to +.BR wait_nohang , +but it also looks for children that have stopped. + +.B wait_stop +is similar to +.BR wait_stopnohang , +but if there are children it will pause waiting for one of them +to stop or exit. + +.B wait_pid +waits for child process +.I pid +to exit. +It eliminates any zombie that shows up in the meantime, +discarding the exit status. + +.B wait_stop +and +.B wait_pid +retry upon +.BR error_intr . +.SH "STATUS PARSING" +If the child stopped, +.B wait_stopped +is nonzero; +.B wait_stopsig +is the signal that caused the child to stop. + +If the child exited by crashing, +.B wait_stopped +is zero; +.B wait_crashed +is nonzero. + +If the child exited normally, +.B wait_stopped +is zero; +.B wait_crashed +is zero; +and +.B wait_exitcode +is the child's exit code. +.SH "SEE ALSO" +wait(2), +error(3) diff --git a/wait.h b/wait.h new file mode 100644 index 0000000..cdb77c3 --- /dev/null +++ b/wait.h @@ -0,0 +1,14 @@ +#ifndef WAIT_H +#define WAIT_H + +extern int wait_pid(); +extern int wait_nohang(); +extern int wait_stop(); +extern int wait_stopnohang(); + +#define wait_crashed(w) ((w) & 127) +#define wait_exitcode(w) ((w) >> 8) +#define wait_stopsig(w) ((w) >> 8) +#define wait_stopped(w) (((w) & 127) == 127) + +#endif diff --git a/wait=0 b/wait=0 new file mode 100644 index 0000000..62a28ab --- /dev/null +++ b/wait=0 @@ -0,0 +1 @@ +wait.3 diff --git a/wait=l b/wait=l new file mode 100644 index 0000000..022ccb2 --- /dev/null +++ b/wait=l @@ -0,0 +1 @@ +wait_pid.o diff --git a/wait_pid.c b/wait_pid.c new file mode 100644 index 0000000..8dde830 --- /dev/null +++ b/wait_pid.c @@ -0,0 +1,13 @@ +#include +#include +#include "error.h" + +/* restriction: you must not care about any other child. */ +int wait_pid(wstat,pid) int *wstat; int pid; +{ + int r; + do + r = wait(wstat); + while ((r != pid) && ((r != -1) || (errno == error_intr))); + return r; +} diff --git a/warn-auto.sh b/warn-auto.sh new file mode 100644 index 0000000..36d2313 --- /dev/null +++ b/warn-auto.sh @@ -0,0 +1,2 @@ +#!/bin/sh +# WARNING: This file was auto-generated. Do not edit! -- 2.11.0