This is a patch that transforms trn 3.4.1 into trn 3.5. It is in unified diff format, so you either need a modern version of patch (any of the ones with 'u' or 'g' in the version or the latest gnu version will work fine) or you need to make the unipatch filter program by typing: make unipatch in the trn source directory. To apply this patch, chdir to your trn 3.4.1 source directory and use one of the following commands: patch -p 8------>8------>8------>8--- Index:patchlevel.h Prereq: 3.4.1 @@ -1,1 +1,1 @@ -#define PATCHLEVEL "Version: 3.4.1 " +#define PATCHLEVEL "Version: 3.5 " Index:Configure @@ -19,7 +19,7 @@ # -# $Id: Head.U,v 3.0.1.1 1993/08/27 14:38:07 ram Exp $ +# $Id: Head.U,v 3.0.1.3 1993/12/15 08:15:07 ram Exp $ # -# Generated on Wed Nov 24 18:29:38 PST 1993 [metaconfig 3.0 PL14] +# Generated on Thu May 5 12:36:48 PDT 1994 [metaconfig 3.0 PL22] cat >/tmp/c1$$ </dev/null 2>&1; then + if (PATH=.; alias -x) >/dev/null 2>&1; then : already under /bin/ksh else @@ -72,5 +84,5 @@ else : Warn them if they use ksh on other systems - (alias -x) >/dev/null 2>&1 && \ + (PATH=.; alias -x) >/dev/null 2>&1 && \ cat <<'EOM' (I see you are using the Korn shell. Some ksh's blow up on Configure, @@ -89,13 +101,16 @@ Mcc='' awk='' +basename='' bash='' cat='' +cp='' cpp='' csh='' date='' +diff='' echo='' +ed='' egrep='' expr='' -gcc='' grep='' inews='' @@ -109,4 +124,5 @@ mkdir='' more='' +munpack='' mv='' nroff='' @@ -118,4 +134,5 @@ smail='' sort='' +spell='' tail='' test='' @@ -126,6 +143,10 @@ vi='' vspell='' +who='' hint='' myuname='' +srcdir='' +vincludes='' +vpath='' Id='' Log='' @@ -146,5 +167,7 @@ cf_time='' contains='' +cpplast='' cppminus='' +cpprun='' cppstdin='' d_ftime='' @@ -163,5 +186,6 @@ d_memcpy='' d_memset='' -d_mime='' +d_mimeshow='' +d_mimestore='' mimeshow='' mimestore='' @@ -206,4 +230,5 @@ d_voidtty='' i_bsdioctl='' +i_sysfilio='' i_sysioctl='' i_syssockio='' @@ -226,4 +251,5 @@ contdist='' locdist='' +multistatedist='' orgdist='' statedist='' @@ -277,32 +303,50 @@ CONFIG='' +: set package name +package=trn +first=`echo $package | sed -e 's/^\(.\).*/\1/'` +last=`echo $package | sed -e 's/^.\(.*\)/\1/'` +spackage=`echo $first | tr '[a-z]' '[A-Z]'`$last + +: determine where the sources are +cd .. +objdir=`pwd` +_srcdir=`expr X$0 : 'X\(.*\)/'` +if test -f MANIFEST -o ! -f $_srcdir/MANIFEST; then + _srcdir='..' + _vpath='.' +else + case "$_srcdir" in + /*) ;; + *) _srcdir=`(cd $_srcdir ; pwd)` ;; + esac + echo "Aha! Your $package sources are really in $_srcdir." + _vpath="$_srcdir" +fi +cd UU + : script used to extract .SH files with variable substitutions cat >extract <<'EOS' CONFIG=true +case "$_srcdir" in +..) _srcdir='.';; +esac echo "Doing variable substitutions on .SH files..." -if test -f MANIFEST; then - set x `awk '{print $1}' &2 + -V) echo "Configure generated by metaconfig 3.0 PL22." >&2 exit 0;; --) break;; @@ -440,10 +484,4 @@ esac -: set package name -package=trn -first=`echo $package | sed -e 's/^\(.\).*/\1/'` -last=`echo $package | sed -e 's/^.\(.*\)/\1/'` -spackage=`echo $first | tr '[a-z]' '[A-Z]'`$last - : Eunice requires " " instead of "", can you believe it echo " " @@ -468,5 +506,6 @@ : list of known cpp symbols -attrlist="__alpha DGUX M_I186 M_I286 M_I386 M_I8086 M_XENIX UTS __DGUX__" +attrlist="__alpha __bsdi__ BSD_NET2 DGUX M_I186 M_I286 M_I386" +attrlist="$attrlist M_I8086 M_XENIX UTS __DGUX__" attrlist="$attrlist _AIX __STDC__ __m88k__ ansi bsd4_2 gcos gimpel" attrlist="$attrlist hp9000s300 hp9000s400 hp9000s500 hp9000s700" @@ -491,4 +530,5 @@ libswanted='' +CTRLA=`echo a | tr a '\001'` large='' inclwanted='/usr/include/NET-5000' @@ -538,10 +578,10 @@ : Now test for existence of everything in MANIFEST echo " " -if test -f ../MANIFEST; then +if test -f $_srcdir/MANIFEST; then echo "First let's make sure your kit is complete. Checking..." >&4 - awk '$1 !~ /PACK[A-Z]+/ {print $1}' ../MANIFEST | split -50 + awk '$1 !~ /PACK[A-Z]+/ {print $1}' $_srcdir/MANIFEST | split -50 rm -f missing for filelist in x??; do - (cd ..; ls `cat UU/$filelist` >/dev/null 2>>UU/missing) + (cd $_srcdir; ls `cat $objdir/UU/$filelist`) >/dev/null 2>>missing done if test -s missing; then @@ -764,5 +804,7 @@ echo " " echo "Okay, let's see if #! works on this system..." - echo "#!/bin/cat" >try + cat=/usr/bin/cat + test -f $cat || cat=/bin/cat + echo "#!$cat" >try $eunicefix try chmod +x try @@ -859,4 +901,5 @@ awk cat +cp echo expr @@ -866,4 +909,5 @@ rm sed +sleep sort tail @@ -873,8 +917,11 @@ trylist=" Mcc +basename bash cpp csh date +diff +ed egrep inews @@ -886,4 +933,5 @@ mhn more +munpack nroff pg @@ -891,4 +939,5 @@ sendmail smail +spell test uname @@ -942,4 +991,5 @@ echo "Using the test built into your sh." test=test + _test=test fi ;; @@ -949,4 +999,5 @@ echo "Hopefully echo is built into your sh." ;; +'') ;; *) echo " " @@ -979,4 +1030,6 @@ '') myuname=`( ($uname -a) 2>/dev/null || hostname) 2>&1` +myuname=`echo $myuname | $sed -e 's/^[^=]*=//' | \ + tr '[A-Z]' '[a-z]' | tr '\012' ' '` dflt=n if test "$fastread" = yes; then @@ -986,4 +1039,6 @@ if $contains myuname= ../config.sh >/dev/null 2>&1; then eval "old`grep myuname= ../config.sh`" + oldmyuname=`echo $oldmyuname | $sed -e 's/^[^=]*=//' | \ + tr '[A-Z]' '[a-z]' | tr '\012' ' '` fi if test "X$myuname" = "X$oldmyuname"; then @@ -995,6 +1050,6 @@ : same system, otherwise use the hints. hint=default -cd .. -if test -f config.sh; then +if test -f ../config.sh; then + cd .. echo " " rp="I see a config.sh file. Do you want to use it to set the defaults?" @@ -1012,6 +1067,7 @@ ;; esac + cd UU fi -if test ! -f config.sh; then +if test ! -f ../config.sh; then $cat <&4 + cd $_srcdir/hints + ls -C *.sh | $sed 's/\.sh/ /g' >&4 dflt='' : Half the following guesses are probably wrong... If you have better @@ -1028,26 +1085,33 @@ $test -f /xenix && dflt="$dflt sco_xenix" $test -f /dynix && dflt="$dflt dynix" + $test -f /dnix && dflt="$dflt dnix" $test -f /bin/mips && /bin/mips && dflt="$dflt mips" $test -f /lib/libc && $test -f /lib/clib && dflt="$dflt domainos" $test -d /NextApps && test -f /usr/adm/software_version && dflt="$dflt next" $test -f Policy.sh && dflt="Policy $dflt" + $test -d /usr/include/minix && dflt="$dflt minix" if $test -f $uname; then - set `$uname -a | tr '[A-Z]' '[a-z]'` + set X $myuname + shift $test -f $5.sh && dflt="$dflt $5" case "$5" in - mips*) dflt="$dflt mips";; + fps*) dflt="$dflt fps";; + mips*) + case "$4" in + umips) dflt="$dflt umips";; + *) dflt="$dflt mips";; + esac;; [23]100) dflt="$dflt mips";; next*) dflt="$dflt next" ;; + news*) dflt="$dflt news" ;; esac case "$1" in aix) dflt="$dflt aix_rs" ;; - sunos) case "$3" in - 4.1*) dflt="$dflt sunos_4_1" ;; - esac - ;; + dnix) dflt="$dflt dnix" ;; dgux) dflt="$dflt dgux" ;; + genix) dflt="$dflt genix" ;; hp*ux) dflt="$dflt hpux" ;; next) dflt="$dflt next" ;; @@ -1055,4 +1119,5 @@ convexos) dflt="$dflt convexos";; domainos) dflt="$dflt domainos";; + OSF1*alpha) dflt="$dflt dec_osf1";; $2) if $test -f /usr/lib/sysadm/sysadm.menu; then if $test ! -f /etc/copyrights/01.sco; then @@ -1074,5 +1139,30 @@ fi fi ;; + ultrix) case "$3" in + 3*) dflt="$dflt ultrix_3" ;; + 4*) dflt="$dflt ultrix_4" ;; + esac + ;; + uts) dflt="$dflt uts" ;; + $2) if test -f /etc/systemid; then + set `echo $3 | sed 's/\./ /'` $4 + if $test -f sco_$1_$2_$3.sh; then + dflt="$dflt sco_$1_$2_$3" + elif $test -f sco_$1_$2.sh; then + dflt="$dflt sco_$1_$2" + elif $test -f sco_$1.sh; then + dflt="$dflt sco_$1" + fi + fi + ;; esac + else + if test -f /vmunix -a -f news_os.sh; then + (what /vmunix | tr '[A-Z]' '[a-z]') > $objdir/UU/kernel.what 2>&1 + if $contains news-os $objdir/UU/kernel.what >/dev/null 2>&1; then + dflt="$dflt news_os" + fi + $rm -f $objdir/UU/kernel.what + fi fi set X `echo $dflt | tr ' ' '\012' | sort | uniq` @@ -1097,11 +1187,11 @@ EOM rp="Which of these apply, if any?" - . ../UU/myread + . $objdir/UU/myread for file in $ans; do if $test -f $file.sh; then . ./$file.sh - $cat $file.sh >> ../UU/config.sh + $cat $file.sh >> $objdir/UU/config.sh elif $test X$ans = X -o X$ans = Xnone ; then - : + : nothing else echo "$file.sh does not exist -- ignored" @@ -1109,7 +1199,6 @@ done hint=recommended - cd .. + cd $objdir/UU fi -cd UU ;; *) @@ -1130,8 +1219,15 @@ : Restore computed paths -for file in $loclist $trylist; do +for file in $loclist $trylist srcdir vpath; do eval $file="\$_$file" done +: include path for Make +if test "X$vpath" = "X." ; then + vincludes= +else + vincludes="-I. -I$srcdir" +fi + : who configured the system cf_time=`$date 2>&1` @@ -1139,42 +1235,5 @@ : set up shell script to do ~ expansion -cat >filexp <&2 - exit 1 - fi - case "\$1" in - */*) - echo \$dir/\`$expr x\$1 : '..[^/]*/\(.*\)'\` - ;; - *) - echo \$dir - ;; - esac - fi - ;; -*) - echo \$1 - ;; -esac -EOSS -chmod +x filexp -$eunicefix filexp +(CONFIG=true . $srcdir/filexp.SH) >/dev/null : check if NNTP is to be used @@ -1256,6 +1315,6 @@ case "$ans" in y*) d_portable="$define" - for file in $loclist; do - eval $file=$file + for file in $loclist $trylist; do + eval $file="\$file" done ;; @@ -1271,8 +1330,16 @@ none_ok='' exp_file='' +nopath_ok='' orig_rp="$rp" orig_dflt="$dflt" case "$fn" in +*:*) + loc_file=`expr $fn : '.*:\(.*\)'` + fn=`expr $fn : '\(.*\):.*'` + ;; +esac + +case "$fn" in *~*) tilde=true;; esac @@ -1289,9 +1356,12 @@ *e*) exp_file=true;; esac +case "$fn" in +*p*) nopath_ok=true;; +esac case "$fn" in *f*) type='File';; *d*) type='Directory';; -*l*) type='Locate'; fn=`expr $fn : '.*:\(.*\)'`;; +*l*) type='Locate';; esac @@ -1390,10 +1460,19 @@ Locate) if test -d "$value"; then - echo "(Looking for $fn in directory $value.)" - value="$value/$fn" + echo "(Looking for $loc_file in directory $value.)" + value="$value/$loc_file" fi if test -f "$value"; then type='' fi + case "$nopath_ok" in + true) case "$value" in + */*) ;; + *) echo "Assuming $value will be in people's path." + type='' + ;; + esac + ;; + esac ;; esac @@ -1460,5 +1539,5 @@ esac $echo " " -fn=l:inews +fn=pl:inews rp='Which inews should be used for posting articles?' . ./getfile @@ -1531,4 +1610,5 @@ echo exit 1 >xenix echo exit 1 >venix +d_bsd="$undef" $cat /usr/include/signal.h /usr/include/sys/signal.h >foo 2>/dev/null if test -f /osf_boot || $contains 'OSF/1' /usr/include/ctype.h >/dev/null 2>&1 @@ -1550,5 +1630,4 @@ echo exit 0 >usg fi - d_bsd="$undef" elif $contains SIGTSTP foo >/dev/null 2>&1 ; then echo "Looks kind of like a BSD system, but we'll see..." @@ -1557,5 +1636,4 @@ else echo "Looks kind of like a Version 7 system, but we'll see..." - d_bsd="$undef" echo exit 0 >v7 fi @@ -1742,8 +1820,5 @@ echo " " $echo $n "Hmm... $c" -case "$usrinc" in -'') dflt='/usr/include';; -*) dflt=$usrinc;; -esac +dflt='/usr/include' incpath='' mips_type='' @@ -1771,4 +1846,8 @@ fi echo " " +case "$usrinc" in +'') ;; +*) dflt="$usrinc";; +esac fn=d/ rp='Where are the include files you want to use?' @@ -1829,5 +1908,14 @@ esac else - echo "No -l$thislib." + xxx=`./loc lib$thislib.so X $libpth` + if $test -f $xxx; then + echo "Found -l$thislib." + case "$dflt" in + *-l$thislib*|*-l$thatlib*);; + *) dflt="$dflt -l$thislib";; + esac + else + echo "No -l$thislib." + fi fi fi @@ -1912,5 +2000,8 @@ try=`./loc Slib$thislib.a blurfl/dyick $xlibpth` if test ! -f $try; then - try='' + try=`./loc lib$thislib.so blurfl/dyick $libpth` + if test ! -f $try; then + try='' + fi fi fi @@ -2022,5 +2113,5 @@ xscan='eval "libc.list"; $echo $n ".$c" >&4' xrun='eval "libc.list"; echo "done" >&4' -if com="$sed -n -e 's/^.* [ADTS] *_[_.]*//p' -e 's/^.* [ADTS] //p'";\ +if com="$sed -n -e 's/^.* [ADTSI] *_[_.]*//p' -e 's/^.* [ADTSI] //p'";\ eval $xscan;\ $contains '^fprintf$' libc.list >/dev/null 2>&1; then @@ -2061,5 +2152,5 @@ else nm -p $* 2>/dev/null >libc.tmp - com="$sed -n -e 's/^.* [ADTS] *_[_.]*//p' -e 's/^.* [ADTS] //p'";\ + com="$sed -n -e 's/^.* [ADTSI] *_[_.]*//p' -e 's/^.* [ADTSI] //p'";\ eval "libc.list" if $contains '^fprintf$' libc.list >/dev/null 2>&1; then @@ -2370,7 +2461,7 @@ else $echo 'Oh well, maybe I can mine it out of whoami.h...' - if ans=`sh -c $contains' sysname $usrinclude/whoami.h' 2>&1` ; then + if ans=`sh -c $contains' sysname $usrinc/whoami.h' 2>&1` ; then thishost=`$echo "$ans" | $sed 's/^.*"\(.*\)"/\1/'` - phostcmd="sed -n -e '"'/sysname/s/^.*\"\\(.*\\)\"/\1/{'"' -e p -e q -e '}' <$usrinclude/whoami.h" + phostcmd="sed -n -e '"'/sysname/s/^.*\"\\(.*\\)\"/\1/{'"' -e p -e q -e '}' <$usrinc/whoami.h" else phostcmd='' @@ -2388,9 +2479,9 @@ set $thishost thishost=$1 +echo "Your local hostname was computed to be '$thishost'." : translate upper to lower if necessary case "$thishost" in -*[A-Z]*) thishost=`$echo $thishost | tr '[A-Z]' '[a-z]'` - ;; +*[A-Z]*) thishost=`$echo $thishost | tr '[A-Z]' '[a-z]'` ;; esac case "$phost" in @@ -2403,7 +2494,4 @@ *) dflt="$phost";; esac -case "$thishost" in -*.*) thishost=`$expr "X$thishost" : "X\([^.]*\)\."`;; -esac $cat <&4 + elif $test "x`$uname 2>/dev/null`" = xAIX; then + # Ok, do the AIX shr.o fun thing + /usr/ccs/bin/nm -en $xxx 2>/dev/null >grimble + if $contains '^tputs .*|extern|' grimble >/dev/null 2>&1; then + termlib='-lcurses' + d_havetlib="$define" + echo "AIX Terminfo library found." >&4 + else + xxx=x + fi else xxx=x @@ -2684,57 +2786,77 @@ chmod 755 cppstdin wrapper=`pwd`/cppstdin +ok='false' cd UU + if $test "X$cppstdin" != "X" && \ $cppstdin $cppminus testcpp.out 2>&1 && \ - $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then + $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 +then echo "You used to use $cppstdin $cppminus so we'll use that again." -elif $test "$cc" = gcc && \ - (echo "Using gcc, eh? We'll try to force gcc -E using a wrapper..."; \ - $wrapper testcpp.out 2>&1; \ - $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1) ; then - echo "Yup, we can." - cppstdin="$wrapper" - cppminus=''; + case "$cpprun" in + '') echo "But let's see if we can live without a wrapper..." ;; + *) + if $cpprun $cpplast testcpp.out 2>&1 && \ + $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 + then + echo "(And we'll use $cpprun $cpplast to preprocess directly.)" + ok='true' + else + echo "(However, $cpprun $cpplast does not work, let's see...)" + fi + ;; + esac +else + case "$cppstdin" in + '') ;; + *) + echo "Good old $cppstdin $cppminus does not seem to be of any help..." + ;; + esac +fi + +if $ok; then + : nothing elif echo 'Maybe "'"$cc"' -E" will work...'; \ $cc -E testcpp.out 2>&1; \ $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then echo "Yup, it does." - cppstdin="$cc -E" - cppminus=''; + x_cpp="$cc -E" + x_minus=''; elif echo 'Nope...maybe "'"$cc"' -E -" will work...'; \ $cc -E - testcpp.out 2>&1; \ $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then echo "Yup, it does." - cppstdin="$cc -E" - cppminus='-'; -elif echo 'No such luck, maybe "'$cpp'" will work...'; \ - $cpp testcpp.out 2>&1; \ - $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then - echo "It works!" - cppstdin="$cpp" - cppminus=''; -elif echo 'Nixed again...maybe "'$cpp' -" will work...'; \ - $cpp - testcpp.out 2>&1; \ - $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then - echo "Hooray, it works! I was beginning to wonder." - cppstdin="$cpp" - cppminus='-'; + x_cpp="$cc -E" + x_minus='-'; elif echo 'Nope...maybe "'"$cc"' -P" will work...'; \ $cc -P testcpp.out 2>&1; \ $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then echo "Yipee, that works!" - cppstdin="$cc -P" - cppminus=''; + x_cpp="$cc -P" + x_minus=''; elif echo 'Nope...maybe "'"$cc"' -P -" will work...'; \ $cc -P - testcpp.out 2>&1; \ $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then echo "At long last!" - cppstdin="$cc -P" - cppminus='-'; + x_cpp="$cc -P" + x_minus='-'; +elif echo 'No such luck, maybe "'$cpp'" will work...'; \ + $cpp testcpp.out 2>&1; \ + $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then + echo "It works!" + x_cpp="$cpp" + x_minus=''; +elif echo 'Nixed again...maybe "'$cpp' -" will work...'; \ + $cpp - testcpp.out 2>&1; \ + $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then + echo "Hooray, it works! I was beginning to wonder." + x_cpp="$cpp" + x_minus='-'; elif echo 'Uh-uh. Time to get fancy. Trying a wrapper...'; \ $wrapper testcpp.out 2>&1; \ $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then - cppstdin="$wrapper" - cppminus='' + x_cpp="$wrapper" + x_minus='' echo "Eureka!" else @@ -2742,6 +2864,7 @@ rp="No dice. I can't find a C preprocessor. Name one:" . ./myread - cppstdin="$ans" - $cppstdin testcpp.out 2>&1 + x_cpp="$ans" + x_minus='' + $x_cpp testcpp.out 2>&1 if $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then echo "OK, that will do." >&4 @@ -2751,4 +2874,36 @@ fi fi + +case "$ok" in +false) + cppstdin="$x_cpp" + cppminus="$x_minus" + cpprun="$x_cpp" + cpplast="$x_minus" + set X $x_cpp + shift + case "$1" in + "$cpp") + echo "Perhaps can we force $cc -E using a wrapper..." + if $wrapper testcpp.out 2>&1; \ + $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 + then + echo "Yup, we can." + cppstdin="$wrapper" + cppminus=''; + else + echo "Nope, we'll have to live without it..." + fi + ;; + esac + case "$cpprun" in + "$wrapper") + cpprun='' + cpplast='' + ;; + esac + ;; +esac + case "$cppstdin" in "$wrapper") ;; @@ -2859,48 +3014,59 @@ eval $inlibc -: see if they want mime support -case "$d_mime" in -'') if $test "$metamail$mhn" != metamailmhn; then - dflt=y +: see if they want mime display processing +case "$d_mimeshow" in +'') if $test "$metamail" != metamail; then + dflt="$metamail -e -p -m trn %A" + elif $test "$mhn" != mhn; then + dflt="$mhn -show -serialonly %A" else - dflt=n + dflt=none fi ;; -"$define") dflt=y;; -*) dflt=n;; +"$define") dflt="$mimeshow";; +*) dflt=none;; esac $cat < found." >&4 +else + val="$undef" + echo "no found." >&4 +fi +set i_sysfilio +eval $setvar + if $test `./findhdr sys/ioctl.h`; then val="$define" @@ -3978,8 +4169,12 @@ else val="$undef" - $test $i_termio = "$define" && xxx="termio.h" - $test $i_termios = "$define" && xxx="termios.h" - $test $i_sgtty = "$define" && xxx="sgtty.h" + if $test $i_sysfilio = "$define"; then + echo "no found." >&4 + else + $test $i_sgtty = "$define" && xxx="sgtty.h" + $test $i_termio = "$define" && xxx="termio.h" + $test $i_termios = "$define" && xxx="termios.h" echo "No found, assuming ioctl args are defined in <$xxx>." >&4 + fi fi set i_sysioctl @@ -4074,8 +4269,11 @@ : back to where it started if test -d ../UU; then - mv filexp .. cd .. fi +case "$srcdir" in +..) srcdir='.';; +esac + : configuration may be patched via a 'config.over' file if $test -f config.over; then @@ -4114,13 +4312,16 @@ Mcc='$Mcc' awk='$awk' +basename='$basename' bash='$bash' cat='$cat' +cp='$cp' cpp='$cpp' csh='$csh' date='$date' +diff='$diff' echo='$echo' +ed='$ed' egrep='$egrep' expr='$expr' -gcc='$gcc' grep='$grep' inews='$inews' @@ -4134,4 +4335,5 @@ mkdir='$mkdir' more='$more' +munpack='$munpack' mv='$mv' nroff='$nroff' @@ -4143,4 +4345,5 @@ smail='$smail' sort='$sort' +spell='$spell' tail='$tail' test='$test' @@ -4151,6 +4354,10 @@ vi='$vi' vspell='$vspell' +who='$who' hint='$hint' myuname='$myuname' +srcdir='$srcdir' +vincludes='$vincludes' +vpath='$vpath' Id='$Id' Log='$Log' @@ -4171,5 +4378,7 @@ cf_time='$cf_time' contains='$contains' +cpplast='$cpplast' cppminus='$cppminus' +cpprun='$cpprun' cppstdin='$cppstdin' d_ftime='$d_ftime' @@ -4188,5 +4397,6 @@ d_memcpy='$d_memcpy' d_memset='$d_memset' -d_mime='$d_mime' +d_mimeshow='$d_mimeshow' +d_mimestore='$d_mimestore' mimeshow="$mimeshow" mimestore="$mimestore" @@ -4231,4 +4441,5 @@ d_voidtty='$d_voidtty' i_bsdioctl='$i_bsdioctl' +i_sysfilio='$i_sysfilio' i_sysioctl='$i_sysioctl' i_syssockio='$i_syssockio' @@ -4251,4 +4462,5 @@ contdist='$contdist' locdist='$locdist' +multistatedist='$multistatedist' orgdist='$orgdist' statedist='$statedist' @@ -4302,6 +4514,6 @@ : add special variables -$test -f patchlevel.h && \ -awk '/^#define/ {printf "%s=%s %s%s\n",$2,$3,$4,$5}' patchlevel.h >>config.sh +$test -f $srcdir/patchlevel.h && \ +awk '/^#define/ {printf "%s=%s %s%s\n",$2,$3,$4,$5}' $srcdir/patchlevel.h >>config.sh echo "CONFIG=true" >>config.sh Index:HINTS.TRN @@ -0,0 +1,171 @@ +You can specify trn environment variables in an initialization file with all +the options. See the first hint for details on that. Certain environment +variables, like RNINIT, must be set in your shell (how else does trn know +to look there for the rest?). Others, like REPLYTO may be useful in other +programs, so you could consider putting that in your shell startup file too. +But most of them are specific, like MAILHEADER, so you might as well set them +in the init file with the -E option. That's why most of them look like +-EMAILHEADER=xx rather than MAILHEADER=xx -- to remind you. + +Helpful hints: + o You can make a file that contains all the flags and initialization that + trn will use at startup. When you're done, point an environment variable + TRNINIT to the file. A good choice is "TRNINIT=~/.trninit". You can put + multiple lines in this init file and/or separate options by spaces. + + o Two new and useful flags are the -p and -G flags. -p means automatically + select any thread that you have posted a message to. This makes it very + easy to track replies to your insightful comments :-) (to automatically + select other threads, try the 'T' command). -G tells the 'g' command + to use a loose match algorithm on groups it can't find. So if you type + "g news.softwre.raeders.genrl", it will assume that you meant to type + news.software.readers and take you there. It is usually easier to type + "/reader" than using a 'g' command, but use -G too. + + o The 'X' command in the selector (kinda like catchup/yes) can be made the + default action on the last page of selections by using the command-line + option: -XX. This lets you browse all the pages, making selections as + you go, and then mark everything that was not selected as read when you + press space at the last page. + + o If you like to select a little, read a little, and then select a little + more, try using the command-line option: -XDD. This makes the 'D' + command the default on all pages of the selector. Thus you can select + the things you want to read on the current page, press space, and you + will read the selected articles immediately (if there were any). All + other articles on the current page will be marked as read. + + o To use mush to send all R)eplies: + -EMAILPOSTER="mush -h %h" + + o To use elm to send all R)eplies: + -EMAILHEADER="\\000" + -EMAILPOSTER="elm -i %h -s \"Re: %S\" %t" + + o To tailor the time field: + A good example is -ELOCALTIMEFMT="%A, %B %e %Y, %r %Z" which becomes: + Date: Saturday, June 12 1993, 08:15:32 PM PDT. (The default is + "%a %b %e %X %Z %Y", which is like the date(1) command). See the + strftime(3C) man page for more details on other % characters. + + o To tailor the "In article , joe@user (Joe User)" line: + person's name only: %)f + person's address only: %>f + For example: -EATTRIBUTION='According to %)f <%>f>:' + + o A better kill file scheme than the default (which creates obtuse + directories all over your ~/News directory) is to use the following: + -EKILLGLOBAL="%p/Kill/Global" + -EKILLLOCAL="%p/Kill/%C" + Where %p is your news directory, usually ~/News, and %C is the full name + of the group, like sci.bio. This means the kill file for sci.bio is in + ~/News/Kill/sci.bio instead of ~/News/sci/bio/KILL. Think about this + next time you subscribe to alt.swedish.chef.bork.bork.bork :-) + + Note that you need a file system that allows long file names to make + this work. + + o If you're tired of endless subscription notices to newsgroups you could + care less about, look at the AUTOUNSUBSCRIBE variable. There's a + companion AUTOSUBSCRIBE function too. For example, to automatically + unsubscribe all NEW alt groups, use ^alt.*. More dramatic, to + unsubscribe to everything BUT certain groups, use "*,!^local.*,!^comp.*", + for example. If you're REALLY tired of them, use -q to tell trn to not + even check for new groups at all. + + o If you want replies to your postings to go to a machine other than the + machine you're posting from, set the REPLYTO environment variable. For + example, you might set this if you were trn's author: + -EREPLYTO="davison@borland.com (Wayne Davison)" + + o You might like to redefine the 'u' keys in the following way: 'u' visits + the "Set unread?" prompt (except in the thread selector), 'U' goes + directly to the already-read article selector, and Ctrl-U unsubscribes + from the group (even while in the thread selector). Put the following + 3 macros in your .rnmac file to accomplish this (or change TRNMACROS to + .trnmac and put them there): + + u %(%m=[aefnp]?U:u) + U %(%m=[aefnp]?U+:U) + ^U %(%m=t?+u:u) + + o If you like to be able to move forward/backward by article number more + often than you need to search by subject, redefine ^N and ^P to be _N + and _P by putting these lines into your macro file: + + ^P %(%m=[aep]?_P:^P) + ^N %(%m=[aep]?_N:^N) + + o If you like the way that 'q' worked in the thread selector in trn 1.x, + put the following macro in your macro file: + + q %(%m=t?+:q) + + o If you would like the 'f' command to always answer yes to the "Are you + starting an unreleated topic?" question, put this line into your macro + file: + + f %(%m=[ap]?fy^m:f) + + o If you want to be able to save your shar headers in a file as they are + extracted and you have access to "unshar" (a program that can extract + shar files while saving the headers in UNSHAR.HDR), twiddle the external + extract command to send the entire article: + + -EEXSAVER="%e <%A" + + and then point the UNSHAR variable at unshar instead of /bin/sh: + + -EUNSHAR="unshar -s" + + Note that this assumes that any other commands you execute with + "e dir|command" can also handle the entire article as input + (uuencoded and shipped files are not affected). + + o The following lines represent trn's default headers for posting an + article. If you want to customize your header copy this to your + .trninit file and modify it (and _don't_ use Pnews directly to post, + use trn -- the ".f" command from newsgroup prompt works well for this). + Note: remove the initial tab from these lines: + + -ENEWSHEADER="%(%[followup-to]=^$?:X-ORIGINAL-NEWSGROUPS: %n + )Newsgroups: %(%F=^$?%C:%F) + Subject: %(%S=^$?%\" + + Subject: \":Re: %S) + Summary: + Expires: + %(%R=^$?:References: %R + )Sender: + Followup-To: + %(%{REPLYTO}=^$?:Reply-To: %{REPLYTO} + )Distribution: %(%i=^$?%\"Distribution: \":%D) + Organization: %o + Keywords: %[keywords] + Cc: %(%F=poster?%t:%(%F!=@?:%F)) + + " + +If you're curious, trn's author has the following .trninit file: +---------------------------------------------------------------------- +-XX -B -N -e -f +m -x11ms "-F> " -p -G -u +-hunrecognized +-ELOCALTIMEFMT="%A, %B %e %Y, %r %Z" +-ESELECTCHARS="abdefgijlmorstuvwxyz1234567890BCFGHIKVW" +-EKILLLOCAL="%p/Kill/%C" +-EKILLGLOBAL="%p/Kill/Global" +-EMAILPOSTER="mush -h %h" +-EATTRIBUTION="According to %)f <%>f>:" +---------------------------------------------------------------------- + +and the following .trnmac file: +---------------------------------------------------------------------- +u %(%m=[aenp]?U:u) +U %(%m=[aenp]?U+:U) +^U %(%m=t?+u:u) +o %(%m=[nf]?O:o) +O %(%m=[nf]?o:O) +~T s ~/Mail/trn +~M | /bin/mail davison +^[^[ ^[ +---------------------------------------------------------------------- Index:INIT @@ -1,1 +1,1 @@ -+Hfrom ++Hfrom Index:INSTALL @@ -30,4 +30,10 @@ them, but all other # comments will be taken care of. + NOTE: This package allows the build to be performed in a directory + other than where the sources are. You will need a "make" that supports + VPATH to do this. Just create a directory where you want to do the + build, cd into it, and run "path/Configure" from there where "path" is + either a relative or absolute path reference to the trn source directory. + 4) Glance through config.h and common.h to make sure system dependencies are correct. Most of them should have been taken care of by running @@ -51,8 +57,8 @@ 6) make install - This will put trn, newsetup, newsgroups, Pnews, and Rnmail into a - public directory (normally /usr/local/bin), and put a number of - files into the private trn library (e.g. /usr/local/lib/trn). It - also tries to put the trn man page in a reasonable place. One of + This will put trn, newsetup, newsgroups, Pnews, Rnmail, trn-artchk, and + nntplist into a public directory (normally /usr/local/bin), and put a + number of files into the private trn library (e.g. /usr/local/lib/trn). + It also tries to put the trn man page in a reasonable place. One of the installed scripts is "newsetup", which creates a .newsrc for a user that doesn't have one. This script reads the subscriptions @@ -61,4 +67,9 @@ new user. If you don't like this, customize the script as desired. + NOTE: if you have an old installation of trn that put artcheck and + getactive into the trn library directory, once you ensure that all + your installed scripts are using the new files (trn-artchk and + nntplist) you can delete the old ones from the lib directory. + 7) Read the manual entry before running trn, or at least read the file NEW if you are already familiar with trn. Those that are brand new Index:MANIFEST @@ -2,5 +2,5 @@ EXTERN.h When included, makes other includes not belong to me. HACKERSGUIDE A brief guide to the contorted innards of [t]rn. -HINTS Some helpful hints to get the most out of using trn. +HINTS.TRN Some helpful hints to get the most out of using trn. INIT Sample system-wide switch file. INSTALL Installation instructions. @@ -20,5 +20,4 @@ art.c Routines to display an article. art.h Public info regarding art.c. -artcheck.c An article-checking program called from Pnews. artio.c Reserved for the article abstract type, someday. artio.h Public info regarding artio.c. @@ -34,4 +33,6 @@ cache.c Routines to handle caching of articles. cache.h Public info regarding cache.c. +charsubst.c Routines for converting between various character sets. +charsubst.h Public info regarding charsubst.c. common.h Global info. config.h.SH Shell script to create config.h @@ -40,7 +41,7 @@ dependencies A pre-made list of the source's dependencies. edit_dist.c Routines to find the edit distance between two strings. +filexp.SH The filename expansion script. final.c Finalization (exit) routines. final.h Public info regarding final.c. -getactive.c Used by shell scripts to get the active file (NNTP only). hash.c Hashing routines. hash.h Public/private info for hashing routines. @@ -81,4 +82,5 @@ nntpclient.h Public info for the nntp client library. nntpinit.c Routines to implement server_init(). +nntplist.c Used by shell scripts to list server resources. (NNTP only) norm.saver.SH Shell script to save an article to a normal file. only.c Routines to perform newsgroup restriction. @@ -119,4 +121,5 @@ trn.c The main program. trn.h Public info for trn.c. +trn-artchk.c An article-checking program called from Pnews. unipatch.c A unified diff filter for use with old versions of patch. unship.c Decodes ship files. Index:Makefile.SH @@ -3,4 +3,7 @@ esac echo "Extracting Makefile (with variable substitutions)" +case "$srcdir" in +'') srcdir='.';; +esac $cat >Makefile <>Makefile <<'!NO!SUBS!' -public = trn newsetup newsgroups Pnews Rnmail -private = norm.saver mbox.saver makedir Pnews.header Speller artcheck $(nntp) +public = trn newsetup newsgroups Pnews Rnmail trn-artchk $(nntpbin) +private = norm.saver mbox.saver makedir Pnews.header Speller filexp util = makedepend newsnews manpages = trn.1 Pnews.1 Rnmail.1 newsetup.1 newsgroups.1 -#NNTPnntp=getactive +#NNTPnntpbin=nntplist #NNTPnntpsrc=nntpinit.c nntpclient.c nntp.c #NNTPnntpobj=nntpinit.o nntpclient.o nntp.o h1 = addng.h art.h artio.h artsrch.h autosub.h backpage.h bits.h cache.h -h2 = common.h decode.h final.h hash.h head.h help.h init.h intrp.h kfile.h -h3 = last.h ng.h ngdata.h ngsrch.h ngstuff.h only.h rcln.h rcstuff.h +h2 = charsubst.h common.h decode.h final.h hash.h head.h help.h init.h intrp.h +h3 = kfile.h last.h ng.h ngdata.h ngsrch.h ngstuff.h only.h rcln.h rcstuff.h h4 = respond.h rthread.h rt-mt.h rt-ov.h rt-page.h rt-process.h rt-select.h h5 = rt-util.h rt-wumpus.h search.h sw.h term.h trn.h util.h @@ -57,17 +70,17 @@ c1 = addng.c art.c artio.c artsrch.c autosub.c backpage.c bits.c cache.c -c2 = decode.c edit_dist.c final.c hash.c head.c help.c init.c intrp.c -c3 = kfile.c last.c $(ndirc) ng.c ngdata.c nghash.c ngsrch.c ngstuff.c +c2 = charsubst.c decode.c edit_dist.c final.c hash.c head.c help.c init.c +c3 = intrp.c kfile.c last.c $(ndirc) ng.c ngdata.c nghash.c ngsrch.c ngstuff.c c4 = only.c rcln.c rcstuff.c respond.c rthread.c rt-mt.c rt-ov.c c5 = rt-process.c rt-page.c rt-select.c rt-util.c rt-wumpus.c search.c c6 = $(strftimec) sw.c term.c trn.c util.c unship.c uudecode.c -c7 = $(nntpsrc) +c7 = $(nntpsrc) charsubst.c c = $(c1) $(c2) $(c3) $(c4) $(c5) $(c6) $(c7) obj1 = addng.o art.o artio.o artsrch.o autosub.o backpage.o bits.o cache.o -obj2 = decode.o edit_dist.o final.o hash.o head.o help.o init.o intrp.o -obj3 = kfile.o last.o $(ndiro) ng.o ngdata.o nghash.o ngsrch.o ngstuff.o -obj4 = only.o rcln.o rcstuff.o respond.o rthread.o rt-mt.o rt-ov.o +obj2 = charsubst.o decode.o edit_dist.o final.o hash.o head.o help.o init.o +obj3 = intrp.o kfile.o last.o $(ndiro) ng.o ngdata.o nghash.o ngsrch.o +obj4 = ngstuff.o only.o rcln.o rcstuff.o respond.o rthread.o rt-mt.o rt-ov.o obj5 = rt-process.o rt-page.o rt-select.o rt-util.o rt-wumpus.o search.o obj6 = $(strftimeo) sw.o term.o trn.o util.o unship.o uudecode.o parsedate.o @@ -76,17 +89,15 @@ obj = $(obj1) $(obj2) $(obj3) $(obj4) $(obj5) $(obj6) $(obj7) -lintflags = -phbvxac +addedbymake = $(public) $(private) $(util) Makefile.old config.h\ + parsedate.c cppstdin all -addedbymake = $(public) $(private) $(util) $(nntp) Makefile.old config.h\ - cppstdin all - # grrr SHELL = /bin/sh .c.o: - $(CC) -c $(CFLAGS) $*.c + $(CC) -c $(CFLAGS) $< all: $(public) $(private) $(util) Makefile - touch all + $(TOUCH) all trn: $(obj) @@ -94,18 +105,16 @@ #NNTP #NNTPnntpinit.o: -#NNTP $(CC) -c $(CFLAGS) $(NNTPFLAGS) $*.c +#NNTP $(CC) -c $(CFLAGS) $(NNTPFLAGS) $(srcdir)/$*.c #NNTP -#NNTPgetactive: getactive.o nntpinit.o nntpclient.o -#NNTP $(CC) $(LDFLAGS) getactive.o nntpinit.o nntpclient.o -o getactive $(libs) +#NNTPnntplist: nntplist.o nntpinit.o nntpclient.o +#NNTP $(CC) $(LDFLAGS) nntplist.o nntpinit.o nntpclient.o -o nntplist $(libs) -artcheck: artcheck.o - $(CC) $(LDFLAGS) artcheck.o -o artcheck $(libs) +trn-artchk: trn-artchk.o + $(CC) $(LDFLAGS) trn-artchk.o -o trn-artchk $(libs) -parsedate.o: parsedate.y +parsedate.c: parsedate.y @echo 'Expect 6 shift/reduce conflicts' - yacc parsedate.y + $(YACC) $(srcdir)/parsedate.y mv -f y.tab.c parsedate.c - $(CC) -c $(CFLAGS) parsedate.c - rm -f parsedate.c #STRFTIME #STRFTIME$(strftimeo): $(strftimec) @@ -115,7 +124,9 @@ $(CC) $(LDFLAGS) unipatch.o -o unipatch +Pnews.header: Pnews + # if a .h file depends on another .h file... $(h): - -touch $@ + -$(TOUCH) $@ install: $(public) $(private) $(manpages) @@ -123,14 +134,16 @@ export PATH || exit 1 - (cd `./filexp $(rnbin)`; mv trn trn.old) - - if test `pwd` != `./filexp $(rnbin)`; then cp $(public) `./filexp $(rnbin)`; fi - - if test $(filexp) = Rnfilexp; then cp ./filexp `./filexp $(rnbin)/Rnfilexp`; fi + - if test `pwd` != `./filexp $(rnbin)`; then cp $(public) `./filexp $(rnbin)`;\ + (cd `./filexp $(rnbin)`; chmod o+x $(public); strip trn trn-artchk $(nntpbin)); fi + - if test $(installfilexp) = Rnfilexp; then cp ./filexp `./filexp $(rnbin)/Rnfilexp`; fi - ./makedir `./filexp $(rnlib)` - - if test `pwd` != `./filexp $(rnlib)`; then cp INIT filexp $(private) `./filexp $(rnlib)`; fi -#NNTP - if test `pwd` != `./filexp $(rnlib)`; then strip `./filexp $(rnlib)`/getactive ; fi + - chmod o+r `./filexp $(rnlib)` + - if test `pwd` != `./filexp $(rnlib)`; then cp INIT $(private) `./filexp $(rnlib)`; fi - if test ! -f `./filexp $(rnlib)/newsnews`; then cp newsnews `./filexp $(rnlib)`; fi + - (cd `./filexp $(rnlib)`; chmod o+x $(private); chmod o+r INIT newsnews) - if test "X$(mansrc)" != "X" -a "X`pwd`" != X`./filexp $(mansrc)`; then \ for page in $(manpages); do \ dest=$(mansrc)/`basename $$page .1`.$(manext); \ -rm -f $$dest; cp $$page $$dest; chmod 444 $$dest; \ +rm -f $$dest; cp $(srcdir)/$$page $$dest; chmod 444 $$dest; \ done; \ fi @@ -149,5 +162,5 @@ spotless: rm -rf UU .config - rm -f *.o core $(addedbymake) Makefile filexp config.sh + rm -f *.o core $(addedbymake) Makefile config.sh # The following lint has practically everything turned on. Unfortunately, @@ -156,12 +169,10 @@ # for that spot. -lint: lint_trn +lint: $(c) parsedate.c + $(LINT) $(lintflags) $(defs) $? > trn.fuzz 2>&1 -lint_trn: - lint $(lintflags) $(defs) $(c) > trn.fuzz +sabertrn: $(c) parsedate.c + #load $(c) parsedate.c $(libs) -sabertrn: $(c) - #load $(c) $(libs) - depend: config.h Makefile makedepend ./makedepend @@ -169,5 +180,9 @@ # AUTOMATICALLY GENERATED MAKE DEPENDENCIES--PUT NOTHING BELOW THIS LINE !NO!SUBS! -$cat dependencies >>Makefile +if test -f dependencies; then + $cat dependencies >>Makefile +else + $cat $srcdir/dependencies >>Makefile +fi case "$d_nntp" in define) sed < Makefile -e '/^#NNTP/s/^#NNTP//' > Makefile.new ;; Index:NEW @@ -6,11 +6,51 @@ trn 2.5 and trn 3.0. -Changes from trn 3.3 to trn 3.4: +Changes from trn 3.4.1 to trn 3.5: + o Enhanced the -p option to allow you to select how you'd like + your postings to be selected. The default (which works the same + as before) is -p (select your posting and its replies). Also + available is -p+ (select all postings in the thread) and -pp + (select the *parent* article and its replies). + o Added the forward (^F) command to forward an article via mail. + o Improved the tab command (skip cited text) to skip empty lines + and choose the quotation character more intelligently. + o You can now junk an article in just the current group via + a search command using 'x'. E.g. /subject/:x + o Included some code from Olaf Titz + that allows you to tell trn to transform high-bit characters + into their 7-bit ascii equivilents. See the _C command and + the -Q option. + o Added the back-scroll command: 'B'. + o Added the -J option to allow you to join truncated subjects + into a common thread. The default for -J is 30 chars, not counting + the Re: portion. I have the lines "&-J27" and "X&+J" in my Babylon + 5 kill file to join all the Genie posts that get truncated into the + proper thread. + o Added the -K option to keep a group static (no new articles) while + you read it. Useful for people who have a really slow kill file + for a group -- use "&-K" and "X&+K" in such a kill file to make + only that group stop growing until you exit the group and re-enter. + o Added optional mouse support in an xterm window. + o Added a new intrp (%q) to get the value of the last quoted input + (%"). Useful for using elm for forwarding articles as it needs + the answer to the question "To?" on the command line: + -EFORWARDPOSTER="elm -i %h -s '%'[subject]' %q" + (though you may wish to redefine the FORWARDHEADER variable too). + o Fixed bugs in the handling of thread kills in partially-threaded + groups (Tj now works even if the -a option wasn't specified) and + and in the handling of the subject-kill command (Aj). + o New files, HINTS.TRN is like HINTS but in a better format. + (I renamed it to avoid conflicts with the directory "hints"). + o Portability enhancements to Configure and the support scripts. + o Some fairly major and minor bugs fixed. + +Changes from trn 3.3 to trn 3.4.1: + o Made the kill-file handling more consistent in how it deals with the THRU line. It now only ignores the THRU line for all selection commands. You can turn off this exception (and thus make all commands obey the THRU line) - by turning of the -k option (using +k). You can also + by turning off the -k option (using +k). You can also specify the 'I' modifier or the 'N' modifier to killfile searches to have them either ignore or not-ignore the Index:Pnews.1 @@ -71,6 +71,6 @@ \&.signature file to be .news_sig and it will be appended before you begin to edit. -Note that .news_sig obeys the setting of DOTDIR, but .signature does -not (since it is out of Pnew's control). +Note that .news_sig obeys the setting of DOTDIR, but .signature may +not, since it is out of Pnews' control. If both .news_sig and .signature exist you'll get two signatures appended. .PP Index:Pnews.SH @@ -37,4 +37,6 @@ # where important rn things are kept rnlib=\`$filexp $privlib\` + artcheck=trn-artchk + nntplist=nntplist ;; undef) @@ -43,4 +45,6 @@ # where important rn things are kept rnlib="$privlib" + artcheck=$bin/trn-artchk + nntplist=$bin/nntplist ;; esac @@ -79,4 +83,10 @@ tr=${tr-tr} inews=${inewsloc-inews} +cp=${cp-cp} +sleep=${sleep-sleep} +rm=${rm-rm} +who=${who-who} +mv=${mv-mv} + nidump=${nidump} ypmatch=${ypmatch} @@ -94,7 +104,7 @@ esac $spitshell >>Pnews <<'!NO!SUBS!' -dotdir=${DOTDIR-${HOME-$LOGDIR}} +homedir=${HOME-$LOGDIR} +dotdir=${DOTDIR-$homedir} tmpart=$dotdir/.article -artcheck=$rnlib/artcheck speller=$rnlib/Speller @@ -104,13 +114,13 @@ news_sig=${NEWSSIGNATURE-$dotdir/.news_sig} -if $test ! -f "$newsgroups" -a -r "$rnlib/getactive"; then +if $test ! -f "$newsgroups"; then newsgroups="$tmp/Pnng.$$"; rmlist="$newsgroups"; - cmdlist="$rnlib/getactive newsgroups $tmp/Pnng.$$ ; "; + cmdlist="$nntplist newsgroups $newsgroups ;"; fi -if $test ! -f "$active" -a -r "$rnlib/getactive"; then +if $test ! -f "$active"; then active="$tmp/Pnact.$$"; rmlist="$rmlist $active"; - cmdlist="$cmdlist $rnlib/getactive active $tmp/Pnact.$$"; + cmdlist="$cmdlist $nntplist active $active"; fi @@ -174,7 +184,7 @@ ;; esac - rescue="sleep 1; $cat $tmpart >>${HOME-$LOGDIR}/dead.article ; rm -f $rmlist ; $echo Article appended to ${HOME-$LOGDIR}/dead.article ; exit" - if $test "$rmlist" ; then - trap "rm -f $rmlist" 0 + rescue="$sleep 1; $cat $tmpart >>${HOME-$LOGDIR}/dead.article ; $rm -f $rmlist ; $echo Article appended to ${HOME-$LOGDIR}/dead.article ; exit" + if $test -n "$rmlist" ; then + trap "$rm -f $rmlist" 0 fi trap "trap : 1; $rescue" 1 @@ -209,6 +219,6 @@ $sed '1,/^[ ]*$/{/^Newsgroups:/d; s/^X-ORIGINAL-NEWSGROUPS:/Newsgroups:/;}' $tmpart >$tweak - cp $tweak $tmpart - rm -f $tweak + $cp $tweak $tmpart + $rm -f $tweak ;; *) exit ;; @@ -328,7 +338,7 @@ esac -# run getactive in the background, if necessary -if $test "$cmdlist"; then - ( eval $cmdlist ) & +# run nntplist in the background, if necessary +if $test -n "$cmdlist"; then + ( eval $cmdlist ) >/dev/null 2>&1 & fi @@ -372,5 +382,5 @@ fi -while true ; do +while : ; do case $state in edit) @@ -430,9 +440,9 @@ check) - # wait for possible background getactive - $test "$cmdlist" && wait + # wait for possible background nntplist + $test -n "$cmdlist" && wait # warn about long lines, malformed headers, misspelled newsgroups - $artcheck $tmpart 79 $newsgroups $active + ($artcheck $tmpart 79 $newsgroups $active) 2>/dev/null state=ask ;; @@ -502,5 +512,5 @@ n*) ;; *) - if $test -f $dotdir/.signature; then + if $test -f $homedir/.signature; then $echo $n "Append .signature file? [y] $c" read ans @@ -508,5 +518,5 @@ ''|y*) $echo "-- " >> $tmpart - $cat $dotdir/.signature >> $tmpart + $cat $homedir/.signature >> $tmpart ;; esac @@ -555,10 +565,18 @@ *recmail) ($echo To: $cc - $sed "$headerstrip" $tmpart) | $mailer + $sed "$headerstrip" $tmpart + if $test -f $homedir/.signature; then + $echo "-- " >> $tmpart + $cat $homedir/.signature >> $tmpart + fi) | $mailer ;; *) - set X `echo $cc | sed 's/,/ /g'` + set X `echo $cc | $sed 's/,/ /g'` shift - $sed "$headerstrip" $tmpart | $mailer $@ + ($sed "$headerstrip" $tmpart + if $test -f $homedir/.signature; then + $echo "-- " >> $tmpart + $cat $homedir/.signature >> $tmpart + fi) | $mailer $@ ;; esac @@ -571,5 +589,5 @@ $echo "Malformed Newsgroups line." $echo "" - sleep 1 + $sleep 1 state=edit ;; @@ -591,5 +609,5 @@ ;; *) - set X ${USER-${LOGNAME-`who am i`}} unknown + set X ${USER-${LOGNAME-`$who am i`}} unknown shift $rnlib/mbox.saver $tmpart "." "." 0 0 Pnews $AUTHORCOPY "From $1 `LANG= date`" @@ -718,6 +736,5 @@ # difficult to omit. Added "while : ; do", ... "done", and "if" # at end of while loop. -while : -do +while : ; do case $# in 0) @@ -764,5 +781,5 @@ # now build a file with a header for them to edit -set X ${USER-${LOGNAME-`who am i`}} +set X ${USER-${LOGNAME-`$who am i`}} shift logname=$1 @@ -820,7 +837,7 @@ !NO!SUBS! case "$d_nntp" in -define) sed < Pnews.header -e '/^#NORMAL/d' > Pnews.h.new ;; -*) sed < Pnews.header -e '/^#NORMAL/s/^#NORMAL//' > Pnews.h.new ;; +define) $sed < Pnews.header -e '/^#NORMAL/d' > Pnews.h.new ;; +*) $sed < Pnews.header -e '/^#NORMAL/s/^#NORMAL//' > Pnews.h.new ;; esac -mv Pnews.h.new Pnews.header +$mv Pnews.h.new Pnews.header $eunicefix Pnews.header Index:Policy.sh.SH @@ -2,7 +2,4 @@ '') . ./config.sh ;; esac -case "$0" in -*/*) cd `expr X$0 : 'X\(.*\)/'` ;; -esac echo "Extracting Policy.sh (with variable substitutions)" $spitshell <Policy.sh @@ -13,13 +10,9 @@ # running Configure. # -# \$Id: Policy.sh.SH,v 1.2 1993/09/15 18:07:06 schnoebe Exp $ - -# Configuration time: $cf_time -# Configured by: $cf_by -# Target system: $myuname +# $Id: Policy.sh.SH,v 3.5 1994/04/24 16:47:38 davison Trn $ -# login name of the person who configured trn. not particularly interesting. +# login name of the person who configured trn (not particularly interesting). cf_by='$cf_by' -# time of configuration. Not particularly interesting. +# time of configuration (not particularly interesting). cf_time='$cf_time' @@ -29,5 +22,5 @@ # name of the final resting place bin='$bin' -# how to get to the final resting place (thank you AFS) +# how to get to the final resting place (thank you, AFS) installbin='$installbin' @@ -36,9 +29,9 @@ # directory (string value) privlib='$privlib' -# How toget to the library final resting place (thanks AFS) +# How to get to the library final resting place (thanks, AFS) installprivlib='$installprivlib' # interesting questions about man -# where to man page sources go? +# where do man page sources go? mansrc='$mansrc' # what extention do man pages get? @@ -60,9 +53,9 @@ # internal options -# ingore the ORGANIZATION environment variable? (define/undef) +# ignore the ORGANIZATION environment variable? (define/undef) d_ignoreorg='$d_ignoreorg' # does the mailer understand FQDN addressing? (define/undef) d_internet='$d_internet' -# Do you have a news admin? (define/undef) +# do you have a news admin? (define/undef) d_newsadm='$d_newsadm' # name of the news admin? (string value) @@ -146,15 +139,21 @@ !GROK!THIS! $eunicefix Policy.sh -if test -f hints/Policy.sh ; then +case "$srcdir" in +'') srcdir='.';; +esac +if test -f $srcdir/hints/Policy.sh ; then echo "Checking for changes." - if diff hints/Policy.sh Policy.sh >/dev/null ; then + grep -v '^cf_' Policy.sh >Policy.tmp + if grep -v '^cf_' $srcdir/hints/Policy.sh | diff - Policy.tmp >/dev/null + then echo "Policy.sh unchanged, retaining original" rm Policy.sh else echo "installing new Policy.sh, old one left in Policy.sh.old" - (cd hints; mv Policy.sh Policy.sh.old) - mv Policy.sh hints + (cd $srcdir/hints; mv Policy.sh Policy.sh.old) + mv Policy.sh $srcdir/hints fi + rm Policy.tmp else - mv Policy.sh hints + mv Policy.sh $srcdir/hints fi Index:README @@ -1,3 +1,3 @@ - Trn Kit, Version 3.4 + Trn Kit, Version 3.5 Copyright (c) 1993, Wayne Davison @@ -18,5 +18,11 @@ in MANIFEST (Configure checks this for you). +If you're unsure if you have the latest release, check ftp.uu.net: + ftp.uu.net:networking/news/readers/trn/trn.tar.gz -> [latest.version].gz + +[A .Z version is also available and mthreads resides in the same spot, +if you need it.] + What is trn? ------------ @@ -54,10 +60,11 @@ available too. You can do this in a variety of way, but I recommend that you send the database from the server to the client via NNTP. To do this -you either need to use INN or modify the reference NNTP (version 1.5.11) -with the included patch (see nntp/nntp.patch). This patch supports both -the XOVER command (to send .overview files) and the XTHREAD command (to -send .thread files). The alternative is to either mount the disk containing -your database via NFS, or build it locally. See the mthreads package for -details on how to do this. +you either need to use INN or a modified reference NNTP -- version 1.5.11-t5 +is the latest as of this writing. See ftp.uu.net:networking/news/nntp for +the file nntp-t5.tar.gz. This version supports the XOVER command (to send +overview files), the XTHREAD command (to send thread files), and the XINDEX +command (though trn doesn't support using it). The alternative is to either +mount the disk containing your database via NFS, or build it locally. See +the mthreads package for details on how to do this. Note that trn is based on rn, and so it does a great job of pretending to Index:Rnmail.SH @@ -54,4 +54,6 @@ grep=${grep-grep} rm=${rm-rm} +sleep=${sleep-sleep} +who=${who-who} !GROK!THIS! @@ -91,5 +93,5 @@ 0) to=h - while $test "$to" = h ; do + while $test "X$to" = Xh ; do $echo "" $echo $n "To: $c" @@ -116,5 +118,5 @@ title=h - while $test "$title" = h ; do + while $test "X$title" = Xh ; do $echo "" $echo $n "Title/Subject: $c" @@ -186,8 +188,8 @@ fi -while true ; do +while : ; do case $state in edit) - rescue="sleep 1; $cat $tmpart >>${HOME-$LOGDIR}/dead.letter ; $echo Message appended to ${HOME-$LOGDIR}/dead.letter ; exit" + rescue="$sleep 1; $cat $tmpart >>${HOME-$LOGDIR}/dead.letter ; $echo Message appended to ${HOME-$LOGDIR}/dead.letter ; exit" trap "$rescue" 1 trap : 2 @@ -200,5 +202,5 @@ ;; esac - while $test "$tmp" = h ; do + while $test "X$tmp" = Xh ; do $echo $n "Editor [${VISUAL-${EDITOR-$defeditor}}]: $c" read tmp @@ -314,5 +316,5 @@ ;; *) - set X ${USER-${LOGNAME-`who am i`}} unknown + set X ${USER-${LOGNAME-`$who am i`}} unknown shift $rnlib/mbox.saver $tmpart "." "." 0 0 Pnews $MAILRECORD "From $1 `LANG= date`" Index:Speller.SH @@ -29,4 +29,6 @@ diff=${diff-diff} ed=${ed-ed} +spell=${spell-spell} +basename=${basename-basename} !GROK!THIS! $spitshell >>Speller <<'!NO!SUBS!' @@ -40,8 +42,9 @@ mine=$tmpdir/sp$$mine quoted=$tmpdir/sp$$quoted +bad=$tmpdir/sp$$bad -Cmdname=`basename $0` +Cmdname=`$basename $0` -if $test "$1 " = " "; then +if $test "X$1" = X; then $echo "$Cmdname: insufficent arguments" >&2 $echo "$Cmdname: usage: $Cmdname " >&2 @@ -49,7 +52,7 @@ fi -trap "$rm -f $hdrs $body $body~ $sig $mine $quoted; exit 1" 0 1 2 15 +trap "$rm -f $hdrs $body $body~ $sig $mine $quoted $bad; exit 1" 0 1 2 15 -while $test "$1" != ""; do +while $test "X$1" != X; do # create the files, so that cat is quiet later.. @@ -119,5 +122,5 @@ # spell check our own pristine prose.. - if $test "$QUOTECHARS " = " " ; then + if $test "X$QUOTECHARS" = X ; then $mv $body $mine else @@ -129,10 +132,15 @@ # the guts of the article.. - if $test "$ispell " = "none "; then - ($echo ---- misspelled words ------------------------------------- - #spell $ispell_options $mine | fmt - spell $ispell_options $mine | pr -t -4 - $echo ----------------------------------------------------------- - ) | $pager + if $test "X$ispell" = "Xnone"; then + $spell $ispell_options $mine > $bad + if $test -s $bad ; then + ($echo ---- misspelled words ------------------------------------- + #$cat $bad | fmt + $cat $bad | pr -t -4 + $echo ----------------------------------------------------------- + ) | $pager + else + $echo 'No misspelled words.' + fi else $ispell $ispell_options $mine Index:addng.c @@ -146,5 +146,12 @@ break; if ((s = index(ser_line, ' ')) != Nullch) - *s = '\0'; + *s++ = '\0'; + else if (findact(buf, ser_line, strlen(ser_line), 0L) >= 0) + s = buf + strlen(ser_line) + 1; + if (s) { + while (isdigit(*s) || isspace(*s)) s++; + if (*s == 'x' || *s == '=') + continue; + } fprintf(tmpfp,"%s\n",ser_line); } @@ -197,6 +204,11 @@ char tmpbuf[LBUFLEN]; *s = '\0'; - if (findact(tmpbuf, buf, s - buf, 0L) >= 0) - get_ng(buf,0); /* add newsgroup, maybe */ + if (findact(tmpbuf, buf, s - buf, 0L) >= 0) { + s = tmpbuf + (s-buf) + 1; + while (isdigit(*s) || isspace(*s)) s++; + if (*s != 'x' && *s != '=') { + get_ng(buf,0); /* add newsgroup, maybe */ + } + } } } @@ -262,5 +274,5 @@ #else /* !USE_NNTP */ - char tst[128]; + char tst[512]; sprintf(tst, ngsize ? "%s/%s/1" : "%s/%s" ,spool,getngdir(ngnam)); Index:art.c @@ -38,4 +38,5 @@ #include "rt-util.h" #include "rt-wumpus.h" +#include "charsubst.h" #include "INTERN.h" #include "art.h" @@ -79,5 +80,5 @@ } -#ifdef MIME_SUPPORT +#ifdef MIMESHOW #define VERY_LONG_STRING 200 int @@ -97,6 +98,6 @@ mode = 'p'; getcmd(buf); - mode = oldmode; setdef(buf,"y"); + mode = oldmode; #ifdef VERIFY printcmd(); @@ -138,12 +139,12 @@ char oldmode = mode; char *ctime(); -#ifdef MIME_SUPPORT +#ifdef MIMESHOW bool tried_display_mime = FALSE; #endif #ifdef INNERSEARCH - register int outputok; + register int outputok = TRUE; #endif -#ifdef MIME_SUPPORT +#if defined(MIMESHOW) || defined(MIMESTORE) mime_article = FALSE; #endif @@ -151,10 +152,16 @@ if (fstat(fileno(artfp),&filestat)) /* get article file stats */ return DA_CLEAN; - if ((filestat.st_mode & S_IFMT) != S_IFREG) + if (!S_ISREG(filestat.st_mode)) return DA_NORM; artsize = filestat.st_size; /* from that get article size */ +#ifdef CHARSUBST + sprintf(prompt_buf, + "%%sEnd of article %ld (of %ld) %%s-- what next? [%%s]", + (long)art,(long)lastart); /* format prompt string */ +#else sprintf(prompt_buf, "%%sEnd of article %ld (of %ld) -- what next? [%%s]", (long)art,(long)lastart); /* format prompt string */ +#endif prompt = prompt_buf; int_count = 0; /* interrupt count is 0 */ @@ -286,5 +293,5 @@ else if (in_header == EXPIR_LINE) { if (!(htype[EXPIR_LINE].ht_flags & HT_HIDE)) - hide_this_line = (strlen(art_buf) < 10); + hide_this_line = ((int)strlen(art_buf) < 10); } else if (in_header == FROM_LINE) { @@ -300,5 +307,5 @@ } #endif -#ifdef MIME_SUPPORT +#if defined(MIMESHOW) || defined(MIMESTORE) else if (!isspace(*art_buf)) { int nontext _((char *)); @@ -338,5 +345,5 @@ } else { /* just a normal line */ -#ifdef MIME_SUPPORT +#ifdef MIMESHOW if (mime_article && do_hiding && !tried_display_mime) { if (display_mime() == 0) @@ -346,4 +353,10 @@ } #endif +#ifdef CLEAREOL +#ifdef INNERSEARCH + if (outputok) +#endif + if (can_home_clear) erase_eol(); +#endif /* CLEAREOL */ if (highlight==artline) { /* this line to be highlit? */ if (marking == STANDOUT) { @@ -368,10 +381,4 @@ /* get it into register, hopefully */ #endif -#ifdef CLEAREOL -#ifdef INNERSEARCH - if (outputok) -#endif - maybe_eol(); -#endif /* CLEAREOL */ #ifdef CUSTOMLINES if (pagestop && bufptr == art_buf && @@ -381,5 +388,5 @@ for (outpos = 0; outpos < COLS; ) { /* while line has room */ - if (*(unsigned char *)bufptr >= ' ') { /* normal char? */ + if (*(unsigned char*)bufptr >= ' ') { /* normal char? */ #ifdef ULSMARTS if (*bufptr == '_') { @@ -408,7 +415,7 @@ un_underline(); if (UG) { + outpos++; if (*bufptr == ' ') goto skip_put; - outpos++; } } @@ -426,10 +433,18 @@ else putchar(*bufptr-13); + outpos++; } else #endif + { +#ifdef CHARSUBST + outpos += putsubstchar(*bufptr); +#else putchar(*bufptr); + outpos++; +#endif + } } - if (*UC && ((highlight==artline && marking == 1) + if (*UC && ((highlight==artline && marking == STANDOUT) #ifdef ULSMARTS || under_lining @@ -441,5 +456,4 @@ skip_put: bufptr++; - outpos++; } else if (*bufptr == '\n' || !*bufptr) { @@ -493,9 +507,12 @@ #endif { - if (dont_filter_control) + if (dont_filter_control) { putchar(*bufptr); + outpos++; + } else { putchar('^'); - if (highlight == artline && *UC && marking == 1) { + if (highlight == artline && *UC + && marking == STANDOUT) { backspace(); underchar(); @@ -506,8 +523,8 @@ else putchar(*bufptr+64); + outpos += 2; } } bufptr++; - outpos += 2; } @@ -536,4 +553,7 @@ un_underline(); highlight = -1; /* no more we are */ + /* in case terminal highlighted rest of line earlier */ + /* when we did an eol with highlight turned on: */ + if (can_home_clear) erase_eol(); } artline++; /* count the line just printed */ @@ -583,5 +603,10 @@ unflush_output(); /* disable any ^O in effect */ standout(); /* enter standout mode */ +#ifdef CHARSUBST + printf("%s--MORE--(%ld%%)",current_charsubst(), + (long)(artpos*100/artsize)); +#else printf("--MORE--(%ld%%)",(long)(artpos*100/artsize)); +#endif un_standout(); /* leave standout mode */ #ifdef CLEAREOL @@ -615,12 +640,10 @@ } carriage_return(); -#ifndef CLEAREOL - erase_eol(); /* and erase the prompt */ -#else +#ifdef CLEAREOL if (erase_screen && can_home_clear) clear_rest(); else +#endif erase_eol(); /* and erase the prompt */ -#endif /* CLEAREOL */ carriage_return(); /* Resets kernel's tab column counter to 0 */ fflush(stdout); @@ -654,29 +677,29 @@ switch (*buf) { - case 'd': - case Ctl('d'): /* half page */ - special = TRUE; - slines = LINES / 2 + 1; - if (marking && *blinebeg != '\f' -#ifdef CUSTOMLINES - && (!pagestop || blinebeg != art_buf || - !execute(&page_compex,blinebeg)) -#endif - ) { - up_line(); - highlight = --artline; - restart = blinebeg; - artpos = alinebeg; - } - return PS_NORM; case '!': /* shell escape */ escapade(); return PS_ASK; #ifdef INNERSEARCH - case Ctl('i'): + case Ctl('i'): { + ART_LINE i = artline; + ART_POS pos; gline = 3; - sprintf(cmd_buf,"^[^%c]",*blinebeg); + s = blinebeg; + while (*s == '\n' && i >= topline) { + pos = vrdary(--i); + if (pos < 0) + pos = -pos; + if (pos < htype[PAST_HEADER].ht_minpos) + break; + fseek(artfp,(long)pos,0); + if (fgets(s = buf+1, sizeof buf - 1, artfp) == Nullch) { + s = blinebeg; + break; + } + } + sprintf(cmd_buf,"^[^%c\n]",*s); compile(&gcompex,cmd_buf,TRUE,TRUE); goto caseG; + } case Ctl('g'): gline = 3; @@ -700,5 +723,4 @@ caseG: case 'G': { - /* ART_LINE lines_to_skip = 0; */ ART_POS start_where; @@ -723,5 +745,4 @@ innersearch = 0; /* assume not found */ while (fgets(buf, sizeof buf, artfp) != Nullch) { - /* lines_to_skip++; NOT USED NOW */ #ifdef DEBUG if (debug & DEB_INNERSRCH) @@ -772,5 +793,5 @@ return PS_ASK; #endif - case '\n': /* one line */ + case '\n': /* one line down */ special = TRUE; slines = 2; @@ -783,4 +804,5 @@ case 'l': case '\f': /* refresh screen */ + refresh_screen: #ifdef DEBUG if (debug & DEB_INNERSRCH) { @@ -797,4 +819,32 @@ firstpage = (topline < 0); return PS_NORM; + case 'B': /* one line up */ + if (topline < 0) + break; + if (*IL && *HO) { + ART_POS pos; + home_cursor(); + insert_line(); + carriage_return(); /* Resets kernel's tab column counter to 0 */ + pos = vrdary(topline-1); + if (pos < 0) + pos = -pos; + if (pos >= htype[PAST_HEADER].ht_minpos) { + fseek(artfp,(long)pos,0); + if (fgets(s = buf, sizeof buf, artfp) != Nullch) { + fputs(buf, stdout) FLUSH; + topline--; + artpos = vrdary(--artline); + if (artpos < 0) + artpos = -artpos; + fseek(artfp,artpos,0); + goto_line(1, LINES-1); + erase_eol(); + carriage_return(); + return PS_ASK; + } + } + } + /* FALL THROUGH */ case 'b': case '\b': @@ -802,16 +852,20 @@ ART_LINE target; -#ifndef CLEAREOL - clear(); -#else - if (can_home_clear) /* if we can home do it */ +#ifdef CLEAREOL + if (can_home_clear) /* if we can let home do it */ home_cursor(); else +#endif clear(); - -#endif /* CLEAREOL */ carriage_return(); /* Resets kernel's tab column counter to 0 */ + do_fseek = TRUE; /* reposition article file */ - target = topline - (LINES - 2); + if (*buf == 'B') + target = topline - 1; + else { + target = topline - (LINES - 2); + if (marking && (marking_areas & BACKPAGE_MARKING)) + highlight = topline; + } artline = topline; if (artline >= 0) do { @@ -841,4 +895,10 @@ return PS_ASK; switch (buf[1] & 0177) { +#ifdef CHARSUBST + case 'C': + if (!*(++charsubst)) + charsubst = charsets; + goto refresh_screen; +#endif default: goto leave_pager; @@ -894,5 +954,5 @@ case Ctl('x'): case 'z': case 'Z': - case '^': + case '^': case Ctl('^'): leave_pager: #ifdef ROTATION @@ -905,5 +965,9 @@ setdfltcmd(); standout(); /* enter standout mode */ +#ifdef CHARSUBST + printf(prompt,mailcall,current_charsubst(),dfltcmd); +#else printf(prompt,mailcall,dfltcmd); +#endif /* print prompt, whatever it is */ un_standout(); /* leave standout mode */ @@ -917,49 +981,49 @@ /* FALL THROUGH */ #endif + case 'd': /* half page */ + case Ctl('d'): + special = TRUE; + slines = LINES / 2 + 1; + /* no divide-by-zero, thank you */ + if (LINES > 2 && (LINES & 1) && artline % (LINES-2) >= LINES/2 - 1) + slines++; + goto go_forward; case 'y': - case Ctl('v'): - /* Leaving it undocumented in case */ + case Ctl('v'): /* Leaving it undocumented in case */ /* I want to steal the key--LAW */ case ' ': /* continue current article */ if (erase_screen) { /* -e? */ -#ifndef CLEAREOL - clear(); /* clear screen */ -#else - if (can_home_clear) /* if we can home do it */ +#ifdef CLEAREOL + if (can_home_clear) /* if we can let home do it */ home_cursor(); else - clear(); /* else clear screen */ - -#endif /* CLEAREOL */ +#endif + clear(); /* clear screen */ carriage_return(); /* Resets kernel's tab column counter to 0 */ fflush(stdout); - - if (*blinebeg != '\f' + } + else { + special = TRUE; + slines = LINES; + } + go_forward: + if (*blinebeg != '\f' #ifdef CUSTOMLINES - && (!pagestop || blinebeg != art_buf || - !execute(&page_compex,blinebeg)) + && (!pagestop || blinebeg != art_buf || + !execute(&page_compex,blinebeg)) #endif - ) { + ) { + if (!special + || (marking && (*buf!='d' || (marking_areas&HALFPAGE_MARKING)))) { restart = blinebeg; artline--; /* restart this line */ artpos = alinebeg; - if (marking) /* and mark repeated line */ + if (special) + up_line(); + if (marking) highlight = artline; } - topline = artline; - /* and remember top line of screen */ - /* (line # within article file) */ - } - else if (marking && *blinebeg != '\f' -#ifdef CUSTOMLINES - && (!pagestop || blinebeg != art_buf || - !execute(&page_compex,blinebeg)) -#endif - ) { - /* are we marking repeats? */ - up_line(); /* go up one line */ - highlight = --artline;/* and get ready to highlight */ - restart = blinebeg; /* the old line */ - artpos = alinebeg; + else + slines--; } return PS_NORM; @@ -972,4 +1036,5 @@ return PS_ASK; } + return PS_ASK; } @@ -1013,5 +1078,5 @@ #endif -#ifdef MIME_SUPPORT +#if defined(MIMESHOW) || defined(MIMESTORE) int nontext(s) Index:artsrch.c @@ -67,5 +67,4 @@ bool foldcase = TRUE; /* fold upper and lower case? */ int ignorethru = 0; /* should we ignore the thru line? */ - ART_NUM srchfirst; @@ -167,8 +166,12 @@ saltaway = TRUE; normal_return = SRCH_DONE; - if (cmdchr == '+') - cmdlst = savestr("I:++"); - else if (cmdchr == '.') - cmdlst = savestr("I:."); + if (cmdchr == '+') { + cmdlst = savestr("+"); + ignorethru = 1; + } + else if (cmdchr == '.') { + cmdlst = savestr("."); + ignorethru = 1; + } else { if (cmdchr == ',') @@ -231,4 +234,6 @@ if (doread) *s++ = 'r'; + if (ignorethru) + *s++ = (ignorethru == 1 ? 'I' : 'N'); if (howmuch != ARTSCOPE_SUBJECT) { *s++ = scopestr[howmuch]; Index:bits.c @@ -72,4 +72,6 @@ if (strnEQ(s,"1-",2)) { /* can we save some time here? */ firstart = atol(s+2)+1; /* process first range thusly */ + if (firstart < absfirst) + firstart = absfirst; s=index(s,',') + 1; for (i = absfirst, ap = article_ptr(i); i < firstart; i++, ap++) @@ -251,5 +253,5 @@ register ART_NUM first = lastart+1; register DIR *dirp; - register struct direct *dp; + register Direntry_t *dp; long an; char ch; @@ -263,5 +265,5 @@ bzero(found_bits, an); - while ((dp = readdir(dirp)) != Null(struct direct *)) { + while ((dp = readdir(dirp)) != Null(Direntry_t*)) { if (sscanf(dp->d_name, "%ld%c", &an, &ch) == 1) { if (an <= lastart && an >= found_min) { Index:cache.c @@ -33,4 +33,6 @@ #include "rthread.h" #include "rt-ov.h" +#include "rt-page.h" +#include "rt-process.h" #include "rt-select.h" #include "rt-util.h" @@ -44,4 +46,5 @@ HASHTABLE *subj_hash = 0; +HASHTABLE *shortsubj_hash = 0; int subject_cmp _((char *,int,HASHDATUM)); @@ -159,4 +162,8 @@ subj_hash = 0; } + if (shortsubj_hash) { + hashdestroy(shortsubj_hash); + shortsubj_hash = 0; + } /* Free all the subjects. */ for (sp = first_subject; sp; sp = next) { @@ -205,24 +212,65 @@ if (!(ap->flags & AF_READ) ^ sel_rereading) { - if (selected_only) { - if (ap->subj->flags & sel_mask) { - ap->flags |= sel_mask; - selected_count++; - } - } else if (ap->subj->flags & SF_WASSELECTED) + if (ap->subj->flags & SF_WASSELECTED) select_article(ap, 0); - else { + else ap->subj->flags |= SF_VISIT; - if (sel_mode == SM_THREAD) - ap->subj->thread->subj->flags |= SF_VISIT; + } + + if (join_subject_len != 0) + check_for_near_subj(ap); +} + +void +check_for_near_subj(ap) +ARTICLE *ap; +{ + register SUBJECT *sp; + if (!shortsubj_hash) { + shortsubj_hash = hashcreate(201, subject_cmp); /*TODO: pick a better size */ + sp = first_subject; + } + else { + sp = ap->subj; + if (sp->next) + sp = 0; + } + while (sp) { + if (strlen(sp->str+4) >= join_subject_len && sp->thread) { + SUBJECT *sp2; + HASHDATUM data; + data = hashfetch(shortsubj_hash, sp->str+4, join_subject_len); + if (!(sp2 = (SUBJECT*)data.dat_ptr)) { + data.dat_ptr = (char*)sp; + hashstorelast(data); + } + else if (sp->thread != sp2->thread) { + merge_threads(sp2, sp); + } } + sp = sp->next; } } void +change_join_subject_len(len) +int len; +{ + if (join_subject_len != len) { + if (shortsubj_hash) { + hashdestroy(shortsubj_hash); + shortsubj_hash = 0; + } + join_subject_len = len; + if (len && first_subject && first_subject->articles) + check_for_near_subj(first_subject->articles); + } +} + +void check_poster(ap) register ARTICLE *ap; { - if (auto_select_postings && !(ap->flags & AF_MISSING)) { + if (auto_select_postings && !(ap->flags & AF_MISSING) && ap->from) { if (ap->flags & AF_FROMTRUNCED) { strcpy(cmd_buf,realname); @@ -254,7 +302,20 @@ h = u = s; if (strEQ(u,loginName)) { - if (instr(h,phostname,FALSE)) - select_subthread(ap,AF_AUTOSELECT); - else { + if (instr(h,phostname,FALSE)) { + switch (auto_select_postings) { + case '.': + select_subthread(ap,AF_AUTOSELECT); + break; + case '+': + select_arts_thread(ap,AF_AUTOSELECT); + break; + case 'p': + if (ap->parent) + select_subthread(ap->parent,AF_AUTOSELECT); + else + select_subthread(ap,AF_AUTOSELECT); + break; + } + } else { #ifdef REPLYTO_POSTER_CHECKING char *reply_buf = fetchlines(article_num(ap),REPLY_LINE); @@ -415,4 +476,6 @@ f++; } + while (size > 4 && t[-1] == ' ') + t--, size--; *t = '\0'; @@ -437,5 +500,5 @@ sp->str = newsubj; sp->thread_link = sp; - sp->flags = SF_THREAD; + sp->flags = 0; data.dat_ptr = (char*)sp; @@ -799,4 +862,6 @@ } if (success && last_cached < last) { + if (ov_opened) + ov_data(last_cached+1, last, FALSE); success = art_data(last_cached+1, last, FALSE, all_arts); cached_all_in_range = (all_arts && success); Index:cache.h @@ -36,5 +36,4 @@ #define SF_INCLUDED 0x0010 -#define SF_THREAD 0x0100 #define SF_VISIT 0x0200 #define SF_WASSELECTED 0x0400 @@ -131,4 +130,6 @@ void close_cache _((void)); void cache_article _((ARTICLE*)); +void check_for_near_subj _((ARTICLE*)); +void change_join_subject_len _((int)); void check_poster _((ARTICLE*)); void uncache_article _((ARTICLE*,bool_int)); Index:charsubst.c @@ -0,0 +1,217 @@ +/* $Id: charsubst.c,v 3.0 1993/12/21 21:54:40 davison Trn $ + */ +/* + * Permission is hereby granted to copy, reproduce, redistribute or otherwise + * use this software as long as: there is no monetary profit gained + * specifically from the use or reproduction of this software, it is not + * sold, rented, traded or otherwise marketed, and this copyright notice is + * included prominently in any copy made. + * + * The authors make no claims as to the fitness or correctness of this software + * for any use whatsoever, and it is provided as is. Any use of this software + * is at the user's own risk. + */ + +#include "EXTERN.h" +#include "common.h" +#include "search.h" +#include "artstate.h" +#include "INTERN.h" +#include "charsubst.h" + +#ifdef CHARSUBST + +/* TeX encoding table - gives ISO char for "x (x=32..127) */ + +static unsigned char textbl[96] = { + 0, 0,'"', 0, 0, 0, 0,'"', 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,214, + 0, 0, 0, 0, 0,220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + '"',228, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,246, + 0, 0, 0,223, 0,252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static void Latin1toASCII _((unsigned char*,unsigned char*,int)); +static char texchar = 0; + +int +putsubstchar(c) +int c; +{ + unsigned char d, oc[2], nc[5]; + int t, i = 0; + switch (*charsubst) { + case 'm': + t = 1; + goto doconvert; + case 'a': + t = 2; + /* FALL THROUGH */ + doconvert: + oc[0] = (unsigned char)c; + oc[1] = 0; + Latin1toASCII(oc, nc, t); + for (; nc[i]; i++) + putchar((char)nc[i]); + break; + case 't': + if (c == '\\') { + texchar = (char)c; + break; + } else if (c == '"') { + if (texchar != '\\') { + putchar(texchar); + i++; + } + texchar = (char)c; + break; + } else if (texchar == '"') { + if (c < 32 || c > 128) + d = 0; + else + d = textbl[c-32]; + if (d == 0) { + putchar(texchar); + i++; + } else + c = d; + texchar = 0; + } + /* FALL THROUGH */ + default: + putchar((char)c); + i++; + break; + } + return i; +} + +char * +current_charsubst() +{ + static char *show; + + switch(*charsubst) { + case 'm': +#ifdef VERBOSE + IF(verbose) + show = "[ISO->monosp] "; + ELSE +#endif +#ifdef TERSE + show = "[M] "; +#endif + break; + case 'a': +#ifdef VERBOSE + IF(verbose) + show = "[ISO->ASCII] "; + ELSE +#endif +#ifdef TERSE + show = "[A] "; +#endif + break; + case 't': +#ifdef VERBOSE + IF(verbose) + show = "[TeX->ISO] "; + ELSE +#endif +#ifdef TERSE + show = "[T] "; +#endif + break; + default: + show = ""; + break; + } + return show; +} + +void +strcharsubst(inb, outb) +char *inb, *outb; +{ + switch(*charsubst) { + case 'a': + Latin1toASCII((unsigned char*)inb, (unsigned char*)outb, 2); + break; + default: + strcpy(outb, inb); + } +} + +/* The following is an adapted version of iso2asc by Markus Kuhn, + University of Erlangen, Germany +*/ + +#define ISO_TABLES 2 /* originally: 7 */ + +/* Conversion tables for displaying the G1 set (0xa0-0xff) of + ISO Latin 1 (ISO 8859-1) with 7-bit ASCII characters. + + Version 1.2 -- error corrections are welcome + + Table Purpose + 0 universal table for many languages + 1 single-spacing universal table + 2 table for Danish, Dutch, German, Norwegian and Swedish + 3 table for Danish, Finnish, Norwegian and Swedish using + the appropriate ISO 646 variant. + 4 table with RFC 1345 codes in brackets + 5 table for printers that allow overstriking with backspace + + Markus Kuhn */ +/* In this version, I have taken out all tables except 1 and 2 -ot */ + +#define SUB NULL /* used if no reasonable ASCII string is possible */ + +static char *iso2asc[ISO_TABLES][96] = { +{ + " ","!","c",SUB,SUB,"Y","|",SUB,"\"","c","a","<","-","-","R","-", + " ",SUB,"2","3","'","u","P",".",",","1","o",">",SUB,SUB,SUB,"?", + "A","A","A","A","A","A","A","C","E","E","E","E","I","I","I","I", + "D","N","O","O","O","O","O","x","O","U","U","U","U","Y","T","s", + "a","a","a","a","a","a","a","c","e","e","e","e","i","i","i","i", + "d","n","o","o","o","o","o",":","o","u","u","u","u","y","t","y" +},{ + " ","!","c",SUB,SUB,"Y","|",SUB,"\"","(c)","a","<<","-","-","(R)","-", + " ","+/-","2","3","'","u","P",".",",","1","o",">>"," 1/4"," 1/2"," 3/4","?", + "A","A","A","A","Ae","Aa","AE","C","E","E","E","E","I","I","I","I", + "D","N","O","O","O","O","Oe","x","Oe","U","U","U","Ue","Y","Th","ss", + "a","a","a","a","ae","aa","ae","c","e","e","e","e","i","i","i","i", + "d","n","o","o","o","o","oe",":","oe","u","u","u","ue","y","th","ij" +} +}; + +/* + * Transform an 8-bit ISO Latin 1 string iso into a 7-bit ASCII string asc + * readable on old terminals using conversion table t. + * + * worst case: strlen(iso) == 4*strlen(asc) + */ +static void +Latin1toASCII(iso, asc, t) +unsigned char *iso, *asc; +int t; +{ + char *p, **tab; + + if (iso == NULL || asc == NULL) + return; + t--; /* offset correction -ot */ + tab = iso2asc[t] - 0xa0; + while (*iso) { + if (*iso > 0x9f) { + p = tab[*iso++]; + while (*p) + *asc++ = *p++; + } else + *asc++ = *iso++; + } + *asc = 0; +} + +#endif Index:charsubst.h @@ -0,0 +1,25 @@ +/* $Id: charsubst.h,v 3.0 1993/12/21 21:54:40 davison Trn $ + */ +/* + * Permission is hereby granted to copy, reproduce, redistribute or otherwise + * use this software as long as: there is no monetary profit gained + * specifically from the use or reproduction of this software, it is not + * sold, rented, traded or otherwise marketed, and this copyright notice is + * included prominently in any copy made. + * + * The authors make no claims as to the fitness or correctness of this software + * for any use whatsoever, and it is provided as is. Any use of this software + * is at the user's own risk. + */ + +#ifdef CHARSUBST + +/* Conversions are: plain, ISO->ascii, TeX -> ISO, ISO->ascii monospaced */ +EXT char *charsets INIT("patm"); +EXT char *charsubst; + +int putsubstchar _((int)); +char *current_charsubst _((void)); +void strcharsubst _((char*,char*)); + +#endif Index:common.h @@ -17,4 +17,15 @@ #include #include + +#ifndef S_ISDIR +#define S_ISDIR(m) ( ((m) & S_IFMT) == S_IFDIR ) +#endif +#ifndef S_ISCHR +#define S_ISCHR(m) ( ((m) & S_IFMT) == S_IFCHR ) +#endif +#ifndef S_ISREG +#define S_ISREG(m) ( ((m) & S_IFMT) == S_IFREG ) +#endif + #include #include "config.h" /* generated by installation script */ @@ -25,14 +36,18 @@ #include #include -#ifdef I_SYS_IOCTL -#include +#ifdef I_SYS_FILIO +# include +#else +# ifdef I_SYS_IOCTL +# include +# endif #endif #ifdef I_VFORK -# include +# include #endif #include #ifdef I_TERMIO -# include +# include #else # ifdef I_TERMIOS @@ -158,4 +173,5 @@ * %P Public news spool directory (NEWSSPOOL) * %r Last reference (parent article id) + * %q The last quoted input (via %"). * %R New references list * %s Subject, with all Re's and (nf)'s stripped off @@ -189,4 +205,6 @@ * pattern that had brackets. %0 matches the last bracket * matched, in case you had alternatives. + * %? Insert a space unless the entire result is > 79 chars, in + * which case the space becomes a newline. * * Put ^ in the middle to capitalize the first letter: %^C = Rec.humor @@ -195,4 +213,5 @@ * Put > in the middle to return the address portion of a name. * Put ) in the middle to return the comment portion of a name. + * Put ' in the middle to protect "'"s in arguments you've put in "'"s. * Put :FMT in the middle to format the result: %:-30.30t * @@ -276,4 +295,5 @@ */ #define ROTATION /* enable x, X and ^X commands to work */ +#define CHARSUBST /* enable the _C command */ #define DELBOGUS /* ask if bogus newsgroups should be deleted */ #define RELOCATE /* allow newsgroup rearranging */ @@ -557,5 +577,5 @@ # ifndef MAILHEADER /* % */ # ifdef CONDSUB -# define MAILHEADER "To: %t\nSubject: Re: %S\n%(%{REPLYTO}=^$?:Reply-To: %{REPLYTO}\n)Newsgroups: %n\nIn-Reply-To: %i\n%(%[references]!=^$?References\\: %[references]\n)Organization: %o\nCc: \nBcc: \n\n" +# define MAILHEADER "To: %t\nSubject: %(%i=^$?:Re: %S\n%(%{REPLYTO}=^$?:Reply-To: %{REPLYTO}\n)Newsgroups: %n\nIn-Reply-To: %i)\n%(%[references]=^$?:References: %[references]\n)Organization: %o\nCc: \nBcc: \n\n" # else # define MAILHEADER "To: %t\nSubject: Re: %S\nNewsgroups: %n\nIn-Reply-To: %i\nReferences: %[references]\nCc: \nBcc: \n\n" @@ -565,5 +585,5 @@ # ifndef MAILHEADER /* % */ # ifdef CONDSUB -# define MAILHEADER "To: %T\nSubject: %(%i=^$?:Re: %S\nNewsgroups: %n\nIn-Reply-To: %i)\n%(%[references]!=^$?References\\: %[references]\n)Organization: %o\nCc: \nBcc: \n\n" +# define MAILHEADER "To: %T\nSubject: %(%i=^$?:Re: %S\n%(%{REPLYTO}=^$?:Reply-To: %{REPLYTO}\n)Newsgroups: %n\nIn-Reply-To: %i)\n%(%[references]=^$?:References: %[references]\n)Organization: %o\nCc: \nBcc: \n\n" # else # define MAILHEADER "To: %T\nSubject: Re: %S\nNewsgroups: %n\nIn-Reply-To: %i\nReferences: %[references]\nCc: \nBcc: \n\n" @@ -576,4 +596,33 @@ #endif +/* command to forward an article */ +#define FORWARDPOSTER MAILPOSTER + +#ifdef INTERNET +# ifndef FORWARDHEADER /* % */ +# ifdef CONDSUB +# define FORWARDHEADER "To: %\"\n\nTo: \"\nSubject: %(%i=^$?:%[subject] (fwd\\)\n%(%{REPLYTO}=^$?:Reply-To: %{REPLYTO}\n)Newsgroups: %n\nIn-Reply-To: %i)\n%(%[references]=^$?:References: %[references]\n)Organization: %o\nCc: \nBcc: \n\n" +# else +# define FORWARDHEADER "To: \nSubject: %[subject] (fwd)\nNewsgroups: %n\nIn-Reply-To: %i\nReferences: %[references]\nCc: \nBcc: \n\n" +# endif +# endif +#else +# ifndef FORWARDHEADER /* % */ +# ifdef CONDSUB +# define FORWARDHEADER "To: %\"\n\nTo: \"\nSubject: %(%i=^$?:%[subject] (fwd\\)\n%(%{REPLYTO}=^$?:Reply-To: %{REPLYTO}\n)Newsgroups: %n\nIn-Reply-To: %i)\n%(%[references]=^$?:References: %[references]\n)Organization: %o\nCc: \nBcc: \n\n" +# else +# define FORWARDHEADER "To: \nSubject: %[subject] (fwd)\nNewsgroups: %n\nIn-Reply-To: %i\nReferences: %[references]\nCc: \nBcc: \n\n" +# endif +# endif +#endif + +#ifndef FORWARDMSG /* % */ +# define FORWARDMSG "------- start of forwarded message -------" +#endif + +#ifndef FORWARDMSGEND /* % */ +# define FORWARDMSGEND "------- end of forwarded message -------" +#endif + /* command to submit a followup article */ #ifndef NEWSPOSTER /* % and ~ */ @@ -605,5 +654,5 @@ #endif -#ifdef MIME_SUPPORT +#ifdef MIMESTORE # ifndef EXMIMESAVER # define EXMIMESAVER "%e %A" @@ -808,5 +857,7 @@ EXT bool dont_filter_control INIT(FALSE); /* -j */ +EXT int join_subject_len INIT(0); /* -J */ EXT bool kill_thru_kludge INIT(TRUE); /* -k */ +EXT bool keep_the_group_static INIT(FALSE); /* -K */ EXT bool mbox_always INIT(FALSE); /* -M */ EXT bool norm_always INIT(FALSE); /* -N */ @@ -817,5 +868,5 @@ EXT bool novice_delays INIT(TRUE); /* +f */ EXT int olden_days INIT(FALSE); /* -o */ -EXT bool auto_select_postings INIT(FALSE); /* -p */ +EXT char auto_select_postings INIT(0); /* -p */ EXT bool checkflag INIT(FALSE); /* -c */ EXT bool suppress_cn INIT(FALSE); /* -s */ @@ -866,4 +917,7 @@ #define UNDERLINE 2 EXT int marking INIT(NOMARKING); /* -m */ +#define HALFPAGE_MARKING 1 +#define BACKPAGE_MARKING 2 +EXT int marking_areas INIT(HALFPAGE_MARKING); EXT ART_LINE initlines INIT(0); /* -i */ @@ -912,5 +966,5 @@ #endif -#ifdef MIME_SUPPORT +#if defined(MIMESHOW) || defined(MIMESTORE) EXT bool mime_article INIT(FALSE); #endif @@ -929,5 +983,7 @@ #endif -#define advise(str) fputs(str,stdout) -#define report_error(str) fputs(str,stderr) -#define fatal_error(str) fputs(str,stderr), finalize(1) +#define nntp_advise(str) fputs(str,stdout) +#define nntp_init_error(str) fputs(str,stderr) +#define nntp_error(str) fputs(str,stderr) +#define NNTP_ERROR_IS_FATAL +#define NNTP_HANDLE_TIMEOUT Index:config.h.SH @@ -2,7 +2,4 @@ '') . ./config.sh ;; esac -case "$0" in -*/*) cd `expr X$0 : 'X\(.*\)/'` ;; -esac echo "Extracting config.h (with variable substitutions)" sed <config.h -e 's!^#undef\(.*\)/\*!/\*#define\1\*//\*!' @@ -147,7 +144,14 @@ /* I_DIRENT: * This symbol, if defined, indicates to the C program that it should - * include . + * include . Using this symbol also triggers the definition + * of the Direntry_t define which ends up being 'struct dirent' or + * 'struct direct' depending on the availability of . */ #$i_dirent I_DIRENT /**/ +#ifdef I_DIRENT +#define Direntry_t struct dirent +#else +#define Direntry_t struct direct +#endif /* I_STDLIB: @@ -173,5 +177,10 @@ * be included. Otherwise, include or . */ +/* I_SYS_FILIO: + * This symbol, if defined, indicates that exists and + * should be included instead of . + */ #$i_sysioctl I_SYS_IOCTL /**/ +#$i_sysfilio I_SYS_FILIO /**/ /* I_SYS_NDIR: @@ -312,8 +321,4 @@ #$d_ignoreorg IGNOREORG /**/ -/* MIME_SUPPORT: - * This symbol, if defined, indicates mime articles should be processed - * by an external program. - */ /* MIMESHOW: * This symbol points to the program to run to show a mime article. @@ -322,7 +327,6 @@ * This symbol points to the program to run to store a mime article. */ -#$d_mime MIME_SUPPORT /**/ -#$d_mime MIMESHOW "$mimeshow" /**/ -#$d_mime MIMESTORE "$mimestore" /**/ +#$d_mimeshow MIMESHOW "$mimeshow" /**/ +#$d_mimestore MIMESTORE "$mimestore" /**/ /* USE_NNTP: Index:dependencies @@ -25,4 +25,5 @@ art.o: bits.h art.o: cache.h +art.o: charsubst.h art.o: common.h art.o: config.h @@ -44,8 +45,4 @@ art.o: trn.h art.o: util.h -artcheck.o: EXTERN.h -artcheck.o: artcheck.c -artcheck.o: common.h -artcheck.o: config.h artio.o: EXTERN.h artio.o: INTERN.h @@ -142,4 +139,6 @@ cache.o: rcstuff.h cache.o: rt-ov.h +cache.o: rt-page.h +cache.o: rt-process.h cache.o: rt-select.h cache.o: rt-util.h @@ -149,4 +148,12 @@ cache.o: trn.h cache.o: util.h +charsubst.o: EXTERN.h +charsubst.o: INTERN.h +charsubst.o: artstate.h +charsubst.o: charsubst.c +charsubst.o: charsubst.h +charsubst.o: common.h +charsubst.o: config.h +charsubst.o: search.h decode.o: EXTERN.h decode.o: INTERN.h @@ -179,9 +186,4 @@ final.o: term.h final.o: util.h -getactive.o: EXTERN.h -getactive.o: common.h -getactive.o: config.h -getactive.o: getactive.c -getactive.o: nntpclient.h hash.o: EXTERN.h hash.o: INTERN.h @@ -283,4 +285,5 @@ kfile.o: INTERN.h kfile.o: artsrch.h +kfile.o: bits.h kfile.o: cache.h kfile.o: common.h @@ -325,4 +328,5 @@ ng.o: bits.h ng.o: cache.h +ng.o: charsubst.h ng.o: common.h ng.o: config.h @@ -452,4 +456,9 @@ nntpinit.o: nntpclient.h nntpinit.o: nntpinit.c +nntplist.o: EXTERN.h +nntplist.o: common.h +nntplist.o: config.h +nntplist.o: nntpclient.h +nntplist.o: nntplist.c only.o: EXTERN.h only.o: INTERN.h @@ -498,4 +507,5 @@ respond.o: artio.h respond.o: cache.h +respond.o: charsubst.h respond.o: common.h respond.o: config.h @@ -567,4 +577,5 @@ rt-page.o: util.h rt-process.o: EXTERN.h +rt-process.o: INTERN.h rt-process.o: bits.h rt-process.o: cache.h @@ -579,4 +590,5 @@ rt-process.o: rcln.h rt-process.o: rt-process.c +rt-process.o: rt-process.h rt-process.o: rt-select.h rt-process.o: rthread.h @@ -641,4 +653,5 @@ rthread.o: common.h rthread.o: config.h +rthread.o: final.h rthread.o: hash.h rthread.o: head.h @@ -676,5 +689,7 @@ sw.o: EXTERN.h sw.o: INTERN.h +sw.o: artstate.h sw.o: cache.h +sw.o: charsubst.h sw.o: common.h sw.o: config.h @@ -701,4 +716,8 @@ term.o: term.h term.o: util.h +trn-artchk.o: EXTERN.h +trn-artchk.o: common.h +trn-artchk.o: config.h +trn-artchk.o: trn-artchk.c trn.o: EXTERN.h trn.o: INTERN.h @@ -750,16 +769,17 @@ uudecode.o: respond.h uudecode.o: uudecode.c -Makefile: Makefile.SH config.sh ; /bin/sh Makefile.SH -Pnews: Pnews.SH config.sh ; /bin/sh Pnews.SH -Policy.sh: Policy.sh.SH config.sh ; /bin/sh Policy.sh.SH -Rnmail: Rnmail.SH config.sh ; /bin/sh Rnmail.SH -Speller: Speller.SH config.sh ; /bin/sh Speller.SH -config.h: config.h.SH config.sh ; /bin/sh config.h.SH -makedepend: makedepend.SH config.sh ; /bin/sh makedepend.SH -makedir: makedir.SH config.sh ; /bin/sh makedir.SH -mbox.saver: mbox.saver.SH config.sh ; /bin/sh mbox.saver.SH -newsetup: newsetup.SH config.sh ; /bin/sh newsetup.SH -newsgroups: newsgroups.SH config.sh ; /bin/sh newsgroups.SH -newsnews: newsnews.SH config.sh ; /bin/sh newsnews.SH -norm.saver: norm.saver.SH config.sh ; /bin/sh norm.saver.SH +Makefile: Makefile.SH config.sh ; /bin/sh $(srcdir)/Makefile.SH +Pnews: Pnews.SH config.sh ; /bin/sh $(srcdir)/Pnews.SH +Policy.sh: Policy.sh.SH config.sh ; /bin/sh $(srcdir)/Policy.sh.SH +Rnmail: Rnmail.SH config.sh ; /bin/sh $(srcdir)/Rnmail.SH +Speller: Speller.SH config.sh ; /bin/sh $(srcdir)/Speller.SH +config.h: config.h.SH config.sh ; /bin/sh $(srcdir)/config.h.SH +filexp: filexp.SH config.sh ; /bin/sh $(srcdir)/filexp.SH +makedepend: makedepend.SH config.sh ; /bin/sh $(srcdir)/makedepend.SH +makedir: makedir.SH config.sh ; /bin/sh $(srcdir)/makedir.SH +mbox.saver: mbox.saver.SH config.sh ; /bin/sh $(srcdir)/mbox.saver.SH +newsetup: newsetup.SH config.sh ; /bin/sh $(srcdir)/newsetup.SH +newsgroups: newsgroups.SH config.sh ; /bin/sh $(srcdir)/newsgroups.SH +newsnews: newsnews.SH config.sh ; /bin/sh $(srcdir)/newsnews.SH +norm.saver: norm.saver.SH config.sh ; /bin/sh $(srcdir)/norm.saver.SH # WARNING: Put nothing here or make depend will gobble it up! Index:filexp.SH @@ -0,0 +1,48 @@ +case $CONFIG in + '') . ./config.sh ;; +esac +echo "Extracting filexp (with variable substitutions)" +$spitshell >filexp <>filexp <<'!NO!SUBS!' +: expand filename +case "$1" in + ~/*|~) + echo $1 | $sed "s|~|${HOME-$LOGDIR}|" + ;; + ~*) + if $test -f /bin/csh; then + /bin/csh -f -c "glob $1" + failed=$? + echo "" + exit $failed + else + name=`$expr x$1 : '..\([^/]*\)'` + dir=`$sed -n -e "/^${name}:/{s/^[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:\([^:]*\).*"'$'"/\1/" -e p -e q -e '}' &2 + exit 1 + fi + case "$1" in + */*) + echo $dir/`$expr x$1 : '..[^/]*/\(.*\)'` + ;; + *) + echo $dir + ;; + esac + fi + ;; +*) + echo $1 + ;; +esac +!NO!SUBS! +chmod +x filexp +$eunicefix filexp Index:final.c @@ -91,4 +91,5 @@ if (bizarre) resetty(); + xmouse_off(); /* turn off mouse tracking (if on) */ if (lockname && *lockname) UNLINK(lockname); @@ -223,4 +224,7 @@ { if (!waiting) { + bool mouse_flag; /* if TRUE, mouse tracking was on */ + mouse_flag = xmouse_status; + xmouse_off(); checkpoint_rc(); /* good chance of crash while stopped */ if (clear_on_stop) { @@ -253,4 +257,6 @@ } } + if (mouse_flag) + xmouse_on(); } sigset(signo,stop_catcher); /* unenable the stop */ Index:hash.c @@ -196,6 +196,8 @@ register unsigned size; - if (BADTBL(tbl)) - fatal_error("Hash table is invalid."); + if (BADTBL(tbl)) { + fputs("Hash table is invalid.",stderr); + finalize(1); + } size = tbl->ht_size; hepp = &tbl->ht_addr[hash(key,keylen) % size]; Index:head.c @@ -91,5 +91,5 @@ * optimization to avoid calling subroutine strEQ unnecessarily. Hauls. */ - if (islower(*f)) { + if (*f >= 'a' && *f <= 'z') { for (i = htypeix[*f - 'a']; *htype[i].ht_name == *f; --i) { if (len == htype[i].ht_length && strEQ(f, htype[i].ht_name)) { @@ -304,6 +304,6 @@ int size; - /* Only return a cached subject line if it isn't the current article */ - if (which_line != SUBJ_LINE || parsed_art != artnum) { + /* Only return a cached line if it isn't the current article */ + if (parsed_art != artnum) { s = fetchcache(artnum,which_line,FILL_CACHE); if (s) @@ -316,4 +316,6 @@ lastpos = htype[which_line].ht_maxpos; size = lastpos - firstpos; + t = headbuf + firstpos; + while (*t == ' ' || *t == '\t') t++, size--; #ifdef DEBUG if (debug && (size < 1 || size > 1000)) { @@ -323,6 +325,4 @@ #endif s = safemalloc((MEM_SIZE)size); - t = headbuf + firstpos; - while (*t == ' ' || *t == '\t') t++; *s = '\0'; safecat(s,t,size); @@ -378,18 +378,22 @@ nntp_command(ser_line); if (nntp_check(TRUE) == NNTP_CLASS_OK) { + char *line, *last_buf = ser_line; + MEM_SIZE last_buflen = sizeof ser_line; for (ap = find_article(artnum); ; ) { - nntp_gets(ser_line, sizeof ser_line); + line = nntp_get_a_line(last_buf,last_buflen,last_buf!=ser_line); # ifdef DEBUG if (debug & DEB_NNTP) - printf("<%s\n", ser_line) FLUSH; + printf("<%s", line) FLUSH; # endif - if (NNTP_LIST_END(ser_line)) + if (NNTP_LIST_END(line)) break; - if ((t = index(ser_line, '\r')) != Nullch) + last_buf = line; + last_buflen = buflen_last_line_got; + if ((t = index(line, '\r')) != Nullch) *t = '\0'; - if (!(t = index(ser_line, ' '))) + if (!(t = index(line, ' '))) continue; t++; - num = atol(ser_line); + num = atol(line); if (num < artnum || num > lastnum) continue; @@ -403,4 +407,6 @@ safecat(s,t,size); } + if (last_buf != ser_line) + free(last_buf); } else { fprintf(stderr,"\nUnexpected close of server socket.\n"); @@ -413,9 +419,9 @@ return s; } -#endif +#endif /* USE_NNTP */ - /* Only return a cached subject line if it isn't the current article */ + /* Only return a cached line if it isn't the current article */ s = Nullch; - if (which_line != SUBJ_LINE || parsed_art != artnum) + if (parsed_art != artnum) s = fetchcache(artnum,which_line,FILL_CACHE); if ((firstpos = htype[which_line].ht_minpos) < 0) @@ -430,4 +436,6 @@ lastpos = htype[which_line].ht_maxpos; size = lastpos - firstpos; + t = headbuf + firstpos; + while (*t == ' ' || *t == '\t') t++, size--; if (copy) s = safemalloc((MEM_SIZE)size); @@ -437,6 +445,4 @@ size = sizeof cmd_buf; } - t = headbuf + firstpos; - while (*t == ' ' || *t == '\t') t++; *s = '\0'; safecat(s,t,size); Index:head.h @@ -89,5 +89,5 @@ {"anpa", 0, 0, 4, HT_HIDE }, {"codes", 0, 0, 5, HT_HIDE }, -#ifdef MIME_SUPPORT +#if defined(MIMESHOW) || defined(MIMESTORE) {"content-type", 0, 0, 12, HT_MAGIC }, {"content-transfer-encoding", Index:help.c @@ -49,4 +49,5 @@ b Back up one page.\n\ ^L,X Refresh the screen (X=rot13).\n\ +_C Switch characterset conversion.\n\ ",NOMARKING)) || (cmd = print_lines("\ @@ -154,4 +155,5 @@ f,F Submit a followup article (F = include this article).\n\ r,R Reply through net mail (R = include this article).\n\ +^F Forward article through net mail.\n\ e dir{|command}\n\ Extract to directory using /bin/sh, uudecode, unship, or command.\n\ @@ -165,4 +167,5 @@ ^R,v Restart article (v=verbose).\n\ ^X Restart article, rot13 mode.\n\ +_C Switch characterset conversion.\n\ c Catch up (mark all articles as read).\n\ b Back up one page.\n\ @@ -397,5 +400,5 @@ (cmd = print_lines("\n\ a-z,0-9 Select/deselect the indicated item by its letter or number. Many of\n\ - the alpha letters are ommitted for the following commands.\n\ + the alpha letters are omitted for the following commands.\n\ SP Perform the default command (usually > or Z).\n\ CR Start reading. Selects the current item if nothing is selected.\n\ @@ -463,4 +466,5 @@ && View or set macro definitions.\n\ !cmd Escape to a subshell.\n\ +h, ? This help message.\n\ q Quit the selector.\n\ Q Quit group and return to news group selection prompt for this group.\n\ Index:init.c @@ -54,4 +54,5 @@ char *tcbuf; register bool foundany = FALSE; + char *s; #ifdef NOLINEBUF static char std_out_buf[BUFSIZ]; /* must be static or malloced */ @@ -192,4 +193,21 @@ #endif +/* xterm mouse initialization -- move somewhere different? */ + /* values of XTERMMOUSE: y/Y/1 -- if appropriate, use it. */ + /* n/N/0 -- don't ever use it. */ + /* a/A -- always use it. */ + s = getval("XTERMMOUSE","-"); + if (*s == 'y' || *s == 'Y' || *s == '1') { + if ((s = getenv("TERM")) != Nullch && strnEQ(s,"xterm",5)) + use_xterm_mouse = TRUE; + } + else if (*s == 'a' || *s == 'A') + use_xterm_mouse = TRUE; + else if (*s != 'n' && *s != 'N' && *s != '0') { + s = argv[0]; + /* if an 'x' is at the end, enable Xterm mouse tracking */ + if (s[strlen(s)-1] == 'x') + use_xterm_mouse = TRUE; + } return foundany; } @@ -202,11 +220,12 @@ lockname = savestr(filexp(LOCKNAME)); if (!checkflag) { + int processnum = 0; tmpfp = fopen(lockname,"r"); if (tmpfp != Nullfp) { - int processnum; - - fgets(buf,LBUFLEN,tmpfp); + if (fgets(buf,LBUFLEN,tmpfp)) + processnum = atoi(buf); fclose(tmpfp); - processnum = atoi(buf); + } + if (processnum) { #ifdef VERBOSE IF(verbose) Index:intrp.c @@ -187,10 +187,7 @@ #endif /* HAS_GETHOSTNAME */ if (*buf) { - char *cp = index(buf,'.'); - if (cp) - *cp = '\0'; - cp = index(phostname,'.'); - if (cp) - strcat(buf,cp); + if (*phostname == '.' && phostname[1]) { + strcat(buf,phostname); + } phostname = savestr(buf); } @@ -355,5 +352,21 @@ #endif if (*pattern == '%' && pattern[1]) { + switch_again: switch (*++pattern) { + case '^': + case '_': + case '\\': + case '\'': + case '>': + case ')': + goto switch_again; + case ':': + pattern++; + while (*pattern + && (*pattern=='.' || *pattern=='-' || isdigit(*pattern))) { + pattern++; + } + pattern--; + goto switch_again; case '{': for (pattern++; *pattern && *pattern != '}'; pattern++) @@ -437,4 +450,6 @@ char scrbuf[512]; char spfbuf[512]; + static char *input_str = Nullch; + static int input_siz = 0; bool upper = FALSE; bool lastcomp = FALSE; @@ -617,5 +632,8 @@ noecho(); crmode(); - s = scrbuf; + i = strlen(scrbuf); + growstr(&input_str, &input_siz, i+1); + safecpy(input_str, scrbuf, i+1); + s = input_str; break; #endif @@ -757,4 +775,5 @@ s = getval("ORGANIZATION",orgname); #endif + s = filexp(s); #ifdef ORGFILE if (*s == '/') { @@ -762,11 +781,14 @@ if (ofp) { - fgets(scrbuf,sizeof scrbuf,ofp); + if (fgets(scrbuf,sizeof scrbuf,ofp) == NULL) + *scrbuf = '\0'; fclose(ofp); s = scrbuf+strlen(scrbuf)-1; - if (*s == '\n') + if (*scrbuf && *s == '\n') *s = '\0'; s = scrbuf; } + else + s = nullstr; } #endif @@ -781,4 +803,7 @@ s = spool; break; + case 'q': + s = input_str; + break; case 'r': parseheader(art); @@ -1002,10 +1027,16 @@ } while (*s) { - if ((re_quote && index(regexp_specials, *s)) - || (tick_quote && *s == '\'')) { + if (re_quote && index(regexp_specials, *s)) { if (--destsize <= 0) abort_interp(); *dest++ = '\\'; } + else if (tick_quote && *s == '\'') { + if ((destsize -= 3) <= 0) + abort_interp(); + *dest++ = '\''; + *dest++ = '\\'; + *dest++ = '\''; + } *dest++ = *s++; } @@ -1075,5 +1106,5 @@ *dest = '\0'; if (line_split != Nullch) - if (strlen(orig_dest) > 79) + if ((int)strlen(orig_dest) > 79) *line_split = '\n'; getout: Index:kfile.c @@ -26,4 +26,5 @@ #include "rcstuff.h" #include "trn.h" +#include "bits.h" #include "hash.h" #include "rthread.h" @@ -86,4 +87,5 @@ { bool first_time = (entering && !killfirst); + bool append_nl = FALSE; ART_UNREAD selections = selected_count; ART_UNREAD unread = toread[ng]; @@ -100,4 +102,6 @@ if (*(cp = buf + strlen(buf) - 1) == '\n') *cp = '\0'; + else + append_nl = TRUE; if (strnEQ(buf,"THRU",4)) { killfirst = atol(buf+4)+1; @@ -244,4 +248,6 @@ kill_mentioned = TRUE; } + if (append_nl) + kf_append(""); #endif return 0; @@ -482,20 +488,23 @@ strcpy(cmd_buf,filexp(getval("KILLLOCAL",killlocal))); if (makedir(cmd_buf,MD_FILE) >= 0) { + if (*cmd) { #ifdef VERBOSE - IF(verbose) - printf("\nDepositing command in %s...",cmd_buf); - ELSE + IF(verbose) + printf("\nDepositing command in %s...",cmd_buf); + ELSE #endif #ifdef TERSE - printf("\n--> %s...",cmd_buf); + printf("\n--> %s...",cmd_buf); #endif - fflush(stdout); - if (novice_delays) - sleep(2); + fflush(stdout); + if (novice_delays) + sleep(2); + } if ((tmpfp = fopen(cmd_buf,"a")) != Nullfp) { fseek(tmpfp,0L,2); /* get to EOF for sure */ fprintf(tmpfp,"%s\n",cmd); fclose(tmpfp); - fputs("done\n",stdout) FLUSH; + if (*cmd) + fputs("done\n",stdout) FLUSH; } else Index:makedepend.SH @@ -3,4 +3,7 @@ esac echo "Extracting makedepend (with variable substitutions)" +case "$srcdir" in +'') srcdir='.';; +esac $spitshell >makedepend <.deptmp +srcdir=$srcdir +objdir=`pwd` +deptmp=\$objdir/.deptmp +$cat /dev/null >\$deptmp $echo "(Note: this is going to take a while.)" +cd \$srcdir for file in *.[cy]; do case "\$file" in @@ -34,29 +41,34 @@ -e 's/\\\\[ ]*$//' \\ -e p \\ - -e '}' | $cppstdin -I/usr/local/include | $sed \\ + -e '}' | $cppstdin -I\$objdir -I$usrinc | $sed \\ -e '/^# *line/s/line//' \ -e '/^# *[0-9]/!d' \\ -e 's/^.*"\(.*\)".*\$/'\$filebase'.o: \1/' \\ -e 's|: \./|: |' \\ + -e "s|\$objdir/||" \\ -e 's/: .*\.c/: '\$file'/' | \\ - $uniq | $sort | $uniq >> .deptmp + $uniq | $sort | $uniq >>\$deptmp done for file in *.SH; do - $echo \`basename \$file .SH\`: \$file config.sh \; /bin/sh \$file >> .deptmp + $echo \`basename \$file .SH\`: \$file config.sh \; /bin/sh "\\\$(srcdir)/\$file" >>\$deptmp done +cd \$objdir + $sed Makefile.new -e '1,/^# AUTOMATICALLY/!d' -if $test -s .deptmp; then +if $test -s \$deptmp; then echo "Updating Makefile..." - $sed -e 's/\\\$/\$\$/g' .deptmp | $egrep -v $usrinc >dependencies + $sed -e 's/\\\$[^(]/\$\$/g' \$deptmp | $egrep -v $usrinc >dependencies else $echo "You don't seem to have a proper C preprocessor. Using grep instead." - $egrep '^#include ' *.[cyh] ?.[cyh] >.deptmp + cd \$srcdir + $egrep '^#include ' *.[cyh] ?.[cyh] >\$deptmp + cd \$objdir echo "Updating Makefile..." - <.deptmp $sed -n 's|c:#include "\(.*\)".*\$\$|o: \1|p' > dependencies - <.deptmp $sed -n 's|y:#include "\(.*\)".*\$\$|o: \1|p' >> dependencies - <.deptmp $sed -n 's|h:#include "\(.*\)".*\$\$|h: \1|p' >> dependencies + <\$deptmp $sed -n 's|c:#include "\(.*\)".*\$\$|o: \1|p' > dependencies + <\$deptmp $sed -n 's|y:#include "\(.*\)".*\$\$|o: \1|p' >> dependencies + <\$deptmp $sed -n 's|h:#include "\(.*\)".*\$\$|h: \1|p' >> dependencies fi $echo "# WARNING: Put nothing here or make depend will gobble it up!" >> dependencies @@ -64,5 +76,5 @@ $mv Makefile.new Makefile $cat dependencies >>Makefile -rm .deptmp +rm \$deptmp !GROK!THIS! $eunicefix makedepend Index:makedir.SH @@ -39,5 +39,5 @@ list='' -while true ; do +while : ; do case \$1 in */*) Index:mbox.saver.SH @@ -51,5 +51,5 @@ $echo "Article: \$4 of \$6" fi - $tail +\$5c \$1 | $sed "s/^From />From /" + $tail +\$5c \$1 | $sed "s/^[Ff]rom />& /" $echo "" $echo "" ) >> \$7 Index:ndir.c @@ -69,10 +69,10 @@ * get next entry in a directory. */ -struct direct * +Direntry_t * readdir(dirp) register DIR *dirp; { register struct olddirect *dp; - static struct direct dir; + static Direntry_t dir; for (;;) { Index:ndir.h @@ -19,7 +19,4 @@ #ifdef I_DIRENT #include -#ifndef direct -#define direct dirent -#endif #else #ifdef I_SYS_NDIR @@ -36,5 +33,5 @@ #define MAXNAMLEN 255 -struct direct { +Direntry_t { long d_ino; /* inode number of entry */ short d_reclen; /* length of this record */ @@ -45,10 +42,10 @@ /* * The DIRSIZ macro gives the minimum record length which will hold - * the directory entry. This requires the amount of space in struct direct + * the directory entry. This requires the amount of space in Direntry_t * without the d_name field, plus enough space for the name with a terminating * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary. */ #undef DIRSIZ -#define DIRSIZ(dp) ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) +#define DIRSIZ(dp) ((sizeof(Direntry_t)-(MAXNAMLEN+1))+(((dp)->d_namlen+1+3)&~3)) /* @@ -65,5 +62,5 @@ #endif extern DIR *opendir _((char*)); -extern struct direct *readdir _((DIR*)); +extern Direntry_t *readdir _((DIR*)); extern long telldir _((DIR*)); extern void seekdir _((DIR*)); Index:newsetup.SH @@ -29,4 +29,5 @@ # where important rn things are kept rnlib=\`$filexp $privlib\` + nntplist=nntplist ;; undef) @@ -35,4 +36,5 @@ # where important rn things are kept rnlib="$privlib" + nntplist=$bin/nntplist ;; esac @@ -43,9 +45,10 @@ mv=${mv-mv} rm=${rm-rm} +cp=${cp-cp} !GROK!THIS! $cat >>newsetup <<'!NO!SUBS!' dotdir="${DOTDIR-${HOME-$LOGDIR}}" -newsrc="${NEWSRC-$dotdir/.newsrc}" +newsrc="$dotdir/.newsrc" tmp="${TMPDIR-/tmp}" @@ -82,11 +85,9 @@ if $test -r $subs; then - cp $subs $newsrc + $cp $subs $newsrc else - if $test -r $rnlib/getactive; then - $rnlib/getactive subscriptions $tmpsubs >/dev/null 2>&1 - fi + ($nntplist subscriptions $tmpsubs) >/dev/null 2>&1 if $test -s $tmpsubs; then - cp $tmpsubs $newsrc + $cp $tmpsubs $newsrc else $cat <$newsrc Index:newsgroups.SH @@ -39,11 +39,12 @@ #NNTP~*) rnlib=\`$filexp \$rnlib\` ;; #NNTPesac +#NNTPnntplist=$bin/nntplist : End of system dependencies, hopefully #NNTP -#NNTPif \$rnlib/getactive ACTIVE \$active; then -#NNTP true; +#NNTPif \$nntplist ACTIVE \$active; then +#NNTP : nothing #NNTPelse -#NNTP exit 1; +#NNTP exit 1 #NNTPfi @@ -55,5 +56,5 @@ dotdir=\${DOTDIR-\${HOME-\$LOGDIR}} -newsrc=\${NEWSRC-\$dotdir/.newsrc} +newsrc=\$dotdir/.newsrc : Throwing .newsrc into the pot twice is a lovely hack to prevent Index:newsnews.SH @@ -7,6 +7,7 @@ *** NEWS NEWS *** -Welcome to trn 3.4. This is mainly a bugfix release of version 3.3 -and a few improvements. Trn is "threaded read news", based on rn. +Welcome to trn 3.5, which fixes quite a few minor and not so minor +bugs in trn 3.4.1 and adds a few new features. Trn is "threaded read +news", based on rn. You can type 'h' at any prompt to display a summary of the commands that Index:ng.c @@ -42,4 +42,5 @@ #include "rt-wumpus.h" #include "decode.h" +#include "charsubst.h" #include "INTERN.h" #include "ng.h" @@ -103,5 +104,9 @@ { char oldmode = mode; +#ifdef CHARSUBST + char *whatnext = "%s%sWhat next? [%s]"; +#else char *whatnext = "%sWhat next? [%s]"; +#endif #ifdef ARTSEARCH @@ -178,8 +183,11 @@ for (; art<=lastart+1; ) { /* for each article */ mode = 'a'; +#ifdef CHARSUBST + charsubst = charsets; +#endif /* do we need to "grow" the newsgroup? */ - if (art > lastart || forcegrow) { + if ((art > lastart || forcegrow) && !keep_the_group_static) { ART_NUM oldlast = lastart; #ifdef USE_NNTP @@ -290,6 +298,15 @@ } clear(); /* clear screen */ +#ifdef USE_NNTP + if (art == 0 && artp && artp->msgid + && !(artp->flags & AF_CACHED)) { + art = nntp_stat_id(artp->msgid); + if (art) + artp = find_article(art); + } +#endif if (!artopen(art)) { /* make sure article is found & open */ char tmpbuf[256]; + ART_LINE linenum; /* see if we have tree data for this article anyway */ init_tree(); @@ -301,7 +318,7 @@ ngname); } - tree_puts(tmpbuf,0,0); - vwtary((ART_LINE)0,(ART_POS)0); - finish_tree(1); + linenum = tree_puts(tmpbuf,0,0); + vwtary(artline,(ART_POS)0); + finish_tree(linenum); prompt = whatnext; #ifdef ARTSEARCH @@ -342,5 +359,10 @@ unflush_output(); /* disable any ^O in effect */ standout(); /* enter standout mode */ - printf(prompt,mailcall,dfltcmd);/* print prompt, whatever it is */ + /* print prompt, whatever it is */ +#ifdef CHARSUBST + printf(prompt,mailcall,current_charsubst(),dfltcmd); +#else + printf(prompt,mailcall,dfltcmd); +#endif un_standout(); /* leave standout mode */ putchar(' '); @@ -432,23 +454,23 @@ switch (*buf) { case '<': /* goto previous subject/thread */ - prev_subject(); + visit_prev_thread(); return AS_NORM; case '>': /* goto next subject/thread */ - next_subject(); + visit_next_thread(); return AS_NORM; case 'U': { /* unread some articles */ char *u_prompt, *u_help_thread; - dfltcmd = "+"; if (!artp) { u_help_thread = nullstr; #ifdef VERBOSE IF(verbose) - u_prompt = "\nSet unread: +select or all? [+an] "; + u_prompt = "\nSet unread: +select or all?"; ELSE #endif #ifdef TERSE - u_prompt = "\nSet unread? [+an] "; + u_prompt = "\nSet unread?"; #endif + dfltcmd = "+an"; } else { @@ -456,5 +478,5 @@ IF(verbose) { u_prompt = "\n\ -Set unread: +select, thread, subthread, or all? [+tsan] "; +Set unread: +select, thread, subthread, or all?"; u_help_thread = "\ Type t or SP to mark this thread's articles as unread.\n\ @@ -465,5 +487,5 @@ #ifdef TERSE { - u_prompt = "\nSet unread? [+tsan] "; + u_prompt = "\nSet unread?"; u_help_thread = "\ t or SP to mark thread unread.\n\ @@ -471,8 +493,8 @@ } #endif + dfltcmd = "+tsan"; } reask_unread: - in_char(u_prompt,'u'); - setdef(buf,dfltcmd); + in_char(u_prompt,'u',dfltcmd); #ifdef VERIFY printcmd(); @@ -750,7 +772,9 @@ } #endif - else + else { inc_art(selected_only,FALSE); - + if (art > lastart) + top_article(); + } #ifdef ARTSEARCH srchahead = 0; @@ -1045,4 +1069,5 @@ #endif case 'l': case Ctl('l'): /* refresh screen */ + refresh_screen: if (art <= lastart) { reread = TRUE; @@ -1054,5 +1079,5 @@ } return AS_NORM; - case Ctl('f'): + case Ctl('^'): carriage_return(); erase_eol(); /* erase the prompt */ @@ -1061,4 +1086,5 @@ #endif return AS_ASK; + case 'B': /* back up one line */ case 'b': case Ctl('b'): /* back up a page */ if (art <= lastart) { @@ -1068,5 +1094,13 @@ clear(); do_fseek = TRUE; - target = topline - (LINES - 2); + if (*buf == 'B') + target = topline - 1; + else { + target = topline - (LINES - 2); + if (marking && (marking_areas & BACKPAGE_MARKING)) { + extern ART_LINE highlight; + highlight = topline; + } + } artline = topline; if (artline >= 0) do { @@ -1102,4 +1136,8 @@ return AS_ASK; } + case Ctl('f'): { /* forward? */ + forward(); + return AS_ASK; + } case '|': case 'w': case 'W': @@ -1170,4 +1208,10 @@ } return AS_ASK; +#ifdef CHARSUBST + case 'C': + if (!*(++charsubst)) + charsubst = charsets; + goto refresh_screen; +#endif case 'a': case 's': case 't': case 'T': *buf = buf[1]; @@ -1201,5 +1245,5 @@ mailcall = getval("MAILCALL","(Mail) "); } - mailcount %= 10; /* check every 10 articles */ + mailcount %= 5; /* check every 5 articles */ } #endif @@ -1240,11 +1284,10 @@ #ifdef VERBOSE IF(verbose) - in_char("Do you really want to mark everything as read? [yn] ", 'C'); + in_char("Do you really want to mark everything as read?",'C',"yn"); ELSE #endif #ifdef TERSE - in_char("Really? [ynh] ", 'C'); + in_char("Really?",'C',"ynh"); #endif - setdef(buf,"y"); #ifdef VERIFY printcmd(); @@ -1297,6 +1340,8 @@ putchar('\n') FLUSH; } - if (ch == 'u') + if (ch == 'u') { rcchar[ng] = NEGCHAR; + printf("(If you meant to hit 'y' instead of 'u', press '-'.)\n"); + } return ch; } @@ -1316,8 +1361,7 @@ if (!use_one_line) putchar('\n') FLUSH; - sprintf(cmd_buf,"Memorize %s command: [+.j,cC]", mode_string); + sprintf(cmd_buf,"Memorize %s command:", mode_string); reask_memorize: - in_char(cmd_buf, 'm'); - setdef(buf,"+"); + in_char(cmd_buf, 'm', "+.j,cC"); #ifdef VERIFY printcmd(); Index:ngdata.c @@ -76,7 +76,9 @@ printf("\nNo spool for %s!\n",ngname) FLUSH; # endif +#if 0 # ifdef CATCHUP catch_up(ng); # endif +#endif } else { # ifdef VERBOSE @@ -141,5 +143,7 @@ if (has_normal_kills) { bool forcelast_save = forcelast; + ARTICLE *artp_save = artp; kill_unwanted(tmpfirst,buf,TRUE); + artp = artp_save; forcelast = forcelast_save; } @@ -241,5 +245,5 @@ return TR_BOGUS; } - + #ifdef DEBUG if (debug & DEB_SOFT_POINTERS) { @@ -247,9 +251,9 @@ } #endif -#ifndef ANCIENT_NEWS - sscanf(tmpbuf+len+1, "%ld %ld %c", &last, &first, &ch); -#else +#ifdef ANCIENT_NEWS sscanf(tmpbuf+len+1, "%ld %c", &last, &ch); first = 1; +#else + sscanf(tmpbuf+len+1, "%ld %ld %c", &last, &first, &ch); #endif if (!abs1st[num]) Index:nghash.c @@ -28,6 +28,6 @@ #include "term.h" -static HASHTABLE *acthash; -static char *actfile; +static HASHTABLE *acthash = 0; +static char *actfile = 0; void @@ -79,4 +79,6 @@ * over; try using a really big buffer to keep it in core. */ (void) fstat(fileno(actfp), &actstat); + if (actfile) + free(actfile); actfile = safemalloc(actstat.st_size + 1); @@ -91,4 +93,6 @@ actfile[actstat.st_size] = '\0'; + if (acthash) + hashdestroy(acthash); acthash = hashcreate((int)(actstat.st_size/40), (int (*)())NULL); @@ -118,5 +122,4 @@ { register ACT_POS retval; - extern int debug; /* see if we know the right place and can just return */ @@ -296,5 +299,4 @@ if (ngn > 9) ngn = 9; /* Since we're using single digits.... */ - *options = '\0'; for (i = 0; i < ngn; i++) { char *cp = index(ngptrs[i], ' '); @@ -303,17 +305,18 @@ sprintf(op++, "%d", i+1); /* Expensive, but avoids ASCII deps */ *cp = ' '; - } /* for */ + } + *op++ = 'n'; + *op = '\0'; #ifdef VERBOSE IF(verbose) - sprintf(promptbuf, "Which of these would you like? [%sn] ", options); + sprintf(promptbuf, "Which of these would you like?"); ELSE #endif #ifdef TERSE - sprintf(promptbuf, "Which? [%sn] ", options); + sprintf(promptbuf, "Which?"); #endif reask: - in_char(promptbuf, 'A'); - setdef(buf, "1"); + in_char(promptbuf, 'A', options); #ifdef VERIFY printcmd(); Index:ngstuff.c @@ -231,5 +231,4 @@ char *cmdstr; int len, ret = 1; - int subj_mask = (sel_mode == SM_THREAD? (SF_THREAD|SF_VISIT) : SF_VISIT); if (!finish_command(TRUE)) /* get rest of command */ @@ -249,20 +248,18 @@ && (((*cmdstr == '+' || *cmdstr == '-') && cmdstr[0] == cmdstr[1]) || *cmdstr == 'T'))) { - for (sp = first_subject; sp; sp = sp->next) { - if ((sp->flags & subj_mask) == subj_mask) { - artp = first_art(sp); - if (artp) { - art = article_num(artp); - if (perform(cmdstr, FALSE)) { - fputs("\nInterrupted\n", stdout) FLUSH; - goto break_out; - } + for (sp = next_subj(Nullsubj,SF_VISIT); sp; sp = next_subj(sp,SF_VISIT)) { + artp = first_art(sp); + if (artp) { + art = article_num(artp); + if (perform(cmdstr, FALSE)) { + fputs("\nInterrupted\n", stdout) FLUSH; + goto break_out; } + } #ifdef VERBOSE - IF(verbose) - if (mode != 't' && *cmdstr != 't' && *cmdstr != 'T') - putchar('\n') FLUSH; + IF(verbose) + if (mode != 't' && *cmdstr != 't' && *cmdstr != 'T') + putchar('\n') FLUSH; #endif - } } } else if (strEQ(cmdstr, "E")) { @@ -288,16 +285,15 @@ } } else { - for (sp = first_subject; sp; sp = sp->next) - if ((sp->flags & subj_mask) == subj_mask) - for (ap = first_art(sp); ap; ap = next_art(ap)) - if ((!(ap->flags & AF_READ) ^ want_read) - && (ap->flags & sel_mask)) { - art = article_num(ap); - artp = ap; - if (perform(cmdstr, TRUE)) { - fputs("\nInterrupted\n", stdout) FLUSH; - goto break_out; - } + for (sp = next_subj(Nullsubj,SF_VISIT); sp; sp = next_subj(sp,SF_VISIT)) + for (ap = first_art(sp); ap; ap = next_art(ap)) + if ((!(ap->flags & AF_READ) ^ want_read) + && (ap->flags & sel_mask)) { + art = article_num(ap); + artp = ap; + if (perform(cmdstr, TRUE)) { + fputs("\nInterrupted\n", stdout) FLUSH; + goto break_out; } + } } } @@ -361,4 +357,14 @@ else kill_arts_subject(artp, saveit? (KF_ALL|KF_KILLFILE) : KF_ALL); + } else if (ch == 'x') { + if (!was_read(art)) { + oneless(artp); +#ifdef VERBOSE + IF(verbose) + fputs("\tKilled",stdout); +#endif + } + if (sel_rereading) + deselect_article(artp); } else if (ch == 't') { entire_tree(artp); Index:nntp.c @@ -70,4 +70,20 @@ } +/* check on an article's existence by its message id */ + +ART_NUM +nntp_stat_id(msgid) +char *msgid; +{ + long artnum; + + sprintf(ser_line, "STAT %s", msgid); + nntp_command(ser_line); + if (nntp_check(TRUE) != NNTP_CLASS_OK + || sscanf(ser_line, "%*d%ld", &artnum) != 1) + return 0; + return (ART_NUM)artnum; +} + /* prepare to get the header */ @@ -192,39 +208,4 @@ } -/* similar to nntp_gets, but will make the buffer bigger if necessary */ - -char * -nntp_get_a_line(original_buffer,buffer_length) -char *original_buffer; -register int buffer_length; -{ - register int bufix = 0; - register int nextch; - register char *some_buffer_or_other = original_buffer; - - do { - if (bufix >= buffer_length) { - buffer_length *= 2; - if (some_buffer_or_other == original_buffer) { - /* currently static? */ - some_buffer_or_other = safemalloc((MEM_SIZE)buffer_length+1); - strncpy(some_buffer_or_other,original_buffer,buffer_length/2); - /* so we must copy it */ - } - else { /* just grow in place, if possible */ - some_buffer_or_other = saferealloc(some_buffer_or_other, - (MEM_SIZE)buffer_length+1); - } - } - if ((nextch = getc(ser_rd_fp)) == EOF) - return Nullch; - some_buffer_or_other[bufix++] = (char) nextch; - } while (nextch && nextch != '\n'); - some_buffer_or_other[bufix] = '\0'; - len_last_line_got = bufix; - buflen_last_line_got = buffer_length; - return some_buffer_or_other; -} - char * nntp_artname() @@ -249,6 +230,8 @@ strcpy(last_command_save, last_command); nntp_close(FALSE); - if (!nntp_connect() || (in_ng && !nntp_group(ngname, -1))) - fatal_error("\n503 Server timed out.\n"); + if (!nntp_connect() || (in_ng && !nntp_group(ngname, -1))) { + nntp_error("\n503 Server timed out.\n"); + finalize(1); + } nntp_command(last_command_save); ch = nntp_check(strict); Index:nntp.h @@ -10,4 +10,5 @@ bool nntp_group _((char*,NG_NUM)); bool nntp_stat _((ART_NUM)); +ART_NUM nntp_stat_id _((char*)); bool nntp_header _((ART_NUM)); FILE *nntp_body _((ART_NUM)); @@ -15,5 +16,4 @@ bool nntp_newgroups _((time_t)); bool nntp_listgroup _((void)); -char *nntp_get_a_line _((char*, int)); char *nntp_artname _((void)); char nntp_handle_timeout _((bool_int)); Index:nntpclient.c @@ -14,4 +14,9 @@ #include "nntpclient.h" +void finalize _((int)); +#ifdef NNTP_HANDLE_TIMEOUT +char nntp_handle_timeout _((bool_int)); +#endif + #define CANTPOST \ "NOTE: This machine does not have permission to post articles.\n" @@ -46,5 +51,5 @@ Couldn't get name of news server from %s\n\ Either fix this file, or put NNTPSERVER in your environment.\n", SERVER_NAME); - report_error(ser_line); + nntp_init_error(ser_line); return 0; } @@ -56,17 +61,17 @@ char tmpbuf[LBUFLEN]; sprintf(tmpbuf,"News server %s unavailable: %s\n",server,&ser_line[4]); - report_error(tmpbuf); + nntp_init_error(tmpbuf); return 0; } case -1: sprintf(ser_line,"News server %s unavailable, try again later.\n",server); - report_error(ser_line); + nntp_init_error(ser_line); return 0; case NNTP_ACCESS_VAL: sprintf(ser_line,CANTUSE,server); - report_error(ser_line); + nntp_init_error(ser_line); return 0; case NNTP_NOPOSTOK_VAL: - advise(CANTPOST); + nntp_advise(CANTPOST); /* FALL THROUGH */ case NNTP_POSTOK_VAL: @@ -74,5 +79,5 @@ default: sprintf(ser_line,"Unknown response code %d from %s.\n", response, server); - report_error(ser_line); + nntp_init_error(ser_line); return 0; } @@ -80,5 +85,7 @@ } +#ifdef NNTP_HANDLE_TIMEOUT char last_command[NNTP_STRLEN]; +#endif void @@ -90,9 +97,15 @@ printf(">%s\n", buf) FLUSH; #endif +#ifdef NNTP_HANDLE_TIMEOUT strcpy(last_command, buf); +#endif fprintf(ser_wr_fp, "%s\r\n", buf); fflush(ser_wr_fp); } +#ifdef NNTP_HANDLE_TIMEOUT +extern char *instr(); +#endif + char nntp_check(strict) @@ -108,10 +121,13 @@ sigrelse(SIGINT); #endif - if (n < 0) -#ifdef fatal_error - fatal_error("\nUnexpected close of server socket.\n"); + if (n < 0) { + nntp_close(FALSE); + nntp_error("\nUnexpected close of server socket.\n"); +#ifdef NNTP_ERROR_IS_FATAL + finalize(1); #else return NNTP_CLASS_FATAL; #endif + } n = strlen(ser_line); if (n >= 2 && ser_line[n-1] == '\n' && ser_line[n-2] == '\r') @@ -121,15 +137,18 @@ printf("<%s\n", ser_line) FLUSH; #endif +#ifdef NNTP_HANDLE_TIMEOUT if (atoi(ser_line) == NNTP_TMPERR_VAL && instr(ser_line,"timeout",FALSE)) { /* See if this was really a timeout */ return nntp_handle_timeout(strict); } -#ifdef fatal_error +#endif if (strict && *ser_line == NNTP_CLASS_FATAL) { /* Fatal error */ char tmpbuf[LBUFLEN]; sprintf(tmpbuf,"\n%s\n",ser_line); - fatal_error(tmpbuf); - } + nntp_error(tmpbuf); +#ifdef NNTP_ERROR_IS_FATAL + finalize(1); #endif + } return *ser_line; } @@ -149,10 +168,13 @@ sigrelse(SIGINT); #endif - if (n < 0) -#ifdef fatal_error - fatal_error("\nUnexpected close of server socket.\n"); + if (n < 0) { + nntp_close(FALSE); + nntp_error("\nUnexpected close of server socket.\n"); +#ifdef NNTP_ERROR_IS_FATAL + finalize(1); #else return -1; #endif + } n = strlen(buf); if (n >= 2 && buf[n-1] == '\n' && buf[n-2] == '\r') @@ -165,9 +187,10 @@ bool_int send_quit; { + if (send_quit && ser_wr_fp != NULL && ser_rd_fp != NULL) { + nntp_command("QUIT"); + nntp_check(FALSE); + } + /* the nntp_check() above might have closed these already. */ if (ser_wr_fp != NULL && ser_rd_fp != NULL) { - if (send_quit) { - nntp_command("QUIT"); - nntp_check(FALSE); - } fclose(ser_wr_fp); ser_wr_fp = NULL; Index:nntpclient.h @@ -18,4 +18,6 @@ #define NNTP_LIST_END(s) ((s)[0]=='.' && ((s)[1]=='\0' || (s)[1]=='\r')) +#define nntp_get_a_line(buf,len,realloc) get_a_line(buf,len,realloc,ser_rd_fp) + /* RFC 977 defines these, so don't change them */ Index:nntplist.c @@ -0,0 +1,141 @@ +/* $Id: nntplist.c,v 3.5 1993/04/18 20:18:23 davison Trn $ + */ +/* This software is Copyright 1991 by Stan Barber. + * + * Permission is hereby granted to copy, reproduce, redistribute or otherwise + * use this software as long as: there is no monetary profit gained + * specifically from the use or reproduction of this software, it is not + * sold, rented, traded or otherwise marketed, and this copyright notice is + * included prominently in any copy made. + * + * The authors make no claims as to the fitness or correctness of this software + * for any use whatsoever, and it is provided as is. Any use of this software + * is at the user's own risk. + */ + +#include "EXTERN.h" +#include "common.h" +#include "nntpclient.h" + +void finalize _((int)); +char nntp_handle_timeout _((bool_int)); + +int debug = 0; /* make nntpclient.c happy */ + +int +main(argc, argv) +int argc; +char *argv[]; +{ + char command[32]; + char *action; + register FILE *actfp; + + if (argc < 2 || argc > 3) { + fprintf(stderr, "Usage: nntplist [active|distributions|newsgroups|subscriptions] filename\n"); + exit(1); + } + if (argc == 2) + action = "ACTIVE"; + else { + action = argv[1]; + argc--; + argv++; + } + if (!nntp_connect()) + exit(1); + sprintf(command,"LIST %s",action); + nntp_command(command); +#ifdef HAS_SIGHOLD + sighold(SIGINT); +#endif + if (nntp_check(FALSE) != NNTP_CLASS_OK) { + fprintf(stderr,"nntplist: Can't get %s file from server.\n",action); + fprintf(stderr, "Server said: %s\n", ser_line); + finalize(1); + } + + actfp = fopen(argv[1], "w"); + if (actfp == NULL) { + perror(argv[1]); + finalize(1); + } + + while (nntp_gets(ser_line, sizeof ser_line) >= 0) { + if (NNTP_LIST_END(ser_line)) /* while there's another line */ + break; /* get it and write it to */ + if (actfp != NULL) { /* the temporary active file */ + fputs(ser_line, actfp); + putc('\n', actfp); + } + } + + if (ferror(actfp)) { + perror(argv[1]); + finalize(1); + } + if (fclose(actfp) == EOF) { + perror(argv[1]); + finalize(1); + } + +#ifdef HAS_SIGHOLD + sigrelse(SIGINT); +#endif + nntp_close(TRUE); + return 0; +} + +/* return ptr to little string in big string, NULL if not found */ + +char * +instr(big, little, case_matters) +char *big, *little; +bool_int case_matters; +{ + register char *t, *s, *x; + + for (t = big; *t; t++) { + for (x=t,s=little; *s; x++,s++) { + if (!*x) + return Nullch; + if (case_matters == TRUE) { + if(*s != *x) + break; + } else { + register char c,d; + if (isupper(*s)) + c = tolower(*s); + else + c = *s; + if (isupper(*x)) + d = tolower(*x); + else + d = *x; + if ( c != d ) + break; + } + } + if (!*s) + return t; + } + return Nullch; +} + +void +finalize(num) +int num; +{ + nntp_close(TRUE); + exit(num); +} + +char +nntp_handle_timeout(strict) +bool_int strict; +{ + nntp_error("\n503 Server timed out.\n"); + if (strict) + finalize(1); + return NNTP_CLASS_FATAL; +} Index:overview.h @@ -41,3 +41,3 @@ /* How many overview lines to read with one NNTP call */ -#define OV_CHUNK_SIZE 100 +#define OV_CHUNK_SIZE 40 Index:rcstuff.c @@ -56,19 +56,12 @@ char *some_buf; long length; -#ifdef USE_NNTP - char *cp; -#endif /* make filenames */ #ifdef USE_NNTP - if (cp = getenv("NEWSRC")) - rcname = savestr(filexp(cp)); - else - rcname = savestr(filexp(RCNAME)); -#else - rcname = savestr(filexp(RCNAME)); + if (getenv("NEWSRC")) + printf("NEWSRC environment variable ignored -- use DOTDIR to set the directory.\n") FLUSH; #endif - + rcname = savestr(filexp(RCNAME)); rctname = savestr(filexp(RCTNAME)); rcbname = savestr(filexp(RCBNAME)); @@ -91,5 +84,5 @@ for (nextrcline = 0; - (some_buf = get_a_line(buf,LBUFLEN,rcfp)) != Nullch; + (some_buf = get_a_line(buf,LBUFLEN,FALSE,rcfp)) != Nullch; nextrcline++) /* for each line in .newsrc */ { @@ -238,5 +231,5 @@ int length = rcnums[ngnum] - 1; - while ((some_buf = get_a_line(buf,LBUFLEN,rcfp)) != Nullch) { + while ((some_buf = get_a_line(buf,LBUFLEN,FALSE,rcfp)) != Nullch) { if (len_last_line_got <= 0) continue; @@ -306,4 +299,5 @@ check_fuzzy_match: if (fuzzyGet && (flags & GNG_FUZZY)) { + flags &= ~GNG_FUZZY; if (find_close_match()) what = ngname; @@ -318,11 +312,5 @@ if (ng >= maxrcline) /* check for overflow */ grow_rc_arrays(maxrcline + 25); -#ifdef USE_NNTP - softptr[ng] = 0; - if (!nntp_group(ngname,ng)) -#else /* !USE_NNTP */ - if ((softptr[ng] = findact(buf,ngname,strlen(ngname),0L)) < 0) -#endif /* !USE_NNTP */ - { + if ((softptr[ng] = findact(buf,ngname,strlen(ngname),0L)) < 0) { dingaling(); #ifdef VERBOSE @@ -358,13 +346,12 @@ #ifdef VERBOSE IF(verbose) - sprintf(promptbuf,"\nNewsgroup %s not in .newsrc -- subscribe? [ynYN] ",ngname); + sprintf(promptbuf,"\nNewsgroup %s not in .newsrc -- subscribe?",ngname); ELSE #endif #ifdef TERSE - sprintf(promptbuf,"\nSubscribe %s? [ynYN] ",ngname); + sprintf(promptbuf,"\nSubscribe %s?",ngname); #endif reask_add: - in_char(promptbuf,'A'); - setdef(buf,"y"); + in_char(promptbuf,'A',"ynYN"); #ifdef VERIFY printcmd(); @@ -431,15 +418,14 @@ IF(verbose) sprintf(promptbuf, -"\nNewsgroup %s is unsubscribed -- resubscribe? [yn] ",ngname) +"\nNewsgroup %s is unsubscribed -- resubscribe?",ngname) FLUSH; ELSE #endif #ifdef TERSE - sprintf(promptbuf,"\nResubscribe %s? [yn] ",ngname) + sprintf(promptbuf,"\nResubscribe %s?",ngname) FLUSH; #endif reask_unsub: - in_char(promptbuf,'R'); - setdef(buf,"y"); + in_char(promptbuf,'R',"yn"); #ifdef VERIFY printcmd(); @@ -807,6 +793,5 @@ #ifdef DELBOGUS reask_bogus: - in_char("Delete bogus newsgroups? [ny] ", 'D'); - setdef(buf,"n"); + in_char("Delete bogus newsgroups?", 'D', "ny"); #ifdef VERIFY printcmd(); @@ -932,4 +917,15 @@ } else { + /* File exists; if zero length and backup isn't, complain */ + if (fstat(fileno(rcfp),&filestat) < 0) { + perror(rcname); + finalize(1); + } + if (filestat.st_size == 0 + && stat(rcbname,&filestat) >= 0 && filestat.st_size > 0) { + printf("Warning: %s is zero length but %s is not.\n",rcname,rcbname); + printf("Either recover your newsrc or else remove the backup copy.\n"); + finalize(1); + } UNLINK(rcbname); /* unlink backup file name */ safelink(rcname,rcbname); /* and backup current name */ Index:respond.c @@ -27,4 +27,5 @@ #include "final.h" #include "decode.h" +#include "charsubst.h" #include "INTERN.h" #include "respond.h" @@ -55,5 +56,5 @@ cmd = tolower(cmd); parseheader(art); -#ifdef MIME_SUPPORT +#ifdef MIMESTORE savefrom = (!mime_article && (cmd == 'w' || cmd == 'e')) #else @@ -167,5 +168,5 @@ if (*art_buf <= ' ') continue; /* Ignore empty or initially-whitespace lines */ -#ifdef MIME_SUPPORT +#ifdef MIMESTORE if (mime_article) { char oldmode = mode; @@ -343,6 +344,5 @@ } for (iter = 0; - (there = stat(s,&filestat) >= 0) && - (filestat.st_mode & S_IFDIR); + (there = stat(s,&filestat) >= 0) && S_ISDIR(filestat.st_mode); iter++) { /* is it a directory? */ @@ -372,10 +372,8 @@ sprintf(cmd_buf, - "\nFile %s doesn't exist--\n use mailbox format? [%s] ", - s,dflt); + "\nFile %s doesn't exist--\n use mailbox format?",s); reask_save: - in_char(cmd_buf, 'M'); + in_char(cmd_buf, 'M', dflt); putchar('\n') FLUSH; - setdef(buf,dflt); #ifdef VERIFY printcmd(); @@ -416,5 +414,5 @@ } } - else if (filestat.st_mode & S_IFCHR) + else if (S_ISCHR(filestat.st_mode)) mailbox = FALSE; else { @@ -484,5 +482,5 @@ IF(verbose) fputs("\n\ -Cancelling null articles is your idea of fun? :-)\n\ +Canceling null articles is your idea of fun? :-)\n\ ",stdout) FLUSH; ELSE @@ -615,5 +613,8 @@ { bool incl_body = (*buf == 'R'); - char *maildoer = savestr(filexp(getval("MAILPOSTER",MAILPOSTER))); +#ifdef CHARSUBST + char hbuf[4*LBUFLEN]; +#endif + char *maildoer = savestr(getval("MAILPOSTER",MAILPOSTER)); artopen(art); @@ -641,10 +642,15 @@ fseek(artfp,(long)htype[PAST_HEADER].ht_minpos,0); while (fgets(buf,LBUFLEN,artfp) != Nullch) { +#ifdef CHARSUBST + strcharsubst(buf,hbuf); + fprintf(tmpfp,"%s%s",indstr,hbuf); +#else fprintf(tmpfp,"%s%s",indstr,buf); +#endif } fprintf(tmpfp,"\n"); } fclose(tmpfp); - interp(cmd_buf, (sizeof cmd_buf), maildoer); + safecpy(cmd_buf,filexp(maildoer),sizeof cmd_buf); invoke(cmd_buf,origdir); UNLINK(headname); /* kill the header file */ @@ -652,4 +658,56 @@ free(maildoer); } + +void +forward() +{ +#ifdef CHARSUBST + char hbuf[4*LBUFLEN]; +#endif + char *maildoer = savestr(getval("FORWARDPOSTER",FORWARDPOSTER)); + + artopen(art); + tmpfp = fopen(headname,"w"); /* open header file */ + if (tmpfp == Nullfp) { + printf(cantcreate,headname) FLUSH; + goto no_forward; + } + interp(buf, (sizeof buf), getval("FORWARDHEADER",FORWARDHEADER)); + fputs(buf,tmpfp); + if (!instr(maildoer,"%h",TRUE)) +#ifdef VERBOSE + IF(verbose) + printf("\n%s\n(Above lines saved in file %s)\n",buf,headname) + FLUSH; + ELSE +#endif +#ifdef TERSE + printf("\n%s\n(Header in %s)\n",buf,headname) FLUSH; +#endif + if (artfp != Nullfp) { + interp(buf, (sizeof buf), getval("FORWARDMSG",FORWARDMSG)); + if (*buf) + fprintf(tmpfp,"%s\n",buf); + parseheader(art); + fseek(artfp,0L,0); + while (fgets(buf,LBUFLEN,artfp) != Nullch) { +#ifdef CHARSUBST + strcharsubst(buf,hbuf); + fprintf(tmpfp,"%s",hbuf); +#else + fprintf(tmpfp,"%s",buf); +#endif + } + interp(buf, (sizeof buf), getval("FORWARDMSGEND",FORWARDMSGEND)); + if (*buf) + fprintf(tmpfp,"%s\n",buf); + } + fclose(tmpfp); + safecpy(cmd_buf,filexp(maildoer),sizeof cmd_buf); + invoke(cmd_buf,origdir); + UNLINK(headname); /* kill the header file */ +no_forward: + free(maildoer); +} void @@ -690,5 +748,10 @@ fseek(artfp,(long)htype[PAST_HEADER].ht_minpos,0); while (fgets(buf,LBUFLEN,artfp) != Nullch) { +#ifdef CHARSUBST + strcharsubst(buf,hbuf); + fprintf(tmpfp,"%s%s",indstr,hbuf); +#else fprintf(tmpfp,"%s%s",indstr,buf); +#endif } fprintf(tmpfp,"\n"); @@ -714,11 +777,15 @@ #ifdef VERBOSE IF(verbose) - printf("\n(leaving cbreak mode; cwd=%s)\nInvoking command: %s\n\n", - dir,cmd) FLUSH; + printf("\n(leaving cbreak mode; cwd=%s)",dir); ELSE #endif #ifdef TERSE - printf("\n(-cbreak; cwd=%s)\nInvoking: %s\n\n",dir,cmd) FLUSH; + printf("\n(-cbreak; cwd=%s)",dir); +#endif +#ifdef DEBUG + if (debug) + printf("\nInvoking command: %s",cmd); #endif + printf("\n\n") FLUSH; resetty(); /* make terminal well-behaved */ doshell(sh,cmd); /* do the command */ Index:respond.h @@ -28,4 +28,5 @@ int supersede_article _((void)); void reply _((void)); +void forward _((void)); void followup _((void)); void invoke _((char*,char*)); Index:rt-mt.c @@ -344,5 +344,4 @@ if (i) subj_ptr[0]->thread_link = subj_ptr[1]; - subj_ptr[0]->flags &= ~SF_THREAD; uni.num = p_root.articles; (*subj_ptr++)->thread = uni.ap; @@ -587,5 +586,4 @@ uni.ap = sp->thread; sp->thread = article_array[uni.num]; - sp->thread->subj->flags |= SF_THREAD; } art_ptr = article_array; @@ -600,4 +598,9 @@ ap->sibling = article_array[uni.num-1]; } + } + + art_ptr = article_array; + for (count = total.article; count--; ) { + ap = *art_ptr++; if (!(ap->flags & AF_MISSING)) cache_article(ap); Index:rt-ov.c @@ -53,7 +53,5 @@ # endif #endif -#ifdef USE_XOVER -ART_NUM ov_next_art; -#else +#ifndef USE_XOVER FILE *ov_in; #endif @@ -77,10 +75,12 @@ setspin(cheating? SPIN_BACKGROUND : SPIN_FOREGROUND); beginning: - if (ov_opened) - first = ov_next_art; - if (last < first) + for (ap = article_ptr(first); first <= last && (ap->flags & AF_CACHED); ) + first++, ap++; + if (first > last) goto exit; if (last - first > OV_CHUNK_SIZE + OV_CHUNK_SIZE/2 - 1) last = first + OV_CHUNK_SIZE - 1; + for (ap = article_ptr(last); last > first && (ap->flags & AF_CACHED); ) + last--, ap--; sprintf(ser_line, "XOVER %ld-%ld", (long)first, (long)last); nntp_command(ser_line); @@ -94,5 +94,4 @@ printf("\nGetting overview file."), fflush(stdout); #endif - ov_next_art = last+1; #else /* !USE_XOVER */ @@ -114,9 +113,10 @@ for (;;) { #ifdef USE_XOVER - line = nntp_get_a_line(last_buf, last_buflen); - if (NNTP_LIST_END(line)) + line = nntp_get_a_line(last_buf, last_buflen, last_buf != buf); + if (!line || NNTP_LIST_END(line)) break; #else - if (!(line = get_a_line(last_buf, last_buflen, ov_in))) + line = get_a_line(last_buf, last_buflen, last_buf != buf, ov_in); + if (!line) break; #endif @@ -127,10 +127,12 @@ if (artnum < first) continue; -#ifndef USE_XOVER if (artnum > last) { artnum = last; +#ifdef USE_XOVER + continue; +#else break; - } #endif + } if ((ap = ov_parse(line, artnum)) != Nullart) { #ifndef OV_XREFS @@ -179,5 +181,10 @@ } cachemask = (ThreadedGroup? AF_THREADED : AF_CACHED); - for (an = first, ap = article_ptr(an); an <= artnum; an++, ap++) { +#ifdef USE_XOVER + an = real_first; +#else + an = first; +#endif + for (ap = article_ptr(an); an <= artnum; an++, ap++) { if (!(ap->flags & cachemask)) { #ifdef USE_NNTP @@ -191,4 +198,5 @@ last_cached = artnum; #ifdef USE_XOVER + exit: if (int_count || !success) { int_count = 0; @@ -199,15 +207,14 @@ } else if (last < real_last) { if (!cheating || !input_pending()) { + first = last+1; last = real_last; goto beginning; } success = FALSE; - } else - ov_next_art = absfirst; + } if (success && real_first <= first_cached) { first_cached = real_first; cached_all_in_range = TRUE; } - exit: #else if (success && first <= first_cached) { @@ -238,8 +245,13 @@ if (len_last_line_got > 0 && line[len_last_line_got-1] == '\n') - line[len_last_line_got-1] = '\0'; +#ifdef USE_NNTP + if (len_last_line_got > 1 && line[len_last_line_got-2] == '\r') + line[len_last_line_got-2] = '\0'; + else +#endif + line[len_last_line_got-1] = '\0'; cp = line; - + for (nf = 0; ; nf++) { fields[nf] = cp; Index:rt-page.c @@ -144,6 +144,20 @@ } +void sel_page_init() +{ + sel_chars = getval("SELECTCHARS", SELECTCHARS); + sel_max_cnt = strlen(sel_chars); + if (sel_max_cnt > MAX_SEL) + sel_max_cnt = MAX_SEL; + if (sel_max_cnt > LINES-5) + sel_max_cnt = LINES-5; + sel_line = 2; + sel_page_arts = 0; + sel_item_cnt = 0; +} + void -init_pages() +init_pages(fill_last_page) +bool_int fill_last_page; { try_again: @@ -203,4 +217,17 @@ else if (sel_page_app >= limit) (void) last_page(); + else if (sel_prior_arts && fill_last_page) { + sel_page_init(); + app = sel_page_app; + do { + if (!((*app)->flags & AF_INCLUDED)) + continue; + sel_page_arts++; + sel_item_cnt++; + } while (++app < limit && sel_item_cnt < sel_max_cnt); + if (sel_prior_arts + sel_page_arts == sel_total_arts) { + (void) last_page(); + } + } } else { SUBJECT *sp, *group_sp; @@ -255,4 +282,37 @@ else if (sel_page_sp == last_subject) (void) last_page(); + else if (sel_prior_arts && fill_last_page) { + int line_cnt, sel; + sel_page_init(); + sp = sel_page_sp; + do { + if (sp->flags & SF_INCLUDED) { + if (sel_mode == SM_THREAD) + line_cnt = count_thread_lines(sp, &sel); + else + line_cnt = count_subject_lines(sp, &sel); + if (line_cnt) { + if (line_cnt > LINES - 5) + line_cnt = LINES - 5; + if (sel_line + line_cnt > LINES - 3) + break; + sel_page_arts += sp->misc; + sel_item_cnt++; + } + } else + line_cnt = 0; + if (sel_mode == SM_THREAD) { + while (sp->next && sp->next->thread == sp->thread) { + sp = sp->next; + if (!line_cnt || !sp->misc) + continue; + sel_page_arts += sp->misc; + } + } + } while ((sp=sp->next)!=Nullsubj && sel_item_cnt MAX_SEL) - sel_max_cnt = MAX_SEL; - if (sel_max_cnt > LINES-5) - sel_max_cnt = LINES-5; -#ifndef CLEAREOL - clear(); -#else +#ifdef CLEAREOL if (can_home_clear) { home_cursor(); maybe_eol(); } else - clear(); #endif + clear(); carriage_return(); @@ -434,7 +486,5 @@ putchar('\n') FLUSH; try_again: - sel_line = 2; - sel_page_arts = 0; - sel_item_cnt = 0; + sel_page_init(); if (!sel_total_arts) Index:rt-page.h @@ -6,8 +6,11 @@ */ +#define PRESERVE_PAGE 0 +#define FILL_LAST_PAGE 1 + bool set_sel_mode _((char_int)); bool set_sel_sort _((char_int)); void set_selector _((int,int)); -void init_pages _((void)); +void init_pages _((bool_int)); bool first_page _((void)); bool last_page _((void)); Index:rt-process.c @@ -21,9 +21,10 @@ #include "rthread.h" #include "rt-select.h" +#include "INTERN.h" +#include "rt-process.h" extern HASHTABLE *msgid_hash; static char *valid_message_id _((char*, char*)); -static void merge_threads _((SUBJECT*, SUBJECT*)); static void link_child _((ARTICLE*)); static void unlink_child _((ARTICLE*)); @@ -198,6 +199,7 @@ register char *cp, *end; ARTICLE *kill_ap = ((article->flags & AF_AUTOKILL)? article : Nullart); - int select_this_art = article->flags + int art_chain_flags = article->flags | (article->subj->articles? article->subj->articles->flags : 0); + int art_thread_flags; /* We're definitely not a fake anymore */ @@ -208,13 +210,16 @@ */ if (fake_had_subj) { - if (fake_had_subj->thread != article->subj->thread) { - fake_had_subj->flags &= ~SF_THREAD; + ARTICLE *stopper; + if (fake_had_subj->thread != article->subj->thread) merge_threads(fake_had_subj, article->subj); - } /* Check for a real or shared-fake parent */ ap = article->parent; - while (ap && (ap->flags&AF_FAKE) == AF_FAKE && !ap->child1->sibling) + while (ap && (ap->flags&AF_FAKE) == AF_FAKE && !ap->child1->sibling) { + last = ap; ap = ap->parent; + } + stopper = ap; unlink_child(article); +#if 0 if (ap) { /* do we have decent parents? */ /* Yes: assume that our references are ok, and just reorder us @@ -234,9 +239,10 @@ goto exit; } +#endif /* We'll assume that this article has as good or better references ** than the child that faked us initially. Free the fake reference- ** chain and process our references as usual. */ - for (ap = article->parent; ap; ap = last) { + for (ap = article->parent; ap != stopper; ap = last) { unlink_child(ap); last = ap->parent; @@ -270,5 +276,5 @@ ap = get_article(cp); *cp = '\0'; - select_this_art |= ap->flags; + art_chain_flags |= ap->flags; if (ap->flags & AF_AUTOKILL) kill_ap = ap; @@ -338,15 +344,32 @@ link_child(article); } +#if 0 exit: +#endif if (!(article->flags & AF_CACHED)) cache_article(article); - if (select_this_art & AF_AUTOSELECTALL) { + art_thread_flags = art_chain_flags; + if (sel_mode == SM_THREAD && article == article->subj->articles) { + SUBJECT *sp = article->subj->thread_link; + while (sp != article->subj) { + if (sp->articles) + art_thread_flags |= sp->articles->flags; + sp = sp->thread_link; + } + } + if (art_thread_flags & AF_AUTOSELECTALL) { if (sel_mode == SM_THREAD) select_arts_thread(article, AF_AUTOSELECTALL); else select_arts_subject(article, AF_AUTOSELECTALL); - } else if (select_this_art & AF_AUTOSELECT) + } else if (art_chain_flags & AF_AUTOSELECT) select_subthread(article, AF_AUTOSELECT); - if (kill_ap) + if (art_thread_flags & AF_AUTOKILLALL) { + if (sel_mode == SM_THREAD) + kill_arts_thread(article, KF_ALL|KF_KILLFILE); + else + kill_arts_subject(article, KF_ALL|KF_KILLFILE); + } + else if (kill_ap) kill_subthread(kill_ap, KF_ALL|KF_KILLFILE); } @@ -451,5 +474,5 @@ /* Merge all of s2's thread into s1's thread. */ -static void +void merge_threads(s1, s2) SUBJECT *s1, *s2; @@ -457,18 +480,11 @@ register SUBJECT *sp; register ARTICLE *t1, *t2; - int visit_flag; t1 = s1->thread; t2 = s2->thread; - t1->subj->flags &= ~SF_THREAD; - if (sel_mode == SM_THREAD) - visit_flag = (t1->subj->flags | (t2? t2->subj->flags : 0)) & SF_VISIT; - else - visit_flag = 0; /* Change all of t2's thread pointers to a common lead article */ sp = s2; do { sp->thread = t1; - sp->flags &= ~SF_THREAD; sp = sp->thread_link; } while (sp != s2); @@ -479,4 +495,37 @@ s1->thread_link = sp; + /* If thread mode is set, ensure the subjects are adjacent in the list. */ + /* Don't do this if the selector is active, because it gets messed up. */ + if (sel_mode == SM_THREAD && mode != 't') { + for (sp = s2; sp->prev && sp->prev->thread == t1; ) { + sp = sp->prev; + if (sp == s1) + goto artlink; + } + while (s2->next && s2->next->thread == t1) { + s2 = s2->next; + if (s2 == s1) + goto artlink; + } + /* Unlink the s2 chunk of subjects from the list */ + if (!sp->prev) + first_subject = s2->next; + else + sp->prev->next = s2->next; + if (!s2->next) + last_subject = sp->prev; + else + s2->next->prev = sp->prev; + /* Link the s2 chunk after s1 */ + sp->prev = s1; + s2->next = s1->next; + if (!s1->next) + last_subject = s2; + else + s1->next->prev = s2; + s1->next = sp; + } + + artlink: /* Link each article that was attached to t2 to t1. */ for (t1 = t2; t1; t1 = t2) { @@ -484,4 +533,3 @@ link_child(t1); /* parent is null, thread is newly set */ } - s1->thread->subj->flags |= SF_THREAD | visit_flag; } Index:rt-process.h @@ -11,2 +11,3 @@ ARTICLE *get_article _((char*)); void thread_article _((ARTICLE*)); +void merge_threads _((SUBJECT*, SUBJECT*)); Index:rt-select.c @@ -37,4 +37,91 @@ static bool clean_screen; +/* CAA hacks: xterm mouse support */ +static char *sel_mouse_save; + +void +sel_go_line(line) +int line; +{ + int i; + + for (i = 0; i < sel_item_cnt; i++) { + if (sel_items[i].line > line) + break; + } + if (i > 0) + i--; + sel_item_index = i; +} + +void +sel_do_mouse(button,x,y) +int button; /* 0: button1 1: button2 2: button3 3: release */ +int x,y; +{ + switch (button) { + case 0: + case 1: + if (!y) + sel_mouse_save = "<"; + else if (y >= sel_last_line) + sel_mouse_save = (button == 0)? " " : ">"; + else { + sel_go_line(y); + if (button == 0) + sel_mouse_save = "."; + } + break; + case 2: + /* move forward or backwards a page: + * if cursor in top half: backwards + * if cursor in bottom half: forwards + */ + if (y<(LINES/2)) + sel_mouse_save = "<"; + else + sel_mouse_save = ">"; + break; + case 3: + /* do range stuff here later? */ + break; + } +} + +void +sel_mouse() +{ + int x,y; + int button; + + sel_mouse_save = Nullch; + read_tty(buf,1); + button = (int)(buf[0]); + read_tty(buf,1); + x = (int)(buf[0])-33; + read_tty(buf,1); + y = (int)(buf[0])-33; + sel_do_mouse(button&3,x,y); + + /* get the button-up event */ + while (1) { + getcmd(buf); + if (*buf == 3) /* got the button-up */ + break; + /* otherwise just eat any other keystrokes */ + } + + /* interpret the button-up event */ + read_tty(buf,1); + button = (int)(buf[0]); + read_tty(buf,1); + x = (int)(buf[0])-33; + read_tty(buf,1); + y = (int)(buf[0])-33; + sel_do_mouse(button&3,x,y); + if (sel_mouse_save) + pushstring(sel_mouse_save,0); +} + /* Display a menu of threads/subjects/articles for the user to choose from. ** If "cmd" is '+' we display all the unread items and allow the user to mark @@ -61,4 +148,5 @@ set_sel_mode(cmd); + xmouse_on(); if (!cache_range(sel_rereading? absfirst : firstart, lastart)) { @@ -93,5 +181,5 @@ goto sel_exit; } - init_pages(); + init_pages(FILL_LAST_PAGE); sel_item_index = 0; *promptbuf = '\0'; @@ -181,4 +269,6 @@ #ifdef CONDSUB getcmd(buf); + if (*buf == ' ') + setdef(buf, sel_at_end? &end_char : &page_char); ch = *buf; #else @@ -197,4 +287,9 @@ disp_status_line = FALSE; } +/* CAA: hack for mouse support */ + if (ch == Ctl('c')) { + sel_mouse(); + goto position_selector; + } if (ch == '-') { got_dash = 1; @@ -203,10 +298,4 @@ goto reinp_selector; } - if (ch == ' ') { - if (sel_at_end) - ch = end_char; - else - ch = page_char; - } in_select = index(sel_chars, ch); if (in_select) { @@ -423,5 +512,4 @@ srchahead = 0; #endif -/* selected_only = (selected_count || !article_count);*/ selected_only = (selected_count != 0); if (sel_ret != '#') @@ -434,4 +522,5 @@ } else top_article(); + xmouse_off(); return sel_ret; } @@ -507,5 +596,5 @@ case Ctl('l'): return DS_DISPLAY; - case Ctl('f'): + case Ctl('^'): erase_eol(); /* erase the prompt */ #ifdef MAILCALL @@ -580,5 +669,5 @@ sel_page_sp = Nullsubj; sel_page_app = Null(ARTICLE**); - init_pages(); + init_pages(PRESERVE_PAGE); return DS_DISPLAY; case 'U': @@ -603,5 +692,5 @@ count_subjects(CS_NORM); sel_item_index = 0; - init_pages(); + init_pages(FILL_LAST_PAGE); return DS_DISPLAY; case 'S': @@ -610,6 +699,5 @@ erase_eol(); /* erase the prompt */ reask_output: - in_char("Selector mode: Threads, Subjects, Articles? [tsa] ", 'o'); - setdef(buf,"t"); + in_char("Selector mode: Threads, Subjects, Articles?", 'o', "tsa"); #ifdef VERIFY printcmd(); @@ -645,5 +733,5 @@ set_sel_mode(*buf); count_subjects(CS_NORM); - init_pages(); + init_pages(FILL_LAST_PAGE); return DS_DISPLAY; case 'O': @@ -653,9 +741,8 @@ reask_sort: if (sel_mode == SM_ARTICLE) - in_char("Order by Date, Subject, Author, subject-date Groups? [dsagDSAG] ", - 'q'); + in_char("Order by Date, Subject, Author, subject-date Groups?", + 'q', "dsagDSAG"); else - in_char("Order by Date, Subject, or Count? [dscDSC] ", 'q'); - setdef(buf,"d"); + in_char("Order by Date, Subject, or Count?", 'q', "dscDSC"); #ifdef VERIFY printcmd(); @@ -718,5 +805,5 @@ sel_page_sp = Nullsubj; sel_page_app = Null(ARTICLE**); - init_pages(); + init_pages(FILL_LAST_PAGE); return DS_DISPLAY; case 'R': @@ -727,5 +814,5 @@ sel_page_sp = Nullsubj; sel_page_app = Null(ARTICLE**); - init_pages(); + init_pages(FILL_LAST_PAGE); return DS_DISPLAY; case 'E': @@ -736,5 +823,5 @@ sel_page_sp = Nullsubj; sel_page_app = Null(ARTICLE**); - init_pages(); + init_pages(FILL_LAST_PAGE); empty_ok = TRUE; return DS_DISPLAY; @@ -778,5 +865,5 @@ if (article_count && (ch == 'J' || (ch == 'D' && !selected_count))) { - init_pages(); + init_pages(FILL_LAST_PAGE); sel_item_index = 0; return DS_DISPLAY; @@ -807,5 +894,5 @@ if (sel_mode == SM_THREAD) { while (!sp->misc) - sp = sp->next; + sp = sp->thread_link; } artp = sp->articles; @@ -816,5 +903,5 @@ case 'j': case ',': count_subjects(sel_rereading ? CS_NORM : CS_UNSELECT); - init_pages(); + init_pages(PRESERVE_PAGE); sprintf(buf,"Kill memorized."); disp_status_line = TRUE; @@ -843,5 +930,7 @@ return DS_ASK; case Ctl('k'): + xmouse_off(); edit_kfile(); + xmouse_on(); return DS_DISPLAY; case ':': case '/': case '&': case '!': @@ -853,4 +942,5 @@ } if (ch == '&' || ch == '!') { + xmouse_off(); one_command = TRUE; perform(buf, FALSE); @@ -858,4 +948,5 @@ putchar('\n') FLUSH; clean_screen = FALSE; + xmouse_on(); } else { int sel_art_save = selected_count; @@ -901,5 +992,5 @@ /* Recount, in case something has changed. */ count_subjects(sel_rereading ? CS_NORM : CS_UNSELECT); - init_pages(); + init_pages(PRESERVE_PAGE); sel_item_index = 0; @@ -949,5 +1040,5 @@ sel_page_sp = Nullsubj; sel_page_app = Null(ARTICLE**); - init_pages(); + init_pages(FILL_LAST_PAGE); return DS_DISPLAY; } Index:rt-util.c @@ -538,5 +538,5 @@ case SPIN_BACKGROUND: if (!spin_level++) { - if ((spin_art = openart) != 0) + if ((spin_art = openart) != 0 && artfp) spin_tell = ftell(artfp); spin_count = 1; /* not 0 to prevent immediate spin display */ @@ -559,5 +559,6 @@ if (spin_art) { artopen(spin_art); - fseek(artfp,spin_tell,0); /* do not screw up the pager */ + if (artfp) + fseek(artfp,spin_tell,0); /* do not screw up the pager */ spin_art = 0; } Index:rthread.c @@ -18,4 +18,5 @@ #include "rcstuff.h" #include "ngdata.h" +#include "final.h" #include "kfile.h" #include "head.h" @@ -201,6 +202,5 @@ { register ARTICLE *ap = artp; - int subj_mask = (sel_mode == SM_THREAD? SF_THREAD : 0) - | (rereading? 0 : SF_VISIT); + int subj_mask = (rereading? 0 : SF_VISIT); /* Use the explicit article-order if it exists */ @@ -238,10 +238,7 @@ sp = ap->subj; else - for (sp = first_subject; sp && (sp->flags&subj_mask) != subj_mask;) - sp = sp->next; + sp = next_subj(Nullsubj, subj_mask); if (!sp) goto num_inc; - if (sel_mode == SM_THREAD && sp->thread) - sp = sp->thread->subj; do { if (ap) @@ -250,7 +247,5 @@ ap = first_art(sp); while (!ap) { - while ((sp = sp->next) != Nullsubj - && (sp->flags & subj_mask) != subj_mask) - ; + sp = next_subj(sp, subj_mask); if (!sp) break; @@ -301,6 +296,5 @@ { register ARTICLE *ap = artp; - int subj_mask = (sel_mode == SM_THREAD? SF_THREAD : 0) - | (rereading? 0 : SF_VISIT); + int subj_mask = (rereading? 0 : SF_VISIT); /* Use the explicit article-order if it exists */ @@ -332,10 +326,7 @@ sp = ap->subj; else - for (sp = last_subject; sp && (sp->flags&subj_mask) != subj_mask;) - sp = sp->prev; + sp = prev_subj(Nullsubj, subj_mask); if (!sp) goto num_dec; - if (sel_mode == SM_THREAD && sp->thread) - sp = sp->thread->subj; do { if (ap) @@ -344,7 +335,5 @@ ap = last_art(sp); while (!ap) { - while ((sp = sp->prev) != Nullsubj - && (sp->flags & subj_mask) != subj_mask) - ; + sp = prev_subj(sp, subj_mask); if (!sp) break; @@ -530,4 +519,48 @@ } +SUBJECT * +next_subj(sp, subj_mask) +register SUBJECT *sp; +int subj_mask; +{ + if (!sp) + sp = first_subject; + else if (sel_mode == SM_THREAD) { + ARTICLE *ap = sp->thread; + do { + sp = sp->next; + } while (sp && sp->thread == ap); + } + else + sp = sp->next; + + while (sp && (sp->flags & subj_mask) != subj_mask) { + sp = sp->next; + } + return sp; +} + +SUBJECT * +prev_subj(sp, subj_mask) +register SUBJECT *sp; +int subj_mask; +{ + if (!sp) + sp = last_subject; + else if (sel_mode == SM_THREAD) { + ARTICLE *ap = sp->thread; + do { + sp = sp->prev; + } while (sp && sp->thread == ap); + } + else + sp = sp->prev; + + while (sp && (sp->flags & subj_mask) != subj_mask) { + sp = sp->prev; + } + return sp; +} + /* Select a single article. */ @@ -568,8 +601,4 @@ selected_subj_cnt++; ap->subj->flags = (ap->subj->flags&~SF_DEL) | sel_mask | SF_VISIT; - if (sel_mode == SM_THREAD) { - if ((ap = ap->subj->thread) != NULL) - ap->subj->flags |= SF_VISIT; - } } selected_only = (selected_only || selected_count != 0); @@ -614,8 +643,4 @@ subj->flags = (subj->flags & ~SF_DEL) | sel_mask | SF_VISIT | SF_WASSELECTED; - if (sel_mode == SM_THREAD) { - if ((ap = subj->thread) != NULL) - ap->subj->flags |= SF_VISIT; - } selected_only = TRUE; } else @@ -687,8 +712,4 @@ selected_subj_cnt++; subj->flags = (subj->flags & ~SF_DEL) | sel_mask | SF_VISIT; - if (sel_mode == SM_THREAD) { - if ((ap = subj->thread) != NULL) - ap->subj->flags |= SF_VISIT; - } selected_only = TRUE; } @@ -803,4 +824,5 @@ kill_arts_subject(ap, kill_flags) register ARTICLE *ap; +int kill_flags; { if (ap->subj && ap->subj->articles) @@ -840,4 +862,5 @@ kill_arts_thread(ap, kill_flags) register ARTICLE *ap; +int kill_flags; { if (ap->subj && ap->subj->thread) @@ -920,8 +943,4 @@ if (!sel_rereading && selected_only && !(subj->flags & SF_SEL)) { subj->flags |= SF_SEL | SF_VISIT | SF_WASSELECTED; - if (sel_mode == SM_THREAD) { - if ((ap = subj->thread) != NULL) - ap->subj->flags |= SF_VISIT; - } selected_subj_cnt++; } @@ -974,8 +993,4 @@ selected_subj_cnt++; sp->flags = (sp->flags & ~SF_DEL) | SF_SEL | SF_VISIT; - if (sel_mode == SM_THREAD) { - if ((ap = sp->thread) != NULL) - ap->subj->flags |= SF_VISIT; - } selected_only = (selected_only || selected_count != 0); } @@ -1063,20 +1078,17 @@ */ void -next_subject() +visit_next_thread() { register SUBJECT *sp; - register ARTICLE *ap; - int subj_mask = (sel_mode == SM_THREAD? (SF_THREAD|SF_VISIT) : SF_VISIT); + register ARTICLE *ap = artp; - sp = ((ap = artp) ? ap->subj->next : first_subject); - for (; sp; sp = sp->next) { - if ((sp->flags & subj_mask) == subj_mask) { - if ((ap = subj_art(sp)) != Nullart) { - art = article_num(ap); - artp = ap; - return; - } - reread = FALSE; + sp = (ap? ap->subj : Nullsubj); + while ((sp = next_subj(sp, SF_VISIT)) != Nullsubj) { + if ((ap = subj_art(sp)) != Nullart) { + art = article_num(ap); + artp = ap; + return; } + reread = FALSE; } artp = Nullart; @@ -1089,20 +1101,17 @@ */ void -prev_subject() +visit_prev_thread() { register SUBJECT *sp; - register ARTICLE *ap; - int subj_mask = (sel_mode == SM_THREAD? (SF_THREAD|SF_VISIT) : SF_VISIT); + register ARTICLE *ap = artp; - sp = ((ap = artp) ? ap->subj->prev : last_subject); - for (; sp; sp = sp->prev) { - if ((sp->flags & subj_mask) == subj_mask) { - if ((ap = subj_art(sp)) != Nullart) { - art = article_num(ap); - artp = ap; - return; - } - reread = FALSE; + sp = (ap? ap->subj : Nullsubj); + while ((sp = prev_subj(sp, SF_VISIT)) != Nullsubj) { + if ((ap = subj_art(sp)) != Nullart) { + art = article_num(ap); + artp = ap; + return; } + reread = FALSE; } artp = Nullart; @@ -1338,8 +1347,4 @@ if (count && (!selected_only || (sp->flags & sel_mask))) { sp->flags |= SF_VISIT; - if (sel_mode == SM_THREAD) { - if ((ap = sp->thread) != NULL) - ap->subj->flags |= SF_VISIT; - } } } @@ -1479,5 +1484,5 @@ lp[1]->prev = lp[0]; if (sel_mode == SM_THREAD) { - if (lp[0]->thread == lp[1]->thread) + if (lp[0]->thread && lp[0]->thread == lp[1]->thread) lp[0]->thread_link = lp[1]; else { Index:rthread.h @@ -27,4 +27,6 @@ bool next_art_with_subj _((void)); bool prev_art_with_subj _((void)); +SUBJECT *next_subj _((SUBJECT*,int)); +SUBJECT *prev_subj _((SUBJECT*,int)); void select_article _((ARTICLE*,int)); @@ -40,5 +42,7 @@ void deselect_thread _((ARTICLE*)); void deselect_all _((void)); +void kill_arts_subject _((ARTICLE*,int)); void kill_subject _((SUBJECT*,int)); +void kill_arts_thread _((ARTICLE*,int)); void kill_thread _((ARTICLE*,int)); void kill_subthread _((ARTICLE*,int)); @@ -49,11 +53,12 @@ void clear_thread _((ARTICLE*)); void clear_subthread _((ARTICLE*)); -#define KF_UNSELECTED 0 -#define KF_ALL 1 -#define KF_KILLFILE 2 +#define KF_UNSELECTED 0 /* leave selected articles, no KILL file */ +#define KF_ALL 0x0001 /* Affect both selected and unselected */ +#define KF_KILLFILE 0x0002 /* Save the command to the KILL file */ + ARTICLE *subj_art _((SUBJECT*)); -void next_subject _((void)); -void prev_subject _((void)); +void visit_next_thread _((void)); +void visit_prev_thread _((void)); bool find_parent _((bool_int)); Index:sw.c @@ -22,7 +22,9 @@ #include "term.h" #include "ng.h" +#include "artstate.h" #include "intrp.h" #include "rt-page.h" #include "rt-util.h" +#include "charsubst.h" #include "INTERN.h" #include "sw.h" @@ -318,7 +320,21 @@ dont_filter_control = TRUE; break; + case 'J': + s++; + if (*s == '=') s++; + if (isdigit(*s)) { + change_join_subject_len(atoi(s)); + do { + s++; + } while (isdigit(*s)); + } else + change_join_subject_len(upordown? 30 : 0); + break; case 'k': kill_thru_kludge = upordown; break; + case 'K': + keep_the_group_static = upordown; + break; case 'l': muck_up_clear = upordown; @@ -336,4 +352,11 @@ case 'm': s++; + if (isdigit(*s)) { + marking_areas = atoi(s); + do { + s++; + } while (isdigit(*s)); + } else + marking_areas = HALFPAGE_MARKING; if (*s == '=') s++; if (!upordown) @@ -356,9 +379,9 @@ s++; if (*s == '=') s++; - if (*s <= '9' && *s >= '0') { + if (isdigit(*s)) { olden_days = atoi(s); do { s++; - } while (*s <= '9' && *s >= '0'); + } while (isdigit(*s)); } else olden_days = upordown; @@ -383,9 +406,30 @@ break; case 'p': - auto_select_postings = upordown; + s++; + if (*s == '=') s++; + if (!upordown) + auto_select_postings = 0; + else { + switch (*s) { + case '+': case '.': case 'p': + auto_select_postings = *s; + break; + default: + auto_select_postings = '.'; + break; + } + } break; case 'q': quickstart = upordown; break; +#ifdef CHARSUBST + case 'Q': + s++; + if (*s == '=') s++; + if (*s) + charsets = savestr(s); + break; +#endif case 'r': findlast = upordown; @@ -448,10 +492,10 @@ s++; if (*s == '=') s++; - if (*s <= '9' && *s >= '0') { + if (isdigit(*s)) { if ((max_tree_lines = atoi(s)) > 11) max_tree_lines = 11; do { s++; - } while (*s <= '9' && *s >= '0'); + } while (isdigit(*s)); } else max_tree_lines = 6; @@ -463,9 +507,9 @@ s++; if (*s == '=') s++; - if (*s <= '9' && *s >= '0') { + if (isdigit(*s)) { select_on = atoi(s); do { s++; - } while (*s <= '9' && *s >= '0'); + } while (isdigit(*s)); } else select_on = upordown; @@ -556,5 +600,10 @@ printf("%cI ", mp[append_unsub]); printf("%cj ", mp[dont_filter_control]); + if (join_subject_len) + printf("-J%d ", join_subject_len); + else + printf("+J "); printf("%ck ", mp[kill_thru_kludge]); + printf("%cK ", mp[keep_the_group_static]); printf("%cl ", mp[muck_up_clear]); #ifdef CLEAREOL @@ -562,5 +611,5 @@ #endif /* CLEAREOL */ if (marking) - printf("-m%c ",marking==UNDERLINE?'u':'s'); + printf("-m%d%c ",marking_areas,marking==UNDERLINE?'u':'s'); else printf("+m "); @@ -571,6 +620,12 @@ else printf("+o "); - printf("%cp ", mp[auto_select_postings]); + if (auto_select_postings) + printf("-p%c ", auto_select_postings); + else + printf("+p "); printf("%cq ", mp[quickstart]); +#ifdef CHARSUBST + printf("-Q%s ", charsets); +#endif printf("%cr ", mp[findlast]); if (countdown) Index:term.c @@ -189,5 +189,6 @@ TI = Tgetstr("ti"); /* initialize display */ TE = Tgetstr("te"); /* reset display */ - HO = Tgetstr("ho"); /* home cursor if no CM */ + HO = Tgetstr("ho"); /* home cursor */ + IL = Tgetstr("al"); /* insert (add) line */ CM = Tgetstr("cm"); /* cursor motion */ if (*CM || *HO) @@ -303,21 +304,21 @@ */ strcpy(lbuf,Tgetstr("ku")); /* up */ - /* '(' at article or pager, 'p' otherwise */ - if (strlen(lbuf)>1) - set_macro(lbuf,"%(%m=[ap]?\\(:p)"); + /* '(' at article or pager, '[' in thread sel, 'p' otherwise */ + if ((int)strlen(lbuf) > 1) + set_macro(lbuf,"%(%m=[ap]?\\(:%(%m=t?[:p))"); strcpy(lbuf,Tgetstr("kd")); /* down */ - /* ')' at article or pager, 'n' otherwise */ - if (strlen(lbuf)>1) - set_macro(lbuf,"%(%m=[ap]?\\):n)"); + /* ')' at article or pager, ']' in thread sel, 'n' otherwise */ + if ((int)strlen(lbuf) > 1) + set_macro(lbuf,"%(%m=[ap]?\\):%(%m=t?]:n))"); strcpy(lbuf,Tgetstr("kl")); /* left */ /* '[' at article or pager, '<' otherwise */ - if (strlen(lbuf)>1) + if ((int)strlen(lbuf) > 1) set_macro(lbuf,"%(%m=[ap]?\\[:<)"); strcpy(lbuf,Tgetstr("kr")); /* right */ /* CR at newsgroups, ']' at article or pager, '>' otherwise */ - if (strlen(lbuf)>1) + if ((int)strlen(lbuf) > 1) set_macro(lbuf,"%(%m=n?^j:%(%m=[ap]?\\]:>))"); } @@ -329,4 +330,8 @@ char tmpbuf[1024]; + /* set up the Xterm mouse sequence */ + sprintf(tmpbuf,"\033[M"); /* enter mouse escape sequence */ + set_macro(tmpbuf,"\003"); + if (auto_arrow_macros) arrow_macros(tmpbuf); @@ -662,8 +667,8 @@ quoteone = TRUE; } -#ifdef cray - } while (*s != '\r'); /* till a newline (not echoed) */ +#if defined(__bsdi__) || defined(cray) + } while (*s != '\r' && *s != '\n'); /* until CR or NL (not echoed) */ #else - } while (*s != '\n'); /* till a newline (not echoed) */ + } while (*s != '\n'); /* until a newline (not echoed) */ #endif *s = '\0'; /* terminate the string nicely */ @@ -1037,7 +1042,8 @@ void -in_char(prompt, newmode) +in_char(prompt, newmode, dflt) char *prompt; char_int newmode; +char *dflt; { char oldmode = mode; @@ -1045,5 +1051,5 @@ reask_in_char: unflush_output(); /* disable any ^O in effect */ - fputs(prompt,stdout); + printf("%s [%s] ", prompt, dflt); fflush(stdout); eat_typeahead(); @@ -1054,4 +1060,5 @@ goto reask_in_char; /* give them a prompt again */ } + setdef(buf,dflt); mode = oldmode; } @@ -1333,8 +1340,9 @@ { #ifdef USETITE - if (TI && *TI) + if (TI && *TI) { tputs(TI,1,putchr); + fflush(stdout); + } #endif - return; } @@ -1343,7 +1351,28 @@ { #ifdef USETITE - if (TE && *TE) + if (TE && *TE) { tputs(TE,1,putchr); + fflush(stdout); + } #endif - return; +} + +void +xmouse_on() +{ + if (use_xterm_mouse && !xmouse_status) { + printf("\033[?1001s"); /* save old highlight mouse tracking */ + printf("\033[?1000h"); /* enable mouse tracking */ + xmouse_status = TRUE; + } +} + +void +xmouse_off() +{ + if (use_xterm_mouse && xmouse_status) { + printf("\033[?10001"); /* disable mouse tracking */ + printf("\033[?1001r"); /* restore old highlight mouse tracking */ + xmouse_status = FALSE; + } } Index:term.h @@ -145,4 +145,5 @@ EXT char *CM INIT(Nullch); /* cursor motion */ EXT char *HO INIT(Nullch); /* home cursor */ +EXT char *IL INIT(Nullch); /* insert line */ #ifdef CLEAREOL EXT char *CD INIT(Nullch); /* clear to end of display */ @@ -187,4 +188,5 @@ #define un_standout() tputs(SE,1,putchr) FLUSH #define up_line() tputs(UP,1,putchr) FLUSH +#define insert_line() tputs(IL,1,putchr) FLUSH #define carriage_return() tputs(CR,1,putchr) FLUSH #define dingaling() tputs(VB,1,putchr) FLUSH @@ -194,6 +196,9 @@ EXT int page_line INIT(1); /* line number for paging in - print_line (origin 1) */ + print_line (origin 1) */ +EXT bool use_xterm_mouse INIT(FALSE); +EXT bool xmouse_status INIT(FALSE); /* TRUE: mouse is on */ + void term_init _((void)); void term_set _((char*)); @@ -224,5 +229,5 @@ int get_anything _((void)); int pause_getcmd _((void)); -void in_char _((char*,char_int)); +void in_char _((char*,char_int,char*)); void in_answer _((char*,char_int)); int print_lines _((char*,int)); @@ -237,2 +242,5 @@ Signal_t winch_catcher _((int)); #endif /* SIGWINCH */ +void arrow_macros _((char*)); +void xmouse_on _((void)); +void xmouse_off _((void)); Index:trn-artchk.c @@ -0,0 +1,188 @@ +/* $Id: trn-artchk.c,v 3.5 1993/04/18 03:09:32 davison Trn $ +*/ +/* The authors make no claims as to the fitness or correctness of this software + * for any use whatsoever, and it is provided as is. Any use of this software + * is at the user's own risk. + */ + +/* A program to check an article's validity and print warnings if problems +** are found. +** +** Usage: trn-artchk
+*/ + +#include "EXTERN.h" +#include "common.h" +#include "config.h" + +#define MAXNGS 100 + +int +main(argc, argv) +int argc; +char *argv[]; +{ + FILE *fp, *fp_active = NULL, *fp_ng = NULL; + char buff[LBUFLEN], *cp, *cp2; + char *ngptrs[MAXNGS]; + int nglens[MAXNGS]; + int foundactive[MAXNGS]; + int i, col, max_col_len, line_num = 0, ngcnt = 0, ngleft; + int found_newsgroups = 0; + + if (argc != 5 || !(max_col_len = atoi(argv[2]))) { + fprintf(stderr, "\ +Usage: trn-artchk
\n"); + exit(1); + } + + if ((fp = fopen(argv[1], "r")) == NULL) { + fprintf(stderr, "trn-artchk: unable to open article `%s'.\n", argv[1]); + exit(1); + } + + /* Check the header for proper format and report on the newsgroups */ + while (fgets(buff, LBUFLEN, fp)) { + line_num++; + buff[strlen(buff)-1] = '\0'; + if (!*buff) + break; + if (*buff == ' ' || *buff == '\t') + continue; + if (!(cp = index(buff, ':'))) { + printf("\nERROR: line %d is an invalid header line:\n%s\n", + line_num, buff); + break; + } + if (cp[1] != ' ' && cp[1] != '\0') { + printf("\n\ +ERROR: header on line %d does not have a space after the colon:\n%s\n", + line_num, buff); + } + if (cp - buff == 10 && strnEQ(buff, "Newsgroups", 10)) { + found_newsgroups = 1; + for (cp = buff + 11; *cp == ' '; cp++) + ; + if (index(cp, ' ')) { + printf("\n\ +ERROR: the \"Newsgroups:\" line has spaces in it that MUST be removed. The\n\ +only allowable space is the one separating the colon (:) from the contents.\n\ +Use a comma (,) to separate multiple newsgroup names.\n"); + continue; + } + while (*cp) { + if (!(cp2 = index(cp, ','))) + cp2 = cp + strlen(cp); + else + *cp2++ = '\0'; + if (ngcnt < MAXNGS) { + nglens[ngcnt] = strlen(cp); + foundactive[ngcnt] = 0; + ngptrs[ngcnt] = malloc(nglens[ngcnt]+1); + if (!ngptrs[ngcnt]) { + fprintf(stderr,"Out of memory.\n"); + exit(1); + } + strcpy(ngptrs[ngcnt], cp); + ngcnt++; + } + cp = cp2; + } + if (!ngcnt) { + printf("\n\ +ERROR: the \"Newsgroups:\" line lists no newsgroups.\n"); + continue; + } + } + } + if (!found_newsgroups) { + printf("\nERROR: the \"Newsgroups:\" line is missing from the header.\n"); + } + + /* Check the body of the article for long lines */ + while (fgets(buff, LBUFLEN, fp)) { + line_num++; + buff[strlen(buff)-1] = '\0'; + col = 0; + for (cp = buff; *cp; cp++) { + if (*cp == '\t') + col += 8 - (col%8); + else + col++; + } + if (col > max_col_len) { + printf("\n\ +Warning: posting exceeds %d columns. Line %d is the first long one:\n%s\n", + max_col_len, line_num, buff); + break; + } + } + if (ngcnt) { + struct stat st; + if (stat(argv[3], &st) != -1 && st.st_size > 0) + fp_ng = fopen(argv[3], "r"); + if (stat(argv[4], &st) != -1 && st.st_size > 0) + fp_active = fopen(argv[4], "r"); + } + if (ngcnt && (fp_ng != NULL || fp_active != NULL)) { + /* Print a note about each newsgroup */ + printf("\nYour article's newsgroup%s:\n", ngcnt == 1? "" : "s"); + if (fp_active == NULL) { + for (i = 0; i < ngcnt; i++) { + foundactive[i] = 1; + } + } else { + ngleft = ngcnt; + while (fgets(buff, LBUFLEN, fp_active)) { + if (!ngleft) + break; + for (i = 0; i < ngcnt; i++) { + if (!foundactive[i]) { + if ((buff[nglens[i]] == '\t' || buff[nglens[i]] == ' ') + && strnEQ(ngptrs[i], buff, nglens[i])) { + foundactive[i] = 1; + ngleft--; + } + } + } + } + fclose(fp_active); + } + if (fp_ng != NULL) { + ngleft = ngcnt; + while (fgets(buff, LBUFLEN, fp_ng)) { + if (!ngleft) + break; + for (i = 0; i < ngcnt; i++) { + if (foundactive[i] && ngptrs[i]) { + if ((buff[nglens[i]] == '\t' || buff[nglens[i]] == ' ') + && strnEQ(ngptrs[i], buff, nglens[i])) { + cp = &buff[nglens[i]]; + *cp++ = '\0'; + while (*cp == ' ' || *cp == '\t') + cp++; + if (cp[0] == '?' && cp[1] == '?') + cp = "[no description available]\n"; + printf("%-23s %s", buff, cp); + free(ngptrs[i]); + ngptrs[i] = 0; + ngleft--; + } + } + } + } + fclose(fp_ng); + } + for (i = 0; i < ngcnt; i++) { + if (!foundactive[i]) { + printf("%-23s ** invalid news group -- check spelling **\n", + ngptrs[i]); + free(ngptrs[i]); + } else if (ngptrs[i]) { + printf("%-23s [no description available]\n", ngptrs[i]); + free(ngptrs[i]); + } + } + } + return 0; +} Index:trn.1 @@ -34,4 +34,5 @@ .ie n \{\ .ds -- \(*W- +.ds qq "" .if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch .if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch @@ -259,8 +260,7 @@ Scan forward for a newsgroup matching .IR pattern . -Patterns do globbing like filenames, i.\|e., use ? to match a single -character, * to match any sequence of characters, and [] to specify a list -of characters to match. -(\*(L"all\*(R" may be used as a synonym for \*(L"*\*(R".) +Patterns do globbing like filenames, i.\|e., use * to match any sequence +of characters, and [] to specify a list of characters to match. +Use . to match a single character. Unlike normal filename globbing, newsgroup-searching is not anchored to the front and back of the filename, i.\|e. \*(L"/ski\*(R" will find @@ -676,4 +676,6 @@ .Ip "number" 8 Go to the numbered article. +.Ip _C 8 +Switch to next available charset conversion. .Ip "range{,range}:command{:command}" 8 Apply a set of commands to a set of articles. @@ -737,5 +739,5 @@ .I pattern in the indicated -.Ip header . +.I header. Because we scan the entire string up to the end of the modifiers, this modifier must be the last one. @@ -768,7 +770,8 @@ Apply the commands listed to articles matching the search command (possibly with h, a, or r modifiers). -Applicable commands include \*(L'm\*(R' (mark as unread), \*(L'M\*(R' -(mark as read-until-exit), \*(L'j\*(R' (mark as read), \*(L"s dest\*(R" -(save to a destination), \*(L"e dir\*(R" (extract to directory), +Applicable commands include \*(L'm\*(R' (mark as UNread), \*(L'M\*(R' +(mark as read-until-exit), \*(L'j\*(R' (junk -- mark as read in all groups), +\&\*(L'x\*(R' (mark as read in this group), +\&\*(L"s dest\*(R" (save to a dest), \*(L"e dir\*(R" (extract to dir), \&\*(L"!command\*(R" (shell escape), \*(L"=\*(R" (print the subject), \&\*(L'+\*(R' (select the article), \*(L'-\*(R' deselect the article, @@ -878,4 +881,6 @@ (See \*(L'F\*(R' command below). The YOUSAID environment variable controls the format of the attribution line. +.Ip ^F 8 +Forward the current article. .Ip f 8 Submit a follow-up article. @@ -1092,4 +1097,6 @@ .Ip b 8 Back up one page. +.Ip _C 8 +Switch to next available charset conversion. .Ip t 8 Display the entire article tree, including its associated subjects, and @@ -1224,5 +1231,5 @@ to your liking. (You might like to know that the author swears by -\*(L"\-x6ms \-e \+m \-S -XX -N -B -p\*(R".) +\*(L"\-x6ms \+e \-mu \-S -XX -N -B -p\*(R".) These options may be set on the command line, via the TRNINIT environment variable, via a file pointed to by the TRNINIT variable, or @@ -1290,11 +1297,11 @@ .TP 5 .B \-d -sets the default save directory to something other than ~/News. +sets your private news directory to something other than ~/News. The directory name will be globbed (via csh) if necessary (and if possible). -Articles saved by -.I trn -may be placed in the save directory or in a subdirectory thereof depending -on the command that you give and the state of the environment variables -SAVEDIR and SAVENAME. +The value of SAVEDIR (where articles are saved) is initially set to this +directory, but is often manipulated via the +.B \-/ +option or by manipulating SAVEDIR directly (perhaps via the memorized +commands (the KILL file) for a group. Any KILL files (see the K command in the Article Selection section) also reside in this directory and its subdirectories, by default. @@ -1424,4 +1431,14 @@ forces trn to leave control characters unmolested in messages. .TP 5 +.B \-J{} +causes trn to join similar subjects into a common thread if they are the +same up to the indicated number of characters (the default is 30). +You can turn this on and off for specific groups by putting the following +lines into your kill file for the group(s): +.Sp +&-J30 +.br +X&+J +.TP 5 .B \-k tells trn to ignore the THRU line when processing selection searches @@ -1432,4 +1449,15 @@ if you want to turn it off. .TP 5 +.B \-K +is used to keep a trn from checking for new news while you're in the group. +Use this when your kill-file processing is so slow that you don't want the +group to expand while you're reading. +If you only want specific groups to be affected, put these lines into +your kill file for the group(s): +.Sp +&-K +.br +X&+K +.TP 5 .B \-l disables the clearing of the screen at the beginning of each @@ -1494,9 +1522,16 @@ \*(L"-Oas\*(R". .TP 5 -.B \-p +.B \-p{opt} tells trn to auto-select your postings and their replies as it encounters them in the various groups you read. -For each article it finds it executes the command \*(L"T.\*(R" on it (which -tells trn to memorize the auto-selection of this article and all its replies). +The optional parameter is either a \*(L'.\*(R', \*(L'p\*(R', or \*(L'+\*(R' +(it defaults to \*(L'.\*(R' if omitted) and affects what command trn should +execute when it encounters your postings. +The default is to execute the command \*(L"T.\*(R" on each of your postings +which tells trn to memorize the auto-selection of this article and all its +replies. +Using \-pp tells trn to use the same command, but start the selection with +the parent article, so that you see any other replies to the same article. +Using \-p+ tells trn to select the whole thread that contains your reply. .TP 5 .B \-q @@ -1504,4 +1539,10 @@ .IR trn . .TP 5 +.B \-Q +defines the set of available charset conversions. This can be useful +to restrict the available conversions to those your terminal can handle +and/or to specify an alternate default. The first element of this set +is taken as default for each article. +.TP 5 .B \-r causes @@ -1647,5 +1688,5 @@ .TP 5 .B \-z -sets the minimum number of minutes that must elaps before the active file +sets the minimum number of minutes that must elapse before the active file is refetched to look for new articles. A value of 0 or using +z turns this off. @@ -1711,4 +1752,40 @@ Up to 10 alternatives may given in a pattern, separated by \e|, with the caveat that \e(\ ...\ \e|\ ...\ \e) is illegal. +.Sh "Characterset conversions" +.I trn +can use character set conversions when displaying articles. This helps +users in non-English-speaking countries to display special characters +on 7-bit displays. +.I trn +assumes that articles use the ISO-8859-1 character set and converts +the special characters (e.g., \*(L"umlauts\*(R") to a string of ASCII +characters. +Currently the following conversions are supported (see the +.I \-Q +option): +.TP 5 +.B p +Plain. No change. This is the default. +.TP 5 +.B a +ISO->ASCII. Special characters are mapped to ASCII, e.g. the umlaut-o +character becomes oe. +.TP 5 +.B m +ISO->ASCII monospaced. Special characters are mapped to exactly one +similar-looking ASCII character, e.g. umlaut-o becomes o. Used where +correct spacing is more important than accuracy. +.TP 5 +.B t +TeX->ISO. Assuming your display can handle the ISO-8859-1 charset, +.I trn +transforms umlauts in the TeX notation, which is commonly used in +Germany, to real ISO characters, e.g. "a becomes umlaut-a. +.PP +The selected conversion, if different from +.BR p , +will be displayed in the article level and pager prompt. The +conversion is also used when including original articles in a reply or +followup. It is not used when saving articles to files. .Sh "Interpretation and Interpolation" Many of the strings that @@ -1831,4 +1908,6 @@ .Ip %P 8 Public news spool directory, normally /usr/spool/news on systems that don't use NNTP. +.Ip %q 8 +The value of the last \*(L"quoted\*(R" input string (see the %" interp). .Ip %r 8 Last reference on references line of current article (parent article id). @@ -1927,8 +2006,14 @@ \*(L"%\\C\*(R" produces \*(L"rec\\.humor\*(R". .PP -Inserting \*(L"'\*(R" will single-quote the entire result and insert a -backslash before any single-quotes in the result itself: -\*(L"%'s\*(R" might produce \*(L"'I\\'m a subject'\*(R". +Inserting \*(L"'\*(R" will insert a backslash before any single-quotes in +the result, suitable for enclosing in single-quotes and sending to a shell: +\*(L"'%'s'\*(R" might produce \*(L"'I'\\''m a subject'\*(R". +.PP +Inserting \*(L">\*(R" will strip out just the address portion +of an address string such as the From line. .PP +Inserting \*(L")\*(R" will strip out just the comment (real name) portion +of an address string such as the From line. +.PP Inserting \*(L":FMT\*(R" will format the result according to the printf-style FMT string: \*(L"%:-50.50s\*(R" left-justifies the subject into a 50 @@ -2025,4 +2110,36 @@ .Sp %C #%a%(%Z=^0$?%(%U!=^0$? (%U more\e)): (%U + %v more\e)) +.Ip "FORWARDHEADER (%)" 8 +The format of the header file for forwarding messages. +See also FORWARDPOSTER. +.Sp +Default: +.Sp +To: +.br +Subject: %(%i=^$?:[subject] (fwd\e\e) +.br +%(%{REPLYTO}=^$?:Reply-To: %{REPLYTO} +.br +)Newsgroups: %n +.br +In-Reply-To: %i) +.br +%(%[references]=^$?:References: %[references] +.br +)Organization: %o +.br +Cc: +.br +Bcc: \en\en +.Ip "FORWARDPOSTER (~)" 8 +The shell command to be used by the forward command (^F) +in order to allow you to edit and deliver the file. +.I trn +will not itself call upon an editor for replies \*(-- this +is a function of the program referenced by FORWARDPOSTER. +See also FORWARDHEADER and MAILPOSTER. +.Sp +Default: QUOTECHARS=%I Rnmail \-h %h .Ip HIDELINE 8 If defined, contains a regular expression which matches article lines to @@ -2100,9 +2217,11 @@ Subject: %(%i=^$?:Re: %S .br -Newsgroups: %n +%(%{REPLYTO}=^$?:Reply-To: %{REPLYTO} .br +)Newsgroups: %n +.br In-Reply-To: %i) .br -%(%[references]!=^$?References\\: %[references] +%(%[references]=^$?:References: %[references] .br )Organization: %o @@ -2116,6 +2235,5 @@ .I trn will not itself call upon an editor for replies \*(-- this -is a function of the program called by -.IR trn . +is a function of the program referenced by MAILPOSTER. See also MAILHEADER. .Sp @@ -2195,8 +2313,4 @@ .Sp Default: QUOTECHARS=%I Pnews \-h %h -.Ip NEWSRC 8 -Your newsgroup subscription list. -.Sp -Default: $HOME/.newsrc .Ip NNTPSERVER 8 The hostname of your NNTPSERVER. @@ -2378,4 +2492,16 @@ .Sp Default: $EDITOR +.Ip XTERMMOUSE 8 +If you set this variable to \*(L'y\*(R' (yes), trn will enable the use of the +xterm mouse in the selector if you are using an xterm. +If you set it to \*(L'a\*(R' (always), trn will assume you have an xterm. +Once enabled left-clicking on an item selects it while middle-clicking an +item will move to that item. +If you click the top (header) line of the selector it moves up a page. +If you click the bottom (footer) line of the selector it executes the +default command for the page (left click) or goes down a page (middle +click). +You can also use the right mouse button to move up or down a page by +clicking in the upper-half or lower-half of the screen, respectively. .Ip "YOUSAID (%)" 8 Gives the format of the attribution line in front of the quoted article @@ -2605,4 +2731,6 @@ .br Regular expression routines are borrowed from emacs, by James Gosling. +.br +Hashing routines are modified versions from Geoffrey Collyer. .SH FILES .Ip "%./.newsrc" 1.25i Index:trn.c @@ -267,7 +267,16 @@ special = TRUE; /* don't skip it if toread==0 */ break; - case 'q': case 'Q': case 'x': /* quit? */ - oh_for_the_good_old_days = (*buf == 'x'); + case 'x': + putchar('\n'); + in_char("Confirm: exit and abandon .newsrc changes?", + 'A', "yn"); putchar('\n') FLUSH; + if (*buf != 'y') + break; + oh_for_the_good_old_days = TRUE; + printf("\nMoving changed version to '.newnewsrc'."); + /* FALL THROUGH */ + case 'q': case 'Q': /* quit? */ + putchar('\n') FLUSH; ng = nextrcline+1; /* satisfy */ retry = FALSE; /* loop conditions */ @@ -441,11 +450,11 @@ #ifdef VERBOSE IF(verbose) - in_char("\nAbandon changes to current newsgroup? [yn] ", 'B'); + in_char("\nAbandon changes to current newsgroup?", + 'B', "yn"); ELSE #endif #ifdef TERSE - in_char("\nAbandon? [ynh] ", 'B'); + in_char("\nAbandon?", 'B', "ynh"); #endif - setdef(buf,"y"); #ifdef VERIFY printcmd(); Index:util.c @@ -293,35 +293,34 @@ char * -get_a_line(original_buffer,buffer_length,fp) -char *original_buffer; +get_a_line(buffer,buffer_length,realloc_ok,fp) +char *buffer; register int buffer_length; +bool_int realloc_ok; FILE *fp; { register int bufix = 0; register int nextch; - register char *some_buffer_or_other = original_buffer; do { if (bufix >= buffer_length) { buffer_length *= 2; - if (some_buffer_or_other == original_buffer) { - /* currently static? */ - some_buffer_or_other = safemalloc((MEM_SIZE)buffer_length+1); - strncpy(some_buffer_or_other,original_buffer,buffer_length/2); - /* so we must copy it */ + if (realloc_ok) { /* just grow in place, if possible */ + buffer = saferealloc(buffer,(MEM_SIZE)buffer_length+1); } - else { /* just grow in place, if possible */ - some_buffer_or_other = saferealloc(some_buffer_or_other, - (MEM_SIZE)buffer_length+1); + else { + char *tmp = safemalloc((MEM_SIZE)buffer_length+1); + strncpy(tmp,buffer,buffer_length/2); + buffer = tmp; + realloc_ok = TRUE; } } if ((nextch = getc(fp)) == EOF) return Nullch; - some_buffer_or_other[bufix++] = (char) nextch; + buffer[bufix++] = (char)nextch; } while (nextch && nextch != '\n'); - some_buffer_or_other[bufix] = '\0'; + buffer[bufix] = '\0'; len_last_line_got = bufix; buflen_last_line_got = buffer_length; - return some_buffer_or_other; + return buffer; } @@ -360,5 +359,5 @@ s = end; for (;;) { - if (stat(dirname,&filestat) >= 0 && (filestat.st_mode & S_IFDIR)) { + if (stat(dirname,&filestat) >= 0 && S_ISDIR(filestat.st_mode)) { /* does this much exist as a dir? */ *s = '/'; /* mark this as existing */ @@ -488,8 +487,8 @@ { if (*dflt == '^' && isupper(dflt[1])) - *buffer = Ctl(dflt[1]); + pushchar(Ctl(dflt[1])); else - *buffer = *dflt; - lastchar = *buffer; + pushchar(*dflt); + getcmd(buffer); } } Index:util.h @@ -18,5 +18,5 @@ EXT int len_last_line_got INIT(0); /* strlen of some_buf after */ - /* some_buf = get_a_line(bufptr,buffersize,fp) */ + /* some_buf = get_a_line(bufptr,bufsize,realloc,fp) */ EXT MEM_SIZE buflen_last_line_got INIT(0); @@ -38,5 +38,5 @@ #endif char *getwd _((char*)); -char *get_a_line _((char*,int,FILE*)); +char *get_a_line _((char*,int,bool_int,FILE*)); char *savestr _((char*)); int makedir _((char*,int)); Index:uudecode.c @@ -373,5 +373,5 @@ bp += 4; } - if (fwrite(outl, 1, blen, decode_fp) <= 0) { + if ((int)fwrite(outl, 1, blen, decode_fp) <= 0) { printf("Error on writing decoded file\n"); return OTHER_ERROR; ---8<------8<------8<------8<---cut here--->8------>8------>8------>8---