# to unbundle, sh this file (in an empty directory) # or use ftp://netlib.bell-labs.com/netlib/access/unshar.c.gz echo bin/Depend 1>&2 sed >bin/Depend <<'-------cut here----- bin/Depend' 's/^X//' X#!/bin/sh Xcase $1 in X X X-c) # creates ".depend" file for local directory, of the form X # F file.c X # D entrypoint1 X # R external1 X # R external2 X > .depend X for FILE in *.[cefr];do X echo "F $FILE" X OBJ=`echo $FILE|sed 's/\..$/.o/'` X make $OBJ 1>&2 X nm $OBJ | # the following works for SGI IRIX 4.0.5 X sed -n 's/^\([^ ]*\) *|[^|]*|\(.*\)/\2| \1/ X /|ref=[0-9].*|Text/d X s/^Proc *|.*|Undefined|/R/p X s/^Proc *|end.*|Text *|/D/p' | X skip_posix | sort -u X rm $OBJ X sed -n 's/^#[ ]*include[ ]*"\(.*\)" *$/R \1/p' $FILE X echo "" X done >> .depend X ls *.h* 2>/dev/null | X while read FILE;do echo "F $FILE";echo "";done >> .depend X ;; X X X-t) # prints filenames covering routines in $* for libraries in $LIBS X shift # get rid of -t X case $* in X all) # *** return all files *** X for i in $LIBS;do X sed -n 's;^F ;'$i'/;p' $i/.depend X done | tr '\012' ' ' X echo;; X *) # ***cat .depend files for all LIBS, then search *** X # subtlety: have to add dir to F, hence make D explicit first. X U= X for i in $*; do U="$U $i $i"_; done X (for i in $LIBS; do X (cd $i X if test -r .depend; then X sed 's;^F \(.*\);F '$i'/\1\ XD \1; X s;^R \([^/]*\)\.h$;R '$i'/\1.h;' .depend X else X ls | sed '/index/d X /readme/d X /disclaimer/d X /depend/d X s;^;F '$i'/;' X fi) X done) | getdepend $U | tr '\012' ' ' X echo;; X esac X ;; X X*) echo $0 -c ... to build .depend file for local directory X echo 'LIBS={directories} $0 -t {symbols} ... for transitive closure' X exit 1 X ;; X Xesac Xexit 0 -------cut here----- bin/Depend chmod +x bin/Depend echo bin/bibexpand 1>&2 sed >bin/bibexpand <<'-------cut here----- bin/bibexpand' 's/^X//' X#!/bin/sh X X# tool to convert bibnet format (strings) to simple BibTeX (no strings) X# Eric Grosse 14 Dec 1994 X Xtmp=/tmp/bib$$ Xsed '/^%/d X s/^ */ /' $* | combline > $tmp X< $tmp sed 's/^ */ /' | tr -d '\015' | X sed -n 's/\\/\\\\/g X s/.*%.*@String/@String/ X s/@String *{\([^ ]*\) *= *\(.*\) *}/s`\1`\2`/p' > $tmp.sed X< $tmp sed -f $tmp.sed $tmp | X sed '/^@String/d X s/" # "//g' | X uncombline Xrm -f $tmp $tmp.sed -------cut here----- bin/bibexpand chmod +x bin/bibexpand echo bin/disclaim 1>&2 sed >bin/disclaim <<'-------cut here----- bin/disclaim' 's/^X//' X#!/bin/sh XPATH=`pwd`/admin/bin:$PATH:/bin:/usr/bin:/usr/bsd:. X# add disclaimer messages to front of return mail Xfor i in $1 X do X if /bin/test -r $i/disclaimer X then X cat $i/disclaimer X fi X done Xcase $1 in X "1127") exit 0;; Xesac Xcat admin/mess/disclaimer Xecho "*** from netlib, `date` ***" -------cut here----- bin/disclaim chmod +x bin/disclaim echo bin/index_chk 1>&2 sed >bin/index_chk <<'-------cut here----- bin/index_chk' 's/^X//' X#!/bin/sh X# expects list of index filenames on stdin, perhaps from "lsr|grep 'index$'" X X# *** this is an interactive script, not automatic! *** X X# gdiff is an SGI program that's handy for merging changes; if you don't X# have it, use your favorite alternative. I hear that there is a similar X# dxdiff on DEC systems. X Xcd /netlib # file names are supposed to be relative to this Xwhile read j; do X echo ===== $j ===== X plauger_chk < $j X index_chk.x $j > $j.FIX X cmp -s $j $j.FIX || \ X (ls -l $j; \ X gdiff -s 1000,900 $j.FIX $j; \ X ls -l $j ) X rm $j.FIX Xdone -------cut here----- bin/index_chk chmod +x bin/index_chk echo bin/ldMx 1>&2 sed >bin/ldMx <<'-------cut here----- bin/ldMx' 's/^X//' X#!/bin/sh XPATH=`pwd`/admin/bin:$PATH:/bin:/usr/bin:/usr/bsd:. X# $1 = libraries, e.g. "linpack blas" X# $2 = routines, e.g. "sgeco" X# $3 = exclusions, e.g. "sgefa" XLIBS=`echo $1|sed 's/-l//g'` XPATH=admin/bin:$PATH Xexport LIBS PATH Xcase "$3" in X "") Depend -t "$2";; X *) Depend -t "$3" | tr ' ' '\012' | sort >/tmp/nl$$ X Depend -t "$2" |tr ' ' '\012'|sort|comm -23 - /tmp/nl$$|tr '\012' ' ' X rm /tmp/nl$$;; Xesac -------cut here----- bin/ldMx chmod +x bin/ldMx echo bin/mgrep 1>&2 sed >bin/mgrep <<'-------cut here----- bin/mgrep' 's/^X//' X#!/bin/sh XPATH=`pwd`/admin/bin:$PATH:/bin:/usr/bin:/usr/bsd:. X# find lines containing keywords X# "$1" = files to be searched X# $2 $3 ... = patterns Xcd list X#... For portability to Berkeley systems, changed egrep to grep. X#... Greg Astfalk convinced me simple string matching is better X#... b='(^|[^a-zA-Z0-9])' X#... e='($|[^a-zA-Z0-9])' X# in System V and Eighth Edition Unix, X# egrep accepts a -i flag to ignore case distinctions X#... cat $1 2>/dev/null | egrep -i "$2" | egrep -i "$b$2$e" >/tmp/w$$ Xcat $1 2>/dev/null | grep -i "$2" >/tmp/w$$ Xshift; shift Xfor i X do X#... egrep -i "$b$i$e" /tmp/x$$ X grep -i "$i" /tmp/x$$ X mv /tmp/x$$ /tmp/w$$ X done Xif test -s /tmp/w$$ X then X tr '\015' '\012' &2 sed >bin/netlibd <<'-------cut here----- bin/netlibd' 's/^X//' X#!/bin/sh XPATH=`pwd`/admin/bin:/usr/local/bin:$PATH:/bin:/usr/bin:/usr/bsd:. X# reply to requests (improperly) sent to netlibd instead of netlib Xcd /netlib Xn=/tmp/net$$ Xr=/tmp/netlibd Xcat >$n Xecho "-----------------------------------------" >>$r Xecho "....The following was sent to netlibd...." >>$r Xu=`admin/bin/retadd <$n` Xif (echo $u |egrep -s -i "(^$)|(mailer)|(uucp)|(postmaster)|(postoffice)|(trouble)|(server)|(netlib)|(!root)|(mail_system)|(!smtp )|(falsmtp)|(mmdf)|(error)|(mail.*daemon)|(unknown-user)|(washington.edu)") X then X echo "....and ignored...." >>$r X else X mail $u <>$r Xecho "-----------------------------------------" >>$r Xrm -f $n Xchmod 666 $r Xexit 0 -------cut here----- bin/netlibd chmod +x bin/netlibd echo bin/netlibnews 1>&2 sed >bin/netlibnews <<'-------cut here----- bin/netlibnews' 's/^X//' X#!/bin/sh XPATH=`pwd`/admin/bin:$PATH:/bin:/usr/bin:/usr/bsd:. X# reply to requests (improperly) sent to netlibnews Xcd /netlib Xn=/tmp/net$$ Xr=/tmp/netlibd Xcat >$n Xecho "-----------------------------------------" >>$r Xecho "....The following was sent to netlibnews...." >>$r Xu=`admin/bin/retadd <$n` Xif (echo $u |egrep -s -i "(mailer)|(uucp)|(postmaster)|(trouble)|(server)|(netlib)|(!root)|(mail_system)|(!smtp )|(falsmtp)|(mmdf)|(error)|(maildaemon)|(unknown-user)") X then X echo "....and ignored...." >>$r X else X mail $u <>$r Xecho "-----------------------------------------" >>$r Xrm -f $n Xchmod 666 $r Xexit 0 -------cut here----- bin/netlibnews chmod +x bin/netlibnews echo bin/skip_posix 1>&2 sed >bin/skip_posix <<'-------cut here----- bin/skip_posix' 's/^X//' Xsed '/^R _/d X/^R assert.h$/d X/^R ctype.h$/d X/^R fcntl.h$/d X/^R float.h$/d X/^R grp.h$/d X/^R limits.h$/d X/^R locale.h$/d X/^R math.h$/d X/^R pwd.h$/d X/^R setjmp.h$/d X/^R signal.h$/d X/^R stdarg.h$/d X/^R stddef.h$/d X/^R stdio.h$/d X/^R stdlib.h$/d X/^R string.h$/d X/^R sys\/times.h$/d X/^R sys\/types.h$/d X/^R sys\/utsname.h$/d X/^R sys\/wait.h$/d X/^R time.h$/d X/^R unistd.h$/d X/^R utime.h$/d X/^R abs$/d X/^R acos$/d X/^R alarm$/d X/^R asctime$/d X/^R asin$/d X/^R atan$/d X/^R atan2$/d X/^R atexit$/d X/^R atof$/d X/^R atoi$/d X/^R atol$/d X/^R bsearch$/d X/^R ceil$/d X/^R chdir$/d X/^R chmod$/d X/^R clearerr$/d X/^R clock$/d X/^R close$/d X/^R closedir$/d X/^R cos$/d X/^R cosh$/d X/^R ctermid$/d X/^R cuserid$/d X/^R difftime$/d X/^R dup$/d X/^R exit$/d X/^R exp$/d X/^R fabs$/d X/^R fclose$/d X/^R fdopen$/d X/^R feof$/d X/^R ferror$/d X/^R fflush$/d X/^R fgetc$/d X/^R fgets$/d X/^R fileno$/d X/^R floor$/d X/^R fmod$/d X/^R fopen$/d X/^R fprintf$/d X/^R fputc$/d X/^R fputs$/d X/^R fread$/d X/^R free$/d X/^R freopen$/d X/^R fscanf$/d X/^R fseek$/d X/^R fstat$/d X/^R ftell$/d X/^R fwrite$/d X/^R getc$/d X/^R getchar$/d X/^R getenv$/d X/^R getopt$/d X/^R getpid$/d X/^R gets$/d X/^R gmtime$/d X/^R isdigit$/d X/^R isspace$/d X/^R isupper$/d X/^R labs$/d X/^R localtime$/d X/^R log$/d X/^R log10$/d X/^R lseek$/d X/^R malloc$/d X/^R memcpy$/d X/^R memmove$/d X/^R memset$/d X/^R mkdir$/d X/^R mkfifo$/d X/^R mknod$/d X/^R mktime$/d X/^R modf$/d X/^R opendir$/d X/^R pause$/d X/^R pclose$/d X/^R perror$/d X/^R pipe$/d X/^R popen$/d X/^R pow$/d X/^R printf$/d X/^R putc$/d X/^R putchar$/d X/^R puts$/d X/^R qsort$/d X/^R read$/d X/^R readdir$/d X/^R realloc$/d X/^R remove$/d X/^R rename$/d X/^R rewind$/d X/^R rewinddir$/d X/^R scanf$/d X/^R seekdir$/d X/^R setbuf$/d X/^R setvbuf$/d X/^R sin$/d X/^R sinh$/d X/^R sleep$/d X/^R sprintf$/d X/^R sqrt$/d X/^R sscanf$/d X/^R strcat$/d X/^R strchr$/d X/^R strcmp$/d X/^R strcpy$/d X/^R strftime$/d X/^R strlen$/d X/^R strncmp$/d X/^R strrchr$/d X/^R strtod$/d X/^R system$/d X/^R tan$/d X/^R tanh$/d X/^R telldir$/d X/^R time$/d X/^R tmpfile$/d X/^R tmpnam$/d X/^R tolower$/d X/^R tzset$/d X/^R umask$/d X/^R ungetc$/d X/^R utime$/d X/^R vfprintf$/d X/^R vprintf$/d X/^R vsprintf$/d X/^R write$/d' -------cut here----- bin/skip_posix chmod +x bin/skip_posix echo bin/sortnames 1>&2 sed >bin/sortnames <<'-------cut here----- bin/sortnames' 's/^X//' X#!/bin/sh XPATH=`pwd`/admin/bin:$PATH:/bin:/usr/bin:/usr/bsd:. X# remove duplicates from names file X# cd /netlib/admin Xn=names Xsort -u -o $n $n -------cut here----- bin/sortnames chmod +x bin/sortnames echo bin/to_subscribers2 1>&2 sed >bin/to_subscribers2 <<'-------cut here----- bin/to_subscribers2' 's/^X//' X#!/bin/sh X# invoked by to_subscribers Xcd /tmp/to_subscribers || exit 1 Xecho begin mailing `date` Xls -l Xls | while read i;do X sort -u $i | X ( cat /netlib/admin/mess/netlibnews X echo " path $i" X echo " unsubscribe unwanteddirectory" X echo "------------------------------------------" X cat - )| mail $i X rm $i X sleep 5 Xdone Xecho end mailing `date` Xcd Xrmdir /tmp/to_subscribers -------cut here----- bin/to_subscribers2 chmod +x bin/to_subscribers2 echo bin/uncombline 1>&2 sed >bin/uncombline <<'-------cut here----- bin/uncombline' 's/^X//' X#!/bin/sh XPATH=`pwd`/admin/bin:$PATH:/bin:/usr/bin:/usr/bsd:. Xtr '\015' '\012' -------cut here----- bin/uncombline chmod +x bin/uncombline echo bin/pgpsigned 1>&2 sed >bin/pgpsigned <<'-------cut here----- bin/pgpsigned' 's/^X//' X#!/bin/sh Xecho ok $1 $2 -------cut here----- bin/pgpsigned chmod +x bin/pgpsigned echo mess/big 1>&2 sed >mess/big <<'-------cut here----- mess/big' 's/^X//' XThe reply to your request is quite large and will be sent in pieces. XIf sometime in the future you should want to check sizes before Xsubmitting the actual request, use the syntax X send list of rg from eispack Xin place of X send rg from eispack. XThis also lists file names, in case all you want to know is what Xdepends on what. X -------cut here----- mess/big echo mess/collided 1>&2 sed >mess/collided <<'-------cut here----- mess/collided' 's/^X//' XUffda! There was a database update collision while we tried to Xcarry out your instructions. Please try again later. -------cut here----- mess/collided echo mess/disclaimer 1>&2 sed >mess/disclaimer <<'-------cut here----- mess/disclaimer' 's/^X//' XCareful! Anything free comes with no guarantee. -------cut here----- mess/disclaimer echo mess/netlibnews 1>&2 sed >mess/netlibnews <<'-------cut here----- mess/netlibnews' 's/^X//' XSubject: new or changed files X XThe following files changed in directories that you asked to monitor. XTo retrieve file "wantedfile", X mail netlib@research.bell-labs.com X send wantedfile XTo turn off notification in "unwanteddirectory", X mail netlib@research.bell-labs.com -------cut here----- mess/netlibnews echo mess/no-topic 1>&2 sed >mess/no-topic <<'-------cut here----- mess/no-topic' 's/^X//' XSorry, no such topic found. -------cut here----- mess/no-topic echo mess/siam 1>&2 sed >mess/siam <<'-------cut here----- mess/siam' 's/^X//' XThis data from the SIAM MEMBERSHIP DIRECTORY is copyright 1996 by XSociety for Industrial and Applied Mathematics. All Rights Reserved. XTo have your name added, join up! email siam@siam.org X XAn independent "nalist" is maintained at ORNL; ask na.help@na-net.ornl.gov Xfor details. In particular, X mail na.whois@na-net.ornl.gov X whois Rosener Xwill look up that name in the "whitepages" database. X X X -------cut here----- mess/siam echo mess/sorry 1>&2 sed >mess/sorry <<'-------cut here----- mess/sorry' 's/^X//' XSorry, no such file was found. Recheck the index. XIf that doesn't explain the problem, send a complaint to research!ehg Xor ehg@research.bell-labs.com. X XHere are some example requests, in case syntax is the problem: X send index X send index for eispack X send rg from eispack X who is eric grosse -------cut here----- mess/sorry echo mess/sorry_cmd 1>&2 sed >mess/sorry_cmd <<'-------cut here----- mess/sorry_cmd' 's/^X//' X XSorry, netlib doesn't recognize or can't execute that command. -------cut here----- mess/sorry_cmd echo mess/sorry_enemy 1>&2 sed >mess/sorry_enemy <<'-------cut here----- mess/sorry_enemy' 's/^X//' X XOne of the machines in your return address is prohibited from Xnetlib access. This is usually because gateway administrators Xhave asked that netlib not forward through their machines. More Xgenerally, such prohibitions result from someone irresponsibly Xasking for large transmissions (with communication costs paid for Xby third parties) and not stopping when asked. X XThere are also user-id's, like "root", "uucp" and "mailer", that are disabled Xto protect against mail disasters. X XOf course, you are probably not the offending individual and it Xis unfortunate that you must suffer for others' sins. Perhaps you Xcan find another, more direct, route that avoids the excommunicated Xmachines. -------cut here----- mess/sorry_enemy echo mess/sorry_f2c 1>&2 sed >mess/sorry_f2c <<'-------cut here----- mess/sorry_f2c' 's/^X//' -------cut here----- mess/sorry_f2c echo mess/sorry_find 1>&2 sed >mess/sorry_find <<'-------cut here----- mess/sorry_find' 's/^X//' X XYour search resulted in too large a match. Please Xrephrase and try again. The long reply would have started... -------cut here----- mess/sorry_find echo mess/sorry_indiv 1>&2 sed >mess/sorry_indiv <<'-------cut here----- mess/sorry_indiv' 's/^X//' X XWere you asking for an entire library? XTo discourage huge requests and to comply with the requirements Xof certain copyright holders, our policy is to require that you Xask for the items in a library that you are specifically interested Xin. In case it helps, here's the index for the library: X -------cut here----- mess/sorry_indiv echo mess/sorry_lib 1>&2 sed >mess/sorry_lib <<'-------cut here----- mess/sorry_lib' 's/^X//' XSorry, no such library is available. Recheck the general index. XHere are some example requests, in case syntax is the problem: X X send index X send index for eispack X send rg from eispack X who is eric grosse -------cut here----- mess/sorry_lib echo mess/sorry_many 1>&2 sed >mess/sorry_many <<'-------cut here----- mess/sorry_many' 's/^X//' X XWe set a limit of 30 requests and 1.5 megabytes. Since that has now Xbeen exceeded, the remainder of your message has been discarded. XYou may resubmit, but remember that someone is paying for communications Xcosts! To get complete libraries you should probably be using ftp anyway, Xsince that transfers compressed files and therefore wastes less bandwith. X XIf you want to check sizes before submitting the actual request, use the Xsyntax X send list of rg from eispack Xin place of X send rg from eispack. XThis also lists file names, in case all you want to know is what Xdepends on what. -------cut here----- mess/sorry_many echo mess/sorry_req 1>&2 sed >mess/sorry_req <<'-------cut here----- mess/sorry_req' 's/^X//' XSubject: netlib syntax error X XSorry, the netlib program couldn't understand your request. XHere are some example requests, in case syntax is the problem: X X send index X send index for eispack X send rg from eispack X who is Gene Golub X find fft X XDue to the stupid, one-pass nature of the parsing program, if you Xput the request in the header Subject: line and some mailer puts Xthat line before any address line, netlib won't know who you are. XSorry, that will be fixed someday; in the meantime, put the Xrequest in the message body proper. X XYour mail, as received here, was... -------cut here----- mess/sorry_req echo mess/sorry_unsafe 1>&2 sed >mess/sorry_unsafe <<'-------cut here----- mess/sorry_unsafe' 's/^X//' XSorry, your request included a shell magic character X "'`$\n;&|^<>() Xprohibited for security reasons. Please try again. -------cut here----- mess/sorry_unsafe echo mess/sorry_mgrep 1>&2 sed >mess/sorry_mgrep <<'-------cut here----- mess/sorry_mgrep' 's/^X//' XSorry, nothing found. X XIf you're looking for material that used to be under /netlib/att, see Xhttp://cm.bell-labs.com/ or http://www.research.att.com/ XBell Labs (Lucent Technologies) AT&T Research Labs X -------cut here----- mess/sorry_mgrep echo LIBS 1>&2 sed >LIBS <<'-------cut here----- LIBS' 's/^X//' X1127 => research X127 => research XDEFAULT => eispack linpack quadpack fn go blas fmm fishpack Xappolo => apollo Xatt/cs/v7 => att/cs/v7man Xatt/cs/prog => research Xawkbookcode => research/awkbookcode Xbenchmarks => benchmark Xblas/gemm-based => blas/gemm_based Xblas1 => blas Xblas2 => blas Xblas3 => blas Xc++/answers => c++/answerbook Xc++/lapack++ => lapack++ Xc/meshark => c/meschach Xcacm => toms Xcalgo => toms Xcascade => ieeecss/cascade Xck => cheney-kincaid Xclapack => clapack clapack/complex clapack/complex16 clapack/double clapack/single clapack/util Xclapack/complex => clapack/complex clapack/single clapack/util Xclapack/complex16 => clapack/complex16 clapack/double clapack/util Xclapack/double => clapack/double clapack/util Xclapack/single => clapack/single clapack/util Xcomputers => machines Xconf => confdb Xconf/icsr3 => confdb/icsr3 Xcor => blas Xcore => blas Xd0min0 => domino Xd0mino => domino Xdeboor => pppack Xdelaunay => voronoi Xdodepack => odepack Xdomin0 => domino Xeispac => eispack Xeispac/ex => eispack/ex Xeispak => eispack Xeispak/ex => eispack/ex Xeispk => eispack Xeratta => errata Xerratta => errata Xfft => fftpack Xfishpak => fishpack Xfitpak => fitpack Xfnlib => fn Xfraley => uncon/data Xgcvpack => gcv Xgolden => go Xgoldies => go Xgraphic => graphics Xgraphix => graphics Xhence/demo => hence/demos Xhompack => hompack blas Xhpff => hpf Xitpak => itpack Xlanczs => lanczos Xlapac => lapack Xlapack => lapack lapack/complex16 lapack/complex lapack/double lapack/single lapack/util Xlapack/single => lapack/single lapack/util Xlapack/double => lapack/double lapack/util Xlapack/complex => lapack/complex lapack/single lapack/util Xlapack/complex16 => lapack/complex16 lapack/double lapack/util Xlapack/lawn => lapack/lawns Xlapacker => lapacker blas Xlapackers => lapacker blas Xlapak => lapack Xlapck => lapack Xlapk => lapack Xlatex => typesetting Xleval => lanczos Xlinpac => linpack blas Xlinpack => linpack blas Xlinpack => linpack blas Xlinpackb => linpack blas Xlinpak => linpack blas Xlinpak => linpack blas Xlinpk => linpack blas Xmachine => machines Xmeschach => c/meschach Xmeshark => c/meschach Xmgghat => pdes/mgghat Xminpak => minpack Xminpak/ex => minpack/ex Xmiscelaneous => misc Xmiscellaneous => misc Xmonmacs => parmacs Xmpi1 => mpi Xna => numeralgo Xode => ode blas Xother => misc Xparmac => parmacs Xpbwg => parkbench Xpchip => slatec/pchip slatec/src Xclawpack => pdes/claw Xperformance => benchmark Xpolyhedron => polyhedra Xportex => port/ex Xportp => port Xportp/chk => port/chk Xportp/ex => port/ex Xportpex => port/ex Xppack => pppack Xpvm => pvm3/pvm2.4 Xpvm/demo => pvm3/pvm2.4/demos Xpvm/demos => pvm3/pvm2.4/demos Xpvm3/example => pvm3/ex Xpvm3/examples => pvm3/ex Xquadpak => quadpack Xrksuite => ode/rksuite Xsblas => blas Xschedule => sched Xsciport => scilib Xscpack => conformal Xseispac => seispack Xseispac/ex => seispack/ex Xseispak => seispack Xseispak/ex => seispack/ex Xseispk => seispack Xsfft => fishpack Xsfftpack => fishpack Xsfftpak => fishpack Xsfnlib => fn Xsiam => typesetting Xsiam/typesetting => typesetting Xsinpack => sminpack Xsitpack => itpack Xsitpak => itpack Xslatec => slatec slatec/src slatec/fishfft slatec/pchip slatec/fnlib slatec/lin Xslatec/fishfft => slatec/fishfft slatec/fnlib slatec/lin slatec/src Xslatec/fnlib => slatec/fnlib slatec/src Xslatec/lin => slatec/lin slatec/src Xslatec/pchip => slatec/pchip slatec/src Xslatec/src => slatec/src slatec/fishfft slatec/pchip slatec/fnlib slatec/lin Xslinpac => linpack blas Xslinpack => linpack blas Xslinpack/chk => linpack/chk Xslinpack/ex => linpack/ex Xslinpak => linpack blas Xslinpk => linpack blas Xsminpak => sminpack Xsminpak/ex => sminpack/ex Xsparse1.3 => sparse Xsparsepack => sparspak Xsparsepak => sparspak Xsparspack => sparspak Xsppack => pppack Xspppack => pppack Xstat => att/stat Xstat/data => att/stat/data Xstat/doc => att/stat/doc Xstat/prog => att/stat/prog Xsvdpac => svdpack Xsvdpak => svdpack Xtemplate => templates Xtool => sched Xtools => sched Xtools => sched Xtypeset => typesetting Xtypeseting => typesetting Xucbtest => fp/ucbtest Xuncon/dat => uncon/data Xvfftpak => vfftpack Xvfftpk => vfftpack Xvfftpk => vfftpack -------cut here----- LIBS echo src/F2cargs.c 1>&2 sed >src/F2cargs.c <<'-------cut here----- src/F2cargs.c' 's/^X//' X#include X X/* For netlib's pipe f2c: check first line of input for flags: X * If the line has the form X * c$f2c -flag -flag... X * (with "c$f2c " starting in column 1) and no funny characters X * in the flags (all of which start with -), then echo "-flag -flag..." X * on stdout; otherwise echo nothing. X */ X Xmain(argc,argv) X char **argv; X{ X FILE *f; X char buf[128]; X static char good[256]; X int i; X register char *s, *s1; X X if (argc <= 1) { X fprintf(stderr, "%s: expected one arg: a file name\n", *argv); X return 1; X } X if (!(f = fopen(argv[1],"r"))) { X fprintf(stderr, "%s: can't open %s\n", argv[0], argv[1]); X return 1; X } X if (fgets(buf, sizeof(buf), f)) { X if (strncmp(buf, "c$f2c ", 6)) X goto done; X for(i = 'a'; i <= 'z'; i++) X good[i] = good[i+'A'-'a'] = 1; X for(i = '0'; i <= '9'; i++) X good[i] = 1; X for(s = "\t -+=,.!%_\n"; *s; s++) X good[*s] = 1; X for(s = buf+6; good[*(unsigned char *)s]; s++); X if (*s) X goto done; X for(s = buf+5, s1 = 0;;) { X while(*++s == ' '); X if (*s != '-') { X if (!*s) X break; X goto done; X } X if (!s1) X s1 = s; X while(*++s != ' ') X if (!*s) X goto for_done; X } X for_done: X if (s1) X printf("%s", s1); X } X done: X fclose(f); X return 0; X } -------cut here----- src/F2cargs.c echo src/Makefile 1>&2 sed >src/Makefile <<'-------cut here----- src/Makefile' 's/^X//' XCFLAGS=-O XCMDS= ../bin/reply \ X ../bin/combline \ X ../bin/getdepend \ X ../bin/index_chk.x \ X ../bin/mk.list \ X ../bin/plauger_chk \ X ../bin/retadd \ X ../bin/seq \ X ../bin/to_subscribers X Xdebug: reply.o bigmail.o mimemail.o hash.o getfrom.o lsr.o subscribe.o Malloc.o X $(CC) -g -o nreply reply.o bigmail.o mimemail.o hash.o getfrom.o \ X lsr.o subscribe.o Malloc.o X date >>../stderr X cd /netlib;\ X (echo "From ehg";echo "send 1127/dup.shar")|\ X DEBUG=on admin/src/nreply X tail -20 ../stderr X Xinstall: all Xall: $(CMDS) X touch ../names ../log X date >../stderr X chmod go+w ../stderr ../names ../log X../bin/reply: reply.c bigmail.c mimemail.c hash.c getfrom.c lsr.c subscribe.c Malloc.c X $(CC) -s -o $@ $(CFLAGS) reply.c bigmail.c mimemail.c hash.c getfrom.c \ X lsr.c subscribe.c Malloc.c X date >>../stderr X cat /dev/null > ../../core X chmod a+w ../stderr ../../core X../bin/getdepend: getdepend.c Malloc.c hash.c X $(CC) -s -o $@ $(CFLAGS) getdepend.c Malloc.c hash.c X../bin/combline: combline.c X $(CC) -s -o $@ $(CFLAGS) combline.c X../bin/seq: seq.c X $(CC) -s -o $@ seq.c X../bin/retadd: getfrom.c X $(CC) -O -DSTANDALONE -o $@ getfrom.c X../bin/plauger_chk: plauger_chk.c X $(CC) -s -o $@ $(CFLAGS) plauger_chk.c X../bin/index_chk.x: index_chk.c Malloc.c hash.c X $(CC) -s -o $@ $(CFLAGS) index_chk.c Malloc.c hash.c X../bin/to_subscribers: to_subscribers.c X $(CC) -s -o $@ to_subscribers.c X../bin/mk.list: mk.list.c X $(CC) -s -o $@ mk.list.c X chmod u+s $@ X Xbigmail.x: bigmail.c X $(CC) -o $@ $(CFLAGS) -DSTANDALONE bigmail.c X rm -f bigmail.o # to be sure reply doesn't get wrong version X Xoldindex_chk.c: index_chk.c X proto -fs index_chk.c > $@ X Xbundle: X cd /netlib/admin; stree `cat bundlefiles; lsr src | grep -v Old` > /netlib/misc/netlib Xclean: X rm -f *.o *.x retadd nreply core X -------cut here----- src/Makefile echo src/Malloc.c 1>&2 sed >src/Malloc.c <<'-------cut here----- src/Malloc.c' 's/^X//' X#include X#include X#include X#include X#include "depend.h" X Xint Error_rc = 1; /* rarely, caller of Error() may want to set this */ Xextern int errno; X Xint XError(char *fmt, ...) X{ X va_list ap; X va_start(ap,fmt); X if(vfprintf(stderr,fmt,ap)<0) X fprintf(stderr,""); X fputc('\n',stderr); X va_end(ap); X if(errno) perror("<"); /* may or may not be relevant */ X exit(Error_rc); X /* NOTREACHED */ X return(0); /* so caller can use crunch() || Error("bad"); */ X} X Xvoid * XMalloc(size_t n) X{ X void *p; X if(n==0) X n=1; X if (!(p = malloc((size_t)n))) X Error("unable to allocate %d bytes",n); X return p; X} X Xvoid * XRealloc(void *ReallocP, int ReallocN) X{ X if(ReallocN == 0) X ReallocN = 1; X if(!ReallocP) X ReallocP = Malloc(ReallocN); X else if(!(ReallocP = realloc(ReallocP, ReallocN))) X Error("unable to allocate %d bytes",ReallocN); X return(ReallocP); X} X Xchar* XStrdup(char* s) X{ X int l; X if (!s) X return 0; X l = strlen(s)+1; X return strcpy((char *)Malloc((size_t)l), s); X} X X/* returns pointer to start of null-terminated line, or NULL if EOF */ Xchar* XFgets(char* buf, int bufl, FILE* fp) X{ X char* s; X int l; X X s = fgets(buf, bufl, fp); X if (s==NULL) X return NULL; X if (ferror(fp)) X Error("read error"); X l = strlen(buf)-1; X if (buf[l] == '\n') X buf[l] = '\0'; X else if (l == bufl) X Error("line longer than %d characters", bufl); X return s; X} X -------cut here----- src/Malloc.c echo src/README 1>&2 sed >src/README <<'-------cut here----- src/README' 's/^X//' XInstallation instructions: X X Caution. You'll find that the most common problems are with X corrupted mail addresses, network errors, and so on. You ought X to be reasonably expert with e-mail before installing this. X XEdit the call to chdir in bin/reply.c to point to the place where the source Xcode is stored on your system. /netlib is assumed for illustration here. XAll the files associated with running the distribution service are in X/netlib/admin; contents of the collection are in /netlib/eispack, etc. X X Special suggestions for SunOS 4.1.4 users from mcmahan@cs.utk.edu: X #define atexit on_exit X #define memmove(a,b,c) bcopy(b,a,c) X #define _IFMT 0170000 /* type of file */ X #define _IFLNK 0120000 /* symbolic link */ X #define S_ISLNK(m) (((m)&_IFMT) == _IFLNK) X XEdit /netlib/master/index to reflect what you are distributing (or, as we Xdo, create that file automatically from ".master" files in each directory.) XEdit the various disclaimers in /netlib/admin/mess. You may also wish to Xadd disclaimer files in the source directories. X XTo activate mail processing: X* if you run 4.1BSD, put X netlib: "|/netlib/admin/bin/reply" X netlibd: "|/netlib/admin/bin/netlibd" X into /usr/lib/aliases and execute newaliases; X* else if your system has no equivalent mechanism, try the X daemon in /netlib/admin/bin/Old-mail-sys. XThe script admin/bin/netlibd contains (on line 3) "cd /netlib", which you Xmay need to change. Since Berkeley's alias facility provides no way to Xset the userid, you probably ought to put your name and address in the Xmessage so people know who is actually sending the mail. X XTo try the system out, "echo send index | mail netlib" and expect return Xmail in a couple minutes. A line should be added to /netlib/admin/log and Xadmin/stderr should remain empty. X XOnce the basics are working, you can polish things a bit. XSet up a nightly process to run /netlib/admin/bin/mkdirectory. XUsing "Depend -c" you can create ".depend" files in each directory to Xrepresent the relationship between source files there. Not only is this Xfile itself useful to browsers, but netlib responds to a requests for X"rg from eispack" by sending not just rg.f, but also balbak.f, hqr2.f... X XYou should permanently save /netlib/admin/log so that bug fixes can be Xdistributed, traffic measurements made, and annual summaries sent to code Xauthors. The format of the log is: date time [address] bytes-sent Xlibrary/item possibly followed by: L = list, F = find. The [address] is Xfollowed by "l" if the address was recognized as local. In contrast, the Xcopy of incoming messages kept in /tmp/netreq is for debugging mail headers Xand monitoring illegal request syntax. Discard when convenient (perhaps by Xan "rm" in /etc/rc) or, if you prefer, comment out the line in Xreply.c:handle() that writes the file. X XSend suggestions to ehg@research.bell-labs.com. X XHappy Hacking XEric Grosse X X X Xindex to files in /netlib/admin/ X XLIBS maps request library name into /netlib directory names Xindex top level description of contents of /netlib X *.lcl describes restricted parts of the collection Xlog record of requests Xnames aid to identify e-mail addresses and human names Xstderr error logfile Xgroups/ lists of machine names X enemies ... from which requests are ignored X local ... authorized for restricted parts of /netlib Xmess/ various error messages X Xbin/ X Old-mail-sys alternative to Version 9 Unix "Pipe to cmd" facility X bigmail.c break up large messages into smaller chunks X combline.c convert paragraph to single line, for searching by mgrep X disclaim script invoked by reply to add disclaimer to message X getfrom.c code for parsing RFC822 Internet standard From: address X ldMx,ldM,lo identify dependencies between files X mgrep script to (sequentially) search a database X mvlower utility for installing source files X netlibd another mailbox daemon; "use netlib, not netlibd" X reply.c netlib server X retadd.c standalone driver for getfrom.c X sortnames compress admin/names X X X X X X Xchecklist for adding new directories X X1. cd /netlib;mkdir foo X X3. ed master/index X X5. cp files foo; be sure they are publicly readable X X6. ed foo/index, foo/.master, foo/changes, and possibly foo/disclaimer X X Xchecklist for adding new file to old directory X X1. cd /netlib/foo X X2. cp files /netlib/foo/; be sure they are publicly readable X X3. ed /netlib/foo/index, foo/changes X -------cut here----- src/README echo src/addr_canon 1>&2 sed >src/addr_canon <<'-------cut here----- src/addr_canon' 's/^X//' X#!/bin/sh X# for canonicalizing /netlib/xxxx/.list Xsed '/\(.*\)@\(.*\)/s//\2!\1/' | Xsort -u -------cut here----- src/addr_canon chmod +x src/addr_canon echo src/bigmail.c 1>&2 sed >src/bigmail.c <<'-------cut here----- src/bigmail.c' 's/^X//' X/* X * bigmail - split files into self-recreating chunks and mail X * X * 1 Apr 1991 by Eric Grosse ehg@research.bell-labs.com X * Copyright (c) 1991,1992 by AT&T. X * Permission to use, copy, modify, and distribute this software for any X * purpose without fee is hereby granted, provided that this entire notice X * is included in all copies of any software which is or includes a copy X * or modification of this software and in all copies of the supporting X * documentation for such software. X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED X * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. X * X * The purpose of this function (or program, if compiled -DSTANDALONE) X * is to mail to argv[1] with subject argv[2] a list of files in argv[3] X * up to argv[n]. The files are to be formated as (several) shell X * archives, each of size X#include /* strrchr(), known to BSD folks as rindex() */ Xextern FILE *popen(const char *, const char *); X X#define MAXLINE 1000 /* max bytes per line, counting newline */ X#define HDR_SIZE 600 /* bytes that might be needed by mail header */ X /* From:, Received:, Subject:, WhoKnowsWhatElse: */ Xstatic char cutstring[] = "bigmail CUT HERE............"; Xstatic int cutsize; Xstatic char disclaimer[] = "Anything free comes with no guarantee!"; Xstatic char piece_space[100][12]; /* constructed filenames */ X X/* open filename for reading; return handle and size */ Xstatic Xvoid Xfopensize(filename, inp, filesizep) X char* filename; FILE** inp; long* filesizep; X{ X if( (*inp = fopen(filename,"r")) == NULL){ X fprintf(stderr,"%s:\n",filename); X quit(1,"can't open"); X } /* would love to zopen(), but then couldn't fseek */ X if( fseek(*inp,0L,2) == -1 ){ X fprintf(stderr,"%s:\n",filename); X quit(1,"can't seek to end"); X } X *filesizep = ftell(*inp); X if( fseek(*inp,0L,0) == -1 ){ X fprintf(stderr,"%s:\n",filename); X quit(1,"can't seek to begin"); X } X} X X X/* begin mail message */ Xstatic Xint Xbeginmess(mcnt, address, maxbyte, subject, outp) X int mcnt; char* address; long maxbyte; char* subject; FILE** outp; X{ X char cmd[512]; X static int first = 0; X if(address){ X if(strlen(address)>=500) X quit(strlen(address)+100,"address too long"); X sprintf(cmd,"/bin/mail %s",address); X if( (*outp = popen(cmd,"w")) == NULL){ /* POSIX.2 */ X fprintf(stderr,"%s:\n",cmd); X quit(1,"can't popen"); X } X }else{ X *outp = stdout; X } X if(!subject) X subject = "Subject: bigmail"; X if(mcnt>=0) X fprintf(*outp,"%s %2d\n\n#!/bin/sh\n",subject,mcnt); X else X fprintf(*outp,"%s\n\n#!/bin/sh\n",subject); X fprintf(*outp,"# to unpack, sh this message in an empty directory\n"); X fprintf(*outp,"PATH=/bin:/usr/bin\n"); X if(first++==0) X fprintf(*outp,"echo \"%s\"\n",disclaimer); X return( maxbyte-HDR_SIZE-strlen(subject)); X} X X X/* end mail message */ Xstatic Xvoid Xendmess(outp,last) X FILE** outp; X int last; /* is this the last message? */ X{ X int rc; X static int mess_cnt = 0; X if(last) X fprintf(*outp,"#define END\n"); X /* this rather odd syntax is designed to allow Fortranners to compile X messages directly, without unbundling */ X fflush(*outp); X if(*outp==stdout){ X fputs("#----------------------------------------\n",*outp); X }else{ X if((rc=pclose(*outp)) != 0) /* POSIX.2 */ X fprintf(stderr,"bad pclose %d\n",rc); X *outp = (FILE*)0; X } X if(mess_cnt++>2) X sleep(1); /* avoid saturating the mail system */ X} X X X/* begin file (possibly several per message) */ Xstatic Xint Xbeginfile(out, filename) X FILE* out; char* filename; X{ X int bytes_used=0; X char *f=filename; X while(f=strchr(f,'/')){ X /* This could be made smarter, remembering which directories X have already been checked in this message. */ X *f = '\0'; X if(out) X fprintf(out,"test ! -d %s && mkdir %s\n", X filename,filename); X bytes_used += 21+2*strlen(filename); X *f++ = '/'; X } X if(out) X fprintf(out,"cat > %s <<'%s'\n",filename,cutstring); X bytes_used += 11+strlen(filename)+cutsize; X return(bytes_used); X} X X Xstatic Xint Xendfile(out) X FILE* out; X{ X fprintf(out,"%s\n",cutstring); X return(cutsize+1); X} X X X/* make up temp file names if file too big for single message */ Xstatic Xint Xpiece_names(filename, out, room, filesize, maxbyte, subjectlen, pieces) X char* filename; FILE* out; long room; long filesize; X long maxbyte; int subjectlen; char* pieces[]; X{ X /* construct filenames of form 12345678P99 */ X int npieces; /* how many messages will file be split over? */ X static int pid = 0; /* so filenames unique across processes */ X static job_cnt = 0; /* so filenames unique in this process */ X int beg_end = beginfile((FILE *)0,filename)+(cutsize+1); X long per_piece; X int i; X if(!pid) X pid = getpid(); X pieces[0] = filename; X npieces = 1; X room -= beg_end; /* space for beginfile/endfile */ X room -= MAXLINE; /* because catfile has no line lookahead */ X if(filesize>room){ X /* can't fit in remainder of this message. */ X filesize -= room; /* how much left? */ X per_piece = maxbyte - HDR_SIZE - subjectlen - beg_end - MAXLINE; X while( filesize>0 ){ X npieces += 1; X filesize -= per_piece; X } X for(i=2; i<=npieces; i++){ X if(job_cnt>99){ X fprintf(out,"too many messages: %s\n",filename); X fprintf(stderr,"%s:\n",filename); X quit(1,"too many messages"); X } X sprintf(pieces[i-1]=piece_space[job_cnt], X "%.5dP%.2d",pid,job_cnt); X job_cnt += 1; X } X } X return(npieces); X} X X X/* return non-zero if file not exhausted */ Xstatic Xint Xcatfile(filename, in, out, proom) X char* filename; FILE *in; FILE *out; long* proom; X{ X char line[MAXLINE]; /* see discussion at top of file */ X register int linesize, lastchar; X register long room = *proom; X static int errmess = 0; X lastchar = '\n'; X while(room>MAXLINE && fgets(line,sizeof(line),in)!=NULL && X (linesize=strlen(line))>0 ){ X if(linesize>=sizeof(line)-1){ X fprintf(out,"line too long in %s\n",filename); X fprintf(stderr,"%s:\n",filename); X quit(1,"line too long"); X } X if(fputs(line,out)==EOF){ X quit(1,"write error"); X } X room -= linesize; X lastchar = line[linesize-1]; /* usually \n */ X if( linesize==2 && *line=='.' && lastchar=='\n' ){ X if(!errmess++) X fprintf(stderr,"%s has a . line\n",filename); X /* exit(1); /* this was too radical */ X line[1]=' '; X line[2]='\n'; X linesize=3; X } X if(*line==*cutstring && strncmp(line,cutstring,cutsize)==0 ){ X fprintf(stderr,"%s has a %s line\n",filename,cutstring); X quit(1,"bad cutstring"); X } X } X if(lastchar!='\n') X fputs("\n",out); X *proom = room; X return(room<=MAXLINE); X} X X Xstatic Xint Xifdone(out, pieces, npieces) X FILE* out; char* pieces[]; int npieces; X{ X int i; X if(npieces>1){ X fprintf(out,"test -w %s &&\n",pieces[0]); X for(i=1; i> %s; rm %s\n", X pieces[i],pieces[0],pieces[i]); X fprintf(out,")\n"); X return(16 + (npieces+2)*strlen(pieces[0])+ X npieces*(2*strlen(pieces[1])+27)); X }else{ X return(0); X } X} X X X/* return length of common directory prefix */ Xstatic Xint Xchopdir(file, nfile) X char** file; /* filenames */ X int nfile; /* number of filenames */ X{ X int ntry = 1; /* number of filenames yet to check */ X char *s; /* end of a candidate common prefix */ X int c; /* prefix length */ X if(nfile<=0) X return(0); X s = file[0]+strlen(file[0]); /* terminating '\0' */ X while(ntry>0){ X s--; X while(s>=file[0] && *s!='/') s--; /* next last '/' */ X c = s-file[0]+1; X if(c<=0) return(0); /* in case strncmp() is buggy */ X for(ntry=nfile-1; ntry>0; ntry--){ X if(strncmp(file[0],file[ntry],c)!=0) X break; X } X } X return(c); X} X X X/* X * It is assumed that the caller has already verified that address X * is safe to give to the shell, i.e. contains no backquotes, spaces, etc. X */ Xvoid Xbigmail(address, maxbyte, subject, file, nfile) X X char* address; /* address to send to, or stdout if 0 */ X long maxbyte; /* max number of bytes per mail message */ X char* subject; /* subject line */ X char** file; /* filenames */ X int nfile; /* number of filenames */ X{ X long room; /* how many bytes can we still send in this message? */ X long filesize; /* how many bytes in this file? */ X int npieces; /* how many pieces might this file require? */ X int piece; /* make sure we send exactly that many */ X char* pieces[101]; /* filenames for pieces */ X int mcnt = 0; /* so users can check for missing pieces */ X FILE *in; /* this file */ X FILE *out = 0; /* pipe to mail process for this message */ X int commprefix = chopdir(file,nfile); X if(maxbyte<=3000+HDR_SIZE){ X room = beginmess(-1,address,maxbyte,subject,&out); X fprintf(out,"Minimum mailsize is %d; you asked for %ld\n", X 3000+HDR_SIZE+1,maxbyte); X endmess(&out,0); X return; X } /* else worry about fragmentation */ X cutsize = strlen(cutstring); X while(nfile>0){ X fopensize(*file,&in,&filesize); X if( !out ) X room = beginmess(++mcnt,address,maxbyte,subject,&out); X npieces = piece_names(*file,out,room,filesize, X maxbyte,strlen(subject),pieces); X pieces[0] = file[0]+commprefix; X#ifdef SEMICRAZY X /* for administrators who want to hide original filename */ X if(nfile>1) quit(1,"can't send several anonymous files"); X pieces[0] = "anon"; X#endif X piece = 1; X room -= beginfile(out,pieces[piece-1]); X while(catfile(pieces[piece-1],in,out,&room)){ X room -= endfile(out); X piece++; X room -= ifdone(out,pieces,npieces); X endmess(&out,0); X if(piece>npieces) quit(666,"INTERNAL ERROR, npieces"); X room = beginmess(++mcnt,address,maxbyte,subject,&out); X room -= beginfile(out,pieces[piece-1]); X } X fclose(in); X room -= endfile(out); X if(npieces>1){ X while(++piece<=npieces){ X /* put out empty pieces as necessary */ X if(room<1000){ X endmess(&out,0); X room = beginmess(++mcnt,address,maxbyte,subject,&out); X } X room -= beginfile(out,pieces[piece-1]); X room -= endfile(out); X } X room -= ifdone(out,pieces,npieces); X } X file++; X nfile--; X } X if(out && out!=stdout) X endmess(&out,1); X} X X X#ifdef STANDALONE X#include Xquit(rc, mess) Xint rc; Xchar *mess; X{ X fprintf(stderr," %s\n", mess); X exit(rc); X} X Xmain(argc, argv) X int argc; char* argv[]; X{ X char *s; X long maxbyte = 100000; X if(s=getenv("N")) X maxbyte = atoi(s); X if(argc<4) X quit(1,"N=100000 bigmail address subject files..."); X bigmail(argv[1],maxbyte,argv[2],argv+3,argc-3); X exit(0); X} X#endif -------cut here----- src/bigmail.c echo src/changes 1>&2 sed >src/changes <<'-------cut here----- src/changes' 's/^X//' XSubject: changes in netlib processor X XFrom grigg!sue Mon Mar 24 10:54 EST 1986 XNetlib was released on 3/21/86 X X27Jun93 ehg X /netlib/admin/bin/ldM Added feature so "send all from x" sends all files mentioned X in "dependencies". This gets around problems with sloppy directories that X have a variety of tar files, subdirectories, etc. X# Eric Grosse ehg@research.att.com 20 Jun 1991 X# This is a replacement for the older version of ldM (used 1985-1991 in X# netlib), which had to be replaced because X# 1) SGI's loader map was buggy. X# 2) some netlib's didn't have Fortran compilers. X# 3) some netlib's run on gateways, for which object libraries X# are not needed for other purposes. X# The obscure sed script is merely glue to make this compatible with X# the previous version of ldM and with the syntax of "lo". X# From dmg Tue Feb 2 18:06 EST 1993 X# I adjusted /netlib/admin/bin/ldM to keep sed from dropping core X# when presented with a line over 4000 characters long. The script, X# though shorter, takes two more processes to do the same job, but X# without danger to sed. X X26Sep93 ehg X added ".research.att.com" as one more suffix to strip off if(upas) X XFrom dmg Fri Nov 19 08:25 EST 1993 XAfter temporarily turning on group write permissions for X/netlib/admin/bin, I moved F2C, F2cargs, F2cargs.c, Netlib.f2c Xand F2c.sh to /netlib/admin/bin and adjusted reply.c to invoke Xadmin/bin/F2C rather than f2c/F2C. X X28Mar94 ehg X moved src back to its own directory. X added plauger_chk, index_chk. X X17Apr94 ehg X substantial clean-up of code, not much intentional change to function. X X20Apr94 ehg X eliminate potential overwriting bug X X4May94 ehg X fixed bug in Depend -t regarding .h files X X22Jun94 ehg X make "send all from x" work even if there is no .depend file. X turn "send x" into "send index for x". X X6Jul94 ehg X add "subscribe" and "unsubscribe" X X11Jul94 ehg X Reply-To: takes precedence X X12Aug94 ehg X more AT&T nonsense X X1Sep94 ehg X Depend -t has to make D explicit before rewriting F X X18Sep94 ehg X Why did "send x/y" parse set depend=0? Removed it. X X13Jan95 ehg X bigmail.c should say "in an empty directory". X X25Jan95 ehg X subscribe.c, to_subscribers.c, mk.list.c X X27Feb95 ehg X reply.c: don't "send x" => "send index from x" when cmd==FIND X reply.c, Malloc.c: only call perror if errno set X X19Mar95 ehg X reply.c: -DFORWARD X Also took .list files out of my ftp archive, to discourage X mirroring of them elsewhere, and to eliminate possible subscriber X confusion because of the delay copying from pyxis to bootes. X X8Apr95 ehg X reply.c: FS0, to work around apparent bug in gcc. X X28May95 ehg X bigmail.c: change cutstring to avoid collision with numeralgo/na7. X (We don't want to use the "sed s/^X//" trick, because we want to X produce shar files that require very little Unix knowledge.) X X31May95 ehg X getfrom.c, reply.c: watch out for empty Reply-To: X X2Jun95 ehg X reply.c NOTE: IMPORTANT SECURITY CHANGE. In the past, only directories Xexplicitly listed could be accessed. Now, the LIBS file is used only to Xsupply aliases, and anything under the chroot'd directory is accessible. X X17Jun96 ehg X subscribe.c: create .newlist in /tmp to avoid permission problems. X30Jun96 ehg X reply.c: add bell-labs.com and lucent.com X X7Nov97 ehg X subscribe.c: change / to _ in tmpname X14Mar99 ehg X mimemail.c new code for emailing binary files. Yes, some netlib X users say they still prefer email, some say they have only email X not ftp or http! X reply.c include mimemail as alternative to bigmail X X27Oct99 ehg X mimemail.c, bigmail.c changed command "mail" to "/bin/mail" X to work better on SunOS 4.1.4 -------cut here----- src/changes echo src/combline.c 1>&2 sed >src/combline.c <<'-------cut here----- src/combline.c' 's/^X//' X/* Joins lines together, with items separated on input by empty lines. */ X/* Designed to replace refer by egrep. */ X X#include X#define MAXITEM 8000 X#define LM '\015' X/* line marker, so item can be reconstructed by tr '\015' '\012' */ X Xchar item[MAXITEM]; Xchar *l; Xint n, item_no; Xint maxlen, maxno; X X X/* like gets(), but safe */ Xchar * Xgetsn(s,m) X char *s; X int m; X{ X if(fgets(s,m,stdin)==NULL) X return(NULL); X m = strlen(s)-1; X if(s[m]=='\n') X s[m] = '\0'; X return(s); X} X X Xmain() X{ X int j; X item_no = 0; X maxno = 0; X maxlen = 0; X initi(); X while (getsn(l, MAXITEM - 1 - n) != NULL) { X j = strlen(l); X if (j == 0) { X flushi(); X } else { X l += j; X *l++ = LM; X *l = '\0'; X n += j + 1; X } X } X if (n > 0) { X flushi(); X } X exit(0); X} X X Xiniti() X{ X item[0] = '\0'; X n = 0; X l = item; X} X X Xflushi() X{ X item_no++; X if (n > maxlen) { X maxlen = n; X maxno = item_no; X } X fputs(item, stdout); X putc('\n', stdout); X initi(); X} -------cut here----- src/combline.c echo src/depend.h 1>&2 sed >src/depend.h <<'-------cut here----- src/depend.h' 's/^X//' Xstruct HashEntry {char* Key; int Code;}; Xtypedef struct HashEntry *HashTable; Xextern char* Fgets(char*,int,FILE*); Xextern void hashdel(HashTable*,int); Xextern int hashins(HashTable*,int,char*,int); Xextern int hashasu(char*,int); Xextern int hashpjw(char*,int); Xextern int hashsrch(HashTable*,char*); Xextern void* Malloc(size_t); Xextern void* Realloc(void*,int); Xextern char* Strdup(char*); -------cut here----- src/depend.h echo src/getdepend.c 1>&2 sed >src/getdepend.c <<'-------cut here----- src/getdepend.c' 's/^X//' X/* read .depend file, compute transitive closure for request */ X/* Eric Grosse 9 Dec 1993; cleaned for export 21 Mar 1994 */ X X/* This reads from stdin a .depend file and builds 1) an array of Xfiles, each with a list of symbols referenced, and 2) a hash table Xmapping defined symbols into files. Now, to compute the transitive Xclosure of a list of symbols given as arguments on the command line, Xkeep a stack of symbols yet to be resolved, a stack of files yet to be Xexpanded, and a list of files processed. */ X X#include X#include X#include "depend.h" X Xtypedef struct{ X char *name; X char **ref; /* array of symbols referenced by this file */ X int nref; X int done; /* has this already been added to hit? */ X} File; X Xtypedef struct{ X File *file; X int nfile; X HashTable Def; /* symbol -> index of file defining it */ X} Dependencies; X Xstatic void Xsave_refs(File *f, int nref, char **ref) X{ X f->ref = (char**)Malloc(nref*sizeof(*f->ref)); X memcpy(f->ref,ref,nref*sizeof(*f->ref)); X f->nref = nref; X} X Xvoid Xgetdepend(Dependencies *d) X{ X int i; /* HashTable index */ X int nf = 0; /* index of file being read */ X int maxf = 1000; /* guess at an upper bound for nf */ X int nref, maxref = 5000; /* guess at an upper bound for nref */ X int linelen; X char *name; X char line[1000]; /* surely 100 would be enough, but what the heck */ X char **ref = Malloc(maxref*sizeof(*ref)); X File *f = Malloc(maxf*sizeof(*f)); X HashTable D = 0; X X while(Fgets(line,sizeof(line),stdin)!=NULL){ X if(line[0]==0 || line[0]=='#') continue; X linelen = strlen(line); X if(line[linelen-1]=='\n') X line[--linelen] = '\0'; X name = Strdup(line+2); X switch(line[0]){ X case 'F': X if(nf>0) X save_refs(&f[nf],nref,ref); X nref = 0; X nf++; X if(nf>=maxf){ X maxf *= 2; X f=Realloc(f,maxf*sizeof(*f)); X } X f[nf].name = name; X f[nf].done = 0; X /* FALL THROUGH (file implicitly defines own name) */ X case 'D': i = hashsrch(&D,name); X if(i<0) hashins(&D,i,name,nf); X break; X case 'R': X nref++; X if(nref>=maxref){ X maxref *= 2; X ref=Realloc(ref,maxref*sizeof(*ref)); X } X ref[nref-1] = name; X break; X /* ignore other lines */ X } X } X if(nf>0 && nref>0) X save_refs(&f[nf],nref,ref); X free(ref); X d->file = f; X d->nfile = nf; X d->Def = D; X} X X X X Xtypedef struct{ X char **p; X int np, maxp; X} stack; X Xstatic void Xnew_stack(stack *s) X{ X s->maxp = 1000; X s->p = (char**)Malloc(s->maxp*sizeof(char*)); X s->np = 0; X} X Xstatic void Xpush(char *p, stack *s) X{ X if(s->np==s->maxp){ X s->maxp *= 2; X s->p = (char**)Realloc(s->p,s->maxp*sizeof(char*)); X } X s->p[s->np++] = p; X} X Xstatic char* Xpop(stack *s) X{ X if(s->np==0) return 0; X return(s->p[--s->np]); X} X X X Xstatic void Xresolve(Dependencies *d, stack *hit, stack *need) X{ X int i, k; X char *r; X File *f; X X while(r = pop(need)){ X i = hashsrch(&d->Def,r); X if(i>0){ X f = &d->file[d->Def[i].Code]; X if(!f->done){ X f->done = 1; X push(f->name,hit); X for(k = 0; knref; k++) X push(f->ref[k],need); X } X } /* else unsatisfied external */ X } X} X Xstatic int Xcmp(const void*a, const void*b) X{ X return(strcmp(*(char **)a,*(char **)b)); X} X Xvoid Xmain(int argc, char**argv) X{ X Dependencies D; X stack hit, need; X int i; X X new_stack(&hit); X new_stack(&need); X while(argc>1) X push(argv[--argc],&need); X getdepend(&D); X resolve(&D,&hit,&need); X /* hit isn't really a stack; now we prove it. */ X qsort(hit.p,hit.np,sizeof(char*),cmp); X for(i = 0; i&2 sed >src/getdepend.mbox <<'-------cut here----- src/getdepend.mbox' 's/^X//' XFrom ehg Tue Apr 9 07:45:18 EDT 1996 XFrom: Eric Grosse XX-URL: http://netlib.bell-labs.com/who/ehg/ XTo: cs.utk.edu!jhorner XSubject: Re: Getdepend X XThe .depend file records symbols defined and referenced by the Xcorresponding object files. Thus it lists only "first order" Xdependencies. X XThe job of getdepend is to take a list of symbols, given as Xcommand line arguments, read the .depend database from its Xstandard input, compute the transitive closure of the named Xsymbols relative to that database, and finally print a list Xof files that together satisfy as many of the dependencies Xas possible. Thus it works very much like a linker in the Xoperating system. X XSymbols are currently derived by looking at object files Xgenerated by compiling the source file. In the case of Fortran, Xthis means a number of system-specific Fortran runtime symbols Xare listed, and then ignored by getdepend. d_cnjg is an Xexample. For a while I used to screen these out, but this Xgets rather tricky when there are systems like f2c around. XSo for safety I leave them all in. X -------cut here----- src/getdepend.mbox echo src/getfrom.c 1>&2 sed >src/getfrom.c <<'-------cut here----- src/getfrom.c' 's/^X//' X#include X#include X Xint Xunsafe(char *s) X{ X char c; X /* check for characters interpreted by the shell (by which nefarious X users might otherwise break into the system) */ X for (c = (*s); c != '\0'; c = (*++s)) { X if ( strchr("\"'`$\n;&|^<>()\\", c) || (c & 0200) ){ X fprintf(stderr,"unsafe(%s) saw %c\n",s,c); X return(1); X } X } X return(0); X} X X X/* X * EXTRACT SENDER'S ADDRESS OUT OF RFC822 "FROM" LINE X * The sender is either the next first whitespace delimited token or X * the first thing enclosed in "<" ">". X * (leading "From: " is already deleted before entry) X * adapted from /n/bowell/src/cmd/upas (Dave Presotto) X * modified by Eric Grosse to stop after comma and to allow nested parens X */ Xint /* 0 on success, 1 if address is unparseable or unsafe */ Xgetfrom(char *line, char *sender) X{ X char *lp, *sp; X int comment = 0; X int anticomment = 0; X X sp = sender; X for (lp = line; *lp; lp++) { X if (comment) { X if (*lp == ')') { X comment--; X } else if (*lp == '(') { X comment++; X } X continue; X } X if (anticomment) { X if (*lp == '>') X break; X } X switch (*lp) { X case '\t': X case '\n': X break; X case ' ': X if (strncmp(lp, " at ", sizeof(" at ") - 1) == 0 || X strncmp(lp, " AT ", sizeof(" AT ") - 1) == 0 ) { X *sp++ = '@'; X lp += sizeof(" at ") - 2; X } X break; X case '<': X anticomment = 1; X sp = sender; X break; X case '(': X comment++; X break; X case ',': /* looks like multiple address; chop */ X *sp++ = '\0'; X default: X *sp++ = *lp; X break; X } X } X *sp = '\0'; X if(!*sender || unsafe(sender)) return 1; X return 0; X} X X X#ifdef STANDALONE X#define LINESIZE 1026 Xchar line[LINESIZE]; /* raw input line */ Xchar from[LINESIZE]; /* unfolded from line */ Xchar address[LINESIZE]; /* return address */ X X/* like gets(), but safe */ Xchar * Xgetsn(s,m) X char *s; X int m; X{ X if(fgets(s,m,stdin)==NULL) X return(NULL); X m = strlen(s)-1; X if(s[m]=='\n') X s[m] = '\0'; X return(s); X} X X/* case independent prefix compare */ Xint Xcicmp(char *s1, char *s2) X{ X int c1, c2; X X for(; *s1; s1++, s2++){ X c1 = *s1; X c2 = isupper(*s2) ? tolower(*s2) : *s2; X if (c1 != c2) X return -1; X } X return(0); X} X Xvoid Xmain(int argc, char**argv) X{ X int inside = 0, replyto = 0; X char c, *p; X X while(getsn(line, LINESIZE) != NULL){ X c = line[0]; X if(inside){ /* unfolding */ X if( c==' ' || c=='\t' ){ X if( strlen(line) + strlen(from) >= LINESIZE ){ X fprintf(stderr,"From line too long\n"); X exit(1); X } X strcat(from, line); X continue; X }else{ /* not a continuation */ X inside = 0; X } X } X if ( c == '\0' ) { X break; /* end of mail header */ X }else if(!replyto && strncmp("From ",line,5)==0){ X strcpy(from, line + 5); X if(p = strchr(from,' ')) *p = '\0'; /* chop date */ X }else if(strlen(line)>9 && cicmp("reply-to:",line)==0){ X strcpy(from, line + 9); X inside = 1; X replyto = 1; X }else if(!replyto && strlen(line)>5 && cicmp("from:",line)==0){ X strcpy(from, line + 5); X inside = 1; X } X } X if(getfrom(from, address)) X exit(1); X puts(address); X exit(0); X} X#endif -------cut here----- src/getfrom.c echo src/hash.c 1>&2 sed >src/hash.c <<'-------cut here----- src/hash.c' 's/^X//' X/* version with Brent reorganization. Eric Grosse */ X/* see Gonnet and Baeza-Yates, Handbook of Algorithms and Data Structures, 1991, p.63 */ X X/* XLet {\tt char* s} be a key, Xlet {\tt int c} be a value to be associated with {\tt s}, Xlet {\tt HashTable H=0} be a symbol table, Xand let {\tt int i=hashsrch(\&H,s)}. XIf {\tt i<0}, then {\tt s}$\not\in${\tt H}, and the pair $(s,c)$ Xmay be inserted by X{\tt hashins(\&H,i,Strdup(s),c)}. XOtherwise, {\tt s}$\in${\tt H} and Xthe associated value is {\tt H[i].Code}. XThe pair may be removed by {\tt hashdel(\&H,i)}. XUse {\tt free(H)} to release the space allocated for {\tt H} Xitself; this does not free the individual keys. XThe implementation uses open hashing, allocating a larger table Xand rehashing when too many collisions occur. X*/ X X#include X#include X#include "depend.h" X X#define LENGTH (H[0].Code) X#define DEAD ((char*)H) X/* H[0] just holds the length n. The hash table proper is H[1],...,H[n]. */ X Xint Xhashpjw(char* key, int n) X{ X unsigned int g, h = 0; X while((unsigned char)*key!=0){ X h = (h<<4)+(unsigned char)*key++; X if(g = h&15<<28){ X h = h^g>>28; X h = h^g; X } X } X return h%n; X} X Xint Xhashasu(char* key, int n) X{ X unsigned int h = 0; X while((unsigned char)*key!=0) X h = 65599*h+(unsigned char)*key++; X return h%n; X} X Xstatic int Xrehash(HashTable*Hp) X{ X int i, j; X char* key; X static int level; /* don't rehash in the middle of a rehash */ X int m; /* m and m-2 must both be prime! */ X HashTable N, H = *Hp; X int n; X X if(!H){ X n = 211; X *Hp = H = (struct HashEntry*)Malloc((n+1)*sizeof(*H)); X LENGTH = n; X for(j=1;j<=n;j++) X H[j].Key = 0; X level = 0; X return(1); X } X level++==0 || Error("rehash: recursive rehash"); /* maybe return(0)? */ X n = LENGTH; X if(n == 211) { m = 1019; X } else if(n == 1019) { m = 5099; X } else if(n == 5099) { m = 25033; X } else if(n == 25033) { m = 100153; X } else if(n == 100153) { m = 500809; X } else if(n == 500809) { m = 2503183; X } else { m = 5007181; Error("HashTable overflowed"); X } X N = (struct HashEntry*)Malloc((m+1)*sizeof(*N)); X N[0].Code = m; /* LENGTH */ X for(j=1;j<=m;j++) X N[j].Key = 0; X for(i = 1; i <= n; i += 1 ) { X if((key = H[i].Key)!=0 && key!=DEAD) { X j = hashsrch(&N, key); X j<0 || Error("%s already in N in rehash!?",key); X hashins(&N, j, key, H[i].Code); X } X } X free(H); X *Hp = N; X level -= 1; X return(1); X} X Xint Xhashsrch(HashTable*Hp, char* key) X{ X int i, inc, last, m; X char *HiKey; X HashTable H = *Hp; X X key || Error("hashsrch: null key"); X H || rehash(Hp); H = *Hp; X m = LENGTH; X i = hashpjw(key,m)+1; X HiKey = H[i].Key; X if(HiKey==0) X return(-i); X if(HiKey!=DEAD && HiKey[0]==key[0] && strcmp(HiKey+1,key+1)==0) X return(i); X inc = hashasu(key,m-2)+1; X last = (i-1+(m-1)*inc)%m+1; X while(1){ X i = (i-1+inc)%m+1; X if(i==last) return(-i); X HiKey = H[i].Key; X if(HiKey==0) return(-i); X if(HiKey==DEAD) continue; X if(HiKey[0]==key[0] && strcmp(HiKey+1,key+1)==0) return(i); X } X} X Xint Xhashins(HashTable*Hp, int j, char* key, int code) X{ X HashTable H = *Hp; X int init, inc, i, ii, jj, m = LENGTH; X char *HiKey; X X j<0 || Error("hashins: Insert should follow unsuccessful Search"); X /* search anyway, in case we can fill a DEAD slot */ X X init = hashpjw(key,m)+1; X HiKey = H[init].Key; X if( HiKey==0 || HiKey==DEAD){ X H[init].Key = key; X H[init].Code = code; X return(init); X } X X inc = hashasu(key,m-2)+1; /* n-2 so probe offset is not zero */ X for(i = 1; i=0; j--){ X jj = (init-1+inc*j)%m + 1; X ii = (jj-1+(hashasu(H[jj].Key,m-2)+1)*(i-j))%m+1; X if(H[ii].Key==0 || H[ii].Key==DEAD){ /* move record forward */ X H[ii].Key = H[jj].Key; H[ii].Code = H[jj].Code; X H[jj].Key = key; H[jj].Code = code; X goto finish; X } X } X } X finish: X /* if there were a lot of probes, rehash to speed future searches */ X if((j>=5||(i-j)>5)&&m<1020 || (j>9||(i-j)>9)&&m<2500000){ X rehash(Hp) || Error("hashsrch: new algorithm needed!"); H = *Hp; X jj = hashsrch(&H,key); X jj>0 || Error("hashins:can't"); X } X return(jj); X} X Xvoid Xhashdel(HashTable*Hp, int j) X{ X HashTable H = *Hp; X j>0 || Error("hashdel must follow successful Search"); X H[j].Key = DEAD; X} X X -------cut here----- src/hash.c echo src/index_chk.c 1>&2 sed >src/index_chk.c <<'-------cut here----- src/index_chk.c' 's/^X//' X/* Check conformance of index to /netlib/bib/thesaurus. X Xarg[1]: index filename, relative to netlib root Xstderr: warnings Xstdout: possibly improved index file X XIt is assumed that the index already passes plauger_chk. X X* Each paragraph starts with file or lib. X* Filenames should have path relative to /netlib. X* Only one file or lib per paragraph. X* Each listed lib or file should exist and be readable. X* If file is bigger than 200kB, list size in index. X* Each line is keyword-tab-value. X* Filenames should be lowercase and not too long. X* Warn about files not in index. X* Files should not be in multiple entries. X XEric Grosse X26 Mar 1994 first cut X 4 Apr 1994 allow .Z; minor fixes X 5 Apr 1994 don't index "dependencies". "global comments deprecated". X People used inconsistent mess of blanks and tabs, so just X rewrite all white space between key and val as single tab. X Remove empty comment lines. Remove trailing space. X12 Jun 1994 use , instead of for continuation. include "readme" X*/ Xchar *exclude[] = { X"index","index.html","index.FIX",".depend","disclaimer", X"permission","Makefile","dependencies",".master", X".cache",".names",".cap",".cache+",0}; X X#define _POSIX_SOURCE X#include X#include X#include X#include X#include X#include X#include X#include X#include "depend.h" Xextern int Error(char*,...); X Xtypedef struct{ X int inside; /* inside a paragraph, i.e. have seen "file" line */ X unsigned long size; /* file size, if large enough to matter */ X} State; X X/* HashTable Code */ X#define File 1 X#define Lib 2 X Xint NR = 0; /* input line number, for error messages */ X Xint /* 1 if chopping succeeds */ Xchop(char *s, char *suffix) X{ X int m, n; X if(!s || !suffix ) return(0); X n = strlen(s); m = strlen(suffix); X if(strcmp(s+n-m,suffix)!=0) return(0); X s[n-m] = 0; X return(1); X} X XHashTable Xactual(void) X{ X struct dirent *d; X struct stat s; X DIR *dir = opendir("."); X char *name; X HashTable H = 0; X int i; X X dir!=NULL || Error("can't open %s"); X while((d=readdir(dir))!=NULL){ X name = d->d_name; assert(name&&name[0]); X if(strcmp(name,".")==0 || strcmp(name,"..")==0) continue; X stat(name,&s)==0 || Error("can't stat %s",name); X i = hashsrch(&H,name); assert(i<0); X if(S_ISREG(s.st_mode)){ X hashins(&H,i,Strdup(name),File); X }else if(S_ISDIR(s.st_mode)){ X hashins(&H,i,Strdup(name),Lib); X } /* symbolic links are deprecated (and ignored). */ X } X closedir(dir); X return(H); X} X Xprintsize(State *state) X{ X if(state->size){ X if(state->size<1000*1000) X printf("size\t%d kB\n",state->size/1000); X else X printf("size\t%.1f MB\n",state->size/(1000*1000.)); X state->size = 0; X } X} X Xvoid Xrules(char *key, char *val, State *state, HashTable *pH, char *path) X{ X char *local, *l; /* local filename (with directory prefix chopped) */ X int file_or_lib = 0; X int i; X struct stat s; X static int globalcomm = 0; X X if(!*key && !*val){ /* empty input line */ X if(state->inside){ X printsize(state); X printf("\n"); X state->inside = 0; X } X return; /* collapse multiple blank lines */ X } X X if(strcmp(key,"file")==0) file_or_lib = File; X else if(strcmp(key,"lib")==0) file_or_lib = Lib; X X /* Each paragraph starts with file or lib. */ X if(!state->inside && !file_or_lib && *key!='#'){ X fprintf(stderr,"expected file or lib at line %d\n",NR); X printf("file %s/???\n",path); X state->inside = 1; X } X X if(file_or_lib){ X int pathlen = strlen(path); X local = val+pathlen+1; /* chop "path/" prefix */ X X /* Only one file or lib per paragraph. */ X if(state->inside){ X fprintf(stderr,"only one file per paragraph! %d",NR); X printf("\n"); /* start new paragraph */ X } X X /* Filenames should have path relative to /netlib. */ X if(strncmp(val,path,pathlen)!=0 || val[pathlen]!='/'){ X fprintf(stderr,"use full path at line %d\n",NR); X !strchr(val,'/') || Error("lost in / at line %d",NR); X /* rewrite "lcl" as "path/lcl" */ X memmove(local,val,strlen(val)+1); X strcpy(val,path); X val[pathlen] = '/'; X } X X /* Files should not be in multiple entries. */ X if((i = hashsrch(pH,local))>0) X fprintf(stderr,"duplicate %s at %d\n",local,NR); X else X hashins(pH,i,Strdup(local),file_or_lib); X X /* Each listed lib or file should exist and be readable. */ X if(stat(local,&s)!=0){ X fprintf(stderr,"%s at %d does not exist\n",local,NR); X }else{ X if(S_ISREG(s.st_mode)){ X if(file_or_lib!=File){ X fprintf(stderr,"lib should be file at %d",NR); X if(val200*1000) X state->size = s.st_size; X } /* stat */ X X /* Filenames should be lowercase and not too long. */ X if(strlen(local)>23) X fprintf(stderr,"Shorten %s!\n",local); X for(l = local; *l; l++){ X if(l[0]=='Z' && l[1]==0) break; /* .Z suffix is ok */ X if(!islower(*l) && !isdigit(*l) && X !strchr("-_+.,~?",*l)){ X fprintf(stderr,"Use lowercase, simple name for %s!\n",local); X break; X } X } X state->inside = 1; X } /* file_or_lib */ X X /* Continuation lines have , as keyword. */ X if(key[0]==0){ X key = ","; X }else if(strcmp(key,"#")==0){ X if(!*val) X return; /* no empty comments */ X if(state->inside) X ; /* *key = 0 is heuristic for round of corrections */ X else if(!globalcomm++) X fprintf(stderr,"global comments are deprecated\n"); X } X X if(strcmp(key,"size")==0) X printsize(state); X else /* Each line is keyword-tab-value. */ X printf("%s\t%s\n",key,val); X} X Xvoid Xmissing(HashTable *pdoc, char *path) X{ X struct dirent *d; X struct stat s; X DIR *dir = opendir("."); X char *name, **excl; X int i; X X for(excl = exclude; *excl; excl++){ X i = hashsrch(pdoc,*excl); X if(i>=0) fprintf(stderr,"don't index %s\n",*excl); X else hashins(pdoc,i,*excl,File); X } X dir!=NULL || Error("can't open %s"); X while((d=readdir(dir))!=NULL){ X name = d->d_name; assert(name&&name[0]); X if(strcmp(name,".")==0 || strcmp(name,"..")==0) continue; X if(hashsrch(pdoc,name)<0){ X stat(name,&s)==0 || Error("can't stat %s",name); X if(S_ISREG(s.st_mode)){ X printf("file\t%s/%s\n\n",path,name); X }else if(S_ISDIR(s.st_mode)){ X printf("lib\t%s/%s\n\n",path,name); X } X } X } X closedir(dir); X} X Xvoid Xmain(int argc, char**argv) X{ X char line[2048], *val, *path; X HashTable doc = 0, act = 0; X FILE *I; /* index file */ X State state; X X /* figure out where we should work and go there */ X argc==2 || Error("%s a/index > index.FIX 2> err",argv[0]); X path = Strdup(argv[1]); X chop(path,"/index") || Error("arg1 should end in /index"); X chdir(path)==0 || Error("can't cd %s",path); X X /* what's the truth? */ X act = actual(); X X /* what's documented? */ X I = fopen("index","r"); I!=NULL || Error("can't read index"); X state.inside = 0; state.size = 0; X while(Fgets(line,sizeof(line)-100,I)!=NULL){ X NR++; X val = line; X while(*val && *val!=' ' && *val!='\t') val++; /* past keyword */ X if(*val){ X *val++ = 0; /* terminate keyword */ X while(*val==' ' || *val=='\t') val++; X } X if(*val){ /* strip trailing space */ X char *endval = &val[strlen(val)-1]; X while(*endval==' '||*endval=='\t') X *endval-- = 0; X } X rules(line,val,&state,&doc,path); X } X rules("","",&state,&doc,path); /* for final printsize(), etc. */ X X /* Warn about files not in index, other than: index, etc.*/ X missing(&doc,path); X X exit(0); X} -------cut here----- src/index_chk.c echo src/lsr.c 1>&2 sed >src/lsr.c <<'-------cut here----- src/lsr.c' 's/^X//' X/* see copyright notice in /netlib/crc/lsr.c */ X X#define _POSIX_SOURCE X#include X#include X#include X#include X#include X#include X#include Xextern char *Strdup(char*); Xextern void *Malloc(int); Xextern void *Realloc(void*,int); Xtypedef unsigned char uchar; X X#ifdef NOSYMLINK X#define lstat(f,s) stat(f,s) X#endif X Xstatic uchar *path, **component, *dest; Xstatic int ncomp; X Xstatic int Xcmp(const void *a, const void *b) X{ X return strcmp(*(char**)a,*(char**)b); X} X Xstatic char ** Xsorted_names(DIR *dir) X{ X int maxnames = 250; /* starting guess at size of directory */ X int nnames = 0; X char **names = (char **)Malloc(maxnames*sizeof(*names)); X char *file, *s; X struct dirent *entry; X X while( entry = readdir(dir) ){ X file = entry->d_name; X if(strcmp(file,".")!=0 && strcmp(file,"..")!=0 ){ X names[nnames++] = Strdup(file); X if(nnames>=maxnames){ X maxnames += 200; X names = (char **)Realloc(names,maxnames*sizeof(char*)); X } X } X for(s = file; *s; s++) X if(!isgraph(*s)){ X strcpy((char*)component[ncomp-1],file); X break; X } X } X qsort((void*)names,nnames,sizeof(*names),cmp); X names[nnames] = 0; X return(names); X} X Xstatic void Xfree_names(char **names) X{ X char **name; X for(name = names; *name; name++) X free(*name); X free(names); X} X Xstatic void Xpr(void) X{ X struct stat s; X DIR *dir; X char buf[BUFSIZ]; X int cc; X char **names, **name; X X if(lstat((char*)path,&s)){ X return; X } X#ifndef NOSYMLINK X if(S_ISLNK(s.st_mode)){ X }else X#endif X if(S_ISREG(s.st_mode)){ X uchar *p = path; X if(p[0]=='.' && p[1]=='/') X p += 2; /* chop off leading ./ */ X strcpy(dest,p); dest += strlen(dest); X *dest = ' '; dest += 1; X }else if(S_ISDIR(s.st_mode)){ X if(dir = opendir((char*)path)){ X cc = strlen((char*)component[ncomp-1]); X component[ncomp] = cc+component[ncomp-1]+1; X component[ncomp][-1] = '/'; X ncomp++; X names = sorted_names(dir); X for(name = names; *name; name++){ X strcpy((char*)component[ncomp-1],*name); X pr(); X } X free_names(names); X ncomp--; X component[ncomp][-1] = '\0'; X closedir(dir); X } X } X} X Xlsr(char *f, char *p) X{ X dest = f; X component = (uchar**)Malloc(1000*sizeof(uchar*)); X /* should check against depth */ X path = (uchar *)Malloc(4096); X /* should be _POSIX_PATH_MAX */ X component[0] = path; X ncomp = 1; X strcpy(path,p); X pr(); X free(path); X free(component); X} X X#ifdef STANDALONE Xmain(int argc, char**argv) X{ X char f[10000]; X lsr(f,argc>1?argv[1]:"."); X printf("%s\n",f); X exit(0); X} X#endif -------cut here----- src/lsr.c echo src/mimemail.c 1>&2 sed >src/mimemail.c <<'-------cut here----- src/mimemail.c' 's/^X//' X/* netlib mimemail - bundle binary files as MIME attachments X * X * Eric Grosse X * Copyright (c) 1999 by Lucent Technologies. X * Permission to use, copy, modify, and distribute this software for any X * purpose without fee is hereby granted, provided that this entire notice X * is included in all copies of any software which is or includes a copy X * or modification of this software and in all copies of the supporting X * documentation for such software. X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED X * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. X * X * The purpose of this function (or program, if compiled -DSTANDALONE) X * is to mail to argv[1] with subject argv[2] a list of files in argv[3] X * up to argv[n]. This is a compatible substitute for netlib bigmail, X * to be used when the files are binary and the recipient can handle MIME. X */ X#define _POSIX_SOURCE X#define _POSIX2_SOURCE X#include X#include Xtypedef unsigned long ulong; Xtypedef unsigned char uchar; Xextern FILE *popen(const char *, const char *); X Xstatic char cutstring[] = "--------12X12E144"; X X/* rfc1521 base64 (3 octets = 4 printables) */ Xstatic char t64e[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; X Xstatic int Xenc64(char *out, uchar *in, int n) X{ X int i; X ulong b24; X char *start = out; X X for(i = n/3; i > 0; i--){ X b24 = (*in++)<<16; X b24 |= (*in++)<<8; X b24 |= *in++; X *out++ = t64e[(b24>>18)]; X *out++ = t64e[(b24>>12)&0x3f]; X *out++ = t64e[(b24>>6)&0x3f]; X *out++ = t64e[(b24)&0x3f]; X } X X switch(n%3){ X case 2: X b24 = (*in++)<<16; X b24 |= (*in)<<8; X *out++ = t64e[(b24>>18)]; X *out++ = t64e[(b24>>12)&0x3f]; X *out++ = t64e[(b24>>6)&0x3f]; X break; X case 1: X b24 = (*in)<<16; X *out++ = t64e[(b24>>18)]; X *out++ = t64e[(b24>>12)&0x3f]; X *out++ = '='; X break; X } X *out++ = '='; X *out = 0; X return out - start; X} X X X/* begin mail message */ Xstatic void Xbeginmess(char* address, char* subject, FILE** outp) X{ X char cmd[512]; X X if(address){ X if(strlen(address)>=500) X quit(strlen(address)+100,"address too long"); X sprintf(cmd,"/bin/mail %s",address); X if( (*outp = popen(cmd,"w")) == NULL){ /* POSIX.2 */ X fprintf(stderr,"%s:\n",cmd); X quit(1,"can't popen"); X } X }else{ X *outp = stdout; X } X if(!subject) X subject = "Subject: netlib mimemail"; X fprintf(*outp,"MIME-Version: 1.0\n"); X fprintf(*outp,"%s\n",subject); X fprintf(*outp,"Content-Type: multipart/mixed;\n"); X fprintf(*outp," boundary=\"%s\"\n\n",cutstring); X fprintf(*outp,"This is a multi-part message in MIME format.\n"); X fprintf(*outp,"--%s\n",cutstring); X fprintf(*outp,"Content-Type: text/plain; charset=us-ascii\n"); X fprintf(*outp,"Anything free comes with no guarantee!\n"); X} X X/* end mail message */ Xstatic void Xendmess(FILE** outp) X{ X int rc; X X fprintf(*outp,"--%s--\n",cutstring); X fflush(*outp); X if(*outp==stdout){ X fputs("#----------------------------------------\n",*outp); X }else{ X if((rc=pclose(*outp)) != 0) /* POSIX.2 */ X fprintf(stderr,"bad pclose %d\n",rc); X *outp = (FILE*)0; X } X} X X/* begin file (possibly several per message) */ Xstatic void Xbeginfile(FILE* out, char* filename) X{ X fprintf(out,"--%s\n",cutstring); X fprintf(out,"Content-Type: application/octet-stream;\n"); X fprintf(out," name=\"%s\"\n",filename); X fprintf(out,"Content-Transfer-Encoding: base64\n"); X fprintf(out,"Content-Disposition: attachment;\n"); X fprintf(out," filename=\"%s\"\n\n",filename); X} X Xstatic void Xendfile(FILE* out) X{ X} X Xstatic void Xcatfile(char* filename, FILE *in, FILE *out) X{ X /* write 72 base64 chars per line, from 54 original octets */ X char line[80], buf[54], *bp, *be; X int n, linesize; X while( (n=fread(buf,1,sizeof(buf),in)) > 0){ X linesize = enc64(line,buf,n); X if(n==sizeof(buf)) X linesize--; /* chop = */ X line[linesize++] = '\n'; X if(fwrite(line,1,linesize,out)==EOF){ X quit(1,"write error"); X } X } X} X X/* X * It is assumed that the caller has already verified that address X * is safe to give to the shell, i.e. contains no backquotes, spaces, etc. X * address = address to send to, or stdout if 0 X * subject = subject line X * file = filenames X * nfile = number of filenames X */ Xvoid Xmimemail(char *address, char *subject, char **file, int nfile) X{ X FILE *in; /* this file */ X FILE *out; /* pipe to mail process for this message */ X X beginmess(address,subject,&out); X while(nfile>0){ X if((in = fopen(*file,"r"))==NULL){ X fprintf(stderr,"%s:\n",*file); X quit(1,"can't open"); X } X beginfile(out,*file); X catfile(*file,in,out); X fclose(in); X endfile(out); X file++; X nfile--; X } X endmess(&out); X} X X X#ifdef STANDALONE X#include Xquit(int rc, char *mess) X{ X fprintf(stderr," %s\n", mess); X exit(rc); X} X Xmain(int argc, char* argv[]) X{ X char *s; X if(argc<4) X quit(1,"mimemail address subject files..."); X mimemail(argv[1],argv[2],argv+3,argc-3); X exit(0); X} X#endif X -------cut here----- src/mimemail.c chmod +x src/mimemail.c echo src/mk.list.c 1>&2 sed >src/mk.list.c <<'-------cut here----- src/mk.list.c' 's/^X//' X/* setuid program, so netlibd can create subscriber list */ X#define _POSIX_SOURCE X#include X#include X#include X#include X#include X#include X Xgid_t groups[] = {0,2,3,4,20,49,50,482,995,997,998}; X Xvoid Xmain(int argc, char**argv) X{ X char path[300], *dir; X setuid(100); X setgroups(sizeof(groups)/sizeof(groups[0]),groups); X if(argc!=2) X exit(1); X if(strlen(argv[1])>250) X exit(2); X sprintf(path,"/netlib/%s/.list",argv[1]); X for( dir = path; dir = strchr(dir,'/'); dir++) X if(strncmp(dir,"/../",4)==0) X exit(3); X umask(0); X if(access(path,F_OK)!=0) X creat(path,0666); X else X chmod(path,0666); X exit(0); X} -------cut here----- src/mk.list.c echo src/plauger_chk.c 1>&2 sed >src/plauger_chk.c <<'-------cut here----- src/plauger_chk.c' 's/^X//' X/* check file for adherence to Plauger's rules of portable i/o */ X/* see: C Users Journal 7:6 (Aug89) 17-25 */ X/* Eric Grosse Sep 1989, tweaked Mar 1994 */ X X#include X#include X#include X#include X Xvoid Xmain(int argc, char**argv) X{ X char line[512], *s; X unsigned char c; X int i, n, NR = 0, nonpr, cnt[256]; X int dot = 0, err = 0, crlf = 0; X X if(argc!=1){ X fprintf(stderr,"%s < file > errors\n",argv[0]); X exit(++err); X } X for(i = 0; i<256; i++) X cnt[i] = 0; X while(fgets(line,sizeof(line),stdin)!=NULL){ X NR++; X n = strlen(line); X if(n>510){ X printf("%d long",NR); err++; X }else{ X n--; X if(line[n]!='\n'){ X printf("%d no newline\n",NR); err++; X } X line[n] = '\0'; /* strip newline */ X } X if(!crlf && line[n-1]=='\r'){ X crlf = 1; X printf("%d CR LF\n",NR); err++; X }else if(isspace(line[n-1])){ X printf("%d trailing space\n",NR); err++; X } X if(dot==0 && n==1 && line[0]=='.'){ X printf("%d line . is dangerous for mail\n",NR); X dot = 1; X } X nonpr = 0; X for(s = line; *s; s++){ X c = *s; X if(!isprint(c) && c!='\t'){ X cnt[c]++; X if(!nonpr){ X nonpr = 1; X printf("%d nonprinting\n",NR); err++; X } X } X } X } X if(NR==0){ X printf("empty files may be discarded\n"); err++; X } X for(i=0; i<256; i++) X if(cnt[i]!=0){ X printf("%d occurrences of '\\0%o'\n",cnt[i],i); err++; X } X exit(err); X} -------cut here----- src/plauger_chk.c echo src/reply.c 1>&2 sed >src/reply.c <<'-------cut here----- src/reply.c' 's/^X//' X/* X * The author of this software is Eric Grosse. Copyright (c)1985,1994 by AT&T. X * Permission to use, copy, modify, and distribute this software for any X * purpose without fee is hereby granted, provided that this entire notice X * is included in all copies of any software which is or includes a copy X * or modification of this software and in all copies of the supporting X * documentation for such software. X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED X * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. X */ X X/* The following program reads an electronic mail message, searches X its database, and tries to reply. X X To explore the program, set DEBUG=on in the shell environment. X Instead of executing shell commands they will be sent to admin/stderr. X X The home directory, /netlib, contains various source directories, X such as /netlib/eispack. The netlib administrative directory X /netlib/admin contains indices, permission tables, and logfiles. X X For a revision log, see /netlib/admin/src/changes. X Send bug reports to ehg@research.bell-labs.com. X X This code has grown in steps over time and is in serious X need of a complete rewrite. X*/ X X#define _POSIX_SOURCE X#include X#include X#include X#include X#include X#include X#include /* on some systems, this is */ X#include X#include X#include /* POSIX; used only in allfiles() */ X#ifndef S_ISDIR X#define S_ISDIR( mode ) (((mode) & S_IFMT) == S_IFDIR) X#endif X#include "depend.h" X Xextern FILE *popen(const char *, const char *); X XFILE *Fopen(); Xchar *get_date(void); Xint unsafe(char*); Xint getfrom(char*,char*); Xextern int subscribe(char*,char*); Xextern int unsubscribe(char*,char*); Xextern void lsr(char*,char*); X X#define LINESIZE 10000 X#define FIELDMAX 400 Xchar FS0[] = " \t\";,"; /* work around apparent bug in gcc */ Xchar *FS = FS0, *field[FIELDMAX]; Xint NR, NF; Xextern int Error_rc, errno; X Xint DEBUG; Xint in_header = 1; Xint group; /* 0=general, 1=local, 10=enemy */ Xint depend; /* send all routines request depends on? */ Xint upas; /* does this system run Presotto's mailer? (used in parse) */ Xchar reply[20]; /* temp file for constructing reply */ Xint siam; /* =1 if searching the SIAM membership list */ Xint dir800; /* =1 if searching the 800 directory */ Xchar usermail[LINESIZE]; /* for use in "sorry" */ Xlong maxbyte; /* max number of bytes per mail message */ Xint mime = 0; /* should reply be sent as one MIME multipart message? */ Xint SEND,LIST,INDEX,FIND,EXEC,SUBSCRIBE,UNSUBSCRIBE,MIME; /* command codes */ X#define SKIP 0 X#define DONE 999 X Xchar *suffix[] = /* for filename expansion in only() */ X {"", ".r", ".f", ".c", ".C", ".h", ".H", X ".tex", ".bib", ".shar", ".ps", ".html", 0 }; X Xvoid Xrmtemp(void) X{ X unlink(reply); X} X Xmain() X{ X char address[LINESIZE]; /* return address */ X int cmd; /* code for type of request in current input line */ X int k; /* field index */ X int item[2], excl[2], lib[2], thru[2]; /* first and last fields */ X /* for routines, exclusions, libraries */ X char zlib[500]; /* strcat of field[lib[0]] ... field[lib[1]] */ X char xlib[1000]; /* zlib after expansion through LIBS file */ X char zitem[500], zexcl[500]; X char files[10*LINESIZE]; /* filenames to be sent as reply */ X int nreq = 0; /* number of recognized requests */ X int kbreq = 0; /* number of kilobytes sent so far */ X char buf[LINESIZE]; X long size, fsiz(); X FILE *F; X char *date; X char *debugs; X char *sp; X char subject[261]; X char execlog[50]; X X if(debugs=getenv("DEBUG")) X DEBUG = strcmp(debugs,"on")==0; X upas = (access("/v/lib/upas", 0) == 0); X if(upas && group>2) X chdir("/netlib2/pub"); X else X chdir("/netlib"); /* MODIFY AS DESCRIBED IN README. */ X if(freopen("admin/stderr","a",stderr)==NULL) exit(0); X date = get_date(); X strcpy(reply, "/tmp/netlibXXXXXX"); X mktemp(reply); X atexit(rmtemp); X Error_rc = 0; /*Some mailers demand 0 return from alias script. */ X errno = 0; X address[0] = '\0'; X X while (awk() != EOF){ /* read next line of message */ X cmd=parse(address,item,excl,lib,thru); X if(cmd==DONE) X break; X if( (address[0] == '\0') || X (cmd == SKIP) || X duplicate(cmd, item, excl, lib) ) X continue; X X /* translate library names */ X if(cmd != EXEC){ X if(!lib[0]){ X k = item[0]; X if(k==item[1] && cmd!=FIND && isdir(field[k])){ X /* "send x" => "send index from x" */ X /* BUG: doesn't work for "send x/y" */ X field[item[0] = item[1] = 1] = "index"; X lib[0] = lib[1] = k; X } else X field[lib[0] = lib[1] = 1] = "DEFAULT"; X } X gather(lib, zlib, sizeof(zlib)); X if(cmd==SEND || cmd==LIST || X cmd==SUBSCRIBE || cmd==UNSUBSCRIBE){ X expand(lib, xlib); X }else{ /* FIND */ X strcpy(xlib, zlib); X if((group == 1) && (strcmp(xlib, "DEFAULT") == 0)) X strcat(xlib, " DEFAULT.lcl"); X } X gather(item, zitem, sizeof(zitem)); X gather(excl, zexcl, sizeof(zexcl)); X } X if(DEBUG){ X fprintf(stderr,"address=%s ", address); X fprintf(stderr,"group=%d ",group); X fprintf(stderr,"cmd=%d\n", cmd); X fprintf(stderr,"zitem=%s ", zitem); X fprintf(stderr,"zexcl=%s\n", zexcl); X fprintf(stderr,"xlib=%s\n", xlib); X fprintf(stderr,"item=%d,%d ", item[0],item[1]); X fprintf(stderr,"excl=%d,%d ", excl[0],excl[1]); X fprintf(stderr,"lib=%d,%d\n", lib[0],lib[1]); X } X sprintf(subject,"To: %.180s\nSubject: Re: %.60s",address,field[0]); X F = Fopen(reply, "w"); X fputs(subject,F); X fputs("\n\n",F); X fclose(F); X X /* execute command */ X if( group == 10 ){ X quit(666,"enemy"); /* fogel@oak.GEOG.UCSB.EDU loop */ X sprintf(buf, "cat admin/mess/sorry_enemy >>%s", reply); X shell(buf); X }else if( cmd == EXEC ){ X /* I considered making an easily edited file of X commands, like LIBS or /usr/lib/uucp/Permissions. X But then I decided that naive administrators would X unknowingly open security holes. Be careful! */ X if( strcmp(field[item[0]],"f2c")==0 ){ X strcpy(execlog,"F2C"); X while(in_header && awk()!=EOF ){ X cmd=parse(address,item,excl,lib); X } X strcpy(files, "/tmp/f2cXXXXXX"); X mktemp(files); /* removed by F2C */ X F = Fopen(files,"w"); X while(fgets(buf,sizeof(buf),stdin)!=NULL) X fputs(buf,F); X fclose(F); X sprintf(buf, "admin/bin/F2C %s %s >> %s", X address, files, reply); X shell(buf); X }else if( strcmp(field[item[0]],"pgpsigned")==0 ){ X strcpy(execlog,"pgpsigned"); X while(in_header && awk()!=EOF ){ X cmd=parse(address,item,excl,lib); X } X strcpy(files, "/tmp/pgpXXXXXX"); X mktemp(files); /* removed by pgpsigned */ X F = Fopen(files,"w"); X while(fgets(buf,sizeof(buf),stdin)!=NULL) X fputs(buf,F); X fclose(F); X sprintf(buf, "admin/bin/pgpsigned %s %s >> %s", X address, files, reply); X shell(buf); X }else if( strcmp(field[item[0]],"auth")==0 ){ X strcpy(execlog,"auth inf"); X sprintf(buf, "admin/bin/auth inf %s >> %s", X address, reply); X shell(buf); X }else{ X strcpy(execlog,"sorry_cmd"); X sprintf(buf, "cat admin/mess/sorry_cmd >>%s", reply); X shell(buf); X } X }else if(xlib[0] == '\0'){ X sprintf(buf, "cat admin/mess/sorry_lib >>%s", reply); X shell(buf); X }else if(unsafe(xlib) || unsafe(zitem) || strchr(zitem,'/') || unsafe(zexcl) ){ X sprintf(buf, "cat admin/mess/sorry_unsafe >>%s", reply); X shell(buf); X }else if( cmd == FIND ){ X if(strcmp(xlib,"800")==0) dir800 = 1; X if(siam){ X sprintf(buf, "cat admin/mess/siam >>%s", reply); X shell(buf); X }else if(dir800){ X sprintf(buf, "cat admin/mess/dir800 >>%s", reply); X shell(buf); X } X sprintf(buf, "admin/bin/mgrep '%s' %s >>%s", xlib, zitem, reply); X shell(buf); X }else if( cmd==SUBSCRIBE || cmd==UNSUBSCRIBE ){ X#ifdef FORWARD X F = Fopen(reply,"a"); X fprintf(F,"path %s\n",address); X fprintf(F,"%s %s\n",(cmd==SUBSCRIBE)?"subscribe":"unsubscribe",xlib); X fclose(F); X strcpy(address,FORWARD); X#else X switch((cmd==SUBSCRIBE)?subscribe(address,xlib): X unsubscribe(address,xlib)){ X case 0: X sprintf(buf,"echo Done. >>%s",reply); X shell(buf); X break; X case 1: X sprintf(buf,"cat admin/mess/no-topic >>%s",reply); X shell(buf); X break; X case 2: X sprintf(buf,"cat admin/mess/collided >>%s",reply); X shell(buf); X break; X case 3: X fprintf(stderr,"[%s]%s: \n",address,xlib); X fflush(stderr); X perror("SUBSCRIBE error"); X break; X } X#endif X }else if( cmd==SEND || cmd==LIST ){ X if(depend){ X sprintf(buf,"admin/bin/ldMx '%s' '%s' '%s'",xlib,zitem,zexcl); X if(DEBUG) fprintf(stderr,"[%s]\n",buf); X F = popen(buf,"r"); X if(fgets(files,LINESIZE,F)==NULL) X files[0] = '\0'; X pclose(F); X nlchop(files); X if(!*files){ /* failed; try only() */ X depend = 0; X } X } X if(!depend) X only(xlib,item,files); X nlchop(files); X if(strncmp("admin/mess/sorry",files,16) != 0){ X sprintf(buf,"admin/bin/disclaim %s >>%s",xlib,reply); X shell(buf); X } X sprintf(buf,"cat %s >>%s",files,reply); X shell(buf); X if( cmd == LIST ){ X size = fsiz(reply); X F = Fopen(reply,"w"); X fprintf(F,"Subject: Re: %s\n\n",field[0]); X fprintf(F,"The following files total %ld bytes\n",size); X if(size > 345600.) X fprintf(F," = %.1f hours per link at 9600bps.\n",size / 3456000.); X for( sp=files; sp=strchr(sp,' '); sp++) X *sp = '\n'; /* for easier reading */ X fprintf(F,"\n%s\n",files); X fclose(F); X } X } X X /* is user being too greedy? */ X size = fsiz(reply); X kbreq += size / 1000; X if( (siam||dir800) && size > 5000 || cmd==FIND && size > 50000 ){ X sprintf(buf, X "sed 200q %s | cat admin/mess/sorry_find - | /bin/mail %s", X reply, address); X shell(buf); X sprintf(buf,"big find: %.40s",field[0]); X quit(5, buf); X }else if( ((nreq++ > 50) || (kbreq > 2000)) && (group == 0) ){ X sprintf(buf, "cat admin/mess/sorry_many | /bin/mail %s", address); X shell(buf); X quit(5, "too many requests"); X } X X /* ship it out */ X if( cmd == SEND && xlib[0] != '\0' ){ X /* new scheme */ X send(address,maxbyte,subject,files,xlib); X }else{ X sprintf(buf, "<%s /bin/mail %s", reply, address); X shell(buf); X } X X /* append summary to log */ X if((F = fopen("admin/log", "a")) != NULL){ X if( group == 10 ){ X fprintf(F, "%s [%s] %ld ENEMY\n", date, address, X size); X exit(0); X }else if(cmd == EXEC){ X fprintf(F, "%s [%s]%s %ld %s\n", date, address, X group==1 ? "l" : "", size, execlog); X }else if(cmd==SUBSCRIBE){ X fprintf(F, "%s [%s]%s %ld %s SUBSCRIBE\n", date, address, X group==1 ? "l" : "", size, xlib); X }else if(cmd==UNSUBSCRIBE){ X fprintf(F, "%s [%s]%s %ld %s UNSUBSCRIBE\n", date, address, X group==1 ? "l" : "", size, xlib); X }else{ X fprintf(F, "%s [%s]%s %ld %s / %s", date, address, X group==1 ? "l" : "", size, zlib, zitem); X if(excl[0]) X fprintf(F, "~%s", zexcl); X if(cmd == LIST) X fprintf(F, " L\n"); X else if(cmd == FIND) X fprintf(F, " F\n"); X else if(DEBUG) X fprintf(F, " DEBUG\n"); X else X fprintf(F, "\n"); X } X fclose(F); X } X siam = 0; X /* continue to next request */ X } X X if(nreq == 0){ X F = Fopen(reply, "w"); X fprintf(F, "%s\n", usermail); X fclose(F); X sprintf(buf, "cat admin/mess/sorry_req %s| /bin/mail %s", X reply, address); X shell(buf); X quit(3, "no requests"); X } X X quit(0, ""); X} X X Xshell(s) Xchar *s; X{ X if(DEBUG){ X fprintf(stderr,"[%s]\n", s); X }else{ X system(s); X } X} X X Xint Xallfiles(files,dirname) Xchar *files; Xchar *dirname; X{ X /* append all files in "dirname" to the string "files" */ X DIR *dir = opendir(dirname); X struct dirent *d; X char buf[LINESIZE]; X int nfiles = 0; X X if(!dir) return(nfiles); X while(d = readdir(dir)) X if(strcmp(d->d_name,".")!=0 && strcmp(d->d_name,"..")!=0){ X sprintf(buf," %s/%s",dirname,d->d_name); X strcat(files,buf); X nfiles++; X } X closedir(dir); X return(nfiles); X} X Xint Xshar(xlib, item, files) Xchar *xlib; Xint item[2]; Xchar *files; X{ X /* At this point, netlib was about to conclude that the requested X files do not exist. Let's check for the case "send xxx.shar" and X see if directory xxx exists. */ X int n; X char *it, buf[LINESIZE]; X X if(item[0]!=item[1]) X return(0); X it = field[item[0]]; X n = strlen(it); X if(DEBUG) X fprintf(stderr,"shar(%s,%s)\n",xlib,it); X if(n<6 || strcmp(".shar",it+n-5)!=0) X return(0); X it[n-5] = '\0'; /* chop .shar */ X sprintf(buf,"%s%s%s",xlib,xlib?"/":"",it); X if( access(buf,F_OK|R_OK|X_OK)!=0 || !isdir(buf) ) X return(0); X lsr(files,buf); X if(DEBUG) X fprintf(stderr,"lsr(%s)=%s\n",buf,files); X return(1); X} X Xonly(xlib, item, files) Xchar *xlib; Xint item[2]; Xchar *files; X{ X /* list all existing files of the form xlib/item */ X int nlib, nfiles, i, j, k; X char buf[LINESIZE]; X char *lib[FIELDMAX]; X X nlib = split(xlib, lib, " \t"); X nfiles = 0; X *files = '\0'; X for (i = 0; i < nlib; i++){ X if(item[0]==item[1] && strcmp("all",field[item[0]])==0){ X nfiles += allfiles(files,lib[i]); X continue; X } X for (j = item[0]; j <= item[1]; j++){ X for (k = 0; suffix[k]; k++){ X sprintf(buf, "%s/%s%s", lib[i], field[j], suffix[k]); X if( access(buf,F_OK|R_OK)==0 && !isdir(buf) ){ X if(nfiles) X strcat(files, " "); X strcat(files, buf); X nfiles++; X break; /* skip remaining suffixes */ X } X } X } X } X if(nfiles == 0){ X if( (group != 1) && (strcmp(xlib, "portP") == 0) ){ X strcpy(files, "admin/mess/sorry_port"); X }else if(shar(xlib,item,files)){ X }else{ X strcpy(files, "admin/mess/sorry"); X sprintf(buf, "%s/index", field[item[0]]); X if(access(buf, 4) == 0){ X strcat(files, " admin/mess/sorry_indiv "); X strcat(files, buf); X } X } X } X} X X X/* Gentle Reader: I realize that hashing is overkill for this X application. But the code was already lying around and you X might find it useful elsewhere. */ Xvoid Xinsert(HashTable*kt, char*key, int code) X{ X int i = hashsrch(kt,key); X i<0 || Error("duplicate keyword %s",key); X hashins(kt,i,key,code); X} X Xint /* non-zero if case changed to lower */ Xcasech(s) Xregister char *s; X{ X register int changed = 0; X while (*s){ X if(isupper(*s)){ X *s = tolower(*s); X changed = 1; X } X s++; X } X return(changed); X} X Xint Xlookup(char*key, HashTable*kt) X{ X /* strips trailing punctuation and may convert to lower case */ X /* also strips surrounding brackets */ X int i; X register char *r = key + strlen(key)-1; /* end of string */ X register char *t; X if( ((*key == '<') && (*r == '>')) || X ((*key == '[') && (*r == ']')) || X ((*key == '{') && (*r == '}')) ){ X *r = '\0'; X for (t = key; t < r; t++) X t[0] = t[1]; X } X for (; (r >= key) && strchr(",?;\"'`.", *r); r--){} X r[1] = '\0'; X i = hashsrch(kt,key); X if(i<0 && casech(key)) X i = hashsrch(kt,key); X if(i<0) X return(0); X else X return((*kt)[i].Code); X} X X/* case independent prefix compare */ Xint Xcicmp(char *s1, char *s2) X{ X int c1, c2; X X for(; *s1; s1++, s2++){ X c1 = *s1; X c2 = isupper(*s2) ? tolower(*s2) : *s2; X if (c1 != c2) X return -1; X } X return(0); X} X Xint Xparse( address, item, excl, lib, thru ) Xchar address[]; Xint item[2], excl[2], lib[2], thru[2]; X{ X /* analyze field[] */ X int cmd, i, k; X char c, *p; X static char buf[LINESIZE]; X static int in_From = 0, replyto = 0, first = 1; X static HashTable keyword_table = 0, *kt; X static int ONLY, OF, WHO, IS, WHOIS, BUT, NOT; X static int THRU, EOL, IGNORE, MAXMAIL, QUIT, PATH; X int code[FIELDMAX+2]; /* = lookup(field[],kt); */ X FILE *F; X X if(first){ X first = 0; X k = SKIP; X EOL = ++k; X kt = &keyword_table; X insert(kt,"path",PATH = ++k); X insert(kt,"send", SEND = ++k); X insert(kt,"list", LIST = ++k); X insert(kt,"only", ONLY = ++k); X insert(kt,"of", OF = ++k); X insert(kt,"whois", WHOIS = ++k); X insert(kt,"who", WHO = ++k); X insert(kt,"is", IS = ++k); X insert(kt,"find", FIND = ++k); X insert(kt,"execute", EXEC = ++k); X insert(kt,"Subject:", IGNORE = ++k); X insert(kt,"index", INDEX = ++k); X insert(kt,"but", BUT = ++k); X insert(kt,"not", NOT = ++k); X insert(kt,"|", THRU = ++k); X insert(kt,"mailsize",MAXMAIL = ++k); X insert(kt,"quit",QUIT = ++k); X insert(kt,"subscribe",SUBSCRIBE = ++k); X insert(kt,"unsubscribe",UNSUBSCRIBE = ++k); X insert(kt,"mime",MIME = ++k); X insert(kt,"please", IGNORE); X insert(kt,"echo", IGNORE); X insert(kt,"sned", SEND); X insert(kt,"mail", SEND); X insert(kt,"request", SEND); X insert(kt,"get", SEND); X insert(kt,"from", OF); X insert(kt,"to", OF); X insert(kt,"<", OF); X insert(kt,"for", OF); X insert(kt,"in", OF); X insert(kt,"where", WHO); X insert(kt,"directory", INDEX); X /*only affects "send directory", not "send directory for x"*/ X insert(kt,"information", INDEX); X insert(kt,"info", INDEX); X insert(kt,"help", INDEX); X insert(kt,"readme", INDEX); X insert(kt,"filter", EXEC); X insert(kt,"pipe", EXEC); X insert(kt,"through", THRU); X insert(kt,"chunk", MAXMAIL); X insert(kt,"maxbyte", MAXMAIL); X insert(kt,"size", MAXMAIL); X insert(kt,"limit", MAXMAIL); X insert(kt,"maillimit", MAXMAIL); X } X X if(in_From){ /* continuation of From: line */ X c = *field[0]; X if( c == ' ' || c == '\t' ){ X if( strlen(field[0]) + strlen(buf) >= LINESIZE ) X quit(2, "long line"); X strcat(buf, field[0]); X return(SKIP); X }else{ /* not a continuation */ X in_From = 0; X if(strchr(buf, '(') || strchr(buf, '<') || strchr(buf, '[')){ X /* address appears to contain actual as well as electronic name */ X if((F = fopen("admin/names", "a")) != NULL){ X fprintf(F, "%s\n", buf); /* log it */ X fclose(F); X } X } X if(getfrom(buf,address)) /* extract RFC822 address */ X quit(3, "bad address"); X chkaddr(address); X } X } X X if(NF == 0){ /* blank line */ X in_header = 0; X return(SKIP); X } X code[1] = lookup(field[1],kt); X X /* look for (start of) return address */ X if( in_header && (NF>1) ){ X /* ignore bogus From: lines in message text (IBM) */ X if(!replyto && strncmp("From ",field[0],5)==0){ X strcpy(address, field[2]); X chkaddr(address); X return(SKIP); X }else if(strlen(field[0])>9 && cicmp("reply-to:",field[0])==0){ X strcpy(buf, 1 + strlen(field[1]) + field[0]); X in_From = 1; X replyto = 1; X return(SKIP); X }else if(!replyto && strlen(field[0])>5 && X cicmp("from:",field[0])==0){ X strcpy(buf, 1 + strlen(field[1]) + field[0]); X in_From = 1; X return(SKIP); X } X } X if( code[1] == PATH ){ X if(NF!=2 || getfrom(field[2],address)) X quit(3, "bad address"); X chkaddr(address); X return(SKIP); X } X X if( in_header && (c = *field[0])!=' ' && c!='\t' && X strchr(field[0],':')==0 ){ X in_header = 0; X } X X /* ignore anything after ". " or " #" */ X for (k = 1; k <= NF; k++){ X p = field[k] + strlen(field[k]) - 1; X if( *p == '.' ){ X *p = '\0'; X NF = k; X }else if( *field[k] == '#' ){ X NF = k - 1; X } X } X X /* finish decoding */ X for (k = 2; k <= NF; k++) X code[k] = lookup(field[k],kt); X code[NF+1] = EOL; X for (k = 1; code[k] == IGNORE; ++k ){} X X /* now look for a request */ X depend = 1; X item[0] = excl[0] = lib[0] = thru[0] = 0; X item[1] = excl[1] = lib[1] = thru[1] = -1; X cmd = code[k]; X if( cmd == INDEX ){ X cmd = SEND; X k--; X }else if( (cmd == SEND) || (cmd == LIST) ){ X if( code[k+1] == ONLY ){ X k++; X depend = 0; X } X if( (code[k+1] == LIST) && (code[k+2] == OF) ){ X k += 2; X cmd = LIST; X } X }else if( (cmd == FIND) || (cmd == WHOIS) ){ X depend = 0; X }else if( cmd == MAXMAIL ){ X if( k+1<=NF ){ X i=atoi(field[k+1]); X for( p = field[k+1]; isdigit(*p); p++){} X if(*p=='\0' && k+2<=NF) X p = field[k+2]; X if(*p=='k' || *p=='K') X i *= 1000; X if(*p=='m' || *p=='M') X i *= 1000000; X maxbyte = i; X } X return(SKIP); X }else if( cmd == WHO ){ X if( code[k+1] == IS ){ X k += 1; X cmd = WHOIS; X depend = 0; X }else{ X return(SKIP); X } X }else if( cmd == SUBSCRIBE || cmd == UNSUBSCRIBE ){ X item[0] = item[1] = k; X lib[0] = lib[1] = k+1; X depend = 0; X return(cmd); X }else if( cmd == MIME ){ X mime = 1; X return(SKIP); X }else if( cmd == QUIT ){ X return(DONE); X }else if( cmd != INDEX && cmd != EXEC ){ X return(SKIP); X } X X /* get items, exclusions, libraries, final filter */ X while( code[++k]==IGNORE ); X item[0] = k; X while( code[k]==0 || code[k]==INDEX ) k++; X item[1] = k-1; X if( code[k]==BUT && code[k+1]==NOT ){ X k++; X while( code[++k]==IGNORE ); X excl[0] = k; X while( code[k]==0 ) k++; X excl[1] = k-1; X } X if( code[k]==OF ){ X while( code[++k]==IGNORE ); X lib[0] = k; X while( code[k]==0 ) k++; X lib[1] = k-1; X } X if( code[k]==THRU ){ X while( code[++k]==IGNORE ); X thru[0] = k; X while( code[k]!=EOL ) k++; X thru[1] = k-1; X } X if( code[k]!=EOL ){ X if(strlen(field[k])>30) field[k][29] = '\0'; X fprintf(stderr,"junk at end, field %d:%s\n",k,field[k]); X return(SKIP); X } X X /* allow "send y/x" notation */ X if( !lib[0] && NFitem[1]) && (cmd==SEND||cmd==LIST||cmd==FIND) ) X return(SKIP); X X return(cmd); X} X X Xint Xduplicate(cmd, item, excl, lib) Xint cmd, item[2], excl[2], lib[2]; X{ X /* Is the current request the same as the previous one? */ X static int execnt = 0; X static int c, i[2], e[2], l[2]; X static char line[LINESIZE], *f[FIELDMAX]; X char *next, *cpfld(); X X if( (execnt != 0) && (c == cmd) && X (cmpfld(i, f, item, field) == 0) && X (cmpfld(e, f, excl, field) == 0) && X (cmpfld(l, f, lib, field) == 0) ){ X return(1); X } X execnt++; X X /* save current request */ X c = cmd; X i[0] = item[0]; X i[1] = item[1]; X e[0] = excl[0]; X e[1] = excl[1]; X l[0] = lib[0]; X l[1] = lib[1]; X next = cpfld(line, i, f); X next = cpfld(next, e, f); X next = cpfld(next, l, f); X return(0); X} X X Xint Xcmpfld(i, f, j, g) Xint i[2], j[2]; Xchar *f[], *g[]; X{ X int k = i[1]-i[0]; X if( k != (j[1] - j[0]) ) X return(1); X while (k >= 0){ X if(strcmp(f[i[0]+k], g[j[0]+k]) != 0) X return(1); X k--; X } X return(0); X} X X Xchar * Xcpfld(p, i, f) Xchar *p; /* next position to put chars */ Xint i[2]; Xchar *f[]; X{ X int k; X for (k = i[0]; k <= i[1]; k++){ X f[k] = p; X strcpy(p, field[k]); X p += strlen(p) + 1; X } X return(p); X} X X X/********* expand library names ***********/ X Xvoid Xmsdos2unix(s) Xchar *s; X{ X while(*s){ X if(*s=='\\') X *s='/'; X s++; X } X} X X Xexpand(lib, xlib) Xint lib[2]; Xchar *xlib; X{ X int j, k; X xlib[0] = '\0'; X for (k = lib[0]; k <= lib[1]; k++){ X msdos2unix(field[k]); X if( group==1 && search("admin/LIBS.lcl",field[k],xlib) ) X ; X else X search("admin/LIBS",field[k],xlib); X } X if(!xlib[0] && lib[0]==lib[1] && isdir(field[lib[0]])) X strcpy(xlib,field[lib[0]]); X} X X Xint /* returns 1 if found, 0 if not */ Xsearch(filename, pat, xlib) Xchar *filename; Xchar *pat; Xchar *xlib; X{ X /* find first line in file starting with pat */ X FILE * f; X int len, i, c, matches = 0; X char **p, line[400], *s; X X if(*filename == '\0') X return(0); X if( (f = fopen(filename, "r")) == NULL ) X return(0); X len = strlen(pat); X while (fgets(line, 400, f) != NULL){ X nlchop(line); X if( (strncmp(line, pat, len) == 0) && (line[len] == ' ') ){ X found(line, xlib); X matches++; X break; X } X } X fclose(f); X return(matches); X} X X Xfound(s, xlib) Xchar *s; Xchar *xlib; X{ X char *r; X r = strchr(s, '>'); /* strip "^.*=> *" */ X r || Error("corrupted LIBS? s=%s",s); X r++; X while (isspace(*r)) X r++; X if(xlib[0] != '\0') X strcat(xlib, " "); X strcat(xlib, r); X} X X X/* make a quick guess; does the file contain unmailable bytes? */ Xint Xis_binary(file) X char *file; X{ X char *suffix; X X suffix = strrchr(file,'.'); X if(suffix){ X suffix++; /* skip . */ X if(suffix[1]==0 && (suffix[0]=='f'||suffix[0]=='c')) X return 0; X if(strcmp(suffix,"tgz")==0 || X strcmp(suffix,"gz") || X strcmp(suffix,"Z") || X strcmp(suffix,"zip") || X strcmp(suffix,"exe") || X strcmp(suffix,"pdf") ) X return 1; X } X return 0; X} X X Xsend(address,maxbyte,subject,files,xlib) X char *address, *subject, *files, *xlib; X long maxbyte; X{ X /* convert "files" to form needed by bigmail() */ X char *f[FIELDMAX]; X int nf = 0; X int i, n; X char *s[FIELDMAX]; X char buf[LINESIZE]; X X n = split(xlib, s, " \t"); X for(i=0; i= 10) X return; X X if(strncmp("attmail!", address, 8) == 0){ X strcat(address, "/COD"); X } X X /* replace this heuristic with something better if you know one */ X if( upas && group==1 ) X maxbyte = 1000000; X else X maxbyte = 100000; X} X X X/* This returns the "security clearance" of address. X Assumes address has (a special case of) the form X @boguspath:uucpname!...!user%another@inter.net.address X and, in particular, does not understand X.400. X return codes: X 0 = general address X 1 = local (all machines in address appear in file "local") X 10 = enemy (some machine is in file "enemies") X*/ X Xint Xgroupid(a) Xchar *a; X{ X char *m[100]; /* machines in address */ X int n; /* size of m */ X char *p; /* a copy of a, for cutting with '\0' */ X char *q, *pp[2]; X int cmp(); X int i, len; X X p = malloc(strlen(a) + 1); X assert(p); X strcpy(p, a); X /* check for full address */ X pp[0] = p; X n = 1; X if(del(pp, &n, "admin/groups/enemies")) X return(10); X /* ok, let's get machine names... */ X n = 0; X /* strip off leading @boguspath: */ X while( p[0]=='@' && (q=strchr(p,':')) ){ X *q = '\0'; X m[n] = p+1; X if(++n>99) Error("too many hops in %s", a); X p = q+1; X } X /* strip off trailing @inter.net.address */ X while( (q=strrchr(p,'@')) ){ X *q = '\0'; X m[n] = q+1; X if(++n>99) Error("too many hops in %s", a); X } X /* strip off leading uucpname! */ X while( (q=strchr(p,'!')) ){ X *q = '\0'; X m[n] = p; X if(++n>99) Error("too many hops in %s", a); X p = q+1; X } X /* strip off trailing %another */ X /* yes, this could be merged with search for @. But X we've built the machine list in path order, which might X be handy for someone else's security policy. */ X while( (q=strrchr(p,'%')) ){ X *q = '\0'; X m[n] = q+1; X if(++n>99) Error("too many hops in %s", a); X } X /* at this point, some sites might */ X /* also want to check for :: or # or other magic, but my X /* mailer will treat those as invalid local addresses */ X /* what's left must be userid */ X pp[0] = p; X i = 1; X /* filter out uucp, root, unknown-user, ... */ X if(del(pp, &i, "admin/groups/badusers")) X return(10); X if(n == 0) X return(1); X /* the following is intended only for netlib@research.bell-labs.com, X but probably harmless elsewhere */ X if(upas){ X for(i=0; i14 && strcmp(m[i]+len-14,".bell-labs.com") == 0 ) X m[i] = "lucent"; X else if( len>11 && strcmp(m[i]+len-11,".lucent.com") == 0 ) X m[i] = "lucent"; X } X } X qsort(m, n, sizeof(char *), cmp); X if(del(m, &n, "admin/groups/enemies")) X return(10); X del(m, &n, "admin/groups/local"); X if(n == 0) X return(1); X return(0); X /* won't be many addresses, so don't bother to free */ X} X X Xint Xcmp ( p, q ) Xchar **p, **q; X{ X /* needed for qsort */ X return(strcmp(*p, *q)); X} X X Xint /* returns number of deletions */ Xdel ( m, nn, file ) Xchar *m[]; /* machine names; matches will be deleted */ Xint *nn; /* number of entries in m (updated if there are deletions) */ Xchar *file; /* where to look for matches, to be deleted from m */ X{ X /* file and m are assumed to be sorted. */ X register int n = *nn; X register int i; /* walks through m */ X int j; /* continue place to put item in m; if j==i, no need to copy */ X int ndel = 0; /* number of deletions */ X int c; /* result of string comparison */ X char *s, a[100]; /* machine name from file */ X FILE * f = fopen(file, "r"); X if(f == NULL) X return(0); X i = j = ndel = 0; X if(fgets(a, 100, f) == NULL) X return(0); X nlchop(a); X while (1){ X c = strcmp(a, m[i]); X if(c < 0){ X /* advance a */ X if(fgets(a, 100, f) == NULL) X break; X nlchop(a); X }else if(c > 0){ X if(i > j) X m[j] = m[i]; X j++; X i++; X if(i >= n) X break; /* advance m */ X continue; X }else{ /* match */ X ndel++; X i++; X if(i >= n) X break; /* advance m */ X continue; X } X } X fclose(f); X if(i > j) X while (i < n) X m[j++] = m[i++]; X *nn = n - ndel; X return(ndel); X} X X X/******* other utilities *********/ X XFILE* XFopen(name,mode) /* fopen() with abort on failure */ Xchar *name; Xchar *mode; X{ X FILE *fp; X X fp = fopen(name,mode); X fp!=NULL || Error("Can't open %s for mode %m",name,mode); X return (fp); /* fopen() succeeded */ X} X X Xstatic char datestr[30]; X Xchar * Xget_date(void) X{ X struct tm *tp, *localtime(); X long clock, time(); X clock = time(0); X tp = localtime(&clock); X sprintf(datestr, "%d %2d %2d %02d%02d", tp->tm_year + 1900, tp->tm_mon + 1, X tp->tm_mday, tp->tm_hour, tp->tm_min ); X return(datestr); X} X X Xquit(rc, mess) Xint rc; Xchar *mess; X{ X rc==0 || Error("%s %s\n",datestr,mess); X exit(0); X} X X Xnlchop(s) Xregister char *s; X{ X /* chop trailing newline */ X if(!*s) X return; X s += strlen(s) - 1; X if(*s == '\n') X *s = '\0'; X} X X Xgather(f, z, n) Xint f[2]; Xchar z[]; Xint n; /* sizeof(z) */ X{ X /* catenate fields f[0]...f[1] */ X char *s = z, *e = z+n-2, *t; X int k; X for (k = f[0]; k <= f[1]; k++){ X if(k > f[0]){ X if(s==e){ X Error("gather overflow %d",n); X quit(9,"gather"); X } X *s++ = ' '; X } X t = field[k]; X while(*t){ X if(s==e){ X Error("gather overflow %d",n); X quit(9,"gather"); X } X *s++ = *t++; X } X } X *s = '\0'; X} X X Xlong Xfsiz ( s ) Xchar *s; X{ X int fd; X long t; X long lseek(); X if( (fd = open(s, 0)) == -1 ){ X Error("can't open %s", s); X quit(7, "open"); X } X if( (t = lseek(fd, 0L, 2)) == -1 ){ X Error("can't seek on %s", s); X quit(8, "seek"); X } X close(fd); X return(t); X} X X Xint isdir ( s ) Xchar *s; X{ X struct stat buf; X char *dot = s; X if(strcmp(s,"admin")==0) return 0; /* disallow "send admin/log" */ X while(dot = strchr(dot,'.')){ /* disallow ".." */ X if(dot[1]=='.' && X (dot[2]=='/' || dot[2]=='\0') && X (dot[-1]=='/' || dot==s) ) X return 0; X dot++; X } X stat(s,&buf); X return( S_ISDIR(buf.st_mode) ); X} X X Xhandle(line) Xchar *line; X{ X /* save message, toss escapes */ X register char *s; /* next char to examine */ X register char *t; /* next place to copy char */ X int userlen = strlen(usermail), linelen = strlen(line); X /****if you don't want to keep a log, remove the next 15 lines *****/ X static int execnt = 0; X static FILE *save; X if( execnt++ == 0 ){ X save = fopen("/tmp/netreq", "a"); X#ifdef S_IRWXU X chmod("/tmp/netreq",(mode_t)S_IRWXU|S_IRWXG|S_IRWXO); X#endif X } X /* closed automatically when program quits */ X /* This won't work if several netlib processes are X running simultaneously; but this log isn't too X important, so we won't worry about that. */ X if(save!=NULL) X fprintf(save, "%s\n", line); X /***************************************************************/ X X /* append to usermail[] */ X if(userlen+linelen+2 line) ){ X t--; /* might not be right for ESC BS, but tough */ X }else if(*s == '\t'){ X *t++ = ' '; X }else if(!iscntrl(*s)){ X *t++ = *s; X } X } X} -------cut here----- src/reply.c echo src/seq.c 1>&2 sed >src/seq.c <<'-------cut here----- src/seq.c' 's/^X//' X#include Xmain(argc, argv) Xchar **argv; X{ X int i, n = atoi(argv[1]); X for (i = 1; i <= n; i += 1) X printf(" %d", i); X printf("\n"); X exit(0); X} X X -------cut here----- src/seq.c echo src/subscribe.c 1>&2 sed >src/subscribe.c <<'-------cut here----- src/subscribe.c' 's/^X//' X#define _POSIX_SOURCE X#include X#include X#include X#include X#include X#include X#include /* on some systems, this is */ X#include X#include X#ifndef S_ISDIR X#define S_ISDIR( mode ) (((mode) & S_IFMT) == S_IFDIR) X#endif X Xextern int isdir(char*); X#ifdef EHGTEST Xchar*addr_canon(char*a); Xvoid*Malloc(int n){return malloc(n);} Xint isdir(char*s){return 0;} Xvoid shell(char*s){return;} Xmain(){printf("%s\n",addr_canon("ehg@bell-labs.com"));} X#endif X Xchar* Xaddr_canon(char*addr) X{ X /* subscribe isn't called often, so ignore memory leak */ X char *addrc; X char *c = strchr(addr,'@'); X if(c){ X addrc = (char*)Malloc(strlen(addr)+1); X strcpy(addrc,c+1); X strcat(addrc,"!"); X strncat(addrc,addr,c-addr); X }else{ X return addr; X } X} X X X/* RETURN CODES X 0 = success X 1 = couldn't find topic X 2 = database update collision; try again later X 3 = internal error X*/ X Xint Xsubscribe(char*addr,char*topic) X{ X FILE *addrlist; X char *addrlistname, *cmd, *s; X char *addrc = addr_canon(addr); X X if(s = strchr(topic,' ')) X *s = '\0'; /* for linpack => linpack blas */ X if(strncmp(topic,"-l",2)==0) X topic += 2; X if(!isdir(topic)) return(1); X addrlistname = (char*)Malloc(strlen(topic)+6); X sprintf(addrlistname,"%s/.list",topic); X if(access(addrlistname,F_OK)!=0){ X cmd = (char*)Malloc(strlen(topic)+strlen("mk.list ")+1); X sprintf(cmd,"/netlib/admin/bin/mk.list %s",topic); X system(cmd); X free(cmd); X } X addrlist = fopen(addrlistname,"a"); X if(!addrlist) return(3); X fprintf(addrlist,"%s\n",addrc); X fclose(addrlist); X free(addrlistname); X return(0); X} X Xint Xunsubscribe(char*addr,char*topic) X{ X FILE *addrlist, *tmp; X char *addrlistname, *t, *tmpname, *addrn, line[1024], *cmd; X char *addrc = addr_canon(addr); X X struct stat before, after; X if(!isdir(topic)) return(1); X addrlistname = (char*)Malloc(strlen(topic)+6); X sprintf(addrlistname,"%s/.list",topic); X stat(addrlistname,&before); X addrlist = fopen(addrlistname,"r"); X if(!addrlist) return(1); X tmpname = (char*)Malloc(strlen(topic)+13); X sprintf(tmpname,"/tmp/%s.newlist",topic); X for(t = tmpname+5; *t; t++) X if(*t=='/') *t = '_'; X if(fopen(tmpname,"r")) return(2); X tmp = fopen(tmpname,"w+"); X if(!tmp){ X fprintf(stderr,"couldn't open %s for writing\n",tmpname); X return(3); X } X addrn = (char*)Malloc(strlen(addr)+2); X sprintf(addrn,"%s\n",addr); X while(fgets(line,sizeof(line),addrlist)!=NULL){ X if(strcmp(addrn,line)==0) continue; X fputs(line,tmp); X } X fclose(addrlist); X fclose(tmp); X chmod(tmpname,0666); X stat(addrlistname,&after); X if(before.st_mtime!=after.st_mtime){ X unlink(tmpname); X return(2); X } X cmd = (char*)Malloc(2*strlen(topic)+20); X sprintf(cmd,"cp %s %s",tmpname,addrlistname); X shell(cmd); X unlink(tmpname); X free(cmd); free(addrn); free(tmpname); free(addrlistname); X return(0); X} -------cut here----- src/subscribe.c echo src/to_subscribers.c 1>&2 sed >src/to_subscribers.c <<'-------cut here----- src/to_subscribers.c' 's/^X//' X/* Send notification to people who have subscribed to directories. X stdin: list of changed files X env: upasname X X Typically, this is invoked from imastercrc. X I was tempted to do it all in that shell script, but worried X about a security bug being introduced if someone (other than netlib) X added nasty addresses to the .list files. X Eric Grosse 25 Jan 1995 X X*/ X#define _POSIX_SOURCE X#include X#include X#include X#include X#include X#include X#include X#ifndef PATH_MAX X#define PATH_MAX 1024 X#endif X#ifndef NAME_MAX X#define NAME_MAX 1024 X#endif X#define FCNT 100 /* files to batch; only an optimization */ X Xchar *exclude[] = { ".list", "index.html", "att_crc" }; X X X/* as in /netlib/admin/src/getfrom.c, but now also rule out slash */ Xint Xunsafe(char *s) X{ X char c; X /* check for characters interpreted by the shell (by which nefarious X users might otherwise break into the system) */ X for (c = (*s); c != '\0'; c = (*++s)) { X if ( strchr("/\"'`$\n;&|^<>()\\", c) || (c & 0200) ){ X fprintf(stderr,"unsafe(%s) saw %c\n",s,c); X return(1); X } X } X return(0); X} X Xunsigned long Xfsize(char *path) X{ X struct stat s; X if(stat((char*)path,&s)){ X fprintf(stderr,"%s: ",path); X perror("can't stat"); X return 0; X } X return (unsigned long)s.st_size; X} X Xint Xsearch(char*s,char**t) X{ X while(*t){ X if(strcmp(s,*t)==0) X return(1); X t++; X } X return(0); X} X Xint Xrecord_files(int nf, char*dir, char files[][NAME_MAX+1], unsigned long*fsizes) X{ X char wdir[PATH_MAX], *slash, subscriber[NAME_MAX+21]; X char cmd[PATH_MAX+NAME_MAX+10], list[PATH_MAX+1]; X FILE *L, *S; X int m, n, nrecords = 0; X X if(nf==0) X return(0); X strcpy(wdir,dir); X strcpy(subscriber,"/tmp/to_subscribers/"); X n = strlen("/tmp/to_subscribers/"); X while(1){ /**** for each subscriber list ****/ X sprintf(list,"%s/.list",wdir); X if(L = fopen(list,"r")){ X while(fgets(subscriber+n,sizeof(subscriber)-n,L)){ X /**** for each subscriber ****/ X m = strlen(subscriber); X if(m==n){ X fprintf(stderr,"empty addr %s\n",list); X continue; X } X if(m>=sizeof(subscriber)-2){ X fprintf(stderr,"long %s %s\n",subscriber+n,list); X continue; X } X if(subscriber[m-1]=='\n') X subscriber[--m] = '\0'; /* chop NL */ X if(unsafe(subscriber+n)) X continue; X S = fopen(subscriber,"a"); X if(!S){ X fprintf(stderr,"can't open %s\n",subscriber); X continue; X } X nrecords += nf; X for(m = 0; m=PATH_MAX-2){ X fprintf(stderr,"long file %s",path); X return 0; X } X if(path[m-1]=='\n') X path[--m] = '\0'; /* chop NL */ X strcpy(dir,path); X file = strrchr(dir,'/'); X if(!file){ X fprintf(stderr,"no dir? %s\n",dir); X return 0; X } X *file++ = '\0'; /* terminate dir */ X if(strlen(file)>NAME_MAX){ X fprintf(stderr,"%s longer than NAME_MAX\n",file); X return 0; X } X if( strlen(dir)+strlen("/.list") > PATH_MAX ){ X fprintf(stderr,"long dir %s\n",dir); X return 0; X } X *pfile = file; X return 1; X} X Xint Xmain(int argc, char**argv) X{ X char path[PATH_MAX+2], dir[PATH_MAX+1], old_dir[PATH_MAX+1]; X char *file, files[FCNT][NAME_MAX+1]; X unsigned long fsizes[FCNT]; X int n, filecnt, nrecords = 0; X X system("rm -rf /tmp/to_subscribers;mkdir /tmp/to_subscribers"); X old_dir[0] = '\0'; X filecnt = 0; X X /* accumulate notifications for each address */ X while(fgets(path,sizeof(path),stdin)){ /**** for each changed file ****/ X if(!valid_file(path,dir,&file)) X continue; X if(search(file,exclude)) X continue; X if(filecnt>=FCNT || strcmp(dir,old_dir)!=0){ X nrecords += record_files(filecnt,old_dir,files,fsizes); X filecnt = 0; X } X strcpy(files[filecnt],file); X fsizes[filecnt] = fsize(path); X strcpy(old_dir,dir); X filecnt++; X } X nrecords += record_files(filecnt,old_dir,files,fsizes); X X /* trickle out the mail */ X if(nrecords) X system("to_subscribers2"); X exit(0); X} -------cut here----- src/to_subscribers.c