hap/ 40755 24036 142 0 6201671533 6171 5ustar hap/README100644 24036 142 2615 6201671122 7144 0ustar This is hap, a mail notification program, meant to substitute for biff on those computers that don't have it, and to offer utility above and beyond biff's on those computers that do. Unlike biff, hap lets you choose how often to be notified of new mail and how much you want to be told about each piece of mail, and, if the appropriate terminal support is there, tries to damage the other contents of the screen as little as possible. Also unlike biff, hap runs as a background user process rather than relying, as biff does, on the presence of a system daemon. For information on what has been added to each version of hap, see the file HISTORY. Currently you can send me e-mail, including bug reports, at either of these addresses: etaoin@uchicago.edu eric@rainbow.uchicago.edu If neither address works and you still want to get in touch with me, you can send ordinary postal mail to Eric Fischer 5759 N. Guilford Ave. Indianapolis, IN 46220 USA Hap may be freely distributed under the terms of the GNU public license. To compile hap, you need to do configure (to create Makefile) make (to create hap) make install (to put it in /usr/local/bin) Configure should be able to figure out what flavor of computer you have and set things appropriately. Previous versions have been tried on SunOS, NeXTSTEP, Linux, Irix, Solaris, BSDI, and AIX, so I think it's pretty portable. hap/HISTORY100644 24036 142 5601 6201671050 7346 0ustar The history of hap, a mail notification program. 1.0: Simple biff replacement. Trampled everything on the screen, just like biff. 1.1: Added the terse and verbose options 1.2: Added the kool option (now --biff) at the request of Alan Jaffray, rendering the entire program instantly unreadable and unmaintanable 2.0: Added support for saving and restoring the cursor position on vt100 terminals. 2.1: Used termcap instead of hardwiring control codes for vt100 2.2: Added special cases for broken termcap entries 2.3: Added checks for terminal idle time, at Matt Ryan's request. 3.0: Complete rewrite, with new option syntax and support for non-mbox file formats and non-BSD systems. 3.0b:Great numbers of changes, as options and warning messages appeared and disappeared without warning. Reinstated the terse option at Chip Ach's request. Converted to K&R C. Added autoconfigure and long options. 3.1: Added support for MH folders 3.2: Improved postmark recognition for mbox files; some internal reorganization so not so much stuff was in main() 3.3: Added % expansion in filenames made no-warn the default when there are no filename args narrowed the string of dashes for non-vt100-style automargin ttys 3.4: Added all-inverse notifications Added no-file option to not tell filenames 3.41:if standout mode leaves garbage chars, don't use it. 3.5: Actually remembered to disable interrupts when going into the background so stray Control-Cs from sh users wouldn't be hap's doom. Handled continuation lines and multiple names in headers properly. Added show-rcpt option. 3.51:Tested on Linux and found some bugs that needed fixing. In particular: 1. signed chars caused very large values for some control characters 2. calculation of the width that a ctrl char was on the screen was screwy 3. basename is in GNU's libc and conflicted with my definition 4. if any line in the headers was long enough to cause a realloc(), the first quoted or verbosed line would be wrong. 3.52:Fixed ioctl.c to work if TIOCGWINSZ isn't defined, for Solaris 3.6: Improved output format and line wrapping. Made many options the default. 3.61:Added a cast for the two mallocs in dir.c that weren't char[]. Removed extra blank at the ends of lines on ttys that could save and move the cursor, so it doesn't matter how their automargin works 3.62:Made hap aware of the obscure :; notation for groups set down in rfc822, since Mort insists on sending me mail that uses it. 3.63:Added --no-inverse at the request of whatshisname who really hated inverse video 3.64:Use cproto to make prototypes; change PSCMD to support 4.4BSD. First release outside uchicago.edu. 3.7: Added --address option, at Judith Freeman's request, since she knows too many people with the same first name; slightly changed the look of the "terse" format hap/Makefile.in100644 24036 142 4626 6173007212 10336 0ustar # Makefile for Hap, a mail notification program by Eric Fischer. # a lot of this Makefile is copied from the Makefile for GNU's # version of grep, which has the following copyright: # Makefile for GNU grep # Copyright (C) 1992 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. SHELL = /bin/sh #### Start of system configuration section. #### srcdir=@srcdir@ VPATH=@srcdir@ INSTALL=@INSTALL@ INSTALL_PROGRAM=@INSTALL_PROGRAM@ INSTALL_DATA=@INSTALL_DATA@ CC=@CC@ # stuff from autoconf about the flavor of computer we have DEFS=@DEFS@ # Extra libraries. Well, termcap isn't very extra, but... LIBS=@LIBS@ CFLAGS=-O LDFLAGS=$(CFLAGS) prefix=/usr/local exec_prefix=$(prefix) # Prefix for installed program, normally empty or `g'. binprefix= # Prefix for installed man page, normally empty or `g'. manprefix= # Where to install executables. bindir=$(exec_prefix)/bin # Where to install man pages. mandir=$(prefix)/man/man1 # Extension for man pages. manext=1 #### End of system configuration section. #### OBJS=fgetl.o file.o getopt.o getopt1.o ioctl.o main.o malloc.o\ num2str.o output.o postmark.o readmbox.o signal.o strerror.o\ string.o usage.o whoami.o global.o alive.o dir.o readmh.o notice.o\ snagheader.o fixaddr.o # PROTOS are the files whose prototypes live in proto.h This # excludes C files that have their very own .h files (getopt, fgetl) # and, importantly, ones that are formatted in some way that breaks # genprot. PROTOS=file.c ioctl.c main.c malloc.c\ num2str.c output.c postmark.c readmbox.c signal.c strerror.c\ string.c usage.c whoami.c global.c alive.c dir.c readmh.c notice.c\ snagheader.c fixaddr.c all: hap .c.o: $(CC) $(CFLAGS) $(DEFS) -I$(srcdir) -c $< install: all $(INSTALL_PROGRAM) hap $(bindir)/$(binprefix)hap $(INSTALL_DATA) $(srcdir)/hap.1 $(mandir)/hap.$(manext) hap: $(OBJS) $(CC) $(LDFLAGS) -o hap $(OBJS) $(LIBS) clean: rm -f core hap *.o proto: cproto -m -f3 $(DEFS) -UHAVE_UNISTD_H $(PROTOS) > proto.h distclean: clean rm -f Makefile config.* dist: distclean cd ..; rm -f hap.tar; tar vcf hap.tar hap # the hap/R stuff is to make sure that README comes at the # top of the shar distribution shar: distclean cd ..; shar -V -l60 -o hap.shar hap/R* hap/[!R]* hap/alive.c100644 24036 142 2203 6173007212 7522 0ustar /* * hap -- a mail notification program * * copyright 1995 by Eric Fischer, etaoin@uchicago.edu * * copies of hap may be redistributed under the terms of the * GNU public license, copies of which are available from * the Free Software Foundation, 59 Temple Place, Boston, MA * 02111 USA. * */ #include "hap.h" /************************************************************************** ALIVE -- check whether our session still exists **************************************************************************/ /* return true if the process 'shell' (a global) is still around. return false if it's passed on. the version 7 manual doesn't explicitly say what happens when you send signal 0 to a process, so I don't know if this will work on such machines. 4.2BSD and 4.3BSD explicitly allow it for process ID checking, as does the DomainOS manual for, I think, SVr3. */ int alive() { int ret; errno = 0; ret = kill (shell, 0); /* send no signal, just see if we can */ if (ret == 0) { return 1; /* no error: it's still there */ } else { return 0; /* can't send signal: process must be dead */ } } hap/configure100755 24036 142 102304 6173007213 10231 0ustar #!/bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated automatically using autoconf version 2.1 # Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. # Defaults: ac_help= ac_default_prefix=/usr/local # Any additions from configure.in: # Initialize some variables set by options. # The variables have the same names as the options, with # dashes changed to underlines. build=NONE cache_file=./config.cache exec_prefix=NONE host=NONE no_create= nonopt=NONE no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= target=NONE verbose= x_includes=NONE x_libraries=NONE # Initialize some other variables. subdirs= ac_prev= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval "$ac_prev=\$ac_option" ac_prev= continue fi case "$ac_option" in -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; *) ac_optarg= ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case "$ac_option" in -build | --build | --buil | --bui | --bu | --b) ac_prev=build ;; -build=* | --build=* | --buil=* | --bui=* | --bu=* | --b=*) build="$ac_optarg" ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file="$ac_optarg" ;; -disable-* | --disable-*) ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` eval "enable_${ac_feature}=no" ;; -enable-* | --enable-*) ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "enable_${ac_feature}='$ac_optarg'" ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix="$ac_optarg" ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he) # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat << EOF Usage: configure [options] [host] Options: [defaults in brackets after descriptions] Configuration: --cache-file=FILE cache test results in FILE --help print this message --no-create do not create output files --quiet, --silent do not print \`checking...' messages --version print the version of autoconf that created configure Directory and file names: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=PREFIX install architecture-dependent files in PREFIX [same as prefix] --srcdir=DIR find the sources in DIR [configure dir or ..] --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names Host type: --build=BUILD configure for building on BUILD [BUILD=HOST] --host=HOST configure for HOST [guessed] --target=TARGET configure for TARGET [TARGET=HOST] Features and packages: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --x-includes=DIR X include files are in DIR --x-libraries=DIR X library files are in DIR --enable and --with options recognized:$ac_help EOF exit 0 ;; -host | --host | --hos | --ho) ac_prev=host ;; -host=* | --host=* | --hos=* | --ho=*) host="$ac_optarg" ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix="$ac_optarg" ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix="$ac_optarg" ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix="$ac_optarg" ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name="$ac_optarg" ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site="$ac_optarg" ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir="$ac_optarg" ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target="$ac_optarg" ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers) echo "configure generated by autoconf version 2.1" exit 0 ;; -with-* | --with-*) ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "with_${ac_package}='$ac_optarg'" ;; -without-* | --without-*) ac_package=`echo $ac_option|sed -e 's/-*without-//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` eval "with_${ac_package}=no" ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes="$ac_optarg" ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries="$ac_optarg" ;; -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } ;; *) if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then echo "configure: warning: $ac_option: invalid host type" 1>&2 fi if test "x$nonopt" != xNONE; then { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } fi nonopt="$ac_option" ;; esac done if test -n "$ac_prev"; then { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } fi trap 'rm -fr conftest* confdefs* core $ac_clean_files; exit 1' 1 2 15 # File descriptor usage: # 0 unused; standard input # 1 file creation # 2 errors and warnings # 3 unused; some systems may open it to /dev/tty # 4 checking for... messages and results # 5 compiler messages saved in config.log if test "$silent" = yes; then exec 4>/dev/null else exec 4>&1 fi exec 5>./config.log echo "\ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. " 1>&5 # Strip out --no-create and --no-recursion so they do not pile up. # Also quote any args containing shell metacharacters. ac_configure_args= for ac_arg do case "$ac_arg" in -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c) ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) ac_configure_args="$ac_configure_args '$ac_arg'" ;; *) ac_configure_args="$ac_configure_args $ac_arg" ;; esac done # NLS nuisances. # Only set LANG and LC_ALL to C if already set. # These must not be set unconditionally because not all systems understand # e.g. LANG=C (notably SCO). if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi if test "${LANG+set}" = set; then LANG=C; export LANG; fi # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo > confdefs.h # A filename unique to this package, relative to the directory that # configure is in, which we can look for to find out if srcdir is correct. ac_unique_file=fgetl.c # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then its parent. ac_prog=$0 ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. srcdir=$ac_confdir if test ! -r $srcdir/$ac_unique_file; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r $srcdir/$ac_unique_file; then if test "$ac_srcdir_defaulted" = yes; then { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } else { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } fi fi srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` # Prefer explicitly selected file to automatically selected ones. if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then echo "loading site script $ac_site_file" . "$ac_site_file" fi done if test -r "$cache_file"; then echo "loading cache $cache_file" . $cache_file else echo "creating cache $cache_file" > $cache_file fi ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} $CFLAGS $CPPFLAGS conftest.$ac_ext -c 1>&5 2>&5' ac_link='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext -o conftest $LIBS 1>&5 2>&5' if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then ac_n= ac_c=' ' ac_t=' ' else ac_n=-n ac_c= ac_t= fi else ac_n= ac_c='\c' ac_t= fi # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&4 if eval "test \"`echo '${'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&4 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_CC="gcc" break fi done IFS="$ac_save_ifs" test -z "$ac_cv_prog_CC" && ac_cv_prog_CC="cc" fi fi CC="$ac_cv_prog_CC" if test -n "$CC"; then echo "$ac_t""$CC" 1>&4 else echo "$ac_t""no" 1>&4 fi echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&4 if eval "test \"`echo '${'ac_cv_prog_gcc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&4 else cat > conftest.c <&5 | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no fi fi echo "$ac_t""$ac_cv_prog_gcc" 1>&4 if test $ac_cv_prog_gcc = yes; then GCC=yes if test "${CFLAGS+set}" != set; then echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&4 if eval "test \"`echo '${'ac_cv_prog_gcc_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&4 else echo 'void f(){}' > conftest.c if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then ac_cv_prog_gcc_g=yes else ac_cv_prog_gcc_g=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_prog_gcc_g" 1>&4 if test $ac_cv_prog_gcc_g = yes; then CFLAGS="-g -O" else CFLAGS="-O" fi fi else GCC= test "${CFLAGS+set}" = set || CFLAGS="-g" fi ac_aux_dir= for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do if test -f $ac_dir/install-sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f $ac_dir/install.sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break fi done if test -z "$ac_aux_dir"; then { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } fi ac_config_guess=$ac_aux_dir/config.guess ac_config_sub=$ac_aux_dir/config.sub ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&4 if test -z "$INSTALL"; then if eval "test \"`echo '${'ac_cv_path_install'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&4 else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" for ac_dir in $PATH; do case "$ac_dir" in ''|.|/etc|/usr/sbin|/usr/etc|/sbin|/usr/afsws/bin|/usr/ucb) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. for ac_prog in ginstall installbsd scoinst install; do if test -f $ac_dir/$ac_prog; then if test $ac_prog = install && grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. # OSF/1 installbsd also uses dspmsg, but is usable. : else ac_cv_path_install="$ac_dir/$ac_prog -c" break 2 fi fi done ;; esac done IFS="$ac_save_ifs" # As a last resort, use the slow shell script. test -z "$ac_cv_path_install" && ac_cv_path_install="$ac_install_sh" fi INSTALL="$ac_cv_path_install" fi echo "$ac_t""$INSTALL" 1>&4 # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' echo $ac_n "checking for -ltermcap""... $ac_c" 1>&4 if eval "test \"`echo '${'ac_cv_lib_termcap'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&4 else ac_save_LIBS="$LIBS" LIBS="$LIBS -ltermcap " cat > conftest.$ac_ext <&4 ac_tr_lib=HAVE_LIB`echo termcap | tr '[a-z]' '[A-Z]'` cat >> confdefs.h <&4 fi echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&4 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if eval "test \"`echo '${'ac_cv_prog_CPP'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&4 else # This must be in double quotes, not single quotes, because CPP may get # substituted into the Makefile and "${CC-cc}" will confuse make. CPP="${CC-cc} -E" # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext < Syntax Error EOF eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then : else echo "$ac_err" >&5 rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext < Syntax Error EOF eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then : else echo "$ac_err" >&5 rm -rf conftest* CPP=/lib/cpp fi rm -f conftest* fi rm -f conftest* ac_cv_prog_CPP="$CPP" fi fi CPP="$ac_cv_prog_CPP" echo "$ac_t""$CPP" 1>&4 for ac_hdr in sgtty.h unistd.h libc.h termcap.h strings.h string.h dirent.h sys/ioctl.h do ac_safe=`echo "$ac_hdr" | tr './\055' '___'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&4 if eval "test \"`echo '${'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&4 else cat > conftest.$ac_ext < EOF eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&4 ac_tr_hdr=HAVE_`echo $ac_hdr | tr '[a-z]./\055' '[A-Z]___'` cat >> confdefs.h <&4 fi done # If we cannot run a trivial program, we must be cross compiling. echo $ac_n "checking whether cross-compiling""... $ac_c" 1>&4 if eval "test \"`echo '${'ac_cv_c_cross'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&4 else if test "$cross_compiling" = yes; then ac_cv_cross=yes else cat > conftest.$ac_ext </dev/null; then ac_cv_c_cross=no else ac_cv_c_cross=yes fi fi rm -fr conftest* fi cross_compiling=$ac_cv_c_cross echo "$ac_t""$ac_cv_c_cross" 1>&4 echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&4 if eval "test \"`echo '${'ac_cv_header_stdc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&4 else cat > conftest.$ac_ext < #include #include #include EOF eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* ac_cv_header_stdc=yes else echo "$ac_err" >&5 rm -rf conftest* ac_cv_header_stdc=no fi rm -f conftest* if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat > conftest.$ac_ext < EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "memchr" >/dev/null 2>&1; then : else rm -rf conftest* ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat > conftest.$ac_ext < EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "free" >/dev/null 2>&1; then : else rm -rf conftest* ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then ac_cv_header_stdc=no else cat > conftest.$ac_ext < #define ISLOWER(c) ('a' <= (c) && (c) <= 'z') #define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); exit (0); } EOF eval $ac_link if test -s conftest && (./conftest; exit) 2>/dev/null; then : else ac_cv_header_stdc=no fi fi rm -fr conftest* fi fi echo "$ac_t""$ac_cv_header_stdc" 1>&4 if test $ac_cv_header_stdc = yes; then cat >> confdefs.h <<\EOF #define STDC_HEADERS 1 EOF fi echo $ac_n "checking for size_t""... $ac_c" 1>&4 if eval "test \"`echo '${'ac_cv_type_size_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&4 else cat > conftest.$ac_ext < #if STDC_HEADERS #include #endif EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "size_t" >/dev/null 2>&1; then rm -rf conftest* ac_cv_type_size_t=yes else rm -rf conftest* ac_cv_type_size_t=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_type_size_t" 1>&4 if test $ac_cv_type_size_t = no; then cat >> confdefs.h <<\EOF #define size_t unsigned EOF fi echo $ac_n "checking for mode_t""... $ac_c" 1>&4 if eval "test \"`echo '${'ac_cv_type_mode_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&4 else cat > conftest.$ac_ext < #if STDC_HEADERS #include #endif EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "mode_t" >/dev/null 2>&1; then rm -rf conftest* ac_cv_type_mode_t=yes else rm -rf conftest* ac_cv_type_mode_t=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_type_mode_t" 1>&4 if test $ac_cv_type_mode_t = no; then cat >> confdefs.h <<\EOF #define mode_t int EOF fi echo $ac_n "checking for pid_t""... $ac_c" 1>&4 if eval "test \"`echo '${'ac_cv_type_pid_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&4 else cat > conftest.$ac_ext < #if STDC_HEADERS #include #endif EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "pid_t" >/dev/null 2>&1; then rm -rf conftest* ac_cv_type_pid_t=yes else rm -rf conftest* ac_cv_type_pid_t=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_type_pid_t" 1>&4 if test $ac_cv_type_pid_t = no; then cat >> confdefs.h <<\EOF #define pid_t int EOF fi if test $ac_cv_prog_gcc = yes; then echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&4 if eval "test \"`echo '${'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&4 else ac_pattern="Autoconf.*'x'" cat > conftest.$ac_ext < Autoconf TIOCGETP EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "$ac_pattern" >/dev/null 2>&1; then rm -rf conftest* ac_cv_prog_gcc_traditional=yes else rm -rf conftest* ac_cv_prog_gcc_traditional=no fi rm -f conftest* if test $ac_cv_prog_gcc_traditional = no; then cat > conftest.$ac_ext < Autoconf TCGETA EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "$ac_pattern" >/dev/null 2>&1; then rm -rf conftest* ac_cv_prog_gcc_traditional=yes fi rm -f conftest* fi fi echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&4 if test $ac_cv_prog_gcc_traditional = yes; then CC="$CC -traditional" fi fi echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&4 if eval "test \"`echo '${'ac_cv_type_signal'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&4 else cat > conftest.$ac_ext < #include #ifdef signal #undef signal #endif extern void (*signal ()) (); int main() { return 0; } int t() { int i; ; return 0; } EOF if eval $ac_compile; then rm -rf conftest* ac_cv_type_signal=void else rm -rf conftest* ac_cv_type_signal=int fi rm -f conftest* fi echo "$ac_t""$ac_cv_type_signal" 1>&4 cat >> confdefs.h <&4 if eval "test \"`echo '${'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&4 else cat > conftest.$ac_ext < /* Arbitrary system header to define __stub macros. */ /* Override any gcc2 internal prototype to avoid an error. */ char $ac_func(); int main() { return 0; } int t() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else $ac_func(); #endif ; return 0; } EOF if eval $ac_link; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else rm -rf conftest* eval "ac_cv_func_$ac_func=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then echo "$ac_t""yes" 1>&4 ac_tr_func=HAVE_`echo $ac_func | tr '[a-z]' '[A-Z]'` cat >> confdefs.h <&4 fi done trap '' 1 2 15 if test -w $cache_file; then echo "updating cache $cache_file" cat > $cache_file <<\EOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs. It is not useful on other systems. # If it contains results you don't want to keep, you may remove or edit it. # # By default, configure uses ./config.cache as the cache file, # creating it if it does not exist already. You can give configure # the --cache-file=FILE option to use a different cache file; that is # what configure does when it calls configure scripts in # subdirectories, so they share the cache. # Giving --cache-file=/dev/null disables caching, for debugging configure. # config.status only pays attention to the cache file if you give it the # --recheck option to rerun configure. # EOF # Ultrix sh set writes to stderr and can't be redirected directly. (set) 2>&1 | sed -n "s/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/: \${\1='\2'}/p" \ >> $cache_file else echo "not updating unwritable cache $cache_file" fi trap 'rm -fr conftest* confdefs* core $ac_clean_files; exit 1' 1 2 15 test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Any assignment to VPATH causes Sun make to only execute # the first set of double-colon rules, so remove it if not needed. # If there is a colon in the path, we need to keep it. if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' fi trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. cat > conftest.defs <<\EOF s%#define \([A-Za-z_][A-Za-z0-9_]*\) \(.*\)%-D\1=\2%g s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g s%\[%\\&%g s%\]%\\&%g s%\$%$$%g EOF DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '` rm -f conftest.defs # Without the "./", some shells look in PATH for config.status. : ${CONFIG_STATUS=./config.status} echo creating $CONFIG_STATUS rm -f $CONFIG_STATUS cat > $CONFIG_STATUS </dev/null | sed 1q`: # # $0 $ac_configure_args # # Compiler output produced by configure, useful for debugging # configure, is in ./config.log if it exists. ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" for ac_option do case "\$ac_option" in -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; -version | --version | --versio | --versi | --vers | --ver | --ve | --v) echo "$CONFIG_STATUS generated by autoconf version 2.1" exit 0 ;; -help | --help | --hel | --he | --h) echo "\$ac_cs_usage"; exit 0 ;; *) echo "\$ac_cs_usage"; exit 1 ;; esac done ac_given_srcdir=$srcdir ac_given_INSTALL="$INSTALL" trap 'rm -f Makefile; exit 1' 1 2 15 # Protect against being on the right side of a sed subst in config.status. sed 's/%@/@@/; s/@%/@@/; s/%g$/@g/; /@g$/s/[\\\\&%]/\\\\&/g; s/@@/%@/; s/@@/@%/; s/@g$/%g/' > conftest.subs <<\CEOF $ac_vpsub $extrasub s%@CFLAGS@%$CFLAGS%g s%@CPPFLAGS@%$CPPFLAGS%g s%@CXXFLAGS@%$CXXFLAGS%g s%@DEFS@%$DEFS%g s%@LDFLAGS@%$LDFLAGS%g s%@LIBS@%$LIBS%g s%@exec_prefix@%$exec_prefix%g s%@prefix@%$prefix%g s%@program_transform_name@%$program_transform_name%g s%@CC@%$CC%g s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g s%@INSTALL_DATA@%$INSTALL_DATA%g s%@CPP@%$CPP%g CEOF EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then # Support "outfile[:infile]", defaulting infile="outfile.in". case "$ac_file" in *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'` ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; *) ac_file_in="${ac_file}.in" ;; esac # Adjust relative srcdir, etc. for subdirectories. # Remove last slash and all that follows it. Not all systems have dirname. ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then # The file is in a subdirectory. test ! -d "$ac_dir" && mkdir "$ac_dir" ac_dir_suffix="/$ac_dir" # A "../" for each directory in $ac_dir_suffix. ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` else ac_dir_suffix= ac_dots= fi case "$ac_given_srcdir" in .) srcdir=. if test -z "$ac_dots"; then top_srcdir=. else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; *) # Relative path. srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" top_srcdir="$ac_dots$ac_given_srcdir" ;; esac case "$ac_given_INSTALL" in [/$]*) INSTALL="$ac_given_INSTALL" ;; *) INSTALL="$ac_dots$ac_given_INSTALL" ;; esac echo creating "$ac_file" rm -f "$ac_file" configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." case "$ac_file" in *Makefile*) ac_comsub="1i\\ # $configure_input" ;; *) ac_comsub= ;; esac sed -e "$ac_comsub s%@configure_input@%$configure_input%g s%@srcdir@%$srcdir%g s%@top_srcdir@%$top_srcdir%g s%@INSTALL@%$INSTALL%g " -f conftest.subs $ac_given_srcdir/$ac_file_in > $ac_file fi; done rm -f conftest.subs exit 0 EOF chmod +x $CONFIG_STATUS rm -fr confdefs* $ac_clean_files test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS hap/configure.in100644 24036 142 1146 6173007213 10575 0ustar dnl Process this file with autoconf to produce a configure script. AC_INIT(fgetl.c) dnl Checks for programs. AC_PROG_CC AC_PROG_INSTALL dnl Checks for libraries. dnl Replace `main' with a function in -ltermcap: AC_CHECK_LIB(termcap, tputs) dnl Checks for header files. AC_CHECK_HEADERS(sgtty.h unistd.h libc.h termcap.h strings.h string.h dirent.h sys/ioctl.h) dnl Checks for typedefs, structures, and compiler characteristics. AC_TYPE_SIZE_T AC_TYPE_MODE_T AC_TYPE_PID_T dnl Checks for library functions. AC_PROG_GCC_TRADITIONAL AC_TYPE_SIGNAL AC_CHECK_FUNCS(strerror setbuffer setvbuf) AC_OUTPUT(Makefile) hap/dir.c100644 24036 142 4033 6173007213 7204 0ustar /* * hap -- a mail notification program * * copyright 1995 by Eric Fischer, etaoin@uchicago.edu * * copies of hap may be redistributed under the terms of the * GNU public license, copies of which are available from * the Free Software Foundation, 59 Temple Place, Boston, MA * 02111 USA. * */ #include "hap.h" #ifdef HAVE_DIRENT_H # include #else # include # include #endif /* remove a carriage return and anything following it from a string. return the end of the new string, for whatever that's worth. */ char * stripcr (s) char *s; { while (*s) { if (*s == '\012') { *s = 0; return s; } s++; } return s; } /* return a linked list of filenames in the directory s. */ flist * lookdir(s) char *s; { flist *ret = 0; DIR *thedir; #ifdef HAVE_DIRENT_H struct dirent *rec; #else struct direct *rec; #endif thedir = opendir (s); if (thedir == 0) return 0; while ((rec = readdir (thedir))) { char c = rec->d_name[0]; /* exclude deleted messages from the list we're interested in. */ if (c != '.' && c != ',' /* soren says current mh uses this */ && c != '#') { flist *new = (flist *) xmalloc (sizeof (flist)); new->name = strdupe (rec->d_name); new->next = ret; ret = new; } } closedir (thedir); return ret; } /* return true if the node 'it' is also found in the list 'new' */ int isin (new, it) flist *new; flist *it; { while (new) { if (strcmp (new->name, it->name) == 0) return 1; new = new->next; } return 0; } /* return a linked list of all the elements of new which aren't in old */ flist * diffdir (old, new) flist *old; flist *new; { flist *ret = 0; while (new) { if (!isin (old, new)) { flist *n = (flist *) xmalloc (sizeof (flist)); n->next = ret; n->name = strdupe (new->name); ret = n; } new = new->next; } return ret; } /* free each element of the linked list 'it' */ void freelist (it) flist *it; { while (it) { flist *tmp = it->next; free (it->name); free (it); it = tmp; } } hap/fgetl.c100644 24036 142 4542 6173007213 7534 0ustar /* * hap -- a mail notification program * * copyright 1995 by Eric Fischer, etaoin@uchicago.edu * * copies of hap may be redistributed under the terms of the * GNU public license, copies of which are available from * the Free Software Foundation, 59 Temple Place, Boston, MA * 02111 USA. * */ #include #include #include "fgetl.h" #define INITBUFSIZE 100 /* line length we start with */ #define BUFSIZEINCR 100 /* amount to incr each time it gets too big */ /* malloc, but die if it fails. only use to allocate char[] */ static char * fgmalloc (size) int size; { char *foo; foo = malloc (size * sizeof (char)); if (foo == 0) { fprintf (stderr, "fgetl: memory allocation failure\n"); exit (1); } return foo; } /* realloc, but die if it fails. again, char[] only */ static char * fgrealloc (what, size) char *what; int size; { what = realloc (what, size * sizeof (char)); if (what == 0) { fprintf (stderr, "fgetl: memory allocation failure\n"); exit (1); } return what; } /* get a line of text from the FILE pointed to by which, and return a pointer to it. This is quite similar to the Berkeley 4.4 fgetln(), except that since they're inside stdio they get to use internal buffers while we have to make our own. Anyway, the memory allocated is *not* to be freed by the calling function; this would be one of those "returns a pointer to static data which is overwritten with each call" except that since our buffer grows as needed it's not quite static. */ char * fgetl (which) FILE *which; { static char *line = 0; static int len = 0; /* longest line[] has ever been */ int c; /* char we read */ int l = 0; /* where we are in the string now */ if (line == 0) { line = fgmalloc (INITBUFSIZE); len = INITBUFSIZE; } while ((c = getc (which)) != EOF) { /* make sure there's room for the new char */ if (l >= len) { len += BUFSIZEINCR; line = fgrealloc (line, len); } line[l] = c; l++; /* if we added a newline, stop */ if (c == '\n') break; } /* if we've read all the chars and l is still 0, we must be at EOF, so return 0 */ if (l == 0) { return 0; } /* make sure there's room for the \0 on the end */ if (l >= len) { len += BUFSIZEINCR; line = fgrealloc (line, len); } /* put it there, return the string */ line[l] = 0; return line; } hap/fgetl.h100644 24036 142 171 6173007213 7513 0ustar /* assumes we already have , for FILE */ #ifdef __STDC__ char *fgetl (FILE *fd); #else char *fgetl(); #endif hap/file.c100644 24036 142 10657 6173007214 7377 0ustar /* * hap -- a mail notification program * * copyright 1995 by Eric Fischer, etaoin@uchicago.edu * * copies of hap may be redistributed under the terms of the * GNU public license, copies of which are available from * the Free Software Foundation, 59 Temple Place, Boston, MA * 02111 USA. * */ #include "hap.h" /**************************************************************************** FILE LOOKUP STUFF ****************************************************************************/ /* try the mail spool directory named 'spool' and see if there's a file with our name on it in there. return a pointer to the full name of the file (spool + our name) if it's there, 0 if not. pointers are only good until the next call, so copy them if you want to keep them. */ char * stry (spool, me) char *spool; char *me; { static char *ya = 0; /* try the /whatever/me/me case I've never actually seen a system that does it this way, but somewhere I heard there were computers like this. Doesn't cost much to check, anyway... */ if (ya) free (ya), ya = 0; ya = xmalloc (strlen (spool) + strlen (me) + 1 + strlen (me) + 1); strcpy (ya, spool); strcat (ya, me); strcat (ya, "/"); strcat (ya, me); if (getsize (ya) != -1) return ya; /* try the /whatever/me case */ if (ya) free (ya), ya = 0; ya = xmalloc (strlen (spool) + strlen (me) + 1); strcpy (ya, spool); strcat (ya, me); if (getsize (ya) != -1) return ya; return 0; } /* try to find the mail spool. Why can't people agree on somewhere to keep this? Anyway, try all the usual possibilities, first looking for real files, then if there's no actual file to be found, looking for directories that might plausibly contain mail files. If none of those can be found either, give up and guess /usr/spool/mail. */ char * getspoolname (me) char *me; { char *x; if ((x = stry ("/usr/spool/mail/", me))) return x; if ((x = stry ("/var/spool/mail/", me))) return x; if ((x = stry ("/usr/mail/", me))) return x; if ((x = stry ("/var/mail/", me))) return x; if (exs("/usr/spool/mail")) return conc("/usr/spool/mail/", me); if (exs("/var/spool/mail")) return conc("/var/spool/mail/", me); if (exs("/usr/mail")) return conc("/usr/mail/", me); if (exs("/var/mail")) return conc("/var/mail/", me); /* we have no clue, take a guess... */ return conc ("/usr/spool/mail/", me); } /* given a filename, either return it unchanged or if it's an alias for a mail spool, expand it into a full path to the mail. THIS FUNCTION ALLOCATES MEMORY and does NOT return a pointer to static data which is overwritten with each call. */ char * expandname (name) char *name; { if (name[0] != '%') { return strdupe (name); } else { if (name[1] == 0) { char *x = getenv ("MAIL"); if (x) return x; else return strdupe (getspoolname (whoami())); } else { return strdupe (getspoolname (name + 1)); } } } /* return the last-modified time of the file named filename. This is used to see if an mh folder has changed. */ time_t getmtime (filename) char *filename; { struct stat buf; if (stat (filename, &buf) == -1) return -1; return buf.st_mtime; } /* returns the size of the file whose path is given in 'filename'. if it doesn't exist, return -1. */ long getsize (filename) char *filename; { struct stat buf; if (stat (filename, &buf) == -1) return -1; return buf.st_size; } /* return true if filename is a directory; 0 if not */ int checkdir(filename) char *filename; { struct stat buf; if (stat (filename, &buf) == -1) return 0; return buf.st_mode & S_IFDIR; } /* returns whether the file 'filename' exists. */ int exs (filename) char *filename; { struct stat buf; if (stat (filename, &buf) == -1) return 0; return 1; } /* get last access time of the file descriptor fd */ time_t getlasttime (fd) int fd; { struct stat buf; if (fstat (fd, &buf) == -1) return -1; return buf.st_atime; } /* check permissions on the file descriptor fd. If group-writeable, return false, otherwise true. (reversed so we can idle with while (mesgy()).) this is for the -m option. */ int mesgy (fd) int fd; { struct stat buf; mode_t mode; /* if it's broken, just leave -- better to overwrite the screen than to loop forever... */ if (fstat (fd, &buf) != 0) return 0; mode = (buf.st_mode & 070) >> 3; /* group permissions */ if (mode & 2) return 0; /* if group-writeable, stop looping */ else return 1; } hap/fixaddr.c100644 24036 142 15671 6173007303 10101 0ustar /* * hap -- a mail notification program * * copyright 1995 by Eric Fischer, etaoin@uchicago.edu * * copies of hap may be redistributed under the terms of the * GNU public license, copies of which are available from * the Free Software Foundation, 59 Temple Place, Boston, MA * 02111 USA. * */ #include "hap.h" /************************************************************* HEADER MANIPULATIONS to retrieve true names and addresses from amidst the rfc822 junk. **************************************************************/ /* end the string at the first at sign. */ void splatat (s) char *s; { while (*s) { if (*s == '@') *s = 0; s++; } } /* return a new string containing a massaged version of the people list `s': if `how' is JUSTNAME return only the names; if JUSTADDR, only the addresses, if CANONICAL return it all in `name
' format. pointer to static data which is overwritten with each call, and all that. */ /* 2 aug: the stuff to handle :; is ugly but I think functional. I'm not quite sure what to do with groupname:; with no intervening addresses, since it is officially legal (and explicitly so) but doesn't actually contain any people's names) so it just gets a ??? user, which is the best I could think of. "foo: bar, baz;" gets canonized into "bar (foo), baz (foo)" which isn't quite the rfc's intent but expresses the group membership reasonably well. */ char * canonaddr (how, s) int how; char *s; { static char *ret = 0; char stopchar; char *groupname = 0; if (ret) free (ret), ret = 0; while (*s == ',' || isspace (*s)) s++; while (*s) { static char *angles = 0; static char *parens = 0; static char *neither = 0; int angleoffset = 0; int parenoffset = 0; int neitheroffset = 0; int inparens = 0; int inquotes = 0; int inangles = 0; int nextspecial = 0; if (angles) free (angles), angles = 0; if (parens) free (parens), parens = 0; if (neither) free (neither), neither = 0; angles = strdupe (s); parens = strdupe (s); neither = strdupe (s); angles[0] = 0; parens[0] = 0; neither[0] = 0; while (*s) { stopchar = ','; if (inangles) { if (nextspecial) { angles[angleoffset++] = *s; nextspecial = 0; } else if (*s == '\\') { nextspecial = 1; } else if (*s == '>') { inangles--; } else if (*s == '<') { inangles++; } else { angles[angleoffset++] = *s; } } else if (inparens) { if (nextspecial) { parens[parenoffset++] = *s; nextspecial = 0; } else if (*s == '\\') { nextspecial = 1; } else if (*s == ')') { inparens--; } else if (*s == '(') { inparens++; } else { parens[parenoffset++] = *s; } } else if (inquotes) { if (nextspecial) { neither[neitheroffset++] = *s; nextspecial = 0; } else if (*s == '\\') { nextspecial = 1; } else if (*s == '\"') { inquotes = 0; } else { neither[neitheroffset++] = *s; } } else { if (*s == '(') { inparens++; } else if (*s == '<') { inangles++; } else if (*s == '\"') { inquotes = 1; } else if (*s == ',' || *s == ';' || *s == ':') { stopchar = *s; break; } else { neither[neitheroffset++] = *s; } } s++; } angles[angleoffset] = 0; parens[parenoffset] = 0; neither[neitheroffset] = 0; { char *theparen = parens; char *theangle = angles; char *theneither = neither; if (theparen) { while (*theparen && isspace (*theparen)) theparen++; while (strlen (theparen) && isspace (theparen[strlen (theparen) - 1])) theparen[strlen (theparen) - 1] = 0; if (!*theparen) theparen = 0; } if (theangle) { while (*theangle && isspace (*theangle)) theangle++; while (strlen (theangle) && isspace (theangle[strlen (theangle) - 1])) theangle[strlen (theangle) - 1] = 0; if (!*theangle) theangle = 0; } if (theneither) { while (*theneither && isspace (*theneither)) theneither++; while (strlen(theneither) && isspace (theneither[strlen(theneither)-1])) theneither[strlen (theneither)-1] = 0; if (!*theneither) theneither = 0; } if (stopchar == ':') { /* there *shouldn't* be a group name at this point, but deal with it if there is one. */ if (groupname) free (groupname), groupname = 0; /* there should be a neither, too, but if there's not, we'll just do without a group name. Who needs 'em anyway? */ if (theneither) { groupname = strdupe (theneither); } } else if (how == JUSTNAME) { if (theangle) { if (theneither) splatat (theneither); addstr (&ret, theneither); if (theparen) { addstr (&ret, " ("); addstr (&ret, theparen); addstr (&ret, ")"); } if (!theneither && !theparen) { splatat (theangle); addstr (&ret, theangle); } } else if (theparen) addstr (&ret, theparen); else if (theneither) { splatat (theneither); addstr (&ret, theneither); } else addstr (&ret, "???"); if (groupname) { addstr (&ret, " ("); addstr (&ret, groupname); addstr (&ret, ")"); } } else if (how == JUSTADDR) { if (theangle) addstr (&ret, theangle); else if (theneither) addstr (&ret, theneither); else addstr (&ret, "???"); } else { if (groupname) { addstr (&ret, " ("); addstr (&ret, groupname); addstr (&ret, ")"); } if (theangle) { if (theparen) { if (theneither) { addstr (&ret, theneither); addstr (&ret, " ("); } addstr (&ret, theparen); if(theneither) addstr(&ret,")"); } else if (theneither) { addstr (&ret, theneither); } addstr (&ret, " <"); addstr (&ret, theangle); addstr (&ret, ">"); } else if (theparen) { addstr (&ret, theparen); addstr (&ret, " <"); if (theneither) addstr(&ret,theneither); else addstr (&ret, "???"); addstr (&ret, ">"); } else { addstr (&ret, "<"); addstr (&ret, theneither); addstr (&ret, ">"); } } if (stopchar == ';') { if (groupname) free (groupname), groupname = 0; } } /* got to make sure we don't trample the ; in a group:; construct with no users, because we want to list the group even if there's no one in it. we can deal with chunks of , and ; so long as we do remember to get rid of the current group at each ; */ if (stopchar == ':') { while (*s == ':' || isspace (*s)) s++; } else { while (*s == ';' || *s == ',' || isspace (*s)) { if (*s == ';') { if (groupname) free (groupname), groupname = 0; } s++; } } if (*s && *s != ':' && stopchar != ':') { addstr (&ret, ", "); } } /* this shouldn't happen, but who knows what fool might not close their :; group */ if (groupname) free (groupname); return ret; } hap/getopt.c100644 24036 142 52367 6173007303 7765 0ustar /* Getopt for GNU. NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu before changing it! Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 1994 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 59 Temple Place, Boston, MA 02111, USA. */ #ifdef HAVE_CONFIG_H #if defined (emacs) || defined (CONFIG_BROKETS) /* We use instead of "config.h" so that a compilation using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h (which it would do because it found this file in $srcdir). */ #include #else #include "config.h" #endif #endif #ifndef __STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ #ifndef const #define const #endif #endif /* This tells Alpha OSF/1 not to define a getopt prototype in . */ #ifndef _NO_PROTO #define _NO_PROTO #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #if defined (_LIBC) || !defined (__GNU_LIBRARY__) /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #if defined(__GNU_LIBRARY__) || defined(STDC_HEADERS) /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ #include #else extern char *getenv (); #endif /* __GNU_LIBRARY || STDC_HEADERS */ /* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a long-named option. Because this is not POSIX.2 compliant, it is being phased out. */ /* #define GETOPT_COMPAT */ /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order. Setting the environment variable POSIXLY_CORRECT disables permutation. Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ #include "getopt.h" /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ char *optarg = 0; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns EOF, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ /* XXX 1003.2 says this must be 1 before any call. */ int optind = 0; /* The next char to be scanned in the option-element in which the last option character we returned was found. This allows us to pick up the scan where we left off. If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ static char *nextchar; /* Callers store zero here to inhibit the error message for unrecognized options. */ int opterr = 1; /* Set to an option character which was unrecognized. This must be initialized on some systems to avoid linking in the system's own getopt implementation. */ int optopt = '?'; /* Describe how to deal with options that follow non-option ARGV-elements. If the caller did not specify anything, the default is REQUIRE_ORDER if the environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. REQUIRE_ORDER means don't recognize them as options; stop option processing when the first non-option is seen. This is what Unix does. This mode of operation is selected by either setting the environment variable POSIXLY_CORRECT, or using `+' as the first character of the list of option characters. PERMUTE is the default. We permute the contents of ARGV as we scan, so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this. RETURN_IN_ORDER is an option available to programs that were written to expect options and other ARGV-elements in any order and that care about the ordering of the two. We describe each non-option ARGV-element as if it were the argument of an option with character code 1. Using `-' as the first character of the list of option characters selects this mode of operation. The special argument `--' forces an end of option-scanning regardless of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return EOF with `optind' != ARGC. */ static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; #if defined(__GNU_LIBRARY__) || defined(STDC_HEADERS) /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ #include #define my_index strchr #else /* Avoid depending on library functions or files whose names are inconsistent. */ static char * my_index (str, chr) const char *str; int chr; { while (*str) { if (*str == chr) return (char *) str; str++; } return 0; } /* If using GCC, we can safely declare strlen this way. If not using GCC, it is ok not to declare it. (Supposedly there are some machines where it might get a warning, but changing this conditional to __STDC__ is too risky.) */ #ifdef __GNUC__ #ifdef IN_GCC #include "gstddef.h" #else #include #endif extern size_t strlen (const char *); #endif #endif /* __GNU_LIBRARY__ || STDC_HEADERS */ /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them. */ static int first_nonopt; static int last_nonopt; /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The other is elements [last_nonopt,optind), which contains all the options processed since those non-options were skipped. `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ static void exchange (argv) char **argv; { int bottom = first_nonopt; int middle = last_nonopt; int top = optind; char *tem; /* Exchange the shorter segment with the far end of the longer segment. That puts the shorter segment into the right place. It leaves the longer segment in the right place overall, but it consists of two parts that need to be swapped next. */ while (top > middle && middle > bottom) { if (top - middle > middle - bottom) { /* Bottom segment is the short one. */ int len = middle - bottom; register int i; /* Swap it with the top part of the top segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; } /* Exclude the moved bottom segment from further swapping. */ top -= len; } else { /* Top segment is the short one. */ int len = top - middle; register int i; /* Swap it with the bottom part of the bottom segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; } /* Exclude the moved top segment from further swapping. */ bottom += len; } } /* Update records for the slots the non-options now occupy. */ first_nonopt += (optind - last_nonopt); last_nonopt = optind; } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If `getopt' is called repeatedly, it returns successively each of the option characters from each of the option elements. If `getopt' finds another option character, it returns that character, updating `optind' and `nextchar' so that the next call to `getopt' can resume the scan with the following option character or ARGV-element. If there are no more option characters, `getopt' returns `EOF'. Then `optind' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return '?' after printing an error message. If you set `opterr' to zero, the error message is suppressed but we still return '?'. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `optarg'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `optarg', otherwise `optarg' is set to zero. If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. The elements of ARGV aren't really const, because we permute them. But we pretend they're const in the prototype to be compatible with other systems. LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a long-named option has been found by the most recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ int _getopt_internal (argc, argv, optstring, longopts, longind, long_only) int argc; char *const *argv; const char *optstring; const struct option *longopts; int *longind; int long_only; { int option_index; optarg = 0; /* Initialize the internal data when the first call is made. Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ if (optind == 0) { first_nonopt = last_nonopt = optind = 1; nextchar = NULL; /* Determine how to handle the ordering of options and nonoptions. */ if (optstring[0] == '-') { ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { ordering = REQUIRE_ORDER; ++optstring; } else if (getenv ("POSIXLY_CORRECT") != NULL) ordering = REQUIRE_ORDER; else ordering = PERMUTE; } if (nextchar == NULL || *nextchar == '\0') { if (ordering == PERMUTE) { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (last_nonopt != optind) first_nonopt = optind; /* Now skip any additional non-options and extend the range of non-options previously skipped. */ while (optind < argc && (argv[optind][0] != '-' || argv[optind][1] == '\0') #ifdef GETOPT_COMPAT && (longopts == NULL || argv[optind][0] != '+' || argv[optind][1] == '\0') #endif /* GETOPT_COMPAT */ ) optind++; last_nonopt = optind; } /* Special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ if (optind != argc && !strcmp (argv[optind], "--")) { optind++; if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (first_nonopt == last_nonopt) first_nonopt = optind; last_nonopt = argc; optind = argc; } /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ if (optind == argc) { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ if (first_nonopt != last_nonopt) optind = first_nonopt; return EOF; } /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ if ((argv[optind][0] != '-' || argv[optind][1] == '\0') #ifdef GETOPT_COMPAT && (longopts == NULL || argv[optind][0] != '+' || argv[optind][1] == '\0') #endif /* GETOPT_COMPAT */ ) { if (ordering == REQUIRE_ORDER) return EOF; optarg = argv[optind++]; return 1; } /* We have found another option-ARGV-element. Start decoding its characters. */ nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); } if (longopts != NULL && ((argv[optind][0] == '-' && (argv[optind][1] == '-' || long_only)) #ifdef GETOPT_COMPAT || argv[optind][0] == '+' #endif /* GETOPT_COMPAT */ )) { const struct option *p; char *s = nextchar; int exact = 0; int ambig = 0; const struct option *pfound = NULL; int indfound; while (*s && *s != '=') s++; /* Test all options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, s - nextchar)) { if (s - nextchar == strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (opterr) fprintf (stderr, "%s: option `%s' is ambiguous\n", argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; return '?'; } if (pfound != NULL) { option_index = indfound; optind++; if (*s) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = s + 1; else { if (opterr) { if (argv[optind - 1][1] == '-') /* --option */ fprintf (stderr, "%s: option `--%s' doesn't allow an argument\n", argv[0], pfound->name); else /* +option or -option */ fprintf (stderr, "%s: option `%c%s' doesn't allow an argument\n", argv[0], argv[optind - 1][0], pfound->name); } nextchar += strlen (nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (opterr) fprintf (stderr, "%s: option `%s' requires an argument\n", argv[0], argv[optind - 1]); nextchar += strlen (nextchar); return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[optind][1] == '-' #ifdef GETOPT_COMPAT || argv[optind][0] == '+' #endif /* GETOPT_COMPAT */ || my_index (optstring, *nextchar) == NULL) { if (opterr) { if (argv[optind][1] == '-') /* --option */ fprintf (stderr, "%s: unrecognized option `--%s'\n", argv[0], nextchar); else /* +option or -option */ fprintf (stderr, "%s: unrecognized option `%c%s'\n", argv[0], argv[optind][0], nextchar); } nextchar = (char *) ""; optind++; return '?'; } } /* Look at and handle the next option-character. */ { char c = *nextchar++; char *temp = my_index (optstring, c); /* Increment `optind' when we start to process its last character. */ if (*nextchar == '\0') ++optind; if (temp == NULL || c == ':') { if (opterr) { #if 0 if (c < 040 || c >= 0177) fprintf (stderr, "%s: unrecognized option, character code 0%o\n", argv[0], c); else fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c); #else /* 1003.2 specifies the format of this message. */ fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c); #endif } optopt = c; return '?'; } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*nextchar != '\0') { optarg = nextchar; optind++; } else optarg = 0; nextchar = NULL; } else { /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (opterr) { #if 0 fprintf (stderr, "%s: option `-%c' requires an argument\n", argv[0], c); #else /* 1003.2 specifies the format of this message. */ fprintf (stderr, "%s: option requires an argument -- %c\n", argv[0], c); #endif } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; nextchar = NULL; } } return c; } } int getopt (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { return _getopt_internal (argc, argv, optstring, (const struct option *) 0, (int *) 0, 0); } #endif /* _LIBC or not __GNU_LIBRARY__. */ #ifdef TEST /* Compile with -DTEST to make an executable for use in testing the above definition of `getopt'. */ int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; c = getopt (argc, argv, "abc:d:0123456789"); if (c == EOF) break; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ hap/getopt.h100644 24036 142 10502 6173007303 7753 0ustar /* Declarations for getopt. Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef _GETOPT_H #define _GETOPT_H 1 #ifdef __cplusplus extern "C" { #endif /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ extern char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns EOF, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ extern int optind; /* Callers store zero here to inhibit the error message `getopt' prints for unrecognized options. */ extern int opterr; /* Set to an option character which was unrecognized. */ extern int optopt; /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct option' terminated by an element containing a name which is zero. The field `has_arg' is: no_argument (or 0) if the option does not take an argument, required_argument (or 1) if the option requires an argument, optional_argument (or 2) if the option takes an optional argument. If the field `flag' is not NULL, it points to a variable that is set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. To have a long-named option do something other than set an `int' to a compiled-in constant, such as set a value from `optarg', set the option's `flag' field to zero and its `val' field to a nonzero value (the equivalent single-letter option character, if there is one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ struct option { #ifdef __STDC__ const char *name; #else char *name; #endif /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; /* Names for the values of the `has_arg' field of `struct option'. */ #define no_argument 0 #define required_argument 1 #define optional_argument 2 #ifdef __STDC__ #if defined(__GNU_LIBRARY__) /* Many other libraries have conflicting prototypes for getopt, with differences in the consts, in stdlib.h. To avoid compilation errors, only prototype getopt for the GNU C library. */ extern int getopt (int argc, char *const *argv, const char *shortopts); #else /* not __GNU_LIBRARY__ */ extern int getopt (); #endif /* not __GNU_LIBRARY__ */ extern int getopt_long (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind); extern int getopt_long_only (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind); /* Internal only. Users should not call this directly. */ extern int _getopt_internal (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind, int long_only); #else /* not __STDC__ */ extern int getopt (); extern int getopt_long (); extern int getopt_long_only (); extern int _getopt_internal (); #endif /* not __STDC__ */ #ifdef __cplusplus } #endif #endif /* _GETOPT_H */ hap/getopt1.c100644 24036 142 10734 6173007304 10037 0ustar /* getopt_long and getopt_long_only entry points for GNU getopt. Copyright (C) 1987, 88, 89, 90, 91, 92, 1993 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 59 Temple Place, Boston, MA 02111, USA. */ #ifdef HAVE_CONFIG_H #if defined (emacs) || defined (CONFIG_BROKETS) /* We use instead of "config.h" so that a compilation using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h (which it would do because it found this file in $srcdir). */ #include #else #include "config.h" #endif #endif #include "getopt.h" #ifndef __STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ #ifndef const #define const #endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #if defined (_LIBC) || !defined (__GNU_LIBRARY__) /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #if defined(__GNU_LIBRARY__) || defined(OS2) || defined(MSDOS) || defined(atarist) #include #else char *getenv (); #endif #ifndef NULL #define NULL 0 #endif int getopt_long (argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal (argc, argv, options, long_options, opt_index, 0); } /* Like getopt_long, but '-' as well as '--' can indicate a long option. If an option that starts with '-' (not '--') doesn't match a long option, but does match a short option, it is parsed as a short option instead. */ int getopt_long_only (argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal (argc, argv, options, long_options, opt_index, 1); } #endif /* _LIBC or not __GNU_LIBRARY__. */ #ifdef TEST #include int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; int option_index = 0; static struct option long_options[] = { {"add", 1, 0, 0}, {"append", 0, 0, 0}, {"delete", 1, 0, 0}, {"verbose", 0, 0, 0}, {"create", 0, 0, 0}, {"file", 1, 0, 0}, {0, 0, 0, 0} }; c = getopt_long (argc, argv, "abc:d:0123456789", long_options, &option_index); if (c == EOF) break; switch (c) { case 0: printf ("option %s", long_options[option_index].name); if (optarg) printf (" with arg %s", optarg); printf ("\n"); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case 'd': printf ("option d with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ hap/global.c100644 24036 142 1615 6201664275 7702 0ustar /* * hap -- a mail notification program * * copyright 1995 by Eric Fischer, etaoin@uchicago.edu * * copies of hap may be redistributed under the terms of the * GNU public license, copies of which are available from * the Free Software Foundation, 59 Temple Place, Boston, MA * 02111 USA. * */ #include "hap.h" char *program = 0; /* program name */ int biff = 0; /* emulating biff? */ int wantquote = 0; /* how much of message to quote */ char thisbuffer [THISBUFFERSIZE]; /* for stdout buffering */ pid_t shell = 0; /* pid of parent process */ char *lastadd; /* last file that a notification's come from */ int likeinverse = 1; /* funky inverse video notifications */ int fileannounce = 1;/* tell what file new mail is in */ int debug = 0; int terse = 0; /* be terse about our messages (--terse) */ int preferaddr = 0; /* announce addresses instead of names */ hap/hap.1100644 24036 142 10061 6201665151 7135 0ustar .TH HAP 1 "August 6, 1996" .SH NAME hap \- watch for the arrival of new mail .SH SYNOPSIS .B hap [ .BI \- seconds ] [ .B \-hVbskqvtmiA ] [ .I --long-option ... ] [ .I file [ .I ... file ]] .SH DESCRIPTION .B hap starts a background process which periodically checks the contents of your system mailbox (or any set of files you specify) and notifies you when new mail messages appear. It continues running in the background until its parent process exits, at which time it does too, or it can be forced to stop with the .B hap --kill command. .LP If you have a terminal capable of saving and restoring the cursor position (like the Digital Equipment .SM VT100\s0), .B hap will use this feature to always put your mail notifications at the top of the screen. If your terminal can't do this, they'll just appear wherever the cursor is when the mail arrives. .LP .B hap understands the .B mbox file format used by Berkeley .B Mail and traditional .SM AT&T .BR mail ; the .B mtxt format used by Columbia University's .SM .BR MM\s0 ; the .B .SM BABYL format used by Emacs .SM .BR RMAIL\s0 ; the .B .SM MMDF format that I think .B .SM MH uses sometimes; and .B .SM MH\s0\fR's directory-of-mail-files mailbox format. .LP If you use .B hap regularly, you'll probably want to include it in your .B .profile or .B .login file with whatever options you prefer. If you want to put it in your .B .cshrc file instead, be sure to use the conditional .LP if ($?prompt) hap .LP so that only interactive shells will start .B hap running. .LP Filenames beginning with .B % refer to system mailboxes. The filename .B % is your mailbox, and .BI % user is .IR user 's mailbox. .SH OPTIONS .if n .ta 1.4i .if n .TP 1.8i .if t .ta 1.1i .if t .TP 1.5i .B --help \-h Summarize the options. .TP .B --version \-V Report the version of .B hap you're using. .TP .B --kill \-k Force all the .B hap processes you have running to quit. .TP .BI \- seconds Check for mail every .I seconds seconds instead of the default 30. .TP .B --biff \-b Emulate net.personality .SM BIFF . Hours of fun for the whole family. .TP .B --silent \-s Don't beep when mail arrives .TP .B --quote \-q Report the first nonblank line of each new message. .TP .B --verbose \-v Like .BR --quote , but include as many as five lines intead of one. .TP .B --terse \-t Give only a very brief summary of new mail, in the upper right corner of the screen. .TP .B --mesg \-m Respect the setting of .BR mesg : don't check the mail while messages are turned off. .TP .B --no-inverse \-i Don't use inverse video to make mail notices stand out. .TP .B --address \-A Announce the addresses of senders and recipients rather than their names. .SH FILES .if t .TP 1.5i .if n .TP 1.8i /usr/spool/mail/* .br .ns .TP /var/spool/mail/* .br .ns .TP /usr/mail/* .br .ns .TP /var/mail/* system mailboxes .SH SEE ALSO .BR biff (1) .br Arthur Miller, .I Death of a Salesman .SH AUTHOR Eric Fischer, etaoin@uchicago.edu .SH BUGS Output with the .B --biff option should arguably be limited to 20 lines of 22 characters each. .LP The .B --quote and .B --verbose options cannot guard against someone reading over your shoulder. .LP What's a postmark to one mailer is regular text to another, and .B hap can't tell the difference. .LP The termcap entries for .B xterm and .B iris-ansi-net fail to mention that they can save and restore the cursor position, even though they emulate the .SM VT100. .B hap silently corrects this. .LP The .B --kill option can't distinguish between a .B hap process and another process whose name happens to end with .BR hap , and tries to kill both. .LP If your mail is kept in an unusual place, .B hap may not be able to find it, particularly if you don't have any mail when the process is started. You can avoid the problem by explicitly passing the path to your mail file as an argument to .B hap or by setting the .B .SM $MAIL environmental variable to your mail file. .LP If a mail file shrinks and then immediately grows again, .B hap may fail to notice that the file ever got smaller. .LP It's too slow on large notifications because of allocating and deallocating memory. hap/hap.h100644 24036 142 5434 6201665267 7224 0ustar #include #include #include #include #include #include #include #include /* configure #defines the types we need that we don't have. unfortunately, this screws up cproto. so work around my broken header files... */ #ifdef size_t typedef size_t #undef size_t size_t; #endif #ifdef mode_t typedef mode_t #undef mode_t mode_t; #endif #ifdef pid_t typedef pid_t #undef pid_t pid_t; #endif #ifdef FILE typedef FILE #undef FILE FILE; #endif typedef RETSIGTYPE retsigtype; #include "fgetl.h" #include "getopt.h" #ifdef __STDC__ typedef void *voidptr; #else typedef char *voidptr; #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_SGTTY_H # include #endif #ifdef HAVE_SYS_IOCTL_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_LIBC_H # include #endif #ifdef HAVE_TERMCAP_H /* does this actually exist anywhere? Yes, under Linux, it looks like. */ # include #else int tgetent(); void tputs(); char *tgetstr(); char *tgoto(); int tgetnum(); #endif /* list all our processes, PID first. Silliness to make it work on both sysv and bsd, and even aix, and brand-new silliness to make it work with 4.4BSD */ #define PSCMD "(ps -opid,ucomm || ps xc || ps -a) 2>/dev/null | sed 's/ *$//'" #define same(a,b) (strcmp ((a), (b)) == 0) #define THISBUFFERSIZE 8000 /* stdout buffer size */ struct flist { char *name; struct flist *next; }; typedef struct flist flist; struct mailbox { char *name; long size; flist *isdir; /* 0 if not a dir; string list ptr if so */ time_t mtime; struct mailbox *next; }; typedef struct mailbox mailbox; struct hlist { char *from; char *to; char *subject; long startpoint; long endpoint; int msgnumint; char *msgnumstr; char *postmark; }; typedef struct hlist hlist; extern int errno; #include "proto.h" #ifndef HAVE_STRERROR # ifdef __STDC__ char *strerror (int); # else char *strerror(); # endif #endif extern char *program; /* program name */ extern int biff; /* --biff option enabled */ extern int wantquote; /* --quote or --verbose enabled */ extern char thisbuffer[]; /* for stdout buffering */ extern pid_t shell; /* process ID of our parent shell */ extern char *lastadd; /* name of last file notified from */ extern int likeinverse; /* funky inverse video notifications */ extern int fileannounce; /* tell what file new mail is in */ extern int debug; extern int terse; /* be terse about our messages (--terse) */ extern int preferaddr; /* addresses instead of names (--address) */ #define JUSTNAME 0 #define JUSTADDR 1 #define CANONICAL 2 hap/install-sh100644 24036 142 11243 6173007304 10305 0ustar #!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. # # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" tranformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 hap/ioctl.c100644 24036 142 3227 6173007304 7545 0ustar /* * hap -- a mail notification program * * copyright 1995 by Eric Fischer, etaoin@uchicago.edu * * copies of hap may be redistributed under the terms of the * GNU public license, copies of which are available from * the Free Software Foundation, 59 Temple Place, Boston, MA * 02111 USA. * */ #include "hap.h" /**************************************************************************** IOCTL THINGS ****************************************************************************/ /* return the width of the screen attached to the standard output */ int screenwid() { extern int tcapcols; int cols = 0; #ifdef TIOCGSIZE { struct ttysize buf; if ((int) ioctl (1, TIOCGSIZE, &buf) != -1) { if (buf.ts_cols > 0) cols = buf.ts_cols; } } #else # ifdef TIOCGWINSZ { struct winsize buf; if ((int) ioctl (1, TIOCGWINSZ, &buf) != -1) { if (buf.ws_col > 0) cols = buf.ws_col; } } # endif #endif if (cols == 0) { char *s = getenv ("COLUMNS"); if (s && atoi(s)) { cols = atoi (s); } } if (cols == 0) cols = tcapcols; return cols; } /* return the number of lines on the screen at stdout */ int screenhigh() { extern int tcaplines; int lines = 0; #ifdef TIOCGSIZE { struct ttysize buf; if ((int) ioctl (1, TIOCGSIZE, &buf) != -1) { if (buf.ts_lines > 0) lines = buf.ts_lines; } } #else # ifdef TIOCGWINSZ { struct winsize buf; if ((int) ioctl (1, TIOCGWINSZ, &buf) != -1) { if (buf.ws_row > 0) lines = buf.ws_row; } } # endif #endif if (lines == 0) { char *s = getenv ("LINES"); if (s && atoi (s)) { lines = atoi (s); } } if (lines == 0) lines = tcaplines; return lines; } hap/main.c100644 24036 142 21614 6201665164 7405 0ustar /* * hap -- a mail notification program * * copyright 1995 by Eric Fischer, etaoin@uchicago.edu * * copies of hap may be redistributed under the terms of the * GNU public license, copies of which are available from * the Free Software Foundation, 59 Temple Place, Boston, MA * 02111 USA. * */ #include "hap.h" #define STANDARD_OUT 1 #define STANDARD_IN 0 extern int savecurs; /* do we have a spiffy terminal? */ /************************************************************************** MAIN PROGRAM ***************************************************************************/ int main (argc, argv) int argc; char **argv; { int delay = 30; /* time between checks (-seconds) */ int beep = 1; /* do we beep at each notification? (--silent) */ int watchmesg = 0; /* watch mesg y/n setting of tty (--mesg) */ int warnmissing = 1; /* warn if files are missing (--no-warn) */ int listall = 0; /* list all messages at startup (--all) */ mailbox *boxes = 0; /* list of mailboxes we're watching */ time_t lastkbtouch = 0; /* time of the last keypress we know about */ char *whattoprint = 0; /* this notice */ char *notices = 0; /* notices already on the screen */ program = argv[0]; if (program == 0) program = "hap"; /* find out who called us. this must be done *before* we fork, of course. */ shell = getppid(); { int tempdelay = 0; int option_index = 0; static struct option longopts[] = { "help", 0, 0, 'h', "version", 0, 0, 'V', "biff", 0, 0, 'b', "silent", 0, 0, 's', "quiet", 0, 0, 's', "kill", 0, 0, 'k', "quote", 0, 0, 'q', "verbose", 0, 0, 'v', "terse", 0, 0, 't', "mesg", 0, 0, 'm', "all", 0, 0, 'a', "debug", 0, 0, 'd', "no-inverse",0,0, 'i', "addresses",0, 0, 'A', "address", 0, 0, 'A', 0, 0, 0, 0 }; while (1) { int c; c = getopt_long(argc, argv, "hVbskqvtmadiA0123456789", longopts, &option_index); if (c == EOF) break; if (isdigit (c)) { tempdelay = (tempdelay * 10) + (c - '0'); continue; } switch (c) { case 'h': usage(); break; case 'V': version(); break; case 'b': biff = 1; break; case 's': beep = 0; break; case 'k': diediedie(); break; case 'q': wantquote = 1; terse = 0; break; case 'v': wantquote = 5; terse = 0; break; case 't': wantquote = 0; terse = 1; break; case 'm': watchmesg = 1; break; case 'a': listall = 1; break; case 'd': debug = 1; break; case 'i': likeinverse = 0; break; case 'A': preferaddr = 1; break; default: usage(); break; } } if (optind < argc) { if (optind + 1 < argc) { fileannounce = 1; } else { fileannounce = 0; } for (; optind < argc; optind++) { mailbox *newm = (mailbox *) xmalloc (sizeof (mailbox)); newm->next = boxes; boxes = newm; boxes->size = 0; boxes->isdir = 0; boxes->name = expandname (argv[optind]); } } else { fileannounce = 0; } if (tempdelay) delay = tempdelay; } /* complain if some idiot put us in their .cshrc */ /* if (!isatty (STANDARD_OUT) && !terminalforce) { fprintf (stderr, "%s: standard output isn't a terminal.\n", program); fprintf (stderr, "%s: use the --file option if you really %s", program, "meant it\n"); exit (1); } */ /* if we don't have a list of files, use the system mailbox */ if (boxes == 0) { boxes = (mailbox *) xmalloc (sizeof (mailbox)); boxes->next = 0; boxes->size = 0; boxes->isdir = 0; boxes->name = expandname ("%"); warnmissing = 0; /* if they don't type a name, they can't misspell it */ } /* warn the user if they've mistyped the names, and find out how big each is intially */ { mailbox *this; for (this = boxes; this; this = this->next) { long size = getsize (this->name); if (size == -1) { if (warnmissing) { fprintf (stderr, "%s: warning: ", mybasename (program)); perror (this->name); } this->size = 0; this->mtime = 0; } else { this->size = size; this->mtime = getmtime (this->name); if (checkdir(this->name)) { this->isdir = lookdir (this->name); } if (listall) { this->size = 0; if (this->isdir) freelist(this->isdir); this->isdir = 0; this->mtime = 0; } } } } /* make sure the output is not in fact line buffered, but buffered for real until we flush it, and with a big buffer */ #ifdef HAVE_SETVBUF setvbuf (stdout, thisbuffer, _IOFBF, THISBUFFERSIZE); #else # ifdef HAVE_SETBUFFER setbuffer (stdout, thisbuffer, THISBUFFERSIZE); # endif #endif /* make sure we've got a terminal that can do something useful */ inittcap(); /* create a daemon process */ { int pid = 0; if (!debug) pid = fork(); if (pid == -1) { fprintf (stderr, "%s: fork failed. Sorry.\n", program); perror (program); exit (1); } if (pid != 0) { exit (0); /* we're the parent process, quit */ } } /* set up signal handler so we can see the blood when we get killed */ signal (SIGTERM, alas); /* and make sure keyboard signals don't take us down (only relevant to sh users, I think) */ if (!debug) { signal (SIGINT, SIG_IGN); signal (SIGQUIT, SIG_IGN); } /* find last keyboard touch time. tiny delay to make sure that we don't check this until the shell has already printed the prompt and done a read(), because if we do it too early it'll have changed by the time we print our first notice, and if they've used --all and get new mail before typing anything they'll get two "New mail in..." lines. Ick. */ sleep (1); lastkbtouch = getlasttime (STANDARD_IN); /* we need this here because mesg gets checked at the end of the loop but we don't want to annoy them with mail notifications if mesg is already n when we start up and there's already mail to list. */ if (watchmesg) { while (mesgy (STANDARD_OUT) && alive()) { sleep (delay); } } /* now loop until our login goes away. */ do { mailbox *each; if (whattoprint) free (whattoprint), whattoprint = 0; /* check to see if the user is actually there. if the last time on the keyboard isn't the same as the previous time we checked, decide that there's actually someone there and get rid of any old messages we have saved up. important to do this before getting the new messages (even though it'd probably be better to wait for the keystroke until just before printing, since it might take a while to get stuff from the file) because the "New mail in..." line is included only if lastadd has changed, and we want it to be included at the top of every notification. */ { time_t kbtime = getlasttime (STANDARD_IN); if (kbtime != lastkbtouch) { /* kb has been touched */ if (notices) free (notices), notices = 0; lastadd = 0; } /* if we have a boring terminal that's not always doing mail at the same place on the screen, don't give multiple notifications for the same message. */ if (!savecurs) { if (notices) free (notices), notices = 0; lastadd = 0; } lastkbtouch = kbtime; } /* step through the mailboxes. if each has changed, add the new messages to the list of all the ones we want to print */ for (each = boxes; each; each = each->next) { if (checkdir (each->name)) { whattoprint = mhnotice (each, whattoprint); } else { whattoprint = filenotice (each, whattoprint); } } /* if there's anything new, spew out any old stuff we've been saving up, followed by whatever's new, then add the new stuff to the old stuff for next time. */ if (whattoprint) { if (beep) printf ("\007"); if (terse) { if (notices) tespewtwo (notices, whattoprint); else tespew (whattoprint); } else { startmessage(); if (notices) spewtwo (notices, whattoprint); else spew (whattoprint); endmessage(); } notices = addtostr (notices, whattoprint); } sleep (delay); /* if they care about mesg, check it and wait until mesg is y again. check alive() because they might log out without resetting mesg to y, and we don't want to get caught in an infinite loop. */ if (watchmesg) { while (mesgy (STANDARD_OUT) && alive()) { sleep (delay); } } } while (alive()); /* issue a few last words... generally the user will never see these; they're visible only if exiting from a subshell or su rather than from a legitimate login. */ /* startmessage(); printf ("the end is near for %s, process id %d, user id %s", mybasename (program), getpid(), whoami()); crlf(); printf ("(parent process, id %d, has exited)", shell); crlf(); endmessage(); */ return 0; } hap/malloc.c100644 24036 142 4440 6173007305 7701 0ustar /* * hap -- a mail notification program * * copyright 1995 by Eric Fischer, etaoin@uchicago.edu * * copies of hap may be redistributed under the terms of the * GNU public license, copies of which are available from * the Free Software Foundation, 59 Temple Place, Boston, MA * 02111 USA. * */ #include "hap.h" /************************************************************************* MEMORY ALLOCATION STUFF **************************************************************************/ /* return a pointer to malloc()ed data of size 'big'; die if it fails */ voidptr xmalloc (big) size_t big; { voidptr foo = malloc (big); if (foo == 0) { fprintf (stderr, "%s: memory failure, %d bytes\n", program, (int) big); perror ("malloc"); sleep (5); exit (1); } return foo; } /* like realloc, but die if it fails */ voidptr xrealloc (old, big) voidptr old; size_t big; { voidptr foo; if (old) foo = realloc (old, big); else foo = xmalloc (big); if (foo == 0) { fprintf (stderr, "%s: memory failure, %d bytes\n", program, (int) big); perror ("realloc"); sleep (5); exit (1); } return foo; } /* reallocate string 'old' to large enough to hold its current contents plus whatever's in 'new', and concatenate 'new' onto the end of it. then return the new address of 'old'. This gets used a lot. if 'old' is null, build a new string from scratch. */ char * addtostr (old, new) char *old; char *new; { if (new == 0) return old; if (old == 0) { char *foo = xmalloc ((strlen (new) + 1) * sizeof (char)); strcpy (foo, new); return foo; } else { old = xrealloc (old, (strlen (old) + strlen (new) + 1) * sizeof (char)); strcat (old, new); return old; } } /* like addtostr, but use a variable parameter instead of returning it so I don't have to type the variable name so often... */ void addstr(old, new) char **old; char *new; { *old = addtostr(*old, new); } /* like addstr, but add just a single character. */ void addchar (str, c) char **str; int c; { if (str == 0) return; if (*str == 0) { *str = xmalloc (2 * sizeof (char)); (*str)[0] = c; (*str)[1] = 0; return; } else { int len = strlen (*str); *str = xrealloc (*str, (strlen (*str) + 2) * sizeof (char)); (*str)[len] = c; (*str)[len + 1] = 0; } } hap/notice.c100644 24036 142 4612 6173007305 7714 0ustar /* * hap -- a mail notification program * * copyright 1995 by Eric Fischer, etaoin@uchicago.edu * * copies of hap may be redistributed under the terms of the * GNU public license, copies of which are available from * the Free Software Foundation, 59 Temple Place, Boston, MA * 02111 USA. * */ #include "hap.h" /* get the new mh-style messages, if any, in "each". This will be catted to the end of whattoprint if there's already something there. */ char * mhnotice(each, whattoprint) mailbox *each; char *whattoprint; { flist *newlist; flist *check; time_t now; now = getmtime(each->name); if (now != each->mtime) { newlist = lookdir(each->name); check = diffdir(each->isdir, newlist); if (check) { flist *it = check; while (it) { char *eep = readmh(each->name, it->name); if (eep) { if (fileannounce) { if (lastadd != each->name) { addstr(&whattoprint, "New mail in "); addstr(&whattoprint, each->name); addstr(&whattoprint, ":\n"); lastadd = each->name; } } addstr(&whattoprint, eep); } it = it->next; } } each->mtime = now; freelist(each->isdir); each->isdir = newlist; freelist(check); } return whattoprint; } /* get the new messages in a regular file. the list will be added to the end of whattoprint. */ char * filenotice(each, whattoprint) mailbox *each; char *whattoprint; { long size = getsize(each->name); /* if size has changed, wait for it to stabilize. if it's the same but not stable, we'll catch it next time around. */ if (size != each->size) { long sizenow = size; /* keep looping until we get the same size twice in a row */ while (1) { sleep(1); size = getsize(each->name); if (size == sizenow) break; sizenow = size; } } if (size > each->size) { char *goo = getmessages(*each, each->size); if (goo) { if (fileannounce && (lastadd != each->name)) { addstr(&whattoprint, "New mail in "); addstr(&whattoprint, each->name); if (each->size > 0) { addstr(&whattoprint, ": (was "); addstr(&whattoprint, ftoa (each->size / 1024.0)); addstr(&whattoprint, "k)\n"); } else { addstr(&whattoprint, ":\n"); } lastadd = each->name; } addstr(&whattoprint, goo); } } each->size = size; return whattoprint; } hap/num2str.c100644 24036 142 1566 6173007305 10052 0ustar /* * hap -- a mail notification program * * copyright 1995 by Eric Fischer, etaoin@uchicago.edu * * copies of hap may be redistributed under the terms of the * GNU public license, copies of which are available from * the Free Software Foundation, 59 Temple Place, Boston, MA * 02111 USA. * */ #include "hap.h" /************************************************************************* NUMBER -> STRING CONVERSION STUFF *************************************************************************/ /* return a pointer to a string containing the integer n. overwritten with each call. */ char * itoa (n) int n; { static char s[12]; sprintf (s, "%4d", n); return s; } /* return a pointerto a string containing the real number n. overwritten with each call. */ char * ftoa (n) double n; { static char s[12]; sprintf (s, "%.1f", n); return s; } hap/output.c100644 24036 142 24003 6201670115 10004 0ustar /* * hap -- a mail notification program * * copyright 1995 by Eric Fischer, etaoin@uchicago.edu * * copies of hap may be redistributed under the terms of the * GNU public license, copies of which are available from * the Free Software Foundation, 59 Temple Place, Boston, MA * 02111 USA. * */ #include "hap.h" /************************************************************************ SCREEN OUTPUT STUFF ************************************************************************/ /* terminals who claim not to be able to save and restore the cursor in their termcap entries, but who are emulating vt100s and therefore really can. It's possible there are ancient terminals by these names that really can't do it. Too bad for them... */ char *brokentermcaplist[] = { "xterm", "iris-ansi-net", 0 }; char *savecurs = 0; /* not static because main() cares */ static char *homecurs = 0; static char *restorecurs = 0; static char *inverse = 0; static char *normal = 0; static char *cleareol = 0; static char *movecurs = 0; static char *leftcurs = 0; int tcaplines; /* used in ioctl.c as a last resort */ int tcapcols; /* ditto */ /* print a single character to the standard output. Return the character we were given, though I'm pretty sure it gets thrown away by tputs(). */ int outchar (what) int what; { printf ("%c", what); return what; } /* get termcap stuff. complain if we're missing something, but continue merrily onward and just do ugly output. contains special cases for xterm-type terminals which can save and restore the cursor but whose termcaps, for whatever insane reason, don't declare this fact. */ void inittcap() { static char tbuf[2048], ttmp[2048], *here = ttmp; char *TERM; TERM = getenv ("TERM"); if (TERM == 0) { fprintf (stderr, "%s: %s %s", program, "warning: you should set TERM if you want things to", "work happily.\n"); return; } if (tgetent (tbuf, TERM) != 1) { fprintf (stderr, "%s: %s ``%s''\n", program, "warning: can't get the termcap entry for your terminal", TERM); return; } savecurs = tgetstr ("sc", &here); restorecurs = tgetstr ("rc", &here); if (savecurs == 0 || restorecurs == 0) { /* help out these poor deprived termcap entries */ char **maybe = brokentermcaplist; while (*maybe) { if (same (TERM, *maybe)) { savecurs = "\0337"; restorecurs = "\0338"; break; } maybe++; } if (savecurs == 0 || restorecurs == 0 ) { /* didn't work -- be boring */ savecurs = 0, restorecurs = 0; /* make sure *both* are 0 */ } } inverse = tgetstr ("so", &here); normal = tgetstr ("se", &here); if (!inverse || !normal) { inverse = 0, normal = 0; } /* if standout mode is going to take up screen space, we don't know how to deal with that. */ if (tgetnum ("sg") > 0) { inverse = 0, normal = 0; } tcaplines = tgetnum ("li"); if (tcaplines <= 0) tcaplines = 24; tcapcols = tgetnum ("co"); if (tcapcols <= 0) tcapcols = 80; homecurs = tgetstr ("ho", &here); cleareol = tgetstr ("ce", &here); movecurs = tgetstr ("cm", &here); if (homecurs == 0 && savecurs != 0) { fprintf (stderr, "%s: %s %s", program, "warning: your terminal can save and restore the cursor\n", "but not *move* it? Weird.\n"); savecurs = 0, restorecurs = 0; } leftcurs = tgetstr ("le", &here); } /* move the cursor to an arbitrary location. for terse (-t). */ void gotoyx (y, x) int y; int x; { char *move = tgoto (movecurs, x, y); if (move) { tputs (move, 1, outchar); } } /* echo as many dashes as the width of the screen and a newline */ void spewlines() { int cols = screenwid(); while (cols--) { printf ("-"); } printf ("\n\r"); } /* print fewer lines, so that the cursor doesn't fall off the right side of the screen when we can't get it back to where it belongs. */ void spewfewerlines() { int cols = screenwid() - 1; while (cols--) { printf ("-"); } printf ("\n\r"); } /* start a message display: save the cursor and move to upper left */ void startmessage() { if (savecurs) { tputs (savecurs, 1, outchar); if (homecurs) tputs (homecurs, 1, outchar); if (normal) tputs (normal, 1, outchar); } else { printf ("\n\r"); if (!inverse || !likeinverse) spewfewerlines(); } } /* end of the message. lay down a line of dashes, put the cursor back, and throw all this output to the terminal in one fell swoop */ void endmessage() { if (restorecurs) { if (!likeinverse) { /* if (inverse) tputs (inverse, 1, outchar); */ spewlines(); /* if (normal) tputs (normal, 1, outchar); */ } tputs (restorecurs, 1, outchar); } else { if (!inverse || !likeinverse) spewfewerlines(); } fflush (stdout); } /* newline. if we have clear to eol, use it; do both \n and \r in case the terminal is in raw mode and nobody told us. */ void crlf() { if (cleareol) tputs (cleareol, 1, outchar); printf ("\n\r"); } /* output a string to the screen. make sure we don't fall off the end of the display, or take up too much vertical space, and handle the biff emulation if we're doing that. control characters other than \n will not be pretty. automatically reduces streams of \n characters to a single \n; if you want blank lines make sure to include a space or something on them. */ void spew (what) char *what; { int c = 0; int wid = screenwid() - 1; int high = screenhigh() / 2 - 1; int msglines; int theline = 0; if (what == 0) return; if (debug) { printf ("%s", what); return; } msglines = numlns (what); if (msglines > high) { what = skiplines (what, msglines - high); } if (likeinverse) { if (inverse) tputs (inverse, 1, outchar); } while (*what) { unsigned char uwhat = *((unsigned char *) what); if (*what == '\n') { if (likeinverse) { while (c < wid) { printf (" "); c++; } c = 0; if (savecurs && movecurs) { printf (" "); gotoyx (++theline, 0); } else { crlf(); } } else { c = 0; crlf(); } /* elide blank lines */ while (what[1] == '\n') what++; } else if (uwhat < ' ' || (uwhat >= 127 && uwhat < 128 + ' ')) { if (c+5 < wid) { printf ("\\%3.3o", uwhat); c += 4; } else if (c < wid) { printf ("^"); c++; } } else if (c < wid) { if (biff) { char w = *what; if (w == '!' && c < wid-8) printf ("."); else if (w == 'o' || w == 'O') printf ("0"); else if (w == 'e' || w == 'E') printf ("3"); else if (w == 'i' || w == 'I') printf ("1"); else if (w == 's' || w == 'S') printf ("Z"); else if (w == '/') printf ("\\"); else if (islower (w)) printf ("%c", toupper(w)); else if (isupper (w)) printf ("%c", tolower(w)); else if (w == '\'') c--; /* nothing */ else if (w == '.' && !isdigit(what[1])) printf ("!"); else printf ("%c", w); } else { printf ("%c", *what); } c++; /* heh. they said c++. heh heh. */ } what++; } if (likeinverse) { if (normal) tputs (normal, 1, outchar); } } /* combine two strings into a temp one, spew them */ void spewtwo (one, two) char *one; char *two; { static char *foo = 0; if (foo) free (foo), foo = 0; foo = addtostr (foo, one); foo = addtostr (foo, two); spew (foo); } /* spew a string as tersely as we can manage. Loses everything but the first word of each line and crams everything into the upper right hand corner of the screen. If it's too big to fit, chop off words from the start until it does. if we don't have cursor save and restore, just print '(mail)' and enough backspaces to get us back to where we were. */ void tespew (s) char *s; { /* this function uses "@" as padding because we specifically never let a word contain an @ */ static char *temp = 0; char *here; int fullwid = screenwid(); int wid = fullwid / 2; if (temp) free (temp), temp = 0; temp = xmalloc ((strlen (s) + 1) * sizeof (char)); here = temp; *here = ' '; here++; while (*s) { if (starts (s, "New mail")) { /* skip such lines */ while (*s && (*s != '\n')) s++; while (*s == '\n') s++; } while (isspace (*s)) s++; /* skip leading spaces */ while (isdigit (*s)) s++; /* skip message number */ while (isspace (*s)) s++; /* skip more spaces... */ while (*s == '-') s++; /* if no sender, skip the -- */ while (isspace (*s)) s++; /* ...and get to the 1st word */ while (*s == '"') s++; /* some mailers quote names */ while ((!isspace (*s)) && (*s) && (*s != '@') && (*s != '"')) { /* copy 1st word */ *here = *s; s++, here++; } while ((*s) && (*s != '\n')) { /* skip to end of line */ s++; } while (*s == '\n') s++; /* skip newline */ if (*s) { /* if not at end of string, add spaces */ *here++ = ' '; *here++ = '@'; *here++ = ' '; } } *here = ' '; here++; *here = 0; here = temp; while (strlen (here) > wid) { while (*here && *here != '@') here++; /* chop a word */ while (*here && *here == '@') here++; /* and a space */ } if (savecurs && movecurs) { tputs (savecurs, 1, outchar); gotoyx (0, fullwid - strlen (here) - 2); printf (" "); if (inverse && likeinverse) tputs (inverse, 1, outchar); while (*here) { if (*here == '@') { if (inverse && likeinverse) tputs (normal, 1, outchar); printf (" "); if (normal && likeinverse) tputs (inverse, 1, outchar); } else { if (*here < ' ' || *here >= 127) { printf ("^"); } else { printf ("%c", *here); } } here++; } if (normal && likeinverse) tputs (normal, 1, outchar); tputs (restorecurs, 1, outchar); } else { int i; printf ("(mail)"); for (i = 0; i < 6; i++) { if (leftcurs) { tputs (leftcurs, 1, outchar); } else { printf ("\b"); } } } fflush (stdout); } /* spew two strings, tersely */ void tespewtwo (one, two) char *one; char *two; { static char *foo = 0; if (foo) free (foo), foo = 0; foo = addtostr (foo, one); foo = addtostr (foo, two); tespew (foo); } hap/postmark.c100644 24036 142 13764 6173007306 10324 0ustar /* * hap -- a mail notification program * * copyright 1995 by Eric Fischer, etaoin@uchicago.edu * * copies of hap may be redistributed under the terms of the * GNU public license, copies of which are available from * the Free Software Foundation, 59 Temple Place, Boston, MA * 02111 USA. * */ #include "hap.h" /************************************************************************** POSTMARK RECOGNITION **************************************************************************/ /* vague definition of an mtxt postmark. Looks something like 11-Jul-92 12:42:03-GMT,748;000000000001 where a one digit number might have a space instead of a digit at the start. returns true if it matches, false if it doesn't. */ int ismtxt (what) char *what; { if (strlen (what) > 34) { if ((isspace (what[0]) || isdigit (what[0])) && isdigit (what[1]) && what[2] == '-' && isalpha (what[3]) && isalpha (what[4]) && isalpha (what[5]) && what[6] == '-' && isdigit (what[7]) && isdigit (what[8]) && isspace (what[9]) && (isspace (what[10]) || isdigit (what[10])) && isdigit (what[11]) && what[12] == ':' && isdigit (what[13]) && isdigit (what[14]) && what[15] == ':' && isdigit (what[16]) && isdigit (what[17]) && what[18] == '-' && isalpha (what[19]) && isalpha (what[20]) && isalpha (what[21]) && what[22] == ',') { char *here = what + 23; if (!isdigit (*here)) return 0; while (isdigit (*here)) here++; if (*here == ';') here++; else return 0; if (!isdigit (*here)) return 0; while (isdigit (*here)) here++; if (*here == '\n') return 1; else return 0; } } return 0; } /* is it a digit or a space? then say so. */ int isdigsp (it) int it; { return (isdigit (it) || isspace (it)); } /* returns true if end points to the *end* of a date in ctime format: Fri Jun 2 15:50:48 1995 ^-- end points here */ int isnormalmbox (end) char *end; { if (isdigit (end[ 0]) /* year */ && isdigit (end[-1]) && isdigit (end[-2]) && isdigit (end[-3]) && isspace (end[-4]) && isdigit (end[-5]) /* seconds */ && isdigit (end[-6]) && ':' == end[-7] && isdigit (end[-8]) /* minutes */ && isdigit (end[-9]) && ':' == end[-10] && isdigit (end[-11]) /* hour */ && isdigsp (end[-12]) && isspace (end[-13]) && isdigit (end[-14]) /* day */ && isdigsp (end[-15]) && isspace (end[-16]) && isalpha (end[-17]) /* month */ && isalpha (end[-18]) && isalpha (end[-19]) && isspace (end[-20]) && isalpha (end[-21]) && isalpha (end[-22]) && isalpha (end[-23])) { return 1; } else return 0; } /* like isnormalmbox, but date format is Fri Jun 2 15:50:48 1995 CDT */ int istrailingmbox (end) char *end; { /* alternate form 1: time zone at the end. this is the one the Mail manual approves of. */ if (isalpha (end[ 0]) /* time zone */ && isalpha (end[-1]) && isalpha (end[-2]) && isspace (end[-3]) && isdigit (end[-4]) /* year */ && isdigit (end[-5]) && isdigit (end[-6]) && isdigit (end[-7]) && isspace (end[-8]) && isdigit (end[-9]) /* seconds */ && isdigit (end[-10]) && ':' == end[-11] && isdigit (end[-12]) /* minutes */ && isdigit (end[-13]) && ':' == end[-14] && isdigit (end[-15]) /* hour */ && isdigsp (end[-16]) && isspace (end[-17]) && isdigit (end[-18]) /* day */ && isdigsp (end[-19]) && isspace (end[-20]) && isalpha (end[-21]) /* month */ && isalpha (end[-22]) && isalpha (end[-23]) && isspace (end[-24]) && isalpha (end[-25]) && isalpha (end[-26]) && isalpha (end[-27])) { return 1; } else return 0; } /* like isnormalmbox, but date format is Fri Jun 2 15:50:48 CDT 1995 */ int isincludedmbox (end) char *end; { /* alternate form 2: time zone before the year this is the one trn uses. */ if (isdigit (end[ 0]) /* year */ && isdigit (end[-1]) && isdigit (end[-2]) && isdigit (end[-3]) && isspace (end[-4]) && isalpha (end[-5]) /* time zone */ && isalpha (end[-6]) && isalpha (end[-7]) && isspace (end[-8]) && isdigit (end[-9]) /* seconds */ && isdigit (end[-10]) && ':' == end[-11] && isdigit (end[-12]) /* minutes */ && isdigit (end[-13]) && ':' == end[-14] && isdigit (end[-15]) /* hour */ && isdigsp (end[-16]) && isspace (end[-17]) && isdigit (end[-18]) /* day */ && isdigsp (end[-19]) && isspace (end[-20]) && isalpha (end[-21]) /* month */ && isalpha (end[-22]) && isalpha (end[-23]) && isspace (end[-24]) && isalpha (end[-25]) && isalpha (end[-26]) && isalpha (end[-27])) { return 1; } else return 0; } /* return true if the line is an mbox From header. somewhat less conservative than 4.3 Mail (it accepts a null username, since bounce messages sometimes are missing this) but much more conservative than simply flagging every line that begins with "From " */ int ismbox (what) char *what; { if (starts (what, "From ")) { int len = strlen (what); if (len > 29) { int kind; char *end = what + len - 2; if ((kind = isnormalmbox (end))) return 26; if ((kind = istrailingmbox (end))) return 30; if ((kind = isincludedmbox (end))) return 30; return 0; } } return 0; } /* return true if the line is the start of a message in whatever that format is that starts messages with four control-As */ int isctrla (what) char *what; { if (starts (what, "\001\001\001\001")) return 1; else return 0; } /* return true if the line matches the start of a babyl message */ int isbabyl (what) char *what; { if (starts (what, "\037\014")) return 1; else return 0; } /* return true if the line is the string that starts a BABYL message's second set of headers */ int isbabyl2 (what) char *what; { if (same (what, "*** EOOH ***\n")) return 1; else return 0; } int ispostmark (what) char *what; { return ismbox (what) || ismtxt (what) || isctrla (what) || isbabyl (what); } hap/proto.h100644 24036 142 6024 6173007306 7603 0ustar #if __STDC__ || defined(__cplusplus) #define P_(s) s #else #define P_(s) () #endif /* file.c */ char *stry P_((char *spool, char *me)); char *getspoolname P_((char *me)); char *expandname P_((char *name)); time_t getmtime P_((char *filename)); long getsize P_((char *filename)); int checkdir P_((char *filename)); int exs P_((char *filename)); time_t getlasttime P_((int fd)); int mesgy P_((int fd)); /* ioctl.c */ int screenwid P_((void)); int screenhigh P_((void)); /* main.c */ int main P_((int argc, char **argv)); /* malloc.c */ voidptr xmalloc P_((size_t big)); voidptr xrealloc P_((voidptr old, size_t big)); char *addtostr P_((char *old, char *new)); void addstr P_((char **old, char *new)); void addchar P_((char **str, int c)); /* num2str.c */ char *itoa P_((int n)); char *ftoa P_((double n)); /* output.c */ int outchar P_((int what)); void inittcap P_((void)); void gotoyx P_((int y, int x)); void spewlines P_((void)); void spewfewerlines P_((void)); void startmessage P_((void)); void endmessage P_((void)); void crlf P_((void)); void spew P_((char *what)); void spewtwo P_((char *one, char *two)); void tespew P_((char *s)); void tespewtwo P_((char *one, char *two)); /* postmark.c */ int ismtxt P_((char *what)); int isdigsp P_((int it)); int isnormalmbox P_((char *end)); int istrailingmbox P_((char *end)); int isincludedmbox P_((char *end)); int ismbox P_((char *what)); int isctrla P_((char *what)); int isbabyl P_((char *what)); int isbabyl2 P_((char *what)); int ispostmark P_((char *what)); /* readmbox.c */ char *getmessages P_((mailbox box, long loc)); int nottobeignored P_((char *s)); /* signal.c */ retsigtype alas P_((int foo)); void diediedie P_((void)); /* strerror.c */ /* string.c */ char *strdupe P_((char *what)); char *mybasename P_((char *what)); void chop P_((char *s)); int starts P_((char *l, char *s)); int cstarts P_((char *l, char *s)); int ends P_((char *l, char *s)); char *contains P_((char *s, int what)); char *scontains P_((char *s, char *what)); char *cscontains P_((char *s, char *what)); int numlns P_((char *what)); char *skiplines P_((char *what, int num)); char *conc P_((char *one, char *two)); char *truncstr P_((char *x, int maxlen)); /* usage.c */ void usage P_((void)); void version P_((void)); /* whoami.c */ char *whoami P_((void)); /* global.c */ /* alive.c */ int alive P_((void)); /* dir.c */ char *stripcr P_((char *s)); flist *lookdir P_((char *s)); int isin P_((flist *new, flist *it)); flist *diffdir P_((flist *old, flist *new)); void freelist P_((flist *it)); /* readmh.c */ char *readmh P_((char *folder, char *file)); /* notice.c */ char *mhnotice P_((mailbox *each, char *whattoprint)); char *filenotice P_((mailbox *each, char *whattoprint)); /* snagheader.c */ void inithlist P_((hlist *it)); void clearheaders P_((hlist *headers)); void addnspaces P_((char **str, int num)); void dumpheaders P_((char **str, hlist *headers)); void readheaders P_((hlist *list, FILE *f)); void dumpquote P_((char **msg, char **quote)); /* fixaddr.c */ void splatat P_((char *s)); char *canonaddr P_((int how, char *s)); #undef P_ hap/readmbox.c100644 24036 142 5326 6173007306 10240 0ustar /* * hap -- a mail notification program * * copyright 1995 by Eric Fischer, etaoin@uchicago.edu * * copies of hap may be redistributed under the terms of the * GNU public license, copies of which are available from * the Free Software Foundation, 59 Temple Place, Boston, MA * 02111 USA. * */ #include "hap.h" /************************************************************************** MAILBOX -> NOTIFICATION STUFF **************************************************************************/ /* returns a big string containing ascii notifications of all the new mail in mailbox 'box' beginning at location 'loc'. the pointer is only good until the next call. */ char * getmessages (box, loc) mailbox box; long loc; { hlist headerlist; static char *msg = 0; int msgnum = 0; static char *thequote = 0; FILE *f; long here = 0; int quotesleft = 0; char *s; if (msg) free (msg), msg = 0; if (thequote) free (thequote), thequote = 0; inithlist (&headerlist); f = fopen (box.name, "r"); if (f == 0) { msg = addtostr (msg, " * Unable to open "); msg = addtostr (msg, box.name); msg = addtostr (msg, ": "); msg = addtostr (msg, strerror (errno)); msg = addtostr (msg, "\n"); return msg; } if (loc < 0) loc = 0; while (here = ftell (f), s = fgetl (f)) { int waspostmark = ispostmark (s); if (waspostmark) msgnum++; if (here < loc) continue; if (waspostmark) { headerlist.endpoint = here; headerlist.msgnumint = msgnum - 1; /* -1 because we just incremented it for the following message... */ dumpheaders (&msg, &headerlist); dumpquote (&msg, &thequote); quotesleft = wantquote; { int mboxkind = ismbox (s); if (mboxkind) { headerlist.postmark = strdupe (s + 5); headerlist.postmark [ strlen (headerlist.postmark) - mboxkind ] = 0; } } readheaders (&headerlist, f); headerlist.startpoint = here; continue; } if (isbabyl2 (s)) { clearheaders (&headerlist); readheaders (&headerlist, f); } if (quotesleft && nottobeignored (s)) { addstr (&thequote, " "); addstr (&thequote, s); quotesleft--; } } fclose (f); headerlist.endpoint = here; headerlist.msgnumint = msgnum; dumpheaders (&msg, &headerlist); dumpquote (&msg, &thequote); return msg; } /* return true if this is a line of the message actually worth printing, instead of some quoted text or suchlike. */ int nottobeignored (s) char *s; { return (s[0] != '\n' && s[0] != '>' && s[0] != ':' && !starts (s, "In article") && !starts (s, "-----BEGIN") && s[0] != '#' && s[0] != '<' /* to keep BABYL message-terminators from getting quoted */ && s[0] != '\037'); } hap/readmh.c100644 24036 142 3255 6173007306 7676 0ustar /* * hap -- a mail notification program * * copyright 1995 by Eric Fischer, etaoin@uchicago.edu * * copies of hap may be redistributed under the terms of the * GNU public license, copies of which are available from * the Free Software Foundation, 59 Temple Place, Boston, MA * 02111 USA. * */ #include "hap.h" /************************************************************************** hacked for mh version of MAILBOX -> NOTIFICATION STUFF **************************************************************************/ /* returns the message in folder/file, assuming it's an mh-style one-message-per-file thing. */ char * readmh (folder, file) char *folder; char *file; { hlist headerlist; static char *msg = 0; char *thequote = 0; static char *fullname = 0; FILE *f; long here = 0; int quotesleft = 0; char *s; if (msg) free (msg), msg = 0; if (fullname) free (fullname), fullname = 0; inithlist (&headerlist); headerlist.msgnumstr = strdupe (file); fullname = strdupe (folder); addstr (&fullname, "/"); addstr (&fullname, file); f = fopen (fullname, "r"); if (f == 0) { msg = addtostr (msg, " * Unable to open "); msg = addtostr (msg, fullname); msg = addtostr (msg, ": "); msg = addtostr (msg, strerror (errno)); msg = addtostr (msg, "\n"); return msg; } quotesleft = wantquote; readheaders (&headerlist, f); headerlist.startpoint = 0; while (here = ftell (f), s = fgetl (f)) { if (quotesleft && nottobeignored (s)) { addstr (&thequote, " "); addstr (&thequote, s); quotesleft--; } } fclose (f); headerlist.endpoint = here; dumpheaders (&msg, &headerlist); dumpquote (&msg, &thequote); return msg; } hap/signal.c100644 24036 142 4006 6173007306 7706 0ustar /* * hap -- a mail notification program * * copyright 1995 by Eric Fischer, etaoin@uchicago.edu * * copies of hap may be redistributed under the terms of the * GNU public license, copies of which are available from * the Free Software Foundation, 59 Temple Place, Boston, MA * 02111 USA. * */ #include "hap.h" /************************************************************************** SIGNAL HANDLING STUFF **************************************************************************/ /* give up the ghost. wait a second, issue a death announcement, then exit */ retsigtype alas (foo) int foo; /* what is this for? */ { /* a statically allocated buffer?!? why?!? well, we're in a signal handler, so it's possible that very bad things would happen if we called malloc, even though we're probably only interrupting sleep() and are about to exit() anyway. 80 for possible filename; max 10 digits in a 32-bit int; 10 for username (even though it can really only be 8); and 41 for the surrounding text and newline and \0. */ char buf[80 + 10 + 10 + 41]; char *bn = mybasename (program); if (strlen (bn) > 79) { bn[79] = 0; } /* make sure the screen has time to scroll the process ID list up before we trample over things */ sleep (1); sprintf (buf, "``ouch!'' says %.80s, process id %d, user id %.10s\n", bn, getpid(), whoami()); startmessage(); spew (buf); endmessage(); exit (1); } /* kill all the other programs that have the same name as us. Used by the -k option. */ void diediedie() { FILE *psout = popen (PSCMD, "r"); char *s; if (psout == 0) { fprintf (stderr, "%s: can't open command %s\n", program, PSCMD); exit (1); } while ((s = fgetl (psout))) { chop (s); if (ends (s, mybasename (program))) { int pid; printf ("%s", s); while (*s == ' ') s++; pid = atoi (s); if (pid == getpid()) { printf (" (that's us)\n"); } else { printf ("\n"); kill (pid, SIGTERM); } } } pclose (psout); exit (0); } hap/snagheader.c100644 24036 142 15104 6201664623 10556 0ustar /* * hap -- a mail notification program * * copyright 1995 by Eric Fischer, etaoin@uchicago.edu * * copies of hap may be redistributed under the terms of the * GNU public license, copies of which are available from * the Free Software Foundation, 59 Temple Place, Boston, MA * 02111 USA. * */ /************************************************************* READ HEADERS FROM FILES; FORMAT THEM FOR NOTIFICATIONS **************************************************************/ #include "hap.h" /* initialize all the fields in a hlist at the start of a function. Assumes that they don't point to anything yet, obviously, or we'd be leaking memory all over the place. */ void inithlist (it) hlist *it; { it->from = 0; it->to = 0; it->subject = 0; it->startpoint = 0; it->endpoint = 0; it->msgnumstr = 0; it->msgnumint = 0; it->postmark = 0; } /* much like inithlist, but this time they might actually point to something. And of course, we must have already done inithlist() earlier or we might have uninitialized pointers pointing to things we definitely don't want to be free()ing */ void clearheaders (headers) hlist *headers; { if (headers->from) free (headers->from), headers->from = 0; if (headers->to) free (headers->to), headers->to = 0; if (headers->subject) free (headers->subject), headers->subject = 0; if (headers->msgnumstr) free(headers->msgnumstr),headers->msgnumstr=0; if (headers->postmark) free (headers->postmark),headers->postmark=0; } /* add num spaces to a malloc string. quicker than calling addtostr over and over again. probably belongs in string.c */ void addnspaces (str, num) char **str; int num; { char *temp; int i; if (num <= 0) return; temp = xmalloc ((num + 1) * sizeof (char)); for (i = 0; i < num; i++) { temp[i] = ' '; } temp[num] = 0; addstr (str, temp); free (temp); } /* dumpheaders both adds a readable version of the headers to *str and frees the headers themselves. */ void dumpheaders (str, headers) char **str; hlist *headers; { /* if we don't have anything to say, don't bother saying it. This will happen when we just hit the first postmark of a file and it's busily trying to output the previous ones, which there aren't any of. */ if (headers->from == 0 && headers->postmark == 0) return; { int maxwid = screenwid() - 1; char *msgnum = 0; char *from = 0; char *to = 0; char *subject = 0; /* if there's a string for a message number, pad it to align with a 4-digit number */ if (headers->msgnumstr) { int l = strlen (headers->msgnumstr); while (l < 4) { addstr (&msgnum, " "); l++; } addstr (&msgnum, headers->msgnumstr); } else { addstr (&msgnum, itoa (headers->msgnumint)); } addstr (&msgnum, " "); /* we already verified above that at least one of headers->from and headers->postmark exists */ if (headers->from) { if (preferaddr) { addstr (&from, canonaddr (JUSTADDR, headers->from)); } else { addstr (&from, canonaddr (JUSTNAME, headers->from)); } } else { addstr (&from, headers->postmark); } if (headers->subject) { addstr (&from, " -- "); addstr (&subject, headers->subject); } else { addstr (&subject, ""); } addstr (&subject, " "); addstr (&subject, ftoa ((headers->endpoint - headers->startpoint)/1024.0)); addstr (&subject, "k"); if (headers->to) { addstr (&to, " to "); if (preferaddr) { addstr (&to, canonaddr (JUSTADDR, headers->to)); } else { addstr (&to, canonaddr (JUSTNAME, headers->to)); } } else { addstr (&to, ""); } if (terse || ( strlen (msgnum) + strlen (from) + strlen (subject) + strlen (to) <= maxwid)) { /* hooray! it all fits! (or we're terse and we don't care) */ int pad = strlen (msgnum) + strlen (from) + strlen (subject) + strlen (to); addstr (str, msgnum); addstr (str, from); addstr (str, subject); if (pad < maxwid) { if (*to) addnspaces (str, maxwid - pad); } addstr (str, to); addstr (str, "\n"); } else if (strlen (msgnum) + strlen (from) + strlen (to) <= maxwid) { /* ok -- can we get the sender and the recipients on a line? */ int pad = strlen (msgnum) + strlen (from) + strlen (to); addstr (str, msgnum); addstr (str, from); if (pad < maxwid) { if (*to) addnspaces (str, maxwid - pad); } addstr (str, to); addstr (str, "\n "); addstr (str, truncstr (subject, maxwid - 5)); addstr (str, "\n"); } else if (strlen (msgnum) + strlen (from) + strlen (subject) <= maxwid) { /* how about the sender and the subject? */ addstr (str, msgnum); addstr (str, from); addstr (str, subject); if (*to) { char *chopto = truncstr (to, maxwid - 6); addstr (str, "\n"); if (maxwid - strlen (chopto) > 0) addnspaces (str, maxwid - strlen (chopto)); addstr (str, chopto); } addstr (str, "\n"); } else { /* ok, we give up... */ addstr (str, msgnum); addstr (str, truncstr(from, maxwid - strlen (msgnum))); addstr (str, "\n "); addstr (str, truncstr (subject, maxwid - 5)); if (*to) { char *chopto = truncstr (to, maxwid - 6); addstr (str, "\n"); if (maxwid - strlen (chopto) > 0) addnspaces (str, maxwid - strlen (chopto)); addstr (str, chopto); } addstr (str, "\n"); } free (msgnum); free (from); free (to); free (subject); clearheaders (headers); } } /* slurp in headers from a file. handles continuation lines properly, and to and cc are lumped together */ void readheaders (list, f) hlist *list; FILE *f; { char *s; char **which = 0; while ((s = fgetl (f))) { if (*s == '\n') break; stripcr (s); if (!isspace (*s)) which = 0; if (cstarts (s, "from:")) which = &(list->from); if (cstarts (s, "subject:")) which = &(list->subject); /* to and cc are both lumped together as just generic recipients */ if (cstarts (s, "to:") || cstarts (s, "cc:")) { which = &(list->to); if (list->to) { addstr (which, ", "); } } if (isspace (*s)) { while (isspace (*s)) s++; } else { while ((*s != ':') && (*s)) s++; while (*s == ':') s++; while (isspace (*s)) s++; } if (which) { if (*which) { addstr (which, " "); } addstr (which, s); } } } /* wow, an exciting one. if quote exists, add it to msg and throw the original away. */ void dumpquote (msg, quote) char **msg; char **quote; { if (*quote) { addstr (msg, *quote); free (*quote); *quote = 0; } } hap/strerror.c100644 24036 142 1520 6173007307 10312 0ustar /* * hap -- a mail notification program * * copyright 1995 by Eric Fischer, etaoin@uchicago.edu * * copies of hap may be redistributed under the terms of the * GNU public license, copies of which are available from * the Free Software Foundation, 59 Temple Place, Boston, MA * 02111 USA. * */ #include "hap.h" /**************************************************************************** if everybody would just get an ANSI libc, we wouldn't have to mess with this... ****************************************************************************/ /* for systems that don't have ANSI strerror(), this retrieves the error string from sys_errlist[]. Returns pointer to extern string. */ #ifndef HAVE_STRERROR extern char *sys_errlist[]; char * strerror (what) int what; { return sys_errlist[what]; } #endif hap/string.c100644 24036 142 10036 6173007307 7760 0ustar /* * hap -- a mail notification program * * copyright 1995 by Eric Fischer, etaoin@uchicago.edu * * copies of hap may be redistributed under the terms of the * GNU public license, copies of which are available from * the Free Software Foundation, 59 Temple Place, Boston, MA * 02111 USA. * */ #include "hap.h" /************************************************************************* STRING MANIPULATION STUFF *************************************************************************/ /* use malloc() to allocate enough space for the string 'what', copy it into there, and return a pointer to it. This because NeXT (like other 4.3 systems, I think) is missing strdup(). */ char * strdupe (what) char *what; { char *s; if (what == 0) return 0; s = xmalloc ((strlen (what) + 1) * sizeof (char)); strcpy (s, what); return s; } /* return the last word of the pathname 'what'. returns a pointer into the string we were passed. */ char * mybasename (what) char *what; { char *yes = what; while (*what) { if (*what == '/') yes = what+1; what++; } return yes; } /* modify the string 's' we were given to end at the first newline. */ void chop (s) char *s; { while (*s) { if (*s == '\n') *s = 0; s++; } } /* return true if string 'l' begins with 's', false otherwise. */ int starts (l, s) char *l; char *s; { while (*s) { if (*l != *s) return 0; l++, s++; } return 1; } int cstarts (l, s) char *l; char *s; { return (strncasecmp (l, s, strlen (s)) == 0); } /* return true if string 'l' ends with 's', false otherwise */ int ends (l, s) char *l; char *s; { int x = strlen (l) - strlen (s); if (x < 0) return 0; return same (l + x, s); } /* return ptr if the string 's' contains the character 'what', false otherwise. yeah, it's like index/strchr, but it seemed easier this way... */ char * contains (s, what) char *s; int what; /* really a char, but -Wall complains */ { while (*s) { if (*s == what) return s; s++; } return 0; } char * scontains (s, what) char *s; char *what; { while (*s) { if (starts (s, what)) return s; s++; } return 0; } char * cscontains (s, what) char *s; char *what; { while (*s) { if (cstarts (s, what)) return s; s++; } return 0; } /* return the number of newline characters in the string 'what'. */ int numlns (what) char *what; { int x = 0; while (*what) { if (*what == '\n') x++; what++; } return x; } /* return a pointer inside the string 'what' to the start of the (num-1)th line. */ char * skiplines (what, num) char *what; int num; { while (*what && num) { if (*what == '\n') num--; what++; } return what; } /* return a new string containing the concatenation of 'one' and 'two'. the string is only valid until the next call to conc(), so copy it if you need to keep it. */ char * conc (one, two) char *one; char *two; { static char *ya = 0; if (ya) free (ya), ya = 0; ya = xmalloc (strlen (one) + strlen (two) + 1); strcpy (ya, one); strcat (ya, two); return ya; } char * truncstr (x, maxlen) char *x; int maxlen; { static char *str = 0; int len = strlen (x); if (str) free (str), str = 0; str = strdupe (x); if (len <= maxlen) return str; if (maxlen < 5) { str[maxlen] = 0; return str; } { int lastspace = -1; int firstspace = -1; int i; for (i = 0; i < len; i++) { if (isspace (str[i]) && !isspace (str[i+1]) && !isdigit (str[i+1])) lastspace = i + 1; } /* give up if there were no spaces at all, or if the last word was enormously long */ if (lastspace == -1 || (len - lastspace) > maxlen / 2) { strcpy (str + maxlen - 3, "..."); return str; } for (i = lastspace - 1; i > 4; i--) { if (isspace (str[i])) { if (i + 3 + strlen(str + lastspace) < maxlen) { firstspace = i; break; } } } /* if it's all one enormously long word, give up in despair */ if (firstspace == -1) { strcpy (str + maxlen - 3, "..."); return str; } strcpy (str + firstspace, "... "); strcat (str, str + lastspace); return str; } } hap/usage.c100644 24036 142 3545 6201671433 7544 0ustar /* * hap -- a mail notification program * * copyright 1995 by Eric Fischer, etaoin@uchicago.edu * * copies of hap may be redistributed under the terms of the * GNU public license, copies of which are available from * the Free Software Foundation, 59 Temple Place, Boston, MA * 02111 USA. * */ #include "hap.h" /************************************************************************** USAGE, VERSION INFO **************************************************************************/ char * usagestr[] = { "\n", "Usage: %s [-seconds] [-hVkbsqvtmiA] [--long-option ...] ", "[file [... file]]\n", "\n", " -h --help print this message\n", " -V --version give version and copyright information\n", "\n", " -seconds wait `seconds' seconds between mail checks\n", " -k --kill kill all %s processes you have running\n", " -b --biff BIFF emulation\n", " -s --silent silent (no beeping)\n", " -q --quote quote the first line of each new message\n", " -v --verbose be verbose: quote up to five lines of each\n", " -t --terse be terse: tiny mail listings off in the corner\n", " -m --mesg delay mail notifications until mesg is y\n", " -i --no-inverse don't put notices in inverse video\n", " -A --address use people's addresses, not their names\n", "\n", 0 }; void usage() { char **here = usagestr; char *bn = mybasename (program); while (*here) { fprintf (stderr, *here, bn); here++; } exit (1); } void version() { printf ("\n This is Hap version 3.7 (August 6, 1996)\n"); printf (" by Eric Fischer, etaoin@uchicago.edu\n"); #ifdef __DATE__ #ifdef __TIME__ printf (" compiled %s, %s\n", __DATE__, __TIME__); #endif #endif printf ("\n Hap is copyright 1996 by Eric Fischer\n"); printf (" and distributed under the GNU public license.\n\n"); exit (0); } hap/whoami.c100644 24036 142 2052 6173007307 7715 0ustar /* * hap -- a mail notification program * * copyright 1995 by Eric Fischer, etaoin@uchicago.edu * * copies of hap may be redistributed under the terms of the * GNU public license, copies of which are available from * the Free Software Foundation, 59 Temple Place, Boston, MA * 02111 USA. * */ #include "hap.h" /************************************************************************* DISCOVERING THEIR SECRET IDENTITY *************************************************************************/ /* find out the name of the user. returns a pointer to static data. */ /* notice that strdupe() is called *before* checking for null, so it's important that strdupe return null when that's what it's passed, rather than trying to duplicate whatever's sitting at the bottom of memory. */ char * whoami() { static char *ret = 0; struct passwd *p; if (ret) return ret; ret = strdupe (getlogin()); if (ret) return ret; p = getpwuid (getuid()); if (p) ret = strdupe (p->pw_name); if (ret) return ret; return "who-are-you?"; }